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 3792838 : 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 1896364 : if (TryRun(&previous) || previous == kRunning) {
19 1690790 : parent_->RemoveFinishedTask(id_);
20 : }
21 1896474 : }
22 :
23 188614 : CancelableTaskManager::CancelableTaskManager()
24 377228 : : task_id_counter_(kInvalidTaskId), canceled_(false) {}
25 :
26 562285 : 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 187428 : CHECK(canceled_);
32 187429 : }
33 :
34 1899117 : CancelableTaskManager::Id CancelableTaskManager::Register(Cancelable* task) {
35 1899117 : base::MutexGuard guard(&mutex_);
36 1899117 : 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 6 : return kInvalidTaskId;
41 : }
42 1899111 : CancelableTaskManager::Id id = ++task_id_counter_;
43 : // Id overflows are not supported.
44 1899111 : CHECK_NE(kInvalidTaskId, id);
45 1899111 : CHECK(!canceled_);
46 1899111 : cancelable_tasks_[id] = task;
47 1899111 : return id;
48 : }
49 :
50 1690214 : void CancelableTaskManager::RemoveFinishedTask(CancelableTaskManager::Id id) {
51 1690214 : CHECK_NE(kInvalidTaskId, id);
52 1690214 : base::MutexGuard guard(&mutex_);
53 : size_t removed = cancelable_tasks_.erase(id);
54 : USE(removed);
55 : DCHECK_NE(0u, removed);
56 1691034 : cancelable_tasks_barrier_.NotifyOne();
57 1690908 : }
58 :
59 1062663 : TryAbortResult CancelableTaskManager::TryAbort(CancelableTaskManager::Id id) {
60 1062663 : CHECK_NE(kInvalidTaskId, id);
61 1062663 : base::MutexGuard guard(&mutex_);
62 : auto entry = cancelable_tasks_.find(id);
63 1062663 : if (entry != cancelable_tasks_.end()) {
64 543217 : Cancelable* value = entry->second;
65 543217 : if (value->Cancel()) {
66 : // Cannot call RemoveFinishedTask here because of recursive locking.
67 : cancelable_tasks_.erase(entry);
68 182820 : cancelable_tasks_barrier_.NotifyOne();
69 182820 : return TryAbortResult::kTaskAborted;
70 : } else {
71 : return TryAbortResult::kTaskRunning;
72 : }
73 : }
74 : return TryAbortResult::kTaskRemoved;
75 : }
76 :
77 190034 : 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 190034 : base::MutexGuard guard(&mutex_);
83 190035 : canceled_ = true;
84 :
85 : // Cancelable tasks could be running or could potentially register new
86 : // tasks, requiring a loop here.
87 201296 : while (!cancelable_tasks_.empty()) {
88 45633 : 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 68744 : if (current->second->Cancel()) {
93 : cancelable_tasks_.erase(current);
94 : }
95 : }
96 : // Wait for already running background tasks.
97 11261 : if (!cancelable_tasks_.empty()) {
98 4005 : cancelable_tasks_barrier_.Wait(&mutex_);
99 : }
100 : }
101 190035 : }
102 :
103 62442 : 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 62442 : base::MutexGuard guard(&mutex_);
107 :
108 62443 : if (cancelable_tasks_.empty()) return TryAbortResult::kTaskRemoved;
109 :
110 21 : for (auto it = cancelable_tasks_.begin(); it != cancelable_tasks_.end();) {
111 30 : 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 6 : : TryAbortResult::kTaskRunning;
120 : }
121 :
122 1673959 : CancelableTask::CancelableTask(Isolate* isolate)
123 1673959 : : CancelableTask(isolate->cancelable_task_manager()) {}
124 :
125 221390 : CancelableTask::CancelableTask(CancelableTaskManager* manager)
126 3790698 : : Cancelable(manager) {}
127 :
128 3739 : CancelableIdleTask::CancelableIdleTask(Isolate* isolate)
129 3739 : : CancelableIdleTask(isolate->cancelable_task_manager()) {}
130 :
131 16 : CancelableIdleTask::CancelableIdleTask(CancelableTaskManager* manager)
132 7510 : : Cancelable(manager) {}
133 :
134 : } // namespace internal
135 122036 : } // namespace v8
|