| Index: webrtc/rtc_base/thread_unittest.cc
|
| diff --git a/webrtc/rtc_base/thread_unittest.cc b/webrtc/rtc_base/thread_unittest.cc
|
| index a8c20d1b772699df4a782cc86fc0e5170c1bd404..e7701e84b38e4ea54fb76099c336bd7b21b24745 100644
|
| --- a/webrtc/rtc_base/thread_unittest.cc
|
| +++ b/webrtc/rtc_base/thread_unittest.cc
|
| @@ -458,19 +458,20 @@ TEST_F(AsyncInvokeTest, KillInvokerDuringExecute) {
|
| thread->Start();
|
| volatile bool invoker_destroyed = false;
|
| {
|
| + auto functor = [&functor_started, &functor_continue, &functor_finished,
|
| + &invoker_destroyed] {
|
| + functor_started.Set();
|
| + functor_continue.Wait(Event::kForever);
|
| + rtc::Thread::Current()->SleepMs(kWaitTimeout);
|
| + EXPECT_FALSE(invoker_destroyed);
|
| + functor_finished.Set();
|
| + };
|
| AsyncInvoker invoker;
|
| - invoker.AsyncInvoke<void>(RTC_FROM_HERE, thread.get(),
|
| - [&functor_started, &functor_continue,
|
| - &functor_finished, &invoker_destroyed] {
|
| - functor_started.Set();
|
| - functor_continue.Wait(Event::kForever);
|
| - rtc::Thread::Current()->SleepMs(kWaitTimeout);
|
| - EXPECT_FALSE(invoker_destroyed);
|
| - functor_finished.Set();
|
| - });
|
| + invoker.AsyncInvoke<void>(RTC_FROM_HERE, thread.get(), functor);
|
| functor_started.Wait(Event::kForever);
|
|
|
| - // Allow the functor to continue and immediately destroy the invoker.
|
| + // Destroy the invoker while the functor is still executing (doing
|
| + // SleepMs).
|
| functor_continue.Set();
|
| }
|
|
|
| @@ -481,6 +482,37 @@ TEST_F(AsyncInvokeTest, KillInvokerDuringExecute) {
|
| functor_finished.Wait(Event::kForever);
|
| }
|
|
|
| +// Variant of the above test where the async-invoked task calls AsyncInvoke
|
| +// *again*, for the thread on which the AsyncInvoker is currently being
|
| +// destroyed. This shouldn't deadlock or crash; this second invocation should
|
| +// just be ignored.
|
| +TEST_F(AsyncInvokeTest, KillInvokerDuringExecuteWithReentrantInvoke) {
|
| + Event functor_started(false, false);
|
| + // Flag used to verify that the recursively invoked task never actually runs.
|
| + bool reentrant_functor_run = false;
|
| +
|
| + Thread* main = Thread::Current();
|
| + Thread thread;
|
| + thread.Start();
|
| + {
|
| + AsyncInvoker invoker;
|
| + auto reentrant_functor = [&reentrant_functor_run] {
|
| + reentrant_functor_run = true;
|
| + };
|
| + auto functor = [&functor_started, &invoker, main, reentrant_functor] {
|
| + functor_started.Set();
|
| + Thread::Current()->SleepMs(kWaitTimeout);
|
| + invoker.AsyncInvoke<void>(RTC_FROM_HERE, main, reentrant_functor);
|
| + };
|
| + // This queues a task on |thread| to sleep for |kWaitTimeout| then queue a
|
| + // task on |main|. But this second queued task should never run, since the
|
| + // destructor will be entered before it's even invoked.
|
| + invoker.AsyncInvoke<void>(RTC_FROM_HERE, &thread, functor);
|
| + functor_started.Wait(Event::kForever);
|
| + }
|
| + EXPECT_FALSE(reentrant_functor_run);
|
| +}
|
| +
|
| TEST_F(AsyncInvokeTest, Flush) {
|
| AsyncInvoker invoker;
|
| AtomicBool flag1;
|
|
|