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

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

Powered by Google App Engine
This is Rietveld 408576698