diff --git a/rtc_base/asyncinvoker-inl.h b/rtc_base/asyncinvoker-inl.h index 073d5bffac..0d546b1f04 100644 --- a/rtc_base/asyncinvoker-inl.h +++ b/rtc_base/asyncinvoker-inl.h @@ -49,13 +49,13 @@ template class FireAndForgetAsyncClosure : public AsyncClosure { public: explicit FireAndForgetAsyncClosure(AsyncInvoker* invoker, - const FunctorT& functor) - : AsyncClosure(invoker), functor_(functor) {} + FunctorT&& functor) + : AsyncClosure(invoker), functor_(std::forward(functor)) {} virtual void Execute() { functor_(); } private: - FunctorT functor_; + typename std::decay::type functor_; }; } // namespace rtc diff --git a/rtc_base/asyncinvoker.h b/rtc_base/asyncinvoker.h index 523e9a95d1..74e8689b84 100644 --- a/rtc_base/asyncinvoker.h +++ b/rtc_base/asyncinvoker.h @@ -97,10 +97,11 @@ class AsyncInvoker : public MessageHandler { template void AsyncInvoke(const Location& posted_from, Thread* thread, - const FunctorT& functor, + FunctorT&& functor, uint32_t id = 0) { std::unique_ptr closure( - new FireAndForgetAsyncClosure(this, functor)); + new FireAndForgetAsyncClosure( + this, std::forward(functor))); DoInvoke(posted_from, thread, std::move(closure), id); } @@ -109,11 +110,12 @@ class AsyncInvoker : public MessageHandler { template void AsyncInvokeDelayed(const Location& posted_from, Thread* thread, - const FunctorT& functor, + FunctorT&& functor, uint32_t delay_ms, uint32_t id = 0) { std::unique_ptr closure( - new FireAndForgetAsyncClosure(this, functor)); + new FireAndForgetAsyncClosure( + this, std::forward(functor))); DoInvokeDelayed(posted_from, thread, std::move(closure), delay_ms, id); } @@ -188,12 +190,13 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> { // immediately. Returns false if the thread has died. template bool AsyncInvoke(const Location& posted_from, - const FunctorT& functor, + FunctorT&& functor, uint32_t id = 0) { CritScope cs(&crit_); if (thread_ == nullptr) return false; - invoker_.AsyncInvoke(posted_from, thread_, functor, id); + invoker_.AsyncInvoke( + posted_from, thread_, std::forward(functor), id); return true; } @@ -201,14 +204,14 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> { // completion. Returns immediately. Returns false if the thread has died. template bool AsyncInvokeDelayed(const Location& posted_from, - const FunctorT& functor, + FunctorT&& functor, uint32_t delay_ms, uint32_t id = 0) { CritScope cs(&crit_); if (thread_ == nullptr) return false; - invoker_.AsyncInvokeDelayed(posted_from, thread_, - functor, delay_ms, id); + invoker_.AsyncInvokeDelayed( + posted_from, thread_, std::forward(functor), delay_ms, id); return true; } @@ -217,7 +220,7 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> { template bool AsyncInvoke(const Location& posted_from, const Location& callback_posted_from, - const FunctorT& functor, + FunctorT&& functor, void (HostT::*callback)(ReturnT), HostT* callback_host, uint32_t id = 0) { @@ -225,8 +228,8 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> { if (thread_ == nullptr) return false; invoker_.AsyncInvoke( - posted_from, callback_posted_from, thread_, functor, callback, - callback_host, id); + posted_from, callback_posted_from, thread_, + std::forward(functor), callback, callback_host, id); return true; } @@ -235,7 +238,7 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> { template bool AsyncInvoke(const Location& posted_from, const Location& callback_posted_from, - const FunctorT& functor, + FunctorT&& functor, void (HostT::*callback)(), HostT* callback_host, uint32_t id = 0) { @@ -243,8 +246,8 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> { if (thread_ == nullptr) return false; invoker_.AsyncInvoke( - posted_from, callback_posted_from, thread_, functor, callback, - callback_host, id); + posted_from, callback_posted_from, thread_, + std::forward(functor), callback, callback_host, id); return true; } diff --git a/rtc_base/thread_unittest.cc b/rtc_base/thread_unittest.cc index 5f00064eb1..01022e9823 100644 --- a/rtc_base/thread_unittest.cc +++ b/rtc_base/thread_unittest.cc @@ -186,6 +186,16 @@ struct FunctorC { return 24; } }; +struct FunctorD { + public: + explicit FunctorD(AtomicBool* flag) : flag_(flag) {} + FunctorD(FunctorD&&) = default; + FunctorD& operator=(FunctorD&&) = default; + void operator()() { if (flag_) *flag_ = true; } + private: + AtomicBool* flag_; + RTC_DISALLOW_COPY_AND_ASSIGN(FunctorD); +}; // See: https://code.google.com/p/webrtc/issues/detail?id=2409 TEST(ThreadTest, DISABLED_Main) { @@ -441,6 +451,18 @@ TEST_F(AsyncInvokeTest, FireAndForget) { thread->Stop(); } +TEST_F(AsyncInvokeTest, NonCopyableFunctor) { + AsyncInvoker invoker; + // Create and start the thread. + auto thread = Thread::CreateWithSocketServer(); + thread->Start(); + // Try calling functor. + AtomicBool called; + invoker.AsyncInvoke(RTC_FROM_HERE, thread.get(), FunctorD(&called)); + EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); + thread->Stop(); +} + TEST_F(AsyncInvokeTest, KillInvokerDuringExecute) { // Use these events to get in a state where the functor is in the middle of // executing, and then to wait for it to finish, ensuring the "EXPECT_FALSE" @@ -602,6 +624,14 @@ TEST_F(GuardedAsyncInvokeTest, FireAndForget) { EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); } +TEST_F(GuardedAsyncInvokeTest, NonCopyableFunctor) { + GuardedAsyncInvoker invoker; + // Try calling functor. + AtomicBool called; + EXPECT_TRUE(invoker.AsyncInvoke(RTC_FROM_HERE, FunctorD(&called))); + EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); +} + TEST_F(GuardedAsyncInvokeTest, Flush) { GuardedAsyncInvoker invoker; AtomicBool flag1;