• 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/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 
Cancelable(CancelableTaskManager * parent)14 Cancelable::Cancelable(CancelableTaskManager* parent)
15     : parent_(parent), status_(kWaiting), id_(0), cancel_counter_(0) {
16   id_ = parent->Register(this);
17 }
18 
19 
~Cancelable()20 Cancelable::~Cancelable() {
21   // The following check is needed to avoid calling an already terminated
22   // manager object. This happens when the manager cancels all pending tasks
23   // in {CancelAndWait} only before destroying the manager object.
24   if (TryRun() || IsRunning()) {
25     parent_->RemoveFinishedTask(id_);
26   }
27 }
28 
CancelableTaskManager()29 CancelableTaskManager::CancelableTaskManager()
30     : task_id_counter_(0), canceled_(false) {}
31 
Register(Cancelable * task)32 CancelableTaskManager::Id CancelableTaskManager::Register(Cancelable* task) {
33   base::LockGuard<base::Mutex> guard(&mutex_);
34   CancelableTaskManager::Id id = ++task_id_counter_;
35   // Id overflows are not supported.
36   CHECK_NE(0, id);
37   CHECK(!canceled_);
38   cancelable_tasks_[id] = task;
39   return id;
40 }
41 
RemoveFinishedTask(CancelableTaskManager::Id id)42 void CancelableTaskManager::RemoveFinishedTask(CancelableTaskManager::Id id) {
43   base::LockGuard<base::Mutex> guard(&mutex_);
44   size_t removed = cancelable_tasks_.erase(id);
45   USE(removed);
46   DCHECK_NE(0u, removed);
47   cancelable_tasks_barrier_.NotifyOne();
48 }
49 
TryAbort(CancelableTaskManager::Id id)50 CancelableTaskManager::TryAbortResult CancelableTaskManager::TryAbort(
51     CancelableTaskManager::Id id) {
52   base::LockGuard<base::Mutex> guard(&mutex_);
53   auto entry = cancelable_tasks_.find(id);
54   if (entry != cancelable_tasks_.end()) {
55     Cancelable* value = entry->second;
56     if (value->Cancel()) {
57       // Cannot call RemoveFinishedTask here because of recursive locking.
58       cancelable_tasks_.erase(entry);
59       cancelable_tasks_barrier_.NotifyOne();
60       return kTaskAborted;
61     } else {
62       return kTaskRunning;
63     }
64   }
65   return kTaskRemoved;
66 }
67 
CancelAndWait()68 void CancelableTaskManager::CancelAndWait() {
69   // Clean up all cancelable fore- and background tasks. Tasks are canceled on
70   // the way if possible, i.e., if they have not started yet.  After each round
71   // of canceling we wait for the background tasks that have already been
72   // started.
73   base::LockGuard<base::Mutex> guard(&mutex_);
74   canceled_ = true;
75 
76   // Cancelable tasks could be running or could potentially register new
77   // tasks, requiring a loop here.
78   while (!cancelable_tasks_.empty()) {
79     for (auto it = cancelable_tasks_.begin(); it != cancelable_tasks_.end();) {
80       auto current = it;
81       // We need to get to the next element before erasing the current.
82       ++it;
83       if (current->second->Cancel()) {
84         cancelable_tasks_.erase(current);
85       }
86     }
87     // Wait for already running background tasks.
88     if (!cancelable_tasks_.empty()) {
89       cancelable_tasks_barrier_.Wait(&mutex_);
90     }
91   }
92 }
93 
TryAbortAll()94 CancelableTaskManager::TryAbortResult CancelableTaskManager::TryAbortAll() {
95   // Clean up all cancelable fore- and background tasks. Tasks are canceled on
96   // the way if possible, i.e., if they have not started yet.
97   base::LockGuard<base::Mutex> guard(&mutex_);
98 
99   if (cancelable_tasks_.empty()) return kTaskRemoved;
100 
101   for (auto it = cancelable_tasks_.begin(); it != cancelable_tasks_.end();) {
102     if (it->second->Cancel()) {
103       it = cancelable_tasks_.erase(it);
104     } else {
105       ++it;
106     }
107   }
108 
109   return cancelable_tasks_.empty() ? kTaskAborted : kTaskRunning;
110 }
111 
CancelableTask(Isolate * isolate)112 CancelableTask::CancelableTask(Isolate* isolate)
113     : CancelableTask(isolate->cancelable_task_manager()) {}
114 
CancelableTask(CancelableTaskManager * manager)115 CancelableTask::CancelableTask(CancelableTaskManager* manager)
116     : Cancelable(manager) {}
117 
CancelableIdleTask(Isolate * isolate)118 CancelableIdleTask::CancelableIdleTask(Isolate* isolate)
119     : CancelableIdleTask(isolate->cancelable_task_manager()) {}
120 
CancelableIdleTask(CancelableTaskManager * manager)121 CancelableIdleTask::CancelableIdleTask(CancelableTaskManager* manager)
122     : Cancelable(manager) {}
123 
124 }  // namespace internal
125 }  // namespace v8
126