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 4862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // Tries to cancel all remaining registered tasks. The return value indicates 4962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // whether 5062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // 5162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // 1) No tasks were registered (kTaskRemoved), or 5262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // 5362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // 2) There is at least one remaining task that couldn't be cancelled 5462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // (kTaskRunning), or 5562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // 5662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // 3) All registered tasks were cancelled (kTaskAborted). 5762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch TryAbortResult TryAbortAll(); 5862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch 59014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 60014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Only called by {Cancelable} destructor. The task is done with executing, 61014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // but needs to be removed. 62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch void RemoveFinishedTask(uint32_t id); 63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 64014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // To mitigate the ABA problem, the api refers to tasks through an id. 65014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t task_id_counter_; 66014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 67014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // A set of cancelable tasks that are currently registered. 68bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch std::map<uint32_t, Cancelable*> cancelable_tasks_; 69014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 70014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Mutex and condition variable enabling concurrent register and removing, as 71014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // well as waiting for background tasks on {CancelAndWait}. 72014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch base::ConditionVariable cancelable_tasks_barrier_; 73014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch base::Mutex mutex_; 74014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 75c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch bool canceled_; 76c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch 77014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch friend class Cancelable; 78014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 79014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(CancelableTaskManager); 80014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 81014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 82c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdochclass V8_EXPORT_PRIVATE Cancelable { 83014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch public: 84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch explicit Cancelable(CancelableTaskManager* parent); 85014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch virtual ~Cancelable(); 86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 87014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Never invoke after handing over the task to the platform! The reason is 88014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // that {Cancelable} is used in combination with {v8::Task} and handed to 89014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // a platform. This step transfers ownership to the platform, which destroys 90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // the task after running it. Since the exact time is not known, we cannot 91014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // access the object after handing it to a platform. 92014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t id() { return id_; } 93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 94014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch protected: 95014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch bool TryRun() { return status_.TrySetValue(kWaiting, kRunning); } 96014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch bool IsRunning() { return status_.Value() == kRunning; } 97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch intptr_t CancelAttempts() { return cancel_counter_.Value(); } 98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 99014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Identifies the state a cancelable task is in: 101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // |kWaiting|: The task is scheduled and waiting to be executed. {TryRun} will 102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // succeed. 103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // |kCanceled|: The task has been canceled. {TryRun} will fail. 104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // |kRunning|: The task is currently running and cannot be canceled anymore. 105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch enum Status { 106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch kWaiting, 107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch kCanceled, 108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch kRunning, 109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch }; 110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Use {CancelableTaskManager} to abort a task that has not yet been 112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // executed. 113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch bool Cancel() { 114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (status_.TrySetValue(kWaiting, kCanceled)) { 115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return true; 116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch cancel_counter_.Increment(1); 118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return false; 119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch CancelableTaskManager* parent_; 122bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch base::AtomicValue<Status> status_; 123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch uint32_t id_; 124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 125014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // The counter is incremented for failing tries to cancel a task. This can be 126014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // used by the task itself as an indication how often external entities tried 127014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // to abort it. 128bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch base::AtomicNumber<intptr_t> cancel_counter_; 129014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch friend class CancelableTaskManager; 131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 132014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(Cancelable); 133014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 134014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 135014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Multiple inheritance can be used because Task is a pure interface. 13762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochclass V8_EXPORT_PRIVATE CancelableTask : public Cancelable, 13862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch NON_EXPORTED_BASE(public Task) { 139014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch public: 140014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch explicit CancelableTask(Isolate* isolate); 14162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch CancelableTask(Isolate* isolate, CancelableTaskManager* manager); 142014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 143014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Task overrides. 144014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch void Run() final { 145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (TryRun()) { 146014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch RunInternal(); 147014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 148014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 150014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch virtual void RunInternal() = 0; 151014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 152014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate() { return isolate_; } 153014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 154014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 155014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate_; 156014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(CancelableTask); 157014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 158014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 159014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Multiple inheritance can be used because IdleTask is a pure interface. 161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochclass CancelableIdleTask : public Cancelable, public IdleTask { 162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch public: 163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch explicit CancelableIdleTask(Isolate* isolate); 16462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch CancelableIdleTask(Isolate* isolate, CancelableTaskManager* manager); 165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // IdleTask overrides. 167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch void Run(double deadline_in_seconds) final { 168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (TryRun()) { 169014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch RunInternal(deadline_in_seconds); 170014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 171014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 172014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 173014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch virtual void RunInternal(double deadline_in_seconds) = 0; 174014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 175014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate() { return isolate_; } 176014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 177014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch private: 178014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Isolate* isolate_; 179014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DISALLOW_COPY_AND_ASSIGN(CancelableIdleTask); 180014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}; 181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 182014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 183014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace internal 184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace v8 185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 186014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#endif // V8_CANCELABLE_TASK_H_ 187