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 class TestTask : public Task, public Cancelable {
17 public:
18 enum Mode { kDoNothing, kWaitTillCanceledAgain, kCheckNotRun };
19
TestTask(CancelableTaskManager * parent,base::AtomicWord * result,Mode mode=kDoNothing)20 TestTask(CancelableTaskManager* parent, base::AtomicWord* result,
21 Mode mode = kDoNothing)
22 : Cancelable(parent), result_(result), mode_(mode) {}
23
24 // Task overrides.
Run()25 void Run() final {
26 if (TryRun()) {
27 RunInternal();
28 }
29 }
30
31 private:
RunInternal()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
55 class SequentialRunner {
56 public:
SequentialRunner(TestTask * task)57 explicit SequentialRunner(TestTask* task) : task_(task) {}
58
Run()59 void Run() {
60 task_->Run();
61 delete task_;
62 }
63
64 private:
65 TestTask* task_;
66 };
67
68
69 class ThreadedRunner final : public base::Thread {
70 public:
ThreadedRunner(TestTask * task)71 explicit ThreadedRunner(TestTask* task)
72 : Thread(Options("runner thread")), task_(task) {}
73
Run()74 virtual void Run() {
75 task_->Run();
76 delete task_;
77 }
78
79 private:
80 TestTask* task_;
81 };
82
83
84 typedef base::AtomicWord ResultType;
85
86
GetValue(ResultType * result)87 intptr_t GetValue(ResultType* result) { return base::Acquire_Load(result); }
88
89 } // namespace
90
91
TEST(CancelableTask,EmptyCancelableTaskManager)92 TEST(CancelableTask, EmptyCancelableTaskManager) {
93 CancelableTaskManager manager;
94 manager.CancelAndWait();
95 }
96
97
TEST(CancelableTask,SequentialCancelAndWait)98 TEST(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
TEST(CancelableTask,SequentialMultipleTasks)111 TEST(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
TEST(CancelableTask,ThreadedMultipleTasksStarted)136 TEST(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
TEST(CancelableTask,ThreadedMultipleTasksNotRun)159 TEST(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
TEST(CancelableTask,RemoveBeforeCancelAndWait)178 TEST(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
TEST(CancelableTask,RemoveAfterCancelAndWait)193 TEST(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
TEST(CancelableTask,RemoveUnmanagedId)208 TEST(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
219