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 #ifndef V8_CANCELABLE_TASK_H_
      6 #define V8_CANCELABLE_TASK_H_
      7 
      8 #include <map>
      9 
     10 #include "include/v8-platform.h"
     11 #include "src/base/atomic-utils.h"
     12 #include "src/base/macros.h"
     13 #include "src/base/platform/condition-variable.h"
     14 #include "src/globals.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 class Cancelable;
     20 class Isolate;
     21 
     22 
     23 // Keeps track of cancelable tasks. It is possible to register and remove tasks
     24 // from any fore- and background task/thread.
     25 class V8_EXPORT_PRIVATE CancelableTaskManager {
     26  public:
     27   CancelableTaskManager();
     28 
     29   // Registers a new cancelable {task}. Returns the unique {id} of the task that
     30   // can be used to try to abort a task by calling {Abort}.
     31   // Must not be called after CancelAndWait.
     32   uint32_t Register(Cancelable* task);
     33 
     34   // Try to abort running a task identified by {id}. The possible outcomes are:
     35   // (1) The task is already finished running or was canceled before and
     36   //     thus has been removed from the manager.
     37   // (2) The task is currently running and cannot be canceled anymore.
     38   // (3) The task is not yet running (or finished) so it is canceled and
     39   //     removed.
     40   //
     41   enum TryAbortResult { kTaskRemoved, kTaskRunning, kTaskAborted };
     42   TryAbortResult TryAbort(uint32_t id);
     43 
     44   // Cancels all remaining registered tasks and waits for tasks that are
     45   // already running. This disallows subsequent Register calls.
     46   void CancelAndWait();
     47 
     48  private:
     49   // Only called by {Cancelable} destructor. The task is done with executing,
     50   // but needs to be removed.
     51   void RemoveFinishedTask(uint32_t id);
     52 
     53   // To mitigate the ABA problem, the api refers to tasks through an id.
     54   uint32_t task_id_counter_;
     55 
     56   // A set of cancelable tasks that are currently registered.
     57   std::map<uint32_t, Cancelable*> cancelable_tasks_;
     58 
     59   // Mutex and condition variable enabling concurrent register and removing, as
     60   // well as waiting for background tasks on {CancelAndWait}.
     61   base::ConditionVariable cancelable_tasks_barrier_;
     62   base::Mutex mutex_;
     63 
     64   bool canceled_;
     65 
     66   friend class Cancelable;
     67 
     68   DISALLOW_COPY_AND_ASSIGN(CancelableTaskManager);
     69 };
     70 
     71 class V8_EXPORT_PRIVATE Cancelable {
     72  public:
     73   explicit Cancelable(CancelableTaskManager* parent);
     74   virtual ~Cancelable();
     75 
     76   // Never invoke after handing over the task to the platform! The reason is
     77   // that {Cancelable} is used in combination with {v8::Task} and handed to
     78   // a platform. This step transfers ownership to the platform, which destroys
     79   // the task after running it. Since the exact time is not known, we cannot
     80   // access the object after handing it to a platform.
     81   uint32_t id() { return id_; }
     82 
     83  protected:
     84   bool TryRun() { return status_.TrySetValue(kWaiting, kRunning); }
     85   bool IsRunning() { return status_.Value() == kRunning; }
     86   intptr_t CancelAttempts() { return cancel_counter_.Value(); }
     87 
     88  private:
     89   // Identifies the state a cancelable task is in:
     90   // |kWaiting|: The task is scheduled and waiting to be executed. {TryRun} will
     91   //   succeed.
     92   // |kCanceled|: The task has been canceled. {TryRun} will fail.
     93   // |kRunning|: The task is currently running and cannot be canceled anymore.
     94   enum Status {
     95     kWaiting,
     96     kCanceled,
     97     kRunning,
     98   };
     99 
    100   // Use {CancelableTaskManager} to abort a task that has not yet been
    101   // executed.
    102   bool Cancel() {
    103     if (status_.TrySetValue(kWaiting, kCanceled)) {
    104       return true;
    105     }
    106     cancel_counter_.Increment(1);
    107     return false;
    108   }
    109 
    110   CancelableTaskManager* parent_;
    111   base::AtomicValue<Status> status_;
    112   uint32_t id_;
    113 
    114   // The counter is incremented for failing tries to cancel a task. This can be
    115   // used by the task itself as an indication how often external entities tried
    116   // to abort it.
    117   base::AtomicNumber<intptr_t> cancel_counter_;
    118 
    119   friend class CancelableTaskManager;
    120 
    121   DISALLOW_COPY_AND_ASSIGN(Cancelable);
    122 };
    123 
    124 
    125 // Multiple inheritance can be used because Task is a pure interface.
    126 class CancelableTask : public Cancelable, public Task {
    127  public:
    128   explicit CancelableTask(Isolate* isolate);
    129 
    130   // Task overrides.
    131   void Run() final {
    132     if (TryRun()) {
    133       RunInternal();
    134     }
    135   }
    136 
    137   virtual void RunInternal() = 0;
    138 
    139   Isolate* isolate() { return isolate_; }
    140 
    141  private:
    142   Isolate* isolate_;
    143   DISALLOW_COPY_AND_ASSIGN(CancelableTask);
    144 };
    145 
    146 
    147 // Multiple inheritance can be used because IdleTask is a pure interface.
    148 class CancelableIdleTask : public Cancelable, public IdleTask {
    149  public:
    150   explicit CancelableIdleTask(Isolate* isolate);
    151 
    152   // IdleTask overrides.
    153   void Run(double deadline_in_seconds) final {
    154     if (TryRun()) {
    155       RunInternal(deadline_in_seconds);
    156     }
    157   }
    158 
    159   virtual void RunInternal(double deadline_in_seconds) = 0;
    160 
    161   Isolate* isolate() { return isolate_; }
    162 
    163  private:
    164   Isolate* isolate_;
    165   DISALLOW_COPY_AND_ASSIGN(CancelableIdleTask);
    166 };
    167 
    168 
    169 }  // namespace internal
    170 }  // namespace v8
    171 
    172 #endif  // V8_CANCELABLE_TASK_H_
    173