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

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

Issue 1439613004: Fix a data race in the thread unit tests. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 1 month 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
« no previous file with comments | « no previous file | 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 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 } 130 }
131 131
132 virtual void Run() { 132 virtual void Run() {
133 // Do nothing. 133 // Do nothing.
134 } 134 }
135 135
136 private: 136 private:
137 Event* event_; 137 Event* event_;
138 }; 138 };
139 139
140 // A bool wrapped in a mutex, do avoid data races. Using a volatile
141 // bool should be sufficient for correct code ("eventual consistency"
142 // between caches is sufficient), but we can't tell the compiler about
143 // that, and then tsan complains about a data race.
144
145 // See also discussion at
146 // http://stackoverflow.com/questions/7223164/is-mutex-needed-to-synchronize-a-s imple-flag-between-pthreads
147
148 // Using std::atomic<bool> or std::atomic_flag in C++11 is probably
149 // the right thing to do, but those features are not yet allowed.
150 // Since the use isn't performance critical, use a plain mutex for the
151 // time being.
152
153 class AtomicFlag
154 {
magjed_webrtc 2015/11/11 15:50:44 You are not following the C++ style guide. The Web
nisse-webrtc 2015/11/12 08:39:05 Done. I've also added a google style in my emacs c
magjed_webrtc 2015/11/12 09:20:51 You can also take a look at go/emacs.
155 public:
156 AtomicFlag(bool value) : flag(value) {}
magjed_webrtc 2015/11/11 15:50:44 I'm not sure you are allowed to use implicit conve
nisse-webrtc 2015/11/12 08:39:05 I can make it explicit. Only reason for implicit w
tommi 2015/11/12 08:49:52 Adding a default ctor that initializes to false ma
magjed_webrtc 2015/11/12 09:20:51 FYI - Here is a link to the style guide: "Do not d
nisse-webrtc 2015/11/12 09:58:23 I changed the constructor to explicit (and with a
nisse-webrtc 2015/11/12 09:58:23 Done.
tommi 2015/11/12 10:16:31 hah! Yeah, well, maybe the class could be called
magjed_webrtc 2015/11/12 11:04:38 Yes, you should probably make the conversion to bo
157 bool operator= (bool value) {
nisse-webrtc 2015/11/12 08:39:05 What's the proper return type for this assignment
tommi 2015/11/12 08:49:52 yes, return a reference to *this.
magjed_webrtc 2015/11/12 09:20:51 The typical copy assignment operator would take th
nisse-webrtc 2015/11/12 09:58:23 Done.
158 cs.Enter();
magjed_webrtc 2015/11/11 15:50:44 Instead of manual Enter() and Leave(), you can use
nisse-webrtc 2015/11/12 08:39:05 Done.
159 flag = value;
160 cs.Leave();
161 return value;
162 }
163 operator bool() const {
164 bool value;
165 cs.Enter();
166 value = flag;
167 cs.Leave();
168 return value;
169 }
170 private:
171 mutable CriticalSection cs;
172 bool flag;
tommi 2015/11/11 16:00:03 fyi - pbos is working on a change that could be he
nisse-webrtc 2015/11/12 08:39:05 I'm adding a reference to rtc::AtomicInt in the co
173 };
174
140 // Function objects to test Thread::Invoke. 175 // Function objects to test Thread::Invoke.
141 struct FunctorA { 176 struct FunctorA {
142 int operator()() { return 42; } 177 int operator()() { return 42; }
143 }; 178 };
144 class FunctorB { 179 class FunctorB {
145 public: 180 public:
146 explicit FunctorB(bool* flag) : flag_(flag) {} 181 explicit FunctorB(AtomicFlag* flag) : flag_(flag) {}
147 void operator()() { if (flag_) *flag_ = true; } 182 void operator()() { if (flag_) *flag_ = true; }
148 private: 183 private:
149 bool* flag_; 184 AtomicFlag* flag_;
150 }; 185 };
151 struct FunctorC { 186 struct FunctorC {
152 int operator()() { 187 int operator()() {
153 Thread::Current()->ProcessMessages(50); 188 Thread::Current()->ProcessMessages(50);
154 return 24; 189 return 24;
155 } 190 }
156 }; 191 };
157 192
158 // See: https://code.google.com/p/webrtc/issues/detail?id=2409 193 // See: https://code.google.com/p/webrtc/issues/detail?id=2409
159 TEST(ThreadTest, DISABLED_Main) { 194 TEST(ThreadTest, DISABLED_Main) {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 delete cthread; 294 delete cthread;
260 current_thread->WrapCurrent(); 295 current_thread->WrapCurrent();
261 } 296 }
262 297
263 TEST(ThreadTest, Invoke) { 298 TEST(ThreadTest, Invoke) {
264 // Create and start the thread. 299 // Create and start the thread.
265 Thread thread; 300 Thread thread;
266 thread.Start(); 301 thread.Start();
267 // Try calling functors. 302 // Try calling functors.
268 EXPECT_EQ(42, thread.Invoke<int>(FunctorA())); 303 EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
269 bool called = false; 304 AtomicFlag called = false;
270 FunctorB f2(&called); 305 FunctorB f2(&called);
271 thread.Invoke<void>(f2); 306 thread.Invoke<void>(f2);
272 EXPECT_TRUE(called); 307 EXPECT_TRUE(called);
273 // Try calling bare functions. 308 // Try calling bare functions.
274 struct LocalFuncs { 309 struct LocalFuncs {
275 static int Func1() { return 999; } 310 static int Func1() { return 999; }
276 static void Func2() {} 311 static void Func2() {}
277 }; 312 };
278 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1)); 313 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
279 thread.Invoke<void>(&LocalFuncs::Func2); 314 thread.Invoke<void>(&LocalFuncs::Func2);
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 Event invoke_started_; 436 Event invoke_started_;
402 Thread* expected_thread_; 437 Thread* expected_thread_;
403 }; 438 };
404 439
405 TEST_F(AsyncInvokeTest, FireAndForget) { 440 TEST_F(AsyncInvokeTest, FireAndForget) {
406 AsyncInvoker invoker; 441 AsyncInvoker invoker;
407 // Create and start the thread. 442 // Create and start the thread.
408 Thread thread; 443 Thread thread;
409 thread.Start(); 444 thread.Start();
410 // Try calling functor. 445 // Try calling functor.
411 bool called = false; 446 AtomicFlag called = false;
412 invoker.AsyncInvoke<void>(&thread, FunctorB(&called)); 447 invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
413 EXPECT_TRUE_WAIT(called, kWaitTimeout); 448 EXPECT_TRUE_WAIT(called, kWaitTimeout);
414 } 449 }
415 450
416 TEST_F(AsyncInvokeTest, WithCallback) { 451 TEST_F(AsyncInvokeTest, WithCallback) {
417 AsyncInvoker invoker; 452 AsyncInvoker invoker;
418 // Create and start the thread. 453 // Create and start the thread.
419 Thread thread; 454 Thread thread;
420 thread.Start(); 455 thread.Start();
421 // Try calling functor. 456 // Try calling functor.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 // Wait for the call to begin. 506 // Wait for the call to begin.
472 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout)); 507 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
473 } 508 }
474 // Invoker is destroyed. Function should not execute. 509 // Invoker is destroyed. Function should not execute.
475 Thread::Current()->ProcessMessages(kWaitTimeout); 510 Thread::Current()->ProcessMessages(kWaitTimeout);
476 EXPECT_EQ(0, int_value_); 511 EXPECT_EQ(0, int_value_);
477 } 512 }
478 513
479 TEST_F(AsyncInvokeTest, Flush) { 514 TEST_F(AsyncInvokeTest, Flush) {
480 AsyncInvoker invoker; 515 AsyncInvoker invoker;
481 bool flag1 = false; 516 AtomicFlag flag1 = false;
482 bool flag2 = false; 517 AtomicFlag flag2 = false;
483 // Queue two async calls to the current thread. 518 // Queue two async calls to the current thread.
484 invoker.AsyncInvoke<void>(Thread::Current(), 519 invoker.AsyncInvoke<void>(Thread::Current(),
485 FunctorB(&flag1)); 520 FunctorB(&flag1));
486 invoker.AsyncInvoke<void>(Thread::Current(), 521 invoker.AsyncInvoke<void>(Thread::Current(),
487 FunctorB(&flag2)); 522 FunctorB(&flag2));
488 // 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.
489 EXPECT_FALSE(flag1); 524 EXPECT_FALSE(flag1);
490 EXPECT_FALSE(flag2); 525 EXPECT_FALSE(flag2);
491 // Force them to run now. 526 // Force them to run now.
492 invoker.Flush(Thread::Current()); 527 invoker.Flush(Thread::Current());
493 EXPECT_TRUE(flag1); 528 EXPECT_TRUE(flag1);
494 EXPECT_TRUE(flag2); 529 EXPECT_TRUE(flag2);
495 } 530 }
496 531
497 TEST_F(AsyncInvokeTest, FlushWithIds) { 532 TEST_F(AsyncInvokeTest, FlushWithIds) {
498 AsyncInvoker invoker; 533 AsyncInvoker invoker;
499 bool flag1 = false; 534 AtomicFlag flag1 = false;
500 bool flag2 = false; 535 AtomicFlag flag2 = false;
501 // Queue two async calls to the current thread, one with a message id. 536 // Queue two async calls to the current thread, one with a message id.
502 invoker.AsyncInvoke<void>(Thread::Current(), 537 invoker.AsyncInvoke<void>(Thread::Current(),
503 FunctorB(&flag1), 538 FunctorB(&flag1),
504 5); 539 5);
505 invoker.AsyncInvoke<void>(Thread::Current(), 540 invoker.AsyncInvoke<void>(Thread::Current(),
506 FunctorB(&flag2)); 541 FunctorB(&flag2));
507 // Because we haven't pumped messages, these should not have run yet. 542 // Because we haven't pumped messages, these should not have run yet.
508 EXPECT_FALSE(flag1); 543 EXPECT_FALSE(flag1);
509 EXPECT_FALSE(flag2); 544 EXPECT_FALSE(flag2);
510 // Execute pending calls with id == 5. 545 // Execute pending calls with id == 5.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 TEST_F(GuardedAsyncInvokeTest, KillThreadFireAndForget) { 592 TEST_F(GuardedAsyncInvokeTest, KillThreadFireAndForget) {
558 // Create and start the thread. 593 // Create and start the thread.
559 scoped_ptr<Thread> thread(new Thread()); 594 scoped_ptr<Thread> thread(new Thread());
560 thread->Start(); 595 thread->Start();
561 scoped_ptr<GuardedAsyncInvoker> invoker; 596 scoped_ptr<GuardedAsyncInvoker> invoker;
562 // Create the invoker on |thread|. 597 // Create the invoker on |thread|.
563 thread->Invoke<void>(CreateInvoker(&invoker)); 598 thread->Invoke<void>(CreateInvoker(&invoker));
564 // Kill |thread|. 599 // Kill |thread|.
565 thread = nullptr; 600 thread = nullptr;
566 // Try calling functor. 601 // Try calling functor.
567 bool called = false; 602 AtomicFlag called = false;
568 EXPECT_FALSE(invoker->AsyncInvoke<void>(FunctorB(&called))); 603 EXPECT_FALSE(invoker->AsyncInvoke<void>(FunctorB(&called)));
569 // With thread gone, nothing should happen. 604 // With thread gone, nothing should happen.
570 WAIT(called, kWaitTimeout); 605 WAIT(called, kWaitTimeout);
571 EXPECT_FALSE(called); 606 EXPECT_FALSE(called);
572 } 607 }
573 608
574 // Test that we can call AsyncInvoke with callback after the thread died. 609 // Test that we can call AsyncInvoke with callback after the thread died.
575 TEST_F(GuardedAsyncInvokeTest, KillThreadWithCallback) { 610 TEST_F(GuardedAsyncInvokeTest, KillThreadWithCallback) {
576 // Create and start the thread. 611 // Create and start the thread.
577 scoped_ptr<Thread> thread(new Thread()); 612 scoped_ptr<Thread> thread(new Thread());
(...skipping 10 matching lines...) Expand all
588 // With thread gone, callback should be cancelled. 623 // With thread gone, callback should be cancelled.
589 Thread::Current()->ProcessMessages(kWaitTimeout); 624 Thread::Current()->ProcessMessages(kWaitTimeout);
590 EXPECT_EQ(0, int_value_); 625 EXPECT_EQ(0, int_value_);
591 } 626 }
592 627
593 // The remaining tests check that GuardedAsyncInvoker behaves as AsyncInvoker 628 // The remaining tests check that GuardedAsyncInvoker behaves as AsyncInvoker
594 // when Thread is still alive. 629 // when Thread is still alive.
595 TEST_F(GuardedAsyncInvokeTest, FireAndForget) { 630 TEST_F(GuardedAsyncInvokeTest, FireAndForget) {
596 GuardedAsyncInvoker invoker; 631 GuardedAsyncInvoker invoker;
597 // Try calling functor. 632 // Try calling functor.
598 bool called = false; 633 AtomicFlag called = false;
599 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&called))); 634 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&called)));
600 EXPECT_TRUE_WAIT(called, kWaitTimeout); 635 EXPECT_TRUE_WAIT(called, kWaitTimeout);
601 } 636 }
602 637
603 TEST_F(GuardedAsyncInvokeTest, WithCallback) { 638 TEST_F(GuardedAsyncInvokeTest, WithCallback) {
604 GuardedAsyncInvoker invoker; 639 GuardedAsyncInvoker invoker;
605 // Try calling functor. 640 // Try calling functor.
606 SetExpectedThreadForIntCallback(Thread::Current()); 641 SetExpectedThreadForIntCallback(Thread::Current());
607 EXPECT_TRUE(invoker.AsyncInvoke(FunctorA(), 642 EXPECT_TRUE(invoker.AsyncInvoke(FunctorA(),
608 &GuardedAsyncInvokeTest::IntCallback, 643 &GuardedAsyncInvokeTest::IntCallback,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 // Wait for the call to begin. 688 // Wait for the call to begin.
654 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout)); 689 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
655 } 690 }
656 // Invoker is destroyed. Function should not execute. 691 // Invoker is destroyed. Function should not execute.
657 Thread::Current()->ProcessMessages(kWaitTimeout); 692 Thread::Current()->ProcessMessages(kWaitTimeout);
658 EXPECT_EQ(0, int_value_); 693 EXPECT_EQ(0, int_value_);
659 } 694 }
660 695
661 TEST_F(GuardedAsyncInvokeTest, Flush) { 696 TEST_F(GuardedAsyncInvokeTest, Flush) {
662 GuardedAsyncInvoker invoker; 697 GuardedAsyncInvoker invoker;
663 bool flag1 = false; 698 AtomicFlag flag1 = false;
664 bool flag2 = false; 699 AtomicFlag flag2 = false;
665 // Queue two async calls to the current thread. 700 // Queue two async calls to the current thread.
666 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1))); 701 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1)));
667 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2))); 702 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2)));
668 // Because we haven't pumped messages, these should not have run yet. 703 // Because we haven't pumped messages, these should not have run yet.
669 EXPECT_FALSE(flag1); 704 EXPECT_FALSE(flag1);
670 EXPECT_FALSE(flag2); 705 EXPECT_FALSE(flag2);
671 // Force them to run now. 706 // Force them to run now.
672 EXPECT_TRUE(invoker.Flush()); 707 EXPECT_TRUE(invoker.Flush());
673 EXPECT_TRUE(flag1); 708 EXPECT_TRUE(flag1);
674 EXPECT_TRUE(flag2); 709 EXPECT_TRUE(flag2);
675 } 710 }
676 711
677 TEST_F(GuardedAsyncInvokeTest, FlushWithIds) { 712 TEST_F(GuardedAsyncInvokeTest, FlushWithIds) {
678 GuardedAsyncInvoker invoker; 713 GuardedAsyncInvoker invoker;
679 bool flag1 = false; 714 AtomicFlag flag1 = false;
680 bool flag2 = false; 715 AtomicFlag flag2 = false;
681 // Queue two async calls to the current thread, one with a message id. 716 // Queue two async calls to the current thread, one with a message id.
682 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1), 5)); 717 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag1), 5));
683 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2))); 718 EXPECT_TRUE(invoker.AsyncInvoke<void>(FunctorB(&flag2)));
684 // Because we haven't pumped messages, these should not have run yet. 719 // Because we haven't pumped messages, these should not have run yet.
685 EXPECT_FALSE(flag1); 720 EXPECT_FALSE(flag1);
686 EXPECT_FALSE(flag2); 721 EXPECT_FALSE(flag2);
687 // Execute pending calls with id == 5. 722 // Execute pending calls with id == 5.
688 EXPECT_TRUE(invoker.Flush(5)); 723 EXPECT_TRUE(invoker.Flush(5));
689 EXPECT_TRUE(flag1); 724 EXPECT_TRUE(flag1);
690 EXPECT_FALSE(flag2); 725 EXPECT_FALSE(flag2);
(...skipping 22 matching lines...) Expand all
713 }; 748 };
714 749
715 TEST_F(ComThreadTest, ComInited) { 750 TEST_F(ComThreadTest, ComInited) {
716 Thread* thread = new ComThread(); 751 Thread* thread = new ComThread();
717 EXPECT_TRUE(thread->Start()); 752 EXPECT_TRUE(thread->Start());
718 thread->Post(this, 0); 753 thread->Post(this, 0);
719 EXPECT_TRUE_WAIT(done_, 1000); 754 EXPECT_TRUE_WAIT(done_, 1000);
720 delete thread; 755 delete thread;
721 } 756 }
722 #endif 757 #endif
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698