Line data Source code
1 : // 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 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 : namespace {
15 :
16 26 : class 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 13 : : Cancelable(parent), result_(result), mode_(mode) {}
23 :
24 : // Task overrides.
25 13 : void Run() final {
26 13 : if (TryRun()) {
27 6 : RunInternal();
28 : }
29 13 : }
30 :
31 : private:
32 6 : void RunInternal() {
33 6 : base::Release_Store(result_, id());
34 :
35 6 : switch (mode_) {
36 : case kWaitTillCanceledAgain:
37 : // Simple busy wait until the main thread tried to cancel.
38 6706936 : while (CancelAttempts() == 0) {
39 : }
40 : break;
41 : case kCheckNotRun:
42 : // Check that we never execute {RunInternal}.
43 0 : EXPECT_TRUE(false);
44 0 : break;
45 : default:
46 : break;
47 : }
48 0 : }
49 :
50 : base::AtomicWord* result_;
51 : Mode mode_;
52 : };
53 :
54 :
55 : class SequentialRunner {
56 : public:
57 2 : explicit SequentialRunner(TestTask* task) : task_(task) {}
58 :
59 3 : void Run() {
60 3 : task_->Run();
61 3 : delete task_;
62 3 : }
63 :
64 : private:
65 : TestTask* task_;
66 : };
67 :
68 :
69 6 : class ThreadedRunner final : public base::Thread {
70 : public:
71 : explicit ThreadedRunner(TestTask* task)
72 10 : : Thread(Options("runner thread")), task_(task) {}
73 :
74 10 : virtual void Run() {
75 10 : task_->Run();
76 10 : delete task_;
77 10 : }
78 :
79 : private:
80 : TestTask* task_;
81 : };
82 :
83 :
84 : typedef base::AtomicWord ResultType;
85 :
86 :
87 : intptr_t GetValue(ResultType* result) { return base::Acquire_Load(result); }
88 :
89 : } // namespace
90 :
91 :
92 13158 : TEST(CancelableTask, EmptyCancelableTaskManager) {
93 1 : CancelableTaskManager manager;
94 1 : manager.CancelAndWait();
95 1 : }
96 :
97 :
98 13158 : TEST(CancelableTask, SequentialCancelAndWait) {
99 1 : CancelableTaskManager manager;
100 1 : ResultType result1 = 0;
101 : SequentialRunner runner1(
102 1 : new TestTask(&manager, &result1, TestTask::kCheckNotRun));
103 3 : EXPECT_EQ(GetValue(&result1), 0);
104 1 : manager.CancelAndWait();
105 3 : EXPECT_EQ(GetValue(&result1), 0);
106 1 : runner1.Run(); // Run to avoid leaking the Task.
107 4 : EXPECT_EQ(GetValue(&result1), 0);
108 1 : }
109 :
110 :
111 13158 : TEST(CancelableTask, SequentialMultipleTasks) {
112 1 : CancelableTaskManager manager;
113 1 : ResultType result1 = 0;
114 1 : ResultType result2 = 0;
115 1 : TestTask* task1 = new TestTask(&manager, &result1);
116 1 : TestTask* task2 = new TestTask(&manager, &result2);
117 : SequentialRunner runner1(task1);
118 : SequentialRunner runner2(task2);
119 2 : EXPECT_EQ(task1->id(), 1u);
120 2 : EXPECT_EQ(task2->id(), 2u);
121 :
122 3 : EXPECT_EQ(GetValue(&result1), 0);
123 1 : runner1.Run(); // Don't touch task1 after running it.
124 3 : EXPECT_EQ(GetValue(&result1), 1);
125 :
126 3 : EXPECT_EQ(GetValue(&result2), 0);
127 1 : runner2.Run(); // Don't touch task2 after running it.
128 3 : EXPECT_EQ(GetValue(&result2), 2);
129 :
130 1 : manager.CancelAndWait();
131 2 : EXPECT_FALSE(manager.TryAbort(1));
132 3 : EXPECT_FALSE(manager.TryAbort(2));
133 1 : }
134 :
135 :
136 13158 : TEST(CancelableTask, ThreadedMultipleTasksStarted) {
137 1 : CancelableTaskManager manager;
138 1 : ResultType result1 = 0;
139 1 : ResultType result2 = 0;
140 : TestTask* task1 =
141 1 : new TestTask(&manager, &result1, TestTask::kWaitTillCanceledAgain);
142 : TestTask* task2 =
143 1 : new TestTask(&manager, &result2, TestTask::kWaitTillCanceledAgain);
144 : ThreadedRunner runner1(task1);
145 : ThreadedRunner runner2(task2);
146 1 : runner1.Start();
147 1 : runner2.Start();
148 : // Busy wait on result to make sure both tasks are done.
149 11388944 : while ((GetValue(&result1) == 0) || (GetValue(&result2) == 0)) {
150 : }
151 1 : manager.CancelAndWait();
152 1 : runner1.Join();
153 1 : runner2.Join();
154 3 : EXPECT_EQ(GetValue(&result1), 1);
155 4 : EXPECT_EQ(GetValue(&result2), 2);
156 1 : }
157 :
158 :
159 13158 : TEST(CancelableTask, ThreadedMultipleTasksNotRun) {
160 1 : CancelableTaskManager manager;
161 1 : ResultType result1 = 0;
162 1 : ResultType result2 = 0;
163 1 : TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun);
164 1 : TestTask* task2 = new TestTask(&manager, &result2, TestTask::kCheckNotRun);
165 : ThreadedRunner runner1(task1);
166 : ThreadedRunner runner2(task2);
167 1 : manager.CancelAndWait();
168 : // Tasks are canceled, hence the runner will bail out and not update result.
169 1 : runner1.Start();
170 1 : runner2.Start();
171 1 : runner1.Join();
172 1 : runner2.Join();
173 3 : EXPECT_EQ(GetValue(&result1), 0);
174 4 : EXPECT_EQ(GetValue(&result2), 0);
175 1 : }
176 :
177 :
178 13158 : TEST(CancelableTask, RemoveBeforeCancelAndWait) {
179 1 : CancelableTaskManager manager;
180 1 : ResultType result1 = 0;
181 1 : TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun);
182 : ThreadedRunner runner1(task1);
183 1 : CancelableTaskManager::Id id = task1->id();
184 2 : EXPECT_EQ(id, 1u);
185 2 : EXPECT_TRUE(manager.TryAbort(id));
186 1 : runner1.Start();
187 1 : runner1.Join();
188 1 : manager.CancelAndWait();
189 4 : EXPECT_EQ(GetValue(&result1), 0);
190 1 : }
191 :
192 :
193 13158 : TEST(CancelableTask, RemoveAfterCancelAndWait) {
194 1 : CancelableTaskManager manager;
195 1 : ResultType result1 = 0;
196 1 : TestTask* task1 = new TestTask(&manager, &result1);
197 : ThreadedRunner runner1(task1);
198 1 : CancelableTaskManager::Id id = task1->id();
199 2 : EXPECT_EQ(id, 1u);
200 1 : runner1.Start();
201 1 : runner1.Join();
202 1 : manager.CancelAndWait();
203 2 : EXPECT_FALSE(manager.TryAbort(id));
204 4 : EXPECT_EQ(GetValue(&result1), 1);
205 1 : }
206 :
207 :
208 13158 : TEST(CancelableTask, RemoveUnmanagedId) {
209 1 : CancelableTaskManager manager;
210 2 : EXPECT_FALSE(manager.TryAbort(1));
211 2 : EXPECT_FALSE(manager.TryAbort(2));
212 1 : manager.CancelAndWait();
213 2 : EXPECT_FALSE(manager.TryAbort(1));
214 3 : EXPECT_FALSE(manager.TryAbort(3));
215 1 : }
216 :
217 13158 : TEST(CancelableTask, EmptyTryAbortAll) {
218 1 : CancelableTaskManager manager;
219 3 : EXPECT_EQ(manager.TryAbortAll(), CancelableTaskManager::kTaskRemoved);
220 1 : }
221 :
222 13158 : TEST(CancelableTask, ThreadedMultipleTasksNotRunTryAbortAll) {
223 1 : CancelableTaskManager manager;
224 1 : ResultType result1 = 0;
225 1 : ResultType result2 = 0;
226 1 : TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun);
227 1 : TestTask* task2 = new TestTask(&manager, &result2, TestTask::kCheckNotRun);
228 : ThreadedRunner runner1(task1);
229 : ThreadedRunner runner2(task2);
230 2 : EXPECT_EQ(manager.TryAbortAll(), CancelableTaskManager::kTaskAborted);
231 : // Tasks are canceled, hence the runner will bail out and not update result.
232 1 : runner1.Start();
233 1 : runner2.Start();
234 1 : runner1.Join();
235 1 : runner2.Join();
236 3 : EXPECT_EQ(GetValue(&result1), 0);
237 4 : EXPECT_EQ(GetValue(&result2), 0);
238 1 : }
239 :
240 13158 : TEST(CancelableTask, ThreadedMultipleTasksStartedTryAbortAll) {
241 1 : CancelableTaskManager manager;
242 1 : ResultType result1 = 0;
243 1 : ResultType result2 = 0;
244 : TestTask* task1 =
245 1 : new TestTask(&manager, &result1, TestTask::kWaitTillCanceledAgain);
246 : TestTask* task2 =
247 1 : new TestTask(&manager, &result2, TestTask::kWaitTillCanceledAgain);
248 : ThreadedRunner runner1(task1);
249 : ThreadedRunner runner2(task2);
250 1 : runner1.Start();
251 : // Busy wait on result to make sure task1 is done.
252 2878159 : while (GetValue(&result1) == 0) {
253 : }
254 2 : EXPECT_EQ(manager.TryAbortAll(), CancelableTaskManager::kTaskRunning);
255 1 : runner2.Start();
256 1 : runner1.Join();
257 1 : runner2.Join();
258 3 : EXPECT_EQ(GetValue(&result1), 1);
259 4 : EXPECT_EQ(GetValue(&result2), 0);
260 1 : }
261 :
262 : } // namespace internal
263 7893 : } // namespace v8
|