1014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Copyright 2015 the V8 project authors. All rights reserved. 2014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// found in the LICENSE file. 4014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#ifndef V8_CANCELABLE_TASK_H_ 6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#define V8_CANCELABLE_TASK_H_ 7014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 8bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include <map> 9bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch 10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "include/v8-platform.h" 11bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/base/atomic-utils.h" 12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/base/macros.h" 13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/base/platform/condition-variable.h" 14c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch#include "src/globals.h" 15014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace v8 { 17014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochnamespace internal { 18014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 19014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochclass Cancelable; 20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochclass Isolate; 21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 23014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Keeps track of cancelable tasks. It is possible to register and remove tasks 24014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// from any fore- and background task/thread. 25c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochclass V8_EXPORT_PRIVATE CancelableTaskManager { 26014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch public: 27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch CancelableTaskManager(); 28014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 29014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Registers a new cancelable {task}. Returns the unique {id} of the task that 30014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // can be used to try to abort a task by calling {Abort}. 31c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch // Must not be called after CancelAndWait. 32014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t Register(Cancelable* task); 33014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 34014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Try to abort running a task identified by {id}. The possible outcomes are: 35c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch // (1) The task is already finished running or was canceled before and 36c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch // thus has been removed from the manager. 37014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // (2) The task is currently running and cannot be canceled anymore. 38014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // (3) The task is not yet running (or finished) so it is canceled and 39014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // removed. 40014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // 41c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch enum TryAbortResult { kTaskRemoved, kTaskRunning, kTaskAborted }; 42c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch TryAbortResult TryAbort(uint32_t id); 43014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 44014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Cancels all remaining registered tasks and waits for tasks that are 45c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch // already running. This disallows subsequent Register calls. 46014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch void CancelAndWait(); 47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Only called by {Cancelable} destructor. The task is done with executing, 50014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // but needs to be removed. 51014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch void RemoveFinishedTask(uint32_t id); 52014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 53014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // To mitigate the ABA problem, the api refers to tasks through an id. 54014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t task_id_counter_; 55014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 56014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // A set of cancelable tasks that are currently registered. 57bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch std::map<uint32_t, Cancelable*> cancelable_tasks_; 58014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 59014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Mutex and condition variable enabling concurrent register and removing, as 60014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // well as waiting for background tasks on {CancelAndWait}. 61014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch base::ConditionVariable cancelable_tasks_barrier_; 62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch base::Mutex mutex_; 63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 64c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch bool canceled_; 65c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch 66014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch friend class Cancelable; 67014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 68014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(CancelableTaskManager); 69014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 70014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 71c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochclass V8_EXPORT_PRIVATE Cancelable { 72014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch public: 73014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch explicit Cancelable(CancelableTaskManager* parent); 74014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch virtual ~Cancelable(); 75014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 76014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Never invoke after handing over the task to the platform! The reason is 77014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // that {Cancelable} is used in combination with {v8::Task} and handed to 78014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // a platform. This step transfers ownership to the platform, which destroys 79014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // the task after running it. Since the exact time is not known, we cannot 80014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // access the object after handing it to a platform. 81014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t id() { return id_; } 82014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 83014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch protected: 84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch bool TryRun() { return status_.TrySetValue(kWaiting, kRunning); } 85014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch bool IsRunning() { return status_.Value() == kRunning; } 86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch intptr_t CancelAttempts() { return cancel_counter_.Value(); } 87014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 88014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 89014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Identifies the state a cancelable task is in: 90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // |kWaiting|: The task is scheduled and waiting to be executed. {TryRun} will 91014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // succeed. 92014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // |kCanceled|: The task has been canceled. {TryRun} will fail. 93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // |kRunning|: The task is currently running and cannot be canceled anymore. 94014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch enum Status { 95014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch kWaiting, 96014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch kCanceled, 97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch kRunning, 98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch }; 99014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Use {CancelableTaskManager} to abort a task that has not yet been 101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // executed. 102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch bool Cancel() { 103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (status_.TrySetValue(kWaiting, kCanceled)) { 104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return true; 105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch cancel_counter_.Increment(1); 107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return false; 108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch CancelableTaskManager* parent_; 111bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch base::AtomicValue<Status> status_; 112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t id_; 113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // The counter is incremented for failing tries to cancel a task. This can be 115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // used by the task itself as an indication how often external entities tried 116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // to abort it. 117bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch base::AtomicNumber<intptr_t> cancel_counter_; 118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch friend class CancelableTaskManager; 120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(Cancelable); 122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 125014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Multiple inheritance can be used because Task is a pure interface. 126014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochclass CancelableTask : public Cancelable, public Task { 127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch public: 128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch explicit CancelableTask(Isolate* isolate); 129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Task overrides. 131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch void Run() final { 132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (TryRun()) { 133014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch RunInternal(); 134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 135014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch virtual void RunInternal() = 0; 138014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 139014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate() { return isolate_; } 140014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 141014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 142014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate_; 143014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(CancelableTask); 144014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 146014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Multiple inheritance can be used because IdleTask is a pure interface. 148014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochclass CancelableIdleTask : public Cancelable, public IdleTask { 149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch public: 150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch explicit CancelableIdleTask(Isolate* isolate); 151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 152014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // IdleTask overrides. 153014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch void Run(double deadline_in_seconds) final { 154014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (TryRun()) { 155014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch RunInternal(deadline_in_seconds); 156014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 157014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 158014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 159014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch virtual void RunInternal(double deadline_in_seconds) = 0; 160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate() { return isolate_; } 162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate_; 165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(CancelableIdleTask); 166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 169014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace internal 170014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace v8 171014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 172014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#endif // V8_CANCELABLE_TASK_H_ 173