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