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

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

Issue 2885143006: Fixing potential AsyncInvoker deadlock that occurs for "reentrant" invocations. (Closed)
Patch Set: Created 3 years, 7 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
« webrtc/base/asyncinvoker.cc ('K') | « webrtc/base/asyncinvoker-inl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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 }
OLDNEW
« webrtc/base/asyncinvoker.cc ('K') | « webrtc/base/asyncinvoker-inl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698