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