Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: webrtc/rtc_base/thread_unittest.cc

Issue 2885143005: Fixing race between ~AsyncInvoker and ~AsyncClosure, using ref-counting. (Closed)
Patch Set: Only clear current thread's message queue in destructor loop Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 // executing, and then to wait for it to finish, ensuring the "EXPECT_FALSE" 451 // executing, and then to wait for it to finish, ensuring the "EXPECT_FALSE"
452 // is run. 452 // is run.
453 Event functor_started(false, false); 453 Event functor_started(false, false);
454 Event functor_continue(false, false); 454 Event functor_continue(false, false);
455 Event functor_finished(false, false); 455 Event functor_finished(false, false);
456 456
457 auto thread = Thread::CreateWithSocketServer(); 457 auto thread = Thread::CreateWithSocketServer();
458 thread->Start(); 458 thread->Start();
459 volatile bool invoker_destroyed = false; 459 volatile bool invoker_destroyed = false;
460 { 460 {
461 auto functor = [&functor_started, &functor_continue, &functor_finished,
462 &invoker_destroyed] {
463 functor_started.Set();
464 functor_continue.Wait(Event::kForever);
465 rtc::Thread::Current()->SleepMs(kWaitTimeout);
466 EXPECT_FALSE(invoker_destroyed);
467 functor_finished.Set();
468 };
461 AsyncInvoker invoker; 469 AsyncInvoker invoker;
462 invoker.AsyncInvoke<void>(RTC_FROM_HERE, thread.get(), 470 invoker.AsyncInvoke<void>(RTC_FROM_HERE, thread.get(), functor);
463 [&functor_started, &functor_continue,
464 &functor_finished, &invoker_destroyed] {
465 functor_started.Set();
466 functor_continue.Wait(Event::kForever);
467 rtc::Thread::Current()->SleepMs(kWaitTimeout);
468 EXPECT_FALSE(invoker_destroyed);
469 functor_finished.Set();
470 });
471 functor_started.Wait(Event::kForever); 471 functor_started.Wait(Event::kForever);
472 472
473 // Allow the functor to continue and immediately destroy the invoker. 473 // Destroy the invoker while the functor is still executing (doing
474 // SleepMs).
474 functor_continue.Set(); 475 functor_continue.Set();
475 } 476 }
476 477
477 // If the destructor DIDN'T wait for the functor to finish executing, it will 478 // If the destructor DIDN'T wait for the functor to finish executing, it will
478 // hit the EXPECT_FALSE(invoker_destroyed) after it finishes sleeping for a 479 // hit the EXPECT_FALSE(invoker_destroyed) after it finishes sleeping for a
479 // second. 480 // second.
480 invoker_destroyed = true; 481 invoker_destroyed = true;
481 functor_finished.Wait(Event::kForever); 482 functor_finished.Wait(Event::kForever);
482 } 483 }
483 484
485 // Variant of the above test where the async-invoked task calls AsyncInvoke
486 // *again*, for the thread on which the AsyncInvoker is currently being
487 // destroyed. This shouldn't deadlock or crash; this second invocation should
488 // just be ignored.
489 TEST_F(AsyncInvokeTest, KillInvokerDuringExecuteWithReentrantInvoke) {
490 Event functor_started(false, false);
491 // Flag used to verify that the recursively invoked task never actually runs.
492 bool reentrant_functor_run = false;
493
494 Thread* main = Thread::Current();
495 Thread thread;
496 thread.Start();
497 {
498 AsyncInvoker invoker;
499 auto reentrant_functor = [&reentrant_functor_run] {
500 reentrant_functor_run = true;
501 };
502 auto functor = [&functor_started, &invoker, main, reentrant_functor] {
503 functor_started.Set();
504 Thread::Current()->SleepMs(kWaitTimeout);
505 invoker.AsyncInvoke<void>(RTC_FROM_HERE, main, reentrant_functor);
506 };
507 // This queues a task on |thread| to sleep for |kWaitTimeout| then queue a
508 // task on |main|. But this second queued task should never run, since the
509 // destructor will be entered before it's even invoked.
510 invoker.AsyncInvoke<void>(RTC_FROM_HERE, &thread, functor);
511 functor_started.Wait(Event::kForever);
512 }
513 EXPECT_FALSE(reentrant_functor_run);
514 }
515
484 TEST_F(AsyncInvokeTest, Flush) { 516 TEST_F(AsyncInvokeTest, Flush) {
485 AsyncInvoker invoker; 517 AsyncInvoker invoker;
486 AtomicBool flag1; 518 AtomicBool flag1;
487 AtomicBool flag2; 519 AtomicBool flag2;
488 // Queue two async calls to the current thread. 520 // Queue two async calls to the current thread.
489 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag1)); 521 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag1));
490 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag2)); 522 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag2));
491 // Because we haven't pumped messages, these should not have run yet. 523 // Because we haven't pumped messages, these should not have run yet.
492 EXPECT_FALSE(flag1.get()); 524 EXPECT_FALSE(flag1.get());
493 EXPECT_FALSE(flag2.get()); 525 EXPECT_FALSE(flag2.get());
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 // Execute pending calls with id == 5. 636 // Execute pending calls with id == 5.
605 EXPECT_TRUE(invoker.Flush(5)); 637 EXPECT_TRUE(invoker.Flush(5));
606 EXPECT_TRUE(flag1.get()); 638 EXPECT_TRUE(flag1.get());
607 EXPECT_FALSE(flag2.get()); 639 EXPECT_FALSE(flag2.get());
608 flag1 = false; 640 flag1 = false;
609 // Execute all pending calls. The id == 5 call should not execute again. 641 // Execute all pending calls. The id == 5 call should not execute again.
610 EXPECT_TRUE(invoker.Flush()); 642 EXPECT_TRUE(invoker.Flush());
611 EXPECT_FALSE(flag1.get()); 643 EXPECT_FALSE(flag1.get());
612 EXPECT_TRUE(flag2.get()); 644 EXPECT_TRUE(flag2.get());
613 } 645 }
OLDNEW
« webrtc/rtc_base/asyncinvoker.cc ('K') | « webrtc/rtc_base/asyncinvoker-inl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698