blob: 37690aaf80678f39e799579b285f184296e71d5e [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/base/atomicops.h"
6#include "src/base/platform/platform.h"
7#include "src/cancelable-task.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10
11namespace v8 {
12namespace internal {
13
14namespace {
15
16class TestTask : public Task, public Cancelable {
17 public:
18 enum Mode { kDoNothing, kWaitTillCanceledAgain, kCheckNotRun };
19
20 TestTask(CancelableTaskManager* parent, base::AtomicWord* result,
21 Mode mode = kDoNothing)
22 : Cancelable(parent), result_(result), mode_(mode) {}
23
24 // Task overrides.
25 void Run() final {
26 if (TryRun()) {
27 RunInternal();
28 }
29 }
30
31 private:
32 void RunInternal() {
33 base::Release_Store(result_, id());
34
35 switch (mode_) {
36 case kWaitTillCanceledAgain:
37 // Simple busy wait until the main thread tried to cancel.
38 while (CancelAttempts() == 0) {
39 }
40 break;
41 case kCheckNotRun:
42 // Check that we never execute {RunInternal}.
43 EXPECT_TRUE(false);
44 break;
45 default:
46 break;
47 }
48 }
49
50 base::AtomicWord* result_;
51 Mode mode_;
52};
53
54
55class SequentialRunner {
56 public:
57 explicit SequentialRunner(TestTask* task) : task_(task) {}
58
59 void Run() {
60 task_->Run();
61 delete task_;
62 }
63
64 private:
65 TestTask* task_;
66};
67
68
69class ThreadedRunner final : public base::Thread {
70 public:
71 explicit ThreadedRunner(TestTask* task)
72 : Thread(Options("runner thread")), task_(task) {}
73
74 virtual void Run() {
75 task_->Run();
76 delete task_;
77 }
78
79 private:
80 TestTask* task_;
81};
82
83
84typedef base::AtomicWord ResultType;
85
86
87intptr_t GetValue(ResultType* result) { return base::Acquire_Load(result); }
88
89} // namespace
90
91
92TEST(CancelableTask, EmptyCancelableTaskManager) {
93 CancelableTaskManager manager;
94 manager.CancelAndWait();
95}
96
97
98TEST(CancelableTask, SequentialCancelAndWait) {
99 CancelableTaskManager manager;
100 ResultType result1 = 0;
101 SequentialRunner runner1(
102 new TestTask(&manager, &result1, TestTask::kCheckNotRun));
103 EXPECT_EQ(GetValue(&result1), 0);
104 manager.CancelAndWait();
105 EXPECT_EQ(GetValue(&result1), 0);
106 runner1.Run(); // Run to avoid leaking the Task.
107 EXPECT_EQ(GetValue(&result1), 0);
108}
109
110
111TEST(CancelableTask, SequentialMultipleTasks) {
112 CancelableTaskManager manager;
113 ResultType result1 = 0;
114 ResultType result2 = 0;
115 TestTask* task1 = new TestTask(&manager, &result1);
116 TestTask* task2 = new TestTask(&manager, &result2);
117 SequentialRunner runner1(task1);
118 SequentialRunner runner2(task2);
119 EXPECT_EQ(task1->id(), 1u);
120 EXPECT_EQ(task2->id(), 2u);
121
122 EXPECT_EQ(GetValue(&result1), 0);
123 runner1.Run(); // Don't touch task1 after running it.
124 EXPECT_EQ(GetValue(&result1), 1);
125
126 EXPECT_EQ(GetValue(&result2), 0);
127 runner2.Run(); // Don't touch task2 after running it.
128 EXPECT_EQ(GetValue(&result2), 2);
129
130 manager.CancelAndWait();
131 EXPECT_FALSE(manager.TryAbort(1));
132 EXPECT_FALSE(manager.TryAbort(2));
133}
134
135
136TEST(CancelableTask, ThreadedMultipleTasksStarted) {
137 CancelableTaskManager manager;
138 ResultType result1 = 0;
139 ResultType result2 = 0;
140 TestTask* task1 =
141 new TestTask(&manager, &result1, TestTask::kWaitTillCanceledAgain);
142 TestTask* task2 =
143 new TestTask(&manager, &result2, TestTask::kWaitTillCanceledAgain);
144 ThreadedRunner runner1(task1);
145 ThreadedRunner runner2(task2);
146 runner1.Start();
147 runner2.Start();
148 // Busy wait on result to make sure both tasks are done.
149 while ((GetValue(&result1) == 0) || (GetValue(&result2) == 0)) {
150 }
151 manager.CancelAndWait();
152 runner1.Join();
153 runner2.Join();
154 EXPECT_EQ(GetValue(&result1), 1);
155 EXPECT_EQ(GetValue(&result2), 2);
156}
157
158
159TEST(CancelableTask, ThreadedMultipleTasksNotRun) {
160 CancelableTaskManager manager;
161 ResultType result1 = 0;
162 ResultType result2 = 0;
163 TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun);
164 TestTask* task2 = new TestTask(&manager, &result2, TestTask::kCheckNotRun);
165 ThreadedRunner runner1(task1);
166 ThreadedRunner runner2(task2);
167 manager.CancelAndWait();
168 // Tasks are canceled, hence the runner will bail out and not update result.
169 runner1.Start();
170 runner2.Start();
171 runner1.Join();
172 runner2.Join();
173 EXPECT_EQ(GetValue(&result1), 0);
174 EXPECT_EQ(GetValue(&result2), 0);
175}
176
177
178TEST(CancelableTask, RemoveBeforeCancelAndWait) {
179 CancelableTaskManager manager;
180 ResultType result1 = 0;
181 TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun);
182 ThreadedRunner runner1(task1);
183 uint32_t id = task1->id();
184 EXPECT_EQ(id, 1u);
185 EXPECT_TRUE(manager.TryAbort(id));
186 runner1.Start();
187 runner1.Join();
188 manager.CancelAndWait();
189 EXPECT_EQ(GetValue(&result1), 0);
190}
191
192
193TEST(CancelableTask, RemoveAfterCancelAndWait) {
194 CancelableTaskManager manager;
195 ResultType result1 = 0;
196 TestTask* task1 = new TestTask(&manager, &result1);
197 ThreadedRunner runner1(task1);
198 uint32_t id = task1->id();
199 EXPECT_EQ(id, 1u);
200 runner1.Start();
201 runner1.Join();
202 manager.CancelAndWait();
203 EXPECT_FALSE(manager.TryAbort(id));
204 EXPECT_EQ(GetValue(&result1), 1);
205}
206
207
208TEST(CancelableTask, RemoveUnmanagedId) {
209 CancelableTaskManager manager;
210 EXPECT_FALSE(manager.TryAbort(1));
211 EXPECT_FALSE(manager.TryAbort(2));
212 manager.CancelAndWait();
213 EXPECT_FALSE(manager.TryAbort(1));
214 EXPECT_FALSE(manager.TryAbort(3));
215}
216
217} // namespace internal
218} // namespace v8