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 14 Cancelable::Cancelable(CancelableTaskManager* parent) 15 : parent_(parent), status_(kWaiting), id_(0), cancel_counter_(0) { 16 id_ = parent->Register(this); 17 } 18 19 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 29 CancelableTaskManager::CancelableTaskManager() 30 : task_id_counter_(0), canceled_(false) {} 31 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 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 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 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 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 112 CancelableTask::CancelableTask(Isolate* isolate) 113 : CancelableTask(isolate->cancelable_task_manager()) {} 114 115 CancelableTask::CancelableTask(CancelableTaskManager* manager) 116 : Cancelable(manager) {} 117 118 CancelableIdleTask::CancelableIdleTask(Isolate* isolate) 119 : CancelableIdleTask(isolate->cancelable_task_manager()) {} 120 121 CancelableIdleTask::CancelableIdleTask(CancelableTaskManager* manager) 122 : Cancelable(manager) {} 123 124 } // namespace internal 125 } // namespace v8 126