OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind_helpers.h" | |
6 #include "base/callback.h" | |
5 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
6 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "base/synchronization/waitable_event.h" | |
10 #include "base/test/sequenced_worker_pool_owner.h" | |
7 #include "base/test/test_simple_task_runner.h" | 11 #include "base/test/test_simple_task_runner.h" |
8 #include "base/timer/timer.h" | 12 #include "base/timer/timer.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
10 | 14 |
15 using base::DoNothing; | |
16 using base::SequencedTaskRunner; | |
11 using base::TimeDelta; | 17 using base::TimeDelta; |
12 using base::SingleThreadTaskRunner; | |
13 | 18 |
14 namespace { | 19 namespace { |
15 | 20 |
16 // The message loops on which each timer should be tested. | 21 // The message loops on which each timer should be tested. |
17 const base::MessageLoop::Type testing_message_loops[] = { | 22 const base::MessageLoop::Type testing_message_loops[] = { |
18 base::MessageLoop::TYPE_DEFAULT, | 23 base::MessageLoop::TYPE_DEFAULT, |
19 base::MessageLoop::TYPE_IO, | 24 base::MessageLoop::TYPE_IO, |
20 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. | 25 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. |
21 base::MessageLoop::TYPE_UI, | 26 base::MessageLoop::TYPE_UI, |
22 #endif | 27 #endif |
23 }; | 28 }; |
24 | 29 |
25 const int kNumTestingMessageLoops = arraysize(testing_message_loops); | 30 const int kNumTestingMessageLoops = arraysize(testing_message_loops); |
26 | 31 |
27 class OneShotTimerTester { | 32 class OneShotTimerTester { |
28 public: | 33 public: |
29 explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10) | 34 explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10) |
30 : did_run_(did_run), | 35 : did_run_(did_run), |
31 delay_ms_(milliseconds), | 36 delay_ms_(milliseconds), |
32 quit_message_loop_(true) { | 37 quit_message_loop_(true) { |
33 } | 38 } |
34 | 39 |
35 void Start() { | 40 void Start() { |
36 timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this, | 41 timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this, |
37 &OneShotTimerTester::Run); | 42 &OneShotTimerTester::Run); |
38 } | 43 } |
39 | 44 |
40 void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { | 45 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { |
41 quit_message_loop_ = false; | 46 quit_message_loop_ = false; |
42 timer_.SetTaskRunner(task_runner); | 47 timer_.SetTaskRunner(task_runner); |
43 } | 48 } |
44 | 49 |
45 private: | 50 private: |
46 void Run() { | 51 void Run() { |
47 *did_run_ = true; | 52 *did_run_ = true; |
48 if (quit_message_loop_) { | 53 if (quit_message_loop_) { |
49 base::MessageLoop::current()->QuitWhenIdle(); | 54 base::MessageLoop::current()->QuitWhenIdle(); |
50 } | 55 } |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
521 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 526 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), |
522 base::Bind(&SetCallbackHappened1)); | 527 base::Bind(&SetCallbackHappened1)); |
523 timer.Reset(); | 528 timer.Reset(); |
524 // Since Reset happened before task ran, the user_task must not be cleared: | 529 // Since Reset happened before task ran, the user_task must not be cleared: |
525 ASSERT_FALSE(timer.user_task().is_null()); | 530 ASSERT_FALSE(timer.user_task().is_null()); |
526 base::MessageLoop::current()->Run(); | 531 base::MessageLoop::current()->Run(); |
527 EXPECT_TRUE(g_callback_happened1); | 532 EXPECT_TRUE(g_callback_happened1); |
528 } | 533 } |
529 } | 534 } |
530 | 535 |
536 const size_t kNumWorkerThreads = 3; | |
537 | |
538 // Fixture for tests requiring a worker pool. Includes a WaitableEvent so | |
539 // that cases may Wait() on one thread and Signal() (explicitly, or implicitly | |
540 // via helper methods) on another. | |
541 class TimerSequenceTest : public testing::Test { | |
542 public: | |
543 TimerSequenceTest() | |
544 : event_(false /* manual_reset */, false /* initially_signaled */) {} | |
545 | |
546 void SetUp() override { ResetPools(); } | |
547 | |
548 void TearDown() override { | |
549 pool1()->Shutdown(); | |
550 pool2()->Shutdown(); | |
551 } | |
552 | |
553 // Block until Signal() is called on another thread. | |
554 void Wait() { event_.Wait(); } | |
555 | |
556 void Signal() { event_.Signal(); } | |
557 | |
558 // Helper to augment a task with a subsequent call to Signal(). | |
559 base::Closure TaskWithSignal(const base::Closure& task) { | |
560 return base::Bind(&TimerSequenceTest::RunTaskAndSignal, | |
561 base::Unretained(this), task); | |
562 } | |
563 | |
564 // Create the timer. | |
565 void CreateTimer() { timer_.reset(new base::OneShotTimer); } | |
566 | |
567 // Schedule an event on the timer. | |
568 void StartTimer(TimeDelta delay, const base::Closure& task) { | |
569 timer_->Start(FROM_HERE, delay, task); | |
570 } | |
571 | |
572 void SetTaskRunner(SequencedTaskRunner* task_runner) { | |
danakj
2015/12/15 22:57:18
nit: SetTaskRunnerForTimer?
jsbell
2015/12/15 23:03:14
Done.
| |
573 timer_->SetTaskRunner(task_runner); | |
574 } | |
575 | |
576 // Tell the timer to abandon the task. | |
577 void AbandonTask() { | |
578 ASSERT_TRUE(timer_->IsRunning()); | |
579 // Reset() to call Timer::AbandonScheduledTask() | |
580 timer_->Reset(); | |
581 ASSERT_TRUE(timer_->IsRunning()); | |
582 timer_->Stop(); | |
583 ASSERT_FALSE(timer_->IsRunning()); | |
584 } | |
585 | |
586 static void VerifyAffinity(scoped_refptr<SequencedTaskRunner> task_runner) { | |
danakj
2015/12/15 22:57:18
did you mean for this to hold a ref, or did you me
jsbell
2015/12/15 23:03:14
Raw ptr is okay, thx.
| |
587 ASSERT_TRUE(task_runner->RunsTasksOnCurrentThread()); | |
588 } | |
589 | |
590 // Delete the timer. | |
591 void DeleteTimer() { timer_.reset(); } | |
592 | |
593 protected: | |
594 const scoped_refptr<base::SequencedWorkerPool>& pool1() { | |
595 return pool1_owner_->pool(); | |
596 } | |
597 const scoped_refptr<base::SequencedWorkerPool>& pool2() { | |
598 return pool2_owner_->pool(); | |
599 } | |
600 | |
601 // Destroys the SequencedWorkerPool instance, blocking until it is fully shut | |
602 // down, and creates a new instance. | |
603 void ResetPools() { | |
604 pool1_owner_.reset( | |
605 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test1")); | |
606 pool2_owner_.reset( | |
607 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test2")); | |
608 } | |
609 | |
610 private: | |
611 void RunTaskAndSignal(const base::Closure& task) { | |
612 task.Run(); | |
613 Signal(); | |
614 } | |
615 | |
616 base::WaitableEvent event_; | |
617 | |
618 base::MessageLoop message_loop_; | |
619 scoped_ptr<base::SequencedWorkerPoolOwner> pool1_owner_; | |
620 scoped_ptr<base::SequencedWorkerPoolOwner> pool2_owner_; | |
621 | |
622 scoped_ptr<base::OneShotTimer> timer_; | |
623 | |
624 DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); | |
625 }; | |
626 | |
627 TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) { | |
628 scoped_refptr<SequencedTaskRunner> task_runner = | |
629 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
630 | |
631 // Timer is created on this thread. | |
632 CreateTimer(); | |
633 | |
634 // Task will execute on a pool thread. | |
635 SetTaskRunner(task_runner.get()); | |
636 StartTimer(TimeDelta::FromMilliseconds(1), | |
637 base::Bind(&TimerSequenceTest::Signal, base::Unretained(this))); | |
638 Wait(); | |
639 | |
640 // Timer will be destroyed on this thread. | |
641 DeleteTimer(); | |
642 } | |
643 | |
644 TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) { | |
645 scoped_refptr<SequencedTaskRunner> task_runner = | |
646 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
647 | |
648 // Timer is created on this thread. | |
649 CreateTimer(); | |
650 | |
651 // Task will be scheduled from a pool thread. | |
652 task_runner->PostTask( | |
653 FROM_HERE, | |
654 base::Bind( | |
655 &TimerSequenceTest::StartTimer, base::Unretained(this), | |
656 TimeDelta::FromMilliseconds(1), | |
657 base::Bind(&TimerSequenceTest::Signal, base::Unretained(this)))); | |
658 Wait(); | |
659 | |
660 // Timer must be destroyed on pool thread, too. | |
661 task_runner->PostTask( | |
662 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
663 base::Unretained(this)))); | |
664 Wait(); | |
665 } | |
666 | |
667 TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) { | |
668 scoped_refptr<SequencedTaskRunner> task_runner1 = | |
669 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
670 scoped_refptr<SequencedTaskRunner> task_runner2 = | |
671 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); | |
672 | |
673 // Create timer on pool #1. | |
674 task_runner1->PostTask( | |
675 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer, | |
676 base::Unretained(this)))); | |
677 Wait(); | |
678 | |
679 // Task will execute on a different pool (#2). | |
680 SetTaskRunner(task_runner2.get()); | |
681 | |
682 // Task will be scheduled from pool #1. | |
683 task_runner1->PostTask( | |
684 FROM_HERE, | |
685 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this), | |
686 TimeDelta::FromHours(1), base::Bind(&DoNothing))); | |
687 | |
688 // Abandon task - must be called from scheduling pool (#1). | |
689 task_runner1->PostTask( | |
690 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::AbandonTask, | |
691 base::Unretained(this)))); | |
692 Wait(); | |
693 | |
694 // Timer must be destroyed on the pool it was scheduled from (#1). | |
695 task_runner1->PostTask( | |
696 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
697 base::Unretained(this)))); | |
698 Wait(); | |
699 } | |
700 | |
701 TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) { | |
702 scoped_refptr<SequencedTaskRunner> task_runner1 = | |
703 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
704 scoped_refptr<SequencedTaskRunner> task_runner2 = | |
705 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); | |
706 | |
707 // Create timer on pool #1. | |
708 task_runner1->PostTask( | |
709 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer, | |
710 base::Unretained(this)))); | |
711 Wait(); | |
712 | |
713 // Task will execute on a different pool (#2). | |
714 SetTaskRunner(task_runner2.get()); | |
715 | |
716 // Task will be scheduled from pool #1. | |
717 task_runner1->PostTask( | |
718 FROM_HERE, | |
719 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this), | |
720 TimeDelta::FromMilliseconds(1), | |
721 TaskWithSignal(base::Bind(&TimerSequenceTest::VerifyAffinity, | |
722 task_runner2)))); | |
723 | |
724 Wait(); | |
725 | |
726 // Timer must be destroyed on the pool it was scheduled from (#1). | |
727 task_runner1->PostTask( | |
728 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
729 base::Unretained(this)))); | |
730 Wait(); | |
731 } | |
732 | |
531 } // namespace | 733 } // namespace |
OLD | NEW |