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

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

Issue 1303443003: Add helper class GuardedAsyncInvoker to protect against thread dying (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Remove AttachToThread() functionality Created 5 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
« webrtc/base/asyncinvoker.cc ('K') | « webrtc/base/asyncinvoker.cc ('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 500 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 invoker.Flush(Thread::Current(), 5); 511 invoker.Flush(Thread::Current(), 5);
512 EXPECT_TRUE(flag1); 512 EXPECT_TRUE(flag1);
513 EXPECT_FALSE(flag2); 513 EXPECT_FALSE(flag2);
514 flag1 = false; 514 flag1 = false;
515 // Execute all pending calls. The id == 5 call should not execute again. 515 // Execute all pending calls. The id == 5 call should not execute again.
516 invoker.Flush(Thread::Current()); 516 invoker.Flush(Thread::Current());
517 EXPECT_FALSE(flag1); 517 EXPECT_FALSE(flag1);
518 EXPECT_TRUE(flag2); 518 EXPECT_TRUE(flag2);
519 } 519 }
520 520
521 class GuardedAsyncInvokeTest : public testing::Test {
522 public:
523 void IntCallback(int value) {
524 EXPECT_EQ(expected_thread_, Thread::Current());
525 int_value_ = value;
526 }
527 void AsyncInvokeIntCallback(GuardedAsyncInvoker* invoker, Thread* thread) {
528 expected_thread_ = thread;
529 invoker->AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback,
530 static_cast<GuardedAsyncInvokeTest*>(this));
531 invoke_started_.Set();
532 }
533 void SetExpectedThreadForIntCallback(Thread* thread) {
534 expected_thread_ = thread;
535 }
536
537 protected:
538 enum { kWaitTimeout = 1000 };
tommi (sloooow) - chröme 2015/08/19 20:01:54 const static int I think using enums this way is
magjed_webrtc 2015/08/20 10:28:33 Done.
539 GuardedAsyncInvokeTest()
540 : int_value_(0), invoke_started_(true, false), expected_thread_(NULL) {}
tommi (sloooow) - chröme 2015/08/19 20:01:54 nit: nullptr
magjed_webrtc 2015/08/20 10:28:33 Done.
541
542 int int_value_;
543 Event invoke_started_;
544 Thread* expected_thread_;
545 };
546
547 struct CreateInvoker {
548 CreateInvoker(scoped_ptr<GuardedAsyncInvoker>* invoker) : invoker_(invoker) {}
549 void operator()() { invoker_->reset(new GuardedAsyncInvoker()); }
550 scoped_ptr<GuardedAsyncInvoker>* invoker_;
551 };
552
553 // Test that we can call AsyncInvoke<void>() after the thread died.
554 TEST_F(GuardedAsyncInvokeTest, KillThreadFireAndForget) {
555 // Create and start the thread.
556 scoped_ptr<Thread> thread(new Thread());
557 thread->Start();
558 scoped_ptr<GuardedAsyncInvoker> invoker;
559 // Create the invoker on |thread|.
560 thread->Invoke<void>(CreateInvoker(&invoker));
561 // Kill |thread|.
562 thread = nullptr;
563 // Try calling functor.
564 bool called = false;
565 invoker->AsyncInvoke<void>(FunctorB(&called));
566 // With thread gone, nothing should happen.
567 WAIT(called, kWaitTimeout);
568 EXPECT_FALSE(called);
569 }
570
571 // Test that we can call AsyncInvoke with callback after the thread died.
572 TEST_F(GuardedAsyncInvokeTest, KillThreadWithCallback) {
573 // Create and start the thread.
574 scoped_ptr<Thread> thread(new Thread());
575 thread->Start();
576 scoped_ptr<GuardedAsyncInvoker> invoker;
577 // Create the invoker on |thread|.
578 thread->Invoke<void>(CreateInvoker(&invoker));
579 // Kill |thread|.
580 thread = nullptr;
581 // Try calling functor.
582 invoker->AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback,
583 static_cast<GuardedAsyncInvokeTest*>(this));
584 // With thread gone, callback should be cancelled.
585 Thread::Current()->ProcessMessages(kWaitTimeout);
586 EXPECT_EQ(0, int_value_);
587 }
588
589 // The remaining tests check that GuardedAsyncInvoker behaves as AsyncInvoker
590 // when Thread is still alive.
591 TEST_F(GuardedAsyncInvokeTest, FireAndForget) {
592 GuardedAsyncInvoker invoker;
593 // Try calling functor.
594 bool called = false;
595 invoker.AsyncInvoke<void>(FunctorB(&called));
596 EXPECT_TRUE_WAIT(called, kWaitTimeout);
597 }
598
599 TEST_F(GuardedAsyncInvokeTest, WithCallback) {
600 GuardedAsyncInvoker invoker;
601 // Try calling functor.
602 SetExpectedThreadForIntCallback(Thread::Current());
603 invoker.AsyncInvoke(FunctorA(), &GuardedAsyncInvokeTest::IntCallback,
604 static_cast<GuardedAsyncInvokeTest*>(this));
605 EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
606 }
607
608 TEST_F(GuardedAsyncInvokeTest, CancelInvoker) {
609 // Try destroying invoker during call.
610 {
611 GuardedAsyncInvoker invoker;
612 invoker.AsyncInvoke(FunctorC(), &GuardedAsyncInvokeTest::IntCallback,
613 static_cast<GuardedAsyncInvokeTest*>(this));
614 }
615 // With invoker gone, callback should be cancelled.
616 Thread::Current()->ProcessMessages(kWaitTimeout);
617 EXPECT_EQ(0, int_value_);
618 }
619
620 TEST_F(GuardedAsyncInvokeTest, CancelCallingThread) {
621 GuardedAsyncInvoker invoker;
622 // Try destroying calling thread during call.
623 {
624 Thread thread;
625 thread.Start();
626 // Try calling functor.
627 thread.Invoke<void>(Bind(&GuardedAsyncInvokeTest::AsyncInvokeIntCallback,
628 static_cast<GuardedAsyncInvokeTest*>(this),
629 &invoker, Thread::Current()));
630 // Wait for the call to begin.
631 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
632 }
633 // Calling thread is gone. Return message shouldn't happen.
634 Thread::Current()->ProcessMessages(kWaitTimeout);
635 EXPECT_EQ(0, int_value_);
636 }
637
638 TEST_F(GuardedAsyncInvokeTest, KillInvokerBeforeExecute) {
639 Thread thread;
640 thread.Start();
641 {
642 GuardedAsyncInvoker invoker;
643 // Try calling functor.
644 thread.Invoke<void>(Bind(&GuardedAsyncInvokeTest::AsyncInvokeIntCallback,
645 static_cast<GuardedAsyncInvokeTest*>(this),
646 &invoker, Thread::Current()));
647 // Wait for the call to begin.
648 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
649 }
650 // Invoker is destroyed. Function should not execute.
651 Thread::Current()->ProcessMessages(kWaitTimeout);
652 EXPECT_EQ(0, int_value_);
653 }
654
655 TEST_F(GuardedAsyncInvokeTest, Flush) {
656 GuardedAsyncInvoker invoker;
657 bool flag1 = false;
658 bool flag2 = false;
659 // Queue two async calls to the current thread.
660 invoker.AsyncInvoke<void>(FunctorB(&flag1));
661 invoker.AsyncInvoke<void>(FunctorB(&flag2));
662 // Because we haven't pumped messages, these should not have run yet.
663 EXPECT_FALSE(flag1);
664 EXPECT_FALSE(flag2);
665 // Force them to run now.
666 invoker.Flush();
667 EXPECT_TRUE(flag1);
668 EXPECT_TRUE(flag2);
669 }
670
671 TEST_F(GuardedAsyncInvokeTest, FlushWithIds) {
672 GuardedAsyncInvoker invoker;
673 bool flag1 = false;
674 bool flag2 = false;
675 // Queue two async calls to the current thread, one with a message id.
676 invoker.AsyncInvoke<void>(FunctorB(&flag1), 5);
677 invoker.AsyncInvoke<void>(FunctorB(&flag2));
678 // Because we haven't pumped messages, these should not have run yet.
679 EXPECT_FALSE(flag1);
680 EXPECT_FALSE(flag2);
681 // Execute pending calls with id == 5.
682 invoker.Flush(5);
683 EXPECT_TRUE(flag1);
684 EXPECT_FALSE(flag2);
685 flag1 = false;
686 // Execute all pending calls. The id == 5 call should not execute again.
687 invoker.Flush();
688 EXPECT_FALSE(flag1);
689 EXPECT_TRUE(flag2);
690 }
521 691
522 #if defined(WEBRTC_WIN) 692 #if defined(WEBRTC_WIN)
523 class ComThreadTest : public testing::Test, public MessageHandler { 693 class ComThreadTest : public testing::Test, public MessageHandler {
524 public: 694 public:
525 ComThreadTest() : done_(false) {} 695 ComThreadTest() : done_(false) {}
526 protected: 696 protected:
527 virtual void OnMessage(Message* message) { 697 virtual void OnMessage(Message* message) {
528 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); 698 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
529 // S_FALSE means the thread was already inited for a multithread apartment. 699 // S_FALSE means the thread was already inited for a multithread apartment.
530 EXPECT_EQ(S_FALSE, hr); 700 EXPECT_EQ(S_FALSE, hr);
531 if (SUCCEEDED(hr)) { 701 if (SUCCEEDED(hr)) {
532 CoUninitialize(); 702 CoUninitialize();
533 } 703 }
534 done_ = true; 704 done_ = true;
535 } 705 }
536 bool done_; 706 bool done_;
537 }; 707 };
538 708
539 TEST_F(ComThreadTest, ComInited) { 709 TEST_F(ComThreadTest, ComInited) {
540 Thread* thread = new ComThread(); 710 Thread* thread = new ComThread();
541 EXPECT_TRUE(thread->Start()); 711 EXPECT_TRUE(thread->Start());
542 thread->Post(this, 0); 712 thread->Post(this, 0);
543 EXPECT_TRUE_WAIT(done_, 1000); 713 EXPECT_TRUE_WAIT(done_, 1000);
544 delete thread; 714 delete thread;
545 } 715 }
546 #endif 716 #endif
OLDNEW
« webrtc/base/asyncinvoker.cc ('K') | « webrtc/base/asyncinvoker.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698