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

Side by Side Diff: base/timer/timer_unittest.cc

Issue 1433373003: Use SequenceChecker to allow Timer to run in SequencedWorkerPool (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Feedback and MOAR tests Created 5 years 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 | « base/timer/timer.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 // 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
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 // Tell the timer to abandon the task.
573 void AbandonTask() {
574 ASSERT_TRUE(timer_->IsRunning());
575 // Reset() to call Timer::AbandonScheduledTask()
576 timer_->Reset();
577 ASSERT_TRUE(timer_->IsRunning());
578 timer_->Stop();
579 ASSERT_FALSE(timer_->IsRunning());
580 }
581
582 static void VerifyAffinity(scoped_refptr<SequencedTaskRunner> task_runner) {
583 ASSERT_TRUE(task_runner->RunsTasksOnCurrentThread());
584 }
585
586 // Delete the timer.
587 void DeleteTimer() { timer_.reset(); }
588
589 protected:
590 const scoped_refptr<base::SequencedWorkerPool>& pool1() {
591 return pool1_owner_->pool();
592 }
593 const scoped_refptr<base::SequencedWorkerPool>& pool2() {
594 return pool2_owner_->pool();
595 }
596
597 // Destroys the SequencedWorkerPool instance, blocking until it is fully shut
598 // down, and creates a new instance.
599 void ResetPools() {
600 pool1_owner_.reset(
601 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test1"));
602 pool2_owner_.reset(
603 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test2"));
604 }
605
606 scoped_ptr<base::OneShotTimer> timer_;
gab 2015/12/15 16:47:41 Feels like this should either be private (i.e. als
jsbell 2015/12/15 18:54:05 Done.
607
608 private:
609 void RunTaskAndSignal(const base::Closure& task) {
610 task.Run();
611 Signal();
612 }
613
614 base::WaitableEvent event_;
615
616 base::MessageLoop message_loop_;
617 scoped_ptr<base::SequencedWorkerPoolOwner> pool1_owner_;
618 scoped_ptr<base::SequencedWorkerPoolOwner> pool2_owner_;
619
620 DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest);
621 };
622
623 TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) {
624 scoped_refptr<SequencedTaskRunner> task_runner =
625 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
626
627 // Timer is created on this thread.
628 CreateTimer();
629
630 // Task will execute on a pool thread.
631 timer_->SetTaskRunner(task_runner.get());
632 StartTimer(TimeDelta::FromMilliseconds(1),
633 base::Bind(&TimerSequenceTest::Signal, base::Unretained(this)));
634 Wait();
635
636 // Timer will be destroyed on this thread.
637 timer_.reset();
638 }
639
640 TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) {
641 scoped_refptr<SequencedTaskRunner> task_runner =
642 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
643
644 // Timer is created on this thread.
645 CreateTimer();
646
647 // Task will be scheduled from a pool thread.
648 task_runner->PostTask(
649 FROM_HERE,
650 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this),
651 TimeDelta::FromMilliseconds(1),
652 TaskWithSignal(base::Bind(&DoNothing))));
gab 2015/12/15 16:47:41 Isn't TaskWithSignal(base::Bind(&DoNothing)) just
jsbell 2015/12/15 18:54:05 Done.
653 Wait();
654
655 // Timer must be destroyed on pool thread, too.
656 task_runner->PostTask(
657 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer,
658 base::Unretained(this))));
659 Wait();
660 }
661
662 TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) {
663 scoped_refptr<SequencedTaskRunner> task_runner1 =
664 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
665 scoped_refptr<SequencedTaskRunner> task_runner2 =
666 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken());
667
668 // Create timer on pool #1.
669 task_runner1->PostTask(
670 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer,
671 base::Unretained(this))));
672 Wait();
673
674 // Task will execute on a different pool (#2).
675 timer_->SetTaskRunner(task_runner2.get());
676
677 // Task will be scheduled from pool #1.
678 task_runner1->PostTask(
679 FROM_HERE,
680 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this),
681 TimeDelta::FromHours(1), base::Bind(&DoNothing)));
682
683 // Abandon task - must be called from scheduling pool (#1).
684 task_runner1->PostTask(
685 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::AbandonTask,
686 base::Unretained(this))));
687 Wait();
688
689 // Timer must be destroyed on the pool it was scheduled from (#1).
690 task_runner1->PostTask(
691 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer,
692 base::Unretained(this))));
693 Wait();
694 }
695
696 TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) {
697 scoped_refptr<SequencedTaskRunner> task_runner1 =
698 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
699 scoped_refptr<SequencedTaskRunner> task_runner2 =
700 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken());
701
702 // Create timer on pool #1.
703 task_runner1->PostTask(
704 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer,
705 base::Unretained(this))));
706 Wait();
707
708 // Task will execute on a different pool (#2).
709 timer_->SetTaskRunner(task_runner2.get());
710
711 // Task will be scheduled from pool #1.
712 task_runner1->PostTask(
713 FROM_HERE,
714 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this),
715 TimeDelta::FromMilliseconds(1),
716 TaskWithSignal(base::Bind(&TimerSequenceTest::VerifyAffinity,
717 task_runner2))));
718
719 Wait();
720
721 // Timer must be destroyed on the pool it was scheduled from (#1).
722 task_runner1->PostTask(
723 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer,
724 base::Unretained(this))));
725 Wait();
726 }
727
531 } // namespace 728 } // namespace
OLDNEW
« no previous file with comments | « base/timer/timer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698