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 : #include "src/cancelable-task.h"
6 :
7 : #include "src/base/platform/platform.h"
8 : #include "src/isolate.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 1813308 : Cancelable::~Cancelable() {
14 : // The following check is needed to avoid calling an already terminated
15 : // manager object. This happens when the manager cancels all pending tasks
16 : // in {CancelAndWait} only before destroying the manager object.
17 : Status previous;
18 1814543 : if (TryRun(&previous) || previous == kRunning) {
19 1639977 : parent_->RemoveFinishedTask(id_);
20 : }
21 1814838 : }
22 :
23 3189655 : CancelableTaskManager::CancelableTaskManager()
24 6379310 : : task_id_counter_(kInvalidTaskId), canceled_(false) {}
25 :
26 6379244 : CancelableTaskManager::~CancelableTaskManager() {
27 : // It is required that {CancelAndWait} is called before the manager object is
28 : // destroyed. This guarantees that all tasks managed by this
29 : // {CancelableTaskManager} are either canceled or finished their execution
30 : // when the {CancelableTaskManager} dies.
31 3189622 : CHECK(canceled_);
32 3189625 : }
33 :
34 1815326 : CancelableTaskManager::Id CancelableTaskManager::Register(Cancelable* task) {
35 1815326 : base::MutexGuard guard(&mutex_);
36 1815328 : if (canceled_) {
37 : // The CancelableTaskManager has already been canceled. Therefore we mark
38 : // the new task immediately as canceled so that it does not get executed.
39 : task->Cancel();
40 5 : return kInvalidTaskId;
41 : }
42 1815323 : CancelableTaskManager::Id id = ++task_id_counter_;
43 : // Id overflows are not supported.
44 1815323 : CHECK_NE(kInvalidTaskId, id);
45 1815323 : CHECK(!canceled_);
46 1815324 : cancelable_tasks_[id] = task;
47 1815324 : return id;
48 : }
49 :
50 1639647 : void CancelableTaskManager::RemoveFinishedTask(CancelableTaskManager::Id id) {
51 1639647 : CHECK_NE(kInvalidTaskId, id);
52 1639647 : base::MutexGuard guard(&mutex_);
53 : size_t removed = cancelable_tasks_.erase(id);
54 : USE(removed);
55 : DCHECK_NE(0u, removed);
56 1640328 : cancelable_tasks_barrier_.NotifyOne();
57 1640273 : }
58 :
59 1101732 : TryAbortResult CancelableTaskManager::TryAbort(CancelableTaskManager::Id id) {
60 1101732 : CHECK_NE(kInvalidTaskId, id);
61 1101732 : base::MutexGuard guard(&mutex_);
62 : auto entry = cancelable_tasks_.find(id);
63 1101732 : if (entry != cancelable_tasks_.end()) {
64 550219 : Cancelable* value = entry->second;
65 550219 : if (value->Cancel()) {
66 : // Cannot call RemoveFinishedTask here because of recursive locking.
67 : cancelable_tasks_.erase(entry);
68 160215 : cancelable_tasks_barrier_.NotifyOne();
69 160215 : return TryAbortResult::kTaskAborted;
70 : } else {
71 : return TryAbortResult::kTaskRunning;
72 : }
73 : }
74 : return TryAbortResult::kTaskRemoved;
75 : }
76 :
77 3192484 : void CancelableTaskManager::CancelAndWait() {
78 : // Clean up all cancelable fore- and background tasks. Tasks are canceled on
79 : // the way if possible, i.e., if they have not started yet. After each round
80 : // of canceling we wait for the background tasks that have already been
81 : // started.
82 3192484 : base::MutexGuard guard(&mutex_);
83 3192485 : canceled_ = true;
84 :
85 : // Cancelable tasks could be running or could potentially register new
86 : // tasks, requiring a loop here.
87 6398122 : while (!cancelable_tasks_.empty()) {
88 41495 : for (auto it = cancelable_tasks_.begin(); it != cancelable_tasks_.end();) {
89 : auto current = it;
90 : // We need to get to the next element before erasing the current.
91 : ++it;
92 30382 : if (current->second->Cancel()) {
93 : cancelable_tasks_.erase(current);
94 : }
95 : }
96 : // Wait for already running background tasks.
97 13152 : if (!cancelable_tasks_.empty()) {
98 300 : cancelable_tasks_barrier_.Wait(&mutex_);
99 : }
100 : }
101 3192485 : }
102 :
103 62882 : TryAbortResult CancelableTaskManager::TryAbortAll() {
104 : // Clean up all cancelable fore- and background tasks. Tasks are canceled on
105 : // the way if possible, i.e., if they have not started yet.
106 62882 : base::MutexGuard guard(&mutex_);
107 :
108 62884 : if (cancelable_tasks_.empty()) return TryAbortResult::kTaskRemoved;
109 :
110 36 : for (auto it = cancelable_tasks_.begin(); it != cancelable_tasks_.end();) {
111 44 : if (it->second->Cancel()) {
112 : it = cancelable_tasks_.erase(it);
113 : } else {
114 : ++it;
115 : }
116 : }
117 :
118 : return cancelable_tasks_.empty() ? TryAbortResult::kTaskAborted
119 7 : : TryAbortResult::kTaskRunning;
120 : }
121 :
122 1751715 : CancelableTask::CancelableTask(Isolate* isolate)
123 1751715 : : CancelableTask(isolate->cancelable_task_manager()) {}
124 :
125 59724 : CancelableTask::CancelableTask(CancelableTaskManager* manager)
126 3622880 : : Cancelable(manager) {}
127 :
128 3859 : CancelableIdleTask::CancelableIdleTask(Isolate* isolate)
129 3859 : : CancelableIdleTask(isolate->cancelable_task_manager()) {}
130 :
131 16 : CancelableIdleTask::CancelableIdleTask(CancelableTaskManager* manager)
132 7750 : : Cancelable(manager) {}
133 :
134 : } // namespace internal
135 183867 : } // namespace v8
|