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

Unified Diff: base/timer/timer_unittest.cc

Issue 2491613004: Make base::Timer sequence-friendly. (Closed)
Patch Set: add back commented out DCHECK in Stop() Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/timer/timer.cc ('k') | build/sanitizers/tsan_suppressions.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/timer/timer_unittest.cc
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc
index 69338eb211b52c32e0bc31250c515597c30d02ca..fd1fff5361ea19066fac9a9fd4f9edc41ad28482 100644
--- a/base/timer/timer_unittest.cc
+++ b/base/timer/timer_unittest.cc
@@ -17,14 +17,12 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/platform_thread.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -108,14 +106,14 @@ class OneShotTimerTester : public OneShotTimerTesterBase {
~OneShotTimerTester() override = default;
- void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) {
+ void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) {
timer_->SetTaskRunner(std::move(task_runner));
// Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure
// needs to run on this thread (where the MessageLoop lives).
- quit_closure_ =
- Bind(IgnoreResult(&SingleThreadTaskRunner::PostTask),
- ThreadTaskRunnerHandle::Get(), FROM_HERE, run_loop_.QuitClosure());
+ quit_closure_ = Bind(IgnoreResult(&SequencedTaskRunner::PostTask),
+ SequencedTaskRunnerHandle::Get(), FROM_HERE,
+ run_loop_.QuitClosure());
}
// Blocks until Run() executes and confirms that Run() didn't fire before
@@ -668,6 +666,8 @@ TEST(TimerTest, RetainNonRepeatIsRunning) {
EXPECT_TRUE(timer.IsRunning());
}
+//-----------------------------------------------------------------------------
+
namespace {
bool g_callback_happened1 = false;
@@ -721,4 +721,206 @@ TEST(TimerTest, ContinuationReset) {
}
}
+namespace {
+
+const size_t kNumWorkerThreads = 3;
+
+// Fixture for tests requiring a worker pool. Includes a WaitableEvent so
+// that cases may Wait() on one thread and Signal() (explicitly, or implicitly
+// via helper methods) on another.
+class TimerSequenceTest : public testing::Test {
+ public:
+ TimerSequenceTest()
+ : event_(WaitableEvent::ResetPolicy::AUTOMATIC,
+ WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+ void SetUp() override {
+ pool1_owner_.reset(
+ new SequencedWorkerPoolOwner(kNumWorkerThreads, "test1"));
+ pool2_owner_.reset(
+ new SequencedWorkerPoolOwner(kNumWorkerThreads, "test2"));
+ }
+
+ // Block until Signal() is called on another thread.
+ void Wait() { event_.Wait(); }
+
+ void Signal() { event_.Signal(); }
+
+ // Helper to augment a task with a subsequent call to Signal().
+ Closure TaskWithSignal(const Closure& task) {
+ return Bind(&TimerSequenceTest::RunTaskAndSignal, Unretained(this), task);
+ }
+
+ // Create the timer.
+ void CreateTimer() { timer_.reset(new OneShotTimer); }
+
+ // Schedule an event on the timer.
+ void StartTimer(TimeDelta delay, const Closure& task) {
+ timer_->Start(FROM_HERE, delay, task);
+ }
+
+ void SetTaskRunnerForTimer(scoped_refptr<SequencedTaskRunner> task_runner) {
+ timer_->SetTaskRunner(std::move(task_runner));
+ }
+
+ // Tell the timer to abandon the task.
+ void AbandonTask() {
+ EXPECT_TRUE(timer_->IsRunning());
+ // Reset() to call Timer::AbandonScheduledTask()
+ timer_->Reset();
+ EXPECT_TRUE(timer_->IsRunning());
+ timer_->Stop();
+ EXPECT_FALSE(timer_->IsRunning());
+ }
+
+ static void VerifyAffinity(const SequencedTaskRunner* task_runner) {
+ EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+ }
+
+ // Delete the timer.
+ void DeleteTimer() { timer_.reset(); }
+
+ protected:
+ const scoped_refptr<SequencedWorkerPool>& pool1() {
+ return pool1_owner_->pool();
+ }
+ const scoped_refptr<SequencedWorkerPool>& pool2() {
+ return pool2_owner_->pool();
+ }
+
+ private:
+ void RunTaskAndSignal(const Closure& task) {
+ task.Run();
+ Signal();
+ }
+
+ WaitableEvent event_;
+
+ MessageLoop message_loop_;
+ std::unique_ptr<SequencedWorkerPoolOwner> pool1_owner_;
+ std::unique_ptr<SequencedWorkerPoolOwner> pool2_owner_;
+
+ std::unique_ptr<OneShotTimer> timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest);
+};
+
+} // namespace
+
+TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) {
+ scoped_refptr<SequencedTaskRunner> task_runner =
+ pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+
+ base::RunLoop run_loop_;
+
+ // Timer is created on this thread.
+ CreateTimer();
+
+ // Task will execute on a pool thread.
+ SetTaskRunnerForTimer(task_runner);
+ StartTimer(TimeDelta::FromMilliseconds(1),
+ Bind(IgnoreResult(&SequencedTaskRunner::PostTask),
+ SequencedTaskRunnerHandle::Get(), FROM_HERE,
+ run_loop_.QuitClosure()));
+
+ // Spin the loop so that the delayed task fires on it, which will forward it
+ // to |task_runner|. And since the Timer's task is one that posts back to this
+ // MessageLoop to quit, we finally unblock.
+ run_loop_.Run();
+
+ // Timer will be destroyed on this thread.
+ DeleteTimer();
+}
+
+TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) {
+ scoped_refptr<SequencedTaskRunner> task_runner =
+ pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+
+ // Timer is created on this thread.
+ CreateTimer();
+
+ // Task will be scheduled from a pool thread.
+ task_runner->PostTask(
+ FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this),
+ TimeDelta::FromMilliseconds(1),
+ Bind(&TimerSequenceTest::Signal, Unretained(this))));
+ Wait();
+
+ // Timer must be destroyed on pool thread, too.
+ task_runner->PostTask(
+ FROM_HERE,
+ TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this))));
+ Wait();
+}
+
+TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) {
+ scoped_refptr<SequencedTaskRunner> task_runner1 =
+ pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+ scoped_refptr<SequencedTaskRunner> task_runner2 =
+ pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken());
+
+ // Create timer on pool #1.
+ task_runner1->PostTask(
+ FROM_HERE,
+ TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this))));
+ Wait();
+
+ // And tell it to execute on a different pool (#2).
+ task_runner1->PostTask(
+ FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer,
+ Unretained(this), task_runner2)));
+ Wait();
+
+ // Task will be scheduled from pool #1.
+ task_runner1->PostTask(FROM_HERE,
+ Bind(&TimerSequenceTest::StartTimer, Unretained(this),
+ TimeDelta::FromHours(1), Bind(&DoNothing)));
+
+ // Abandon task - must be called from scheduling pool (#1).
+ task_runner1->PostTask(
+ FROM_HERE,
+ TaskWithSignal(Bind(&TimerSequenceTest::AbandonTask, Unretained(this))));
+ Wait();
+
+ // Timer must be destroyed on the pool it was scheduled from (#1).
+ task_runner1->PostTask(
+ FROM_HERE,
+ TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this))));
+ Wait();
+}
+
+TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) {
+ scoped_refptr<SequencedTaskRunner> task_runner1 =
+ pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+ scoped_refptr<SequencedTaskRunner> task_runner2 =
+ pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken());
+
+ // Create timer on pool #1.
+ task_runner1->PostTask(
+ FROM_HERE,
+ TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this))));
+ Wait();
+
+ // And tell it to execute on a different pool (#2).
+ task_runner1->PostTask(
+ FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer,
+ Unretained(this), task_runner2)));
+ Wait();
+
+ // Task will be scheduled from pool #1.
+ task_runner1->PostTask(
+ FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this),
+ TimeDelta::FromMilliseconds(1),
+ TaskWithSignal(Bind(&TimerSequenceTest::VerifyAffinity,
+ Unretained(task_runner2.get())))));
+
+ Wait();
+
+ // Timer must be destroyed on the pool it was scheduled from (#1).
+ task_runner1->PostTask(
+ FROM_HERE,
+ TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this))));
+ Wait();
+}
+
} // namespace base
« no previous file with comments | « base/timer/timer.cc ('k') | build/sanitizers/tsan_suppressions.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698