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 : #ifndef V8_CANCELABLE_TASK_H_
6 : #define V8_CANCELABLE_TASK_H_
7 :
8 : #include <unordered_map>
9 :
10 : #include "include/v8-platform.h"
11 : #include "src/base/atomic-utils.h"
12 : #include "src/base/macros.h"
13 : #include "src/base/platform/condition-variable.h"
14 : #include "src/globals.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 : class Cancelable;
20 : class Isolate;
21 :
22 :
23 : // Keeps track of cancelable tasks. It is possible to register and remove tasks
24 : // from any fore- and background task/thread.
25 521966 : class V8_EXPORT_PRIVATE CancelableTaskManager {
26 : public:
27 : using Id = uint64_t;
28 :
29 : CancelableTaskManager();
30 :
31 : // Registers a new cancelable {task}. Returns the unique {id} of the task that
32 : // can be used to try to abort a task by calling {Abort}.
33 : // Must not be called after CancelAndWait.
34 : Id Register(Cancelable* task);
35 :
36 : // Try to abort running a task identified by {id}. The possible outcomes are:
37 : // (1) The task is already finished running or was canceled before and
38 : // thus has been removed from the manager.
39 : // (2) The task is currently running and cannot be canceled anymore.
40 : // (3) The task is not yet running (or finished) so it is canceled and
41 : // removed.
42 : //
43 : enum TryAbortResult { kTaskRemoved, kTaskRunning, kTaskAborted };
44 : TryAbortResult TryAbort(Id id);
45 :
46 : // Cancels all remaining registered tasks and waits for tasks that are
47 : // already running. This disallows subsequent Register calls.
48 : void CancelAndWait();
49 :
50 : // Tries to cancel all remaining registered tasks. The return value indicates
51 : // whether
52 : //
53 : // 1) No tasks were registered (kTaskRemoved), or
54 : //
55 : // 2) There is at least one remaining task that couldn't be cancelled
56 : // (kTaskRunning), or
57 : //
58 : // 3) All registered tasks were cancelled (kTaskAborted).
59 : TryAbortResult TryAbortAll();
60 :
61 : private:
62 : // Only called by {Cancelable} destructor. The task is done with executing,
63 : // but needs to be removed.
64 : void RemoveFinishedTask(Id id);
65 :
66 : // To mitigate the ABA problem, the api refers to tasks through an id.
67 : Id task_id_counter_;
68 :
69 : // A set of cancelable tasks that are currently registered.
70 : std::unordered_map<Id, Cancelable*> cancelable_tasks_;
71 :
72 : // Mutex and condition variable enabling concurrent register and removing, as
73 : // well as waiting for background tasks on {CancelAndWait}.
74 : base::ConditionVariable cancelable_tasks_barrier_;
75 : base::Mutex mutex_;
76 :
77 : bool canceled_;
78 :
79 : friend class Cancelable;
80 :
81 : DISALLOW_COPY_AND_ASSIGN(CancelableTaskManager);
82 : };
83 :
84 : class V8_EXPORT_PRIVATE Cancelable {
85 : public:
86 : explicit Cancelable(CancelableTaskManager* parent);
87 : virtual ~Cancelable();
88 :
89 : // Never invoke after handing over the task to the platform! The reason is
90 : // that {Cancelable} is used in combination with {v8::Task} and handed to
91 : // a platform. This step transfers ownership to the platform, which destroys
92 : // the task after running it. Since the exact time is not known, we cannot
93 : // access the object after handing it to a platform.
94 : CancelableTaskManager::Id id() { return id_; }
95 :
96 : protected:
97 4179407 : bool TryRun() { return status_.TrySetValue(kWaiting, kRunning); }
98 2092122 : bool IsRunning() { return status_.Value() == kRunning; }
99 : intptr_t CancelAttempts() { return cancel_counter_.Value(); }
100 :
101 : private:
102 : // Identifies the state a cancelable task is in:
103 : // |kWaiting|: The task is scheduled and waiting to be executed. {TryRun} will
104 : // succeed.
105 : // |kCanceled|: The task has been canceled. {TryRun} will fail.
106 : // |kRunning|: The task is currently running and cannot be canceled anymore.
107 : enum Status {
108 : kWaiting,
109 : kCanceled,
110 : kRunning,
111 : };
112 :
113 : // Use {CancelableTaskManager} to abort a task that has not yet been
114 : // executed.
115 84415 : bool Cancel() {
116 84415 : if (status_.TrySetValue(kWaiting, kCanceled)) {
117 : return true;
118 : }
119 : cancel_counter_.Increment(1);
120 44264 : return false;
121 : }
122 :
123 : CancelableTaskManager* parent_;
124 : base::AtomicValue<Status> status_;
125 : CancelableTaskManager::Id id_;
126 :
127 : // The counter is incremented for failing tries to cancel a task. This can be
128 : // used by the task itself as an indication how often external entities tried
129 : // to abort it.
130 : base::AtomicNumber<intptr_t> cancel_counter_;
131 :
132 : friend class CancelableTaskManager;
133 :
134 : DISALLOW_COPY_AND_ASSIGN(Cancelable);
135 : };
136 :
137 :
138 : // Multiple inheritance can be used because Task is a pure interface.
139 2078572 : class V8_EXPORT_PRIVATE CancelableTask : public Cancelable,
140 : NON_EXPORTED_BASE(public Task) {
141 : public:
142 : explicit CancelableTask(Isolate* isolate);
143 : explicit CancelableTask(CancelableTaskManager* manager);
144 :
145 : // Task overrides.
146 1039306 : void Run() final {
147 1039306 : if (TryRun()) {
148 1000275 : RunInternal();
149 : }
150 1039603 : }
151 :
152 : virtual void RunInternal() = 0;
153 :
154 : private:
155 : DISALLOW_COPY_AND_ASSIGN(CancelableTask);
156 : };
157 :
158 :
159 : // Multiple inheritance can be used because IdleTask is a pure interface.
160 11232 : class CancelableIdleTask : public Cancelable, public IdleTask {
161 : public:
162 : explicit CancelableIdleTask(Isolate* isolate);
163 : explicit CancelableIdleTask(CancelableTaskManager* manager);
164 :
165 : // IdleTask overrides.
166 5603 : void Run(double deadline_in_seconds) final {
167 5603 : if (TryRun()) {
168 5603 : RunInternal(deadline_in_seconds);
169 : }
170 5603 : }
171 :
172 : virtual void RunInternal(double deadline_in_seconds) = 0;
173 :
174 : private:
175 : DISALLOW_COPY_AND_ASSIGN(CancelableIdleTask);
176 : };
177 :
178 :
179 : } // namespace internal
180 : } // namespace v8
181 :
182 : #endif // V8_CANCELABLE_TASK_H_
|