Chromium Code Reviews| OLD | NEW | 
|---|---|
| 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 TestMessage* msg = static_cast<TestMessage*>(pmsg->pdata); | 97 TestMessage* msg = static_cast<TestMessage*>(pmsg->pdata); | 
| 98 int result = Next(msg->value); | 98 int result = Next(msg->value); | 
| 99 EXPECT_GE(socket_->Send(&result, sizeof(result)), 0); | 99 EXPECT_GE(socket_->Send(&result, sizeof(result)), 0); | 
| 100 delete msg; | 100 delete msg; | 
| 101 } | 101 } | 
| 102 | 102 | 
| 103 private: | 103 private: | 
| 104 Socket* socket_; | 104 Socket* socket_; | 
| 105 }; | 105 }; | 
| 106 | 106 | 
| 107 class CustomThread : public rtc::Thread { | 107 class CustomThread : public Thread { | 
| 108 public: | 108 public: | 
| 109 CustomThread() {} | 109 CustomThread() {} | 
| 110 virtual ~CustomThread() { Stop(); } | 110 virtual ~CustomThread() { Stop(); } | 
| 111 bool Start() { return false; } | 111 bool Start() { return false; } | 
| 112 | 112 | 
| 113 bool WrapCurrent() { | 113 bool WrapCurrent() { | 
| 114 return Thread::WrapCurrent(); | 114 return Thread::WrapCurrent(); | 
| 115 } | 115 } | 
| 116 void UnwrapCurrent() { | 116 void UnwrapCurrent() { | 
| 117 Thread::UnwrapCurrent(); | 117 Thread::UnwrapCurrent(); | 
| (...skipping 25 matching lines...) Expand all Loading... | |
| 143 // A bool wrapped in a mutex, to avoid data races. Using a volatile | 143 // A bool wrapped in a mutex, to avoid data races. Using a volatile | 
| 144 // bool should be sufficient for correct code ("eventual consistency" | 144 // bool should be sufficient for correct code ("eventual consistency" | 
| 145 // between caches is sufficient), but we can't tell the compiler about | 145 // between caches is sufficient), but we can't tell the compiler about | 
| 146 // that, and then tsan complains about a data race. | 146 // that, and then tsan complains about a data race. | 
| 147 | 147 | 
| 148 // See also discussion at | 148 // See also discussion at | 
| 149 // http://stackoverflow.com/questions/7223164/is-mutex-needed-to-synchronize-a-s imple-flag-between-pthreads | 149 // http://stackoverflow.com/questions/7223164/is-mutex-needed-to-synchronize-a-s imple-flag-between-pthreads | 
| 150 | 150 | 
| 151 // Using std::atomic<bool> or std::atomic_flag in C++11 is probably | 151 // Using std::atomic<bool> or std::atomic_flag in C++11 is probably | 
| 152 // the right thing to do, but those features are not yet allowed. Or | 152 // the right thing to do, but those features are not yet allowed. Or | 
| 153 // rtc::AtomicInt, if/when that is added. Since the use isn't | 153 // AtomicInt, if/when that is added. Since the use isn't | 
| 154 // performance critical, use a plain critical section for the time | 154 // performance critical, use a plain critical section for the time | 
| 155 // being. | 155 // being. | 
| 156 | 156 | 
| 157 class AtomicBool { | 157 class AtomicBool { | 
| 158 public: | 158 public: | 
| 159 explicit AtomicBool(bool value = false) : flag_(value) {} | 159 explicit AtomicBool(bool value = false) : flag_(value) {} | 
| 160 AtomicBool& operator=(bool value) { | 160 AtomicBool& operator=(bool value) { | 
| 161 CritScope scoped_lock(&cs_); | 161 CritScope scoped_lock(&cs_); | 
| 162 flag_ = value; | 162 flag_ = value; | 
| 163 return *this; | 163 return *this; | 
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 444 AtomicBool called; | 444 AtomicBool called; | 
| 445 invoker.AsyncInvoke<void>(RTC_FROM_HERE, &thread, FunctorB(&called)); | 445 invoker.AsyncInvoke<void>(RTC_FROM_HERE, &thread, FunctorB(&called)); | 
| 446 EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); | 446 EXPECT_TRUE_WAIT(called.get(), kWaitTimeout); | 
| 447 } | 447 } | 
| 448 | 448 | 
| 449 TEST_F(AsyncInvokeTest, KillInvokerDuringExecute) { | 449 TEST_F(AsyncInvokeTest, KillInvokerDuringExecute) { | 
| 450 // Use these events to get in a state where the functor is in the middle of | 450 // Use these events to get in a state where the functor is in the middle of | 
| 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); | |
| 455 Event functor_finished(false, false); | 454 Event functor_finished(false, false); | 
| 456 | 455 | 
| 457 Thread thread; | 456 Thread thread; | 
| 458 thread.Start(); | 457 thread.Start(); | 
| 459 volatile bool invoker_destroyed = false; | 458 volatile bool invoker_destroyed = false; | 
| 460 { | 459 { | 
| 460 auto functor = [&functor_started, &functor_finished, &invoker_destroyed] { | |
| 461 functor_started.Set(); | |
| 462 Thread::Current()->SleepMs(kWaitTimeout); | |
| 463 EXPECT_FALSE(invoker_destroyed); | |
| 464 functor_finished.Set(); | |
| 465 }; | |
| 461 AsyncInvoker invoker; | 466 AsyncInvoker invoker; | 
| 462 invoker.AsyncInvoke<void>(RTC_FROM_HERE, &thread, | 467 invoker.AsyncInvoke<void>(RTC_FROM_HERE, &thread, 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); | 468 functor_started.Wait(Event::kForever); | 
| 472 | 469 // Destroy the invoker while the functor is still executing (doing | 
| 473 // Allow the functor to continue and immediately destroy the invoker. | 470 // SleepMs). | 
| 474 functor_continue.Set(); | |
| 475 } | 471 } | 
| 476 | 472 | 
| 477 // If the destructor DIDN'T wait for the functor to finish executing, it will | 473 // 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 | 474 // hit the EXPECT_FALSE(invoker_destroyed) after it finishes sleeping for a | 
| 479 // second. | 475 // second. | 
| 480 invoker_destroyed = true; | 476 invoker_destroyed = true; | 
| 481 functor_finished.Wait(Event::kForever); | 477 functor_finished.Wait(Event::kForever); | 
| 482 } | 478 } | 
| 483 | 479 | 
| 480 // Variant of the above test where the async-invoked task calls AsyncInvoke | |
| 481 // again, for the thread on which the AsyncInvoker is currently being | |
| 482 // destroyed. This shouldn't deadlock or crash; this second invocation should | |
| 483 // just be ignored. | |
| 484 TEST_F(AsyncInvokeTest, KillInvokerDuringExecuteWithReentrantInvoke) { | |
| 485 Event functor_started(false, false); | |
| 486 bool reentrant_functor_run = false; | |
| 487 | |
| 488 Thread* main = Thread::Current(); | |
| 489 Thread thread; | |
| 490 thread.Start(); | |
| 491 { | |
| 492 AsyncInvoker invoker; | |
| 493 auto reentrant_functor = [&reentrant_functor_run] { | |
| 494 reentrant_functor_run = true; | |
| 495 }; | |
| 496 auto functor = [&functor_started, &invoker, main, reentrant_functor] { | |
| 497 functor_started.Set(); | |
| 498 Thread::Current()->SleepMs(kWaitTimeout); | |
| 499 invoker.AsyncInvoke<void>(RTC_FROM_HERE, main, reentrant_functor); | |
| 500 }; | |
| 501 // This queues a task on |thread| to sleep for |kWaitTimeout| then queue a | |
| 502 // task on |main|. But this second queued task should never run. | |
| 503 invoker.AsyncInvoke<void>(RTC_FROM_HERE, &thread, functor); | |
| 504 functor_started.Wait(Event::kForever); | |
| 505 } | |
| 
 
nisse-webrtc
2017/05/18 08:04:55
I'm trying to understand what happens here... Scop
 
 | |
| 506 EXPECT_FALSE(reentrant_functor_run); | |
| 507 } | |
| 508 | |
| 484 TEST_F(AsyncInvokeTest, Flush) { | 509 TEST_F(AsyncInvokeTest, Flush) { | 
| 485 AsyncInvoker invoker; | 510 AsyncInvoker invoker; | 
| 486 AtomicBool flag1; | 511 AtomicBool flag1; | 
| 487 AtomicBool flag2; | 512 AtomicBool flag2; | 
| 488 // Queue two async calls to the current thread. | 513 // Queue two async calls to the current thread. | 
| 489 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag1)); | 514 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag1)); | 
| 490 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag2)); | 515 invoker.AsyncInvoke<void>(RTC_FROM_HERE, Thread::Current(), FunctorB(&flag2)); | 
| 491 // Because we haven't pumped messages, these should not have run yet. | 516 // Because we haven't pumped messages, these should not have run yet. | 
| 492 EXPECT_FALSE(flag1.get()); | 517 EXPECT_FALSE(flag1.get()); | 
| 493 EXPECT_FALSE(flag2.get()); | 518 EXPECT_FALSE(flag2.get()); | 
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 604 // Execute pending calls with id == 5. | 629 // Execute pending calls with id == 5. | 
| 605 EXPECT_TRUE(invoker.Flush(5)); | 630 EXPECT_TRUE(invoker.Flush(5)); | 
| 606 EXPECT_TRUE(flag1.get()); | 631 EXPECT_TRUE(flag1.get()); | 
| 607 EXPECT_FALSE(flag2.get()); | 632 EXPECT_FALSE(flag2.get()); | 
| 608 flag1 = false; | 633 flag1 = false; | 
| 609 // Execute all pending calls. The id == 5 call should not execute again. | 634 // Execute all pending calls. The id == 5 call should not execute again. | 
| 610 EXPECT_TRUE(invoker.Flush()); | 635 EXPECT_TRUE(invoker.Flush()); | 
| 611 EXPECT_FALSE(flag1.get()); | 636 EXPECT_FALSE(flag1.get()); | 
| 612 EXPECT_TRUE(flag2.get()); | 637 EXPECT_TRUE(flag2.get()); | 
| 613 } | 638 } | 
| OLD | NEW |