diff options
Diffstat (limited to 'deps/v8/test/unittests/cancelable-tasks-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/cancelable-tasks-unittest.cc | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/deps/v8/test/unittests/cancelable-tasks-unittest.cc b/deps/v8/test/unittests/cancelable-tasks-unittest.cc new file mode 100644 index 0000000000..37690aaf80 --- /dev/null +++ b/deps/v8/test/unittests/cancelable-tasks-unittest.cc @@ -0,0 +1,218 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/base/atomicops.h" +#include "src/base/platform/platform.h" +#include "src/cancelable-task.h" +#include "testing/gtest/include/gtest/gtest.h" + + +namespace v8 { +namespace internal { + +namespace { + +class TestTask : public Task, public Cancelable { + public: + enum Mode { kDoNothing, kWaitTillCanceledAgain, kCheckNotRun }; + + TestTask(CancelableTaskManager* parent, base::AtomicWord* result, + Mode mode = kDoNothing) + : Cancelable(parent), result_(result), mode_(mode) {} + + // Task overrides. + void Run() final { + if (TryRun()) { + RunInternal(); + } + } + + private: + void RunInternal() { + base::Release_Store(result_, id()); + + switch (mode_) { + case kWaitTillCanceledAgain: + // Simple busy wait until the main thread tried to cancel. + while (CancelAttempts() == 0) { + } + break; + case kCheckNotRun: + // Check that we never execute {RunInternal}. + EXPECT_TRUE(false); + break; + default: + break; + } + } + + base::AtomicWord* result_; + Mode mode_; +}; + + +class SequentialRunner { + public: + explicit SequentialRunner(TestTask* task) : task_(task) {} + + void Run() { + task_->Run(); + delete task_; + } + + private: + TestTask* task_; +}; + + +class ThreadedRunner final : public base::Thread { + public: + explicit ThreadedRunner(TestTask* task) + : Thread(Options("runner thread")), task_(task) {} + + virtual void Run() { + task_->Run(); + delete task_; + } + + private: + TestTask* task_; +}; + + +typedef base::AtomicWord ResultType; + + +intptr_t GetValue(ResultType* result) { return base::Acquire_Load(result); } + +} // namespace + + +TEST(CancelableTask, EmptyCancelableTaskManager) { + CancelableTaskManager manager; + manager.CancelAndWait(); +} + + +TEST(CancelableTask, SequentialCancelAndWait) { + CancelableTaskManager manager; + ResultType result1 = 0; + SequentialRunner runner1( + new TestTask(&manager, &result1, TestTask::kCheckNotRun)); + EXPECT_EQ(GetValue(&result1), 0); + manager.CancelAndWait(); + EXPECT_EQ(GetValue(&result1), 0); + runner1.Run(); // Run to avoid leaking the Task. + EXPECT_EQ(GetValue(&result1), 0); +} + + +TEST(CancelableTask, SequentialMultipleTasks) { + CancelableTaskManager manager; + ResultType result1 = 0; + ResultType result2 = 0; + TestTask* task1 = new TestTask(&manager, &result1); + TestTask* task2 = new TestTask(&manager, &result2); + SequentialRunner runner1(task1); + SequentialRunner runner2(task2); + EXPECT_EQ(task1->id(), 1u); + EXPECT_EQ(task2->id(), 2u); + + EXPECT_EQ(GetValue(&result1), 0); + runner1.Run(); // Don't touch task1 after running it. + EXPECT_EQ(GetValue(&result1), 1); + + EXPECT_EQ(GetValue(&result2), 0); + runner2.Run(); // Don't touch task2 after running it. + EXPECT_EQ(GetValue(&result2), 2); + + manager.CancelAndWait(); + EXPECT_FALSE(manager.TryAbort(1)); + EXPECT_FALSE(manager.TryAbort(2)); +} + + +TEST(CancelableTask, ThreadedMultipleTasksStarted) { + CancelableTaskManager manager; + ResultType result1 = 0; + ResultType result2 = 0; + TestTask* task1 = + new TestTask(&manager, &result1, TestTask::kWaitTillCanceledAgain); + TestTask* task2 = + new TestTask(&manager, &result2, TestTask::kWaitTillCanceledAgain); + ThreadedRunner runner1(task1); + ThreadedRunner runner2(task2); + runner1.Start(); + runner2.Start(); + // Busy wait on result to make sure both tasks are done. + while ((GetValue(&result1) == 0) || (GetValue(&result2) == 0)) { + } + manager.CancelAndWait(); + runner1.Join(); + runner2.Join(); + EXPECT_EQ(GetValue(&result1), 1); + EXPECT_EQ(GetValue(&result2), 2); +} + + +TEST(CancelableTask, ThreadedMultipleTasksNotRun) { + CancelableTaskManager manager; + ResultType result1 = 0; + ResultType result2 = 0; + TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun); + TestTask* task2 = new TestTask(&manager, &result2, TestTask::kCheckNotRun); + ThreadedRunner runner1(task1); + ThreadedRunner runner2(task2); + manager.CancelAndWait(); + // Tasks are canceled, hence the runner will bail out and not update result. + runner1.Start(); + runner2.Start(); + runner1.Join(); + runner2.Join(); + EXPECT_EQ(GetValue(&result1), 0); + EXPECT_EQ(GetValue(&result2), 0); +} + + +TEST(CancelableTask, RemoveBeforeCancelAndWait) { + CancelableTaskManager manager; + ResultType result1 = 0; + TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun); + ThreadedRunner runner1(task1); + uint32_t id = task1->id(); + EXPECT_EQ(id, 1u); + EXPECT_TRUE(manager.TryAbort(id)); + runner1.Start(); + runner1.Join(); + manager.CancelAndWait(); + EXPECT_EQ(GetValue(&result1), 0); +} + + +TEST(CancelableTask, RemoveAfterCancelAndWait) { + CancelableTaskManager manager; + ResultType result1 = 0; + TestTask* task1 = new TestTask(&manager, &result1); + ThreadedRunner runner1(task1); + uint32_t id = task1->id(); + EXPECT_EQ(id, 1u); + runner1.Start(); + runner1.Join(); + manager.CancelAndWait(); + EXPECT_FALSE(manager.TryAbort(id)); + EXPECT_EQ(GetValue(&result1), 1); +} + + +TEST(CancelableTask, RemoveUnmanagedId) { + CancelableTaskManager manager; + EXPECT_FALSE(manager.TryAbort(1)); + EXPECT_FALSE(manager.TryAbort(2)); + manager.CancelAndWait(); + EXPECT_FALSE(manager.TryAbort(1)); + EXPECT_FALSE(manager.TryAbort(3)); +} + +} // namespace internal +} // namespace v8 |