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