• 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 #include "src/tasks/cancelable-task.h"
6 
7 #include "src/base/platform/platform.h"
8 #include "src/execution/isolate.h"
9 
10 namespace v8 {
11 namespace internal {
12 
~Cancelable()13 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   if (TryRun(&previous) || previous == kRunning) {
19     parent_->RemoveFinishedTask(id_);
20   }
21 }
22 
CancelableTaskManager()23 CancelableTaskManager::CancelableTaskManager()
24     : task_id_counter_(kInvalidTaskId), canceled_(false) {}
25 
~CancelableTaskManager()26 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   CHECK(canceled_);
32 }
33 
Register(Cancelable * task)34 CancelableTaskManager::Id CancelableTaskManager::Register(Cancelable* task) {
35   base::MutexGuard guard(&mutex_);
36   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     return kInvalidTaskId;
41   }
42   CancelableTaskManager::Id id = ++task_id_counter_;
43   // Id overflows are not supported.
44   CHECK_NE(kInvalidTaskId, id);
45   CHECK(!canceled_);
46   cancelable_tasks_[id] = task;
47   return id;
48 }
49 
RemoveFinishedTask(CancelableTaskManager::Id id)50 void CancelableTaskManager::RemoveFinishedTask(CancelableTaskManager::Id id) {
51   CHECK_NE(kInvalidTaskId, id);
52   base::MutexGuard guard(&mutex_);
53   size_t removed = cancelable_tasks_.erase(id);
54   USE(removed);
55   DCHECK_NE(0u, removed);
56   cancelable_tasks_barrier_.NotifyOne();
57 }
58 
TryAbort(CancelableTaskManager::Id id)59 TryAbortResult CancelableTaskManager::TryAbort(CancelableTaskManager::Id id) {
60   CHECK_NE(kInvalidTaskId, id);
61   base::MutexGuard guard(&mutex_);
62   auto entry = cancelable_tasks_.find(id);
63   if (entry != cancelable_tasks_.end()) {
64     Cancelable* value = entry->second;
65     if (value->Cancel()) {
66       // Cannot call RemoveFinishedTask here because of recursive locking.
67       cancelable_tasks_.erase(entry);
68       cancelable_tasks_barrier_.NotifyOne();
69       return TryAbortResult::kTaskAborted;
70     } else {
71       return TryAbortResult::kTaskRunning;
72     }
73   }
74   return TryAbortResult::kTaskRemoved;
75 }
76 
CancelAndWait()77 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   base::MutexGuard guard(&mutex_);
83   canceled_ = true;
84 
85   // Cancelable tasks could be running or could potentially register new
86   // tasks, requiring a loop here.
87   while (!cancelable_tasks_.empty()) {
88     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       if (current->second->Cancel()) {
93         cancelable_tasks_.erase(current);
94       }
95     }
96     // Wait for already running background tasks.
97     if (!cancelable_tasks_.empty()) {
98       cancelable_tasks_barrier_.Wait(&mutex_);
99     }
100   }
101 }
102 
TryAbortAll()103 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   base::MutexGuard guard(&mutex_);
107 
108   if (cancelable_tasks_.empty()) return TryAbortResult::kTaskRemoved;
109 
110   for (auto it = cancelable_tasks_.begin(); it != cancelable_tasks_.end();) {
111     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                                    : TryAbortResult::kTaskRunning;
120 }
121 
CancelableTask(Isolate * isolate)122 CancelableTask::CancelableTask(Isolate* isolate)
123     : CancelableTask(isolate->cancelable_task_manager()) {}
124 
CancelableTask(CancelableTaskManager * manager)125 CancelableTask::CancelableTask(CancelableTaskManager* manager)
126     : Cancelable(manager) {}
127 
CancelableIdleTask(Isolate * isolate)128 CancelableIdleTask::CancelableIdleTask(Isolate* isolate)
129     : CancelableIdleTask(isolate->cancelable_task_manager()) {}
130 
CancelableIdleTask(CancelableTaskManager * manager)131 CancelableIdleTask::CancelableIdleTask(CancelableTaskManager* manager)
132     : Cancelable(manager) {}
133 
134 }  // namespace internal
135 }  // namespace v8
136