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 3312082 : 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 1655938 : if (TryRun(&previous) || previous == kRunning) {
19 1466195 : parent_->RemoveFinishedTask(id_);
20 : }
21 1656144 : }
22 :
23 185769 : CancelableTaskManager::CancelableTaskManager()
24 371538 : : task_id_counter_(kInvalidTaskId), canceled_(false) {}
25 :
26 553760 : 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 184586 : CHECK(canceled_);
32 184588 : }
33 :
34 1658766 : CancelableTaskManager::Id CancelableTaskManager::Register(Cancelable* task) {
35 1658766 : base::MutexGuard guard(&mutex_);
36 1658768 : 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 1658762 : CancelableTaskManager::Id id = ++task_id_counter_;
43 : // Id overflows are not supported.
44 1658762 : CHECK_NE(kInvalidTaskId, id);
45 1658762 : CHECK(!canceled_);
46 1658760 : cancelable_tasks_[id] = task;
47 1658760 : return id;
48 : }
49 :
50 1465451 : void CancelableTaskManager::RemoveFinishedTask(CancelableTaskManager::Id id) {
51 1465451 : CHECK_NE(kInvalidTaskId, id);
52 1465451 : base::MutexGuard guard(&mutex_);
53 : size_t removed = cancelable_tasks_.erase(id);
54 : USE(removed);
55 : DCHECK_NE(0u, removed);
56 1466476 : cancelable_tasks_barrier_.NotifyOne();
57 1466410 : }
58 :
59 1034597 : TryAbortResult CancelableTaskManager::TryAbort(CancelableTaskManager::Id id) {
60 1034597 : CHECK_NE(kInvalidTaskId, id);
61 1034597 : base::MutexGuard guard(&mutex_);
62 : auto entry = cancelable_tasks_.find(id);
63 1034597 : if (entry != cancelable_tasks_.end()) {
64 548644 : Cancelable* value = entry->second;
65 548644 : if (value->Cancel()) {
66 : // Cannot call RemoveFinishedTask here because of recursive locking.
67 : cancelable_tasks_.erase(entry);
68 170246 : cancelable_tasks_barrier_.NotifyOne();
69 170246 : return TryAbortResult::kTaskAborted;
70 : } else {
71 : return TryAbortResult::kTaskRunning;
72 : }
73 : }
74 : return TryAbortResult::kTaskRemoved;
75 : }
76 :
77 187100 : 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 187100 : base::MutexGuard guard(&mutex_);
83 187103 : canceled_ = true;
84 :
85 : // Cancelable tasks could be running or could potentially register new
86 : // tasks, requiring a loop here.
87 196007 : while (!cancelable_tasks_.empty()) {
88 37040 : 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 56272 : if (current->second->Cancel()) {
93 : cancelable_tasks_.erase(current);
94 : }
95 : }
96 : // Wait for already running background tasks.
97 8904 : if (!cancelable_tasks_.empty()) {
98 2886 : cancelable_tasks_barrier_.Wait(&mutex_);
99 : }
100 : }
101 187102 : }
102 :
103 61534 : 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 61534 : base::MutexGuard guard(&mutex_);
107 :
108 61535 : if (cancelable_tasks_.empty()) return TryAbortResult::kTaskRemoved;
109 :
110 17 : for (auto it = cancelable_tasks_.begin(); it != cancelable_tasks_.end();) {
111 20 : 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 1616884 : CancelableTask::CancelableTask(Isolate* isolate)
123 1616884 : : CancelableTask(isolate->cancelable_task_manager()) {}
124 :
125 38987 : CancelableTask::CancelableTask(CancelableTaskManager* manager)
126 3311743 : : Cancelable(manager) {}
127 :
128 2863 : CancelableIdleTask::CancelableIdleTask(Isolate* isolate)
129 2863 : : CancelableIdleTask(isolate->cancelable_task_manager()) {}
130 :
131 19 : CancelableIdleTask::CancelableIdleTask(CancelableTaskManager* manager)
132 5764 : : Cancelable(manager) {}
133 :
134 : } // namespace internal
135 120216 : } // namespace v8
|