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

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: Review feedback 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
« base/timer/timer.cc ('K') | « 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 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
OLDNEW
« base/timer/timer.cc ('K') | « base/timer/timer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698