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