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 CHECK(id_ != 0); 18 } 19 20 21 Cancelable::~Cancelable() { 22 // The following check is needed to avoid calling an already terminated 23 // manager object. This happens when the manager cancels all pending tasks 24 // in {CancelAndWait} only before destroying the manager object. 25 if (TryRun() || IsRunning()) { 26 parent_->RemoveFinishedTask(id_); 27 } 28 } 29 30 31 static bool ComparePointers(void* ptr1, void* ptr2) { return ptr1 == ptr2; } 32 33 34 CancelableTaskManager::CancelableTaskManager() 35 : task_id_counter_(0), cancelable_tasks_(ComparePointers) {} 36 37 38 uint32_t CancelableTaskManager::Register(Cancelable* task) { 39 base::LockGuard<base::Mutex> guard(&mutex_); 40 uint32_t id = ++task_id_counter_; 41 // The loop below is just used when task_id_counter_ overflows. 42 while ((id == 0) || (cancelable_tasks_.Lookup(reinterpret_cast<void*>(id), 43 id) != nullptr)) { 44 ++id; 45 } 46 HashMap::Entry* entry = 47 cancelable_tasks_.LookupOrInsert(reinterpret_cast<void*>(id), id); 48 entry->value = task; 49 return id; 50 } 51 52 53 void CancelableTaskManager::RemoveFinishedTask(uint32_t id) { 54 base::LockGuard<base::Mutex> guard(&mutex_); 55 void* removed = cancelable_tasks_.Remove(reinterpret_cast<void*>(id), id); 56 USE(removed); 57 DCHECK(removed != nullptr); 58 cancelable_tasks_barrier_.NotifyOne(); 59 } 60 61 62 bool CancelableTaskManager::TryAbort(uint32_t id) { 63 base::LockGuard<base::Mutex> guard(&mutex_); 64 HashMap::Entry* entry = 65 cancelable_tasks_.Lookup(reinterpret_cast<void*>(id), id); 66 if (entry != nullptr) { 67 Cancelable* value = reinterpret_cast<Cancelable*>(entry->value); 68 if (value->Cancel()) { 69 // Cannot call RemoveFinishedTask here because of recursive locking. 70 void* removed = cancelable_tasks_.Remove(reinterpret_cast<void*>(id), id); 71 USE(removed); 72 DCHECK(removed != nullptr); 73 cancelable_tasks_barrier_.NotifyOne(); 74 return true; 75 } 76 } 77 return false; 78 } 79 80 81 void CancelableTaskManager::CancelAndWait() { 82 // Clean up all cancelable fore- and background tasks. Tasks are canceled on 83 // the way if possible, i.e., if they have not started yet. After each round 84 // of canceling we wait for the background tasks that have already been 85 // started. 86 base::LockGuard<base::Mutex> guard(&mutex_); 87 88 // HashMap does not support removing while iterating, hence keep a set of 89 // entries that are to be removed. 90 std::set<uint32_t> to_remove; 91 92 // Cancelable tasks could potentially register new tasks, requiring a loop 93 // here. 94 while (cancelable_tasks_.occupancy() > 0) { 95 for (HashMap::Entry* p = cancelable_tasks_.Start(); p != nullptr; 96 p = cancelable_tasks_.Next(p)) { 97 if (reinterpret_cast<Cancelable*>(p->value)->Cancel()) { 98 to_remove.insert(reinterpret_cast<Cancelable*>(p->value)->id()); 99 } 100 } 101 // Remove tasks that were successfully canceled. 102 for (auto id : to_remove) { 103 cancelable_tasks_.Remove(reinterpret_cast<void*>(id), id); 104 } 105 to_remove.clear(); 106 107 // Finally, wait for already running background tasks. 108 if (cancelable_tasks_.occupancy() > 0) { 109 cancelable_tasks_barrier_.Wait(&mutex_); 110 } 111 } 112 } 113 114 115 CancelableTask::CancelableTask(Isolate* isolate) 116 : Cancelable(isolate->cancelable_task_manager()), isolate_(isolate) {} 117 118 119 CancelableIdleTask::CancelableIdleTask(Isolate* isolate) 120 : Cancelable(isolate->cancelable_task_manager()), isolate_(isolate) {} 121 122 } // namespace internal 123 } // namespace v8 124