Home | History | Annotate | Download | only in src
      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