11cb0ef41Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_TASKS_CANCELABLE_TASK_H_
61cb0ef41Sopenharmony_ci#define V8_TASKS_CANCELABLE_TASK_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <atomic>
91cb0ef41Sopenharmony_ci#include <unordered_map>
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include "include/v8-platform.h"
121cb0ef41Sopenharmony_ci#include "src/base/macros.h"
131cb0ef41Sopenharmony_ci#include "src/base/platform/condition-variable.h"
141cb0ef41Sopenharmony_ci#include "src/common/globals.h"
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cinamespace v8 {
171cb0ef41Sopenharmony_cinamespace internal {
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciclass Cancelable;
201cb0ef41Sopenharmony_ciclass Isolate;
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci// The possible outcomes of trying to abort a job are:
231cb0ef41Sopenharmony_ci// (1) The task is already finished running or was canceled before and
241cb0ef41Sopenharmony_ci//     thus has been removed from the manager.
251cb0ef41Sopenharmony_ci// (2) The task is currently running and cannot be canceled anymore.
261cb0ef41Sopenharmony_ci// (3) The task is not yet running (or finished) so it is canceled and
271cb0ef41Sopenharmony_ci//     removed.
281cb0ef41Sopenharmony_cienum class TryAbortResult { kTaskRemoved, kTaskRunning, kTaskAborted };
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci// Keeps track of cancelable tasks. It is possible to register and remove tasks
311cb0ef41Sopenharmony_ci// from any fore- and background task/thread.
321cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE CancelableTaskManager {
331cb0ef41Sopenharmony_ci public:
341cb0ef41Sopenharmony_ci  using Id = uint64_t;
351cb0ef41Sopenharmony_ci  static constexpr Id kInvalidTaskId = 0;
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  CancelableTaskManager();
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  ~CancelableTaskManager();
401cb0ef41Sopenharmony_ci  CancelableTaskManager(const CancelableTaskManager&) = delete;
411cb0ef41Sopenharmony_ci  CancelableTaskManager& operator=(const CancelableTaskManager&) = delete;
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  // Registers a new cancelable {task}. Returns the unique {id} of the task that
441cb0ef41Sopenharmony_ci  // can be used to try to abort a task by calling {Abort}.
451cb0ef41Sopenharmony_ci  // If {Register} is called after {CancelAndWait}, then the task will be
461cb0ef41Sopenharmony_ci  // aborted immediately.
471cb0ef41Sopenharmony_ci  // {Register} should only be called by the thread which owns the
481cb0ef41Sopenharmony_ci  // {CancelableTaskManager}, or by a task which is managed by the
491cb0ef41Sopenharmony_ci  // {CancelableTaskManager}.
501cb0ef41Sopenharmony_ci  Id Register(Cancelable* task);
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  // Try to abort running a task identified by {id}.
531cb0ef41Sopenharmony_ci  TryAbortResult TryAbort(Id id);
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  // Tries to cancel all remaining registered tasks. The return value indicates
561cb0ef41Sopenharmony_ci  // whether
571cb0ef41Sopenharmony_ci  //
581cb0ef41Sopenharmony_ci  // 1) No tasks were registered (kTaskRemoved), or
591cb0ef41Sopenharmony_ci  //
601cb0ef41Sopenharmony_ci  // 2) There is at least one remaining task that couldn't be cancelled
611cb0ef41Sopenharmony_ci  // (kTaskRunning), or
621cb0ef41Sopenharmony_ci  //
631cb0ef41Sopenharmony_ci  // 3) All registered tasks were cancelled (kTaskAborted).
641cb0ef41Sopenharmony_ci  TryAbortResult TryAbortAll();
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  // Cancels all remaining registered tasks and waits for tasks that are
671cb0ef41Sopenharmony_ci  // already running. This disallows subsequent Register calls.
681cb0ef41Sopenharmony_ci  void CancelAndWait();
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  // Returns true of the task manager has been cancelled.
711cb0ef41Sopenharmony_ci  bool canceled() const { return canceled_; }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci private:
741cb0ef41Sopenharmony_ci  // Only called by {Cancelable} destructor. The task is done with executing,
751cb0ef41Sopenharmony_ci  // but needs to be removed.
761cb0ef41Sopenharmony_ci  void RemoveFinishedTask(Id id);
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  // To mitigate the ABA problem, the api refers to tasks through an id.
791cb0ef41Sopenharmony_ci  Id task_id_counter_;
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  // A set of cancelable tasks that are currently registered.
821cb0ef41Sopenharmony_ci  std::unordered_map<Id, Cancelable*> cancelable_tasks_;
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  // Mutex and condition variable enabling concurrent register and removing, as
851cb0ef41Sopenharmony_ci  // well as waiting for background tasks on {CancelAndWait}.
861cb0ef41Sopenharmony_ci  base::ConditionVariable cancelable_tasks_barrier_;
871cb0ef41Sopenharmony_ci  base::Mutex mutex_;
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  bool canceled_;
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  friend class Cancelable;
921cb0ef41Sopenharmony_ci};
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE Cancelable {
951cb0ef41Sopenharmony_ci public:
961cb0ef41Sopenharmony_ci  explicit Cancelable(CancelableTaskManager* parent)
971cb0ef41Sopenharmony_ci      : parent_(parent), id_(parent->Register(this)) {}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  virtual ~Cancelable();
1001cb0ef41Sopenharmony_ci  Cancelable(const Cancelable&) = delete;
1011cb0ef41Sopenharmony_ci  Cancelable& operator=(const Cancelable&) = delete;
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  // Never invoke after handing over the task to the platform! The reason is
1041cb0ef41Sopenharmony_ci  // that {Cancelable} is used in combination with {v8::Task} and handed to
1051cb0ef41Sopenharmony_ci  // a platform. This step transfers ownership to the platform, which destroys
1061cb0ef41Sopenharmony_ci  // the task after running it. Since the exact time is not known, we cannot
1071cb0ef41Sopenharmony_ci  // access the object after handing it to a platform.
1081cb0ef41Sopenharmony_ci  CancelableTaskManager::Id id() { return id_; }
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci protected:
1111cb0ef41Sopenharmony_ci  // Identifies the state a cancelable task is in:
1121cb0ef41Sopenharmony_ci  // |kWaiting|: The task is scheduled and waiting to be executed. {TryRun} will
1131cb0ef41Sopenharmony_ci  //   succeed.
1141cb0ef41Sopenharmony_ci  // |kCanceled|: The task has been canceled. {TryRun} will fail.
1151cb0ef41Sopenharmony_ci  // |kRunning|: The task is currently running and cannot be canceled anymore.
1161cb0ef41Sopenharmony_ci  enum Status { kWaiting, kCanceled, kRunning };
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  bool TryRun(Status* previous = nullptr) {
1191cb0ef41Sopenharmony_ci    return CompareExchangeStatus(kWaiting, kRunning, previous);
1201cb0ef41Sopenharmony_ci  }
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci private:
1231cb0ef41Sopenharmony_ci  friend class CancelableTaskManager;
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  // Use {CancelableTaskManager} to abort a task that has not yet been
1261cb0ef41Sopenharmony_ci  // executed.
1271cb0ef41Sopenharmony_ci  bool Cancel() { return CompareExchangeStatus(kWaiting, kCanceled); }
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  bool CompareExchangeStatus(Status expected, Status desired,
1301cb0ef41Sopenharmony_ci                             Status* previous = nullptr) {
1311cb0ef41Sopenharmony_ci    // {compare_exchange_strong} updates {expected}.
1321cb0ef41Sopenharmony_ci    bool success = status_.compare_exchange_strong(expected, desired,
1331cb0ef41Sopenharmony_ci                                                   std::memory_order_acq_rel,
1341cb0ef41Sopenharmony_ci                                                   std::memory_order_acquire);
1351cb0ef41Sopenharmony_ci    if (previous) *previous = expected;
1361cb0ef41Sopenharmony_ci    return success;
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  CancelableTaskManager* const parent_;
1401cb0ef41Sopenharmony_ci  std::atomic<Status> status_{kWaiting};
1411cb0ef41Sopenharmony_ci  const CancelableTaskManager::Id id_;
1421cb0ef41Sopenharmony_ci};
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci// Multiple inheritance can be used because Task is a pure interface.
1451cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE CancelableTask : public Cancelable,
1461cb0ef41Sopenharmony_ci                                         NON_EXPORTED_BASE(public Task) {
1471cb0ef41Sopenharmony_ci public:
1481cb0ef41Sopenharmony_ci  explicit CancelableTask(Isolate* isolate);
1491cb0ef41Sopenharmony_ci  explicit CancelableTask(CancelableTaskManager* manager);
1501cb0ef41Sopenharmony_ci  CancelableTask(const CancelableTask&) = delete;
1511cb0ef41Sopenharmony_ci  CancelableTask& operator=(const CancelableTask&) = delete;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  // Task overrides.
1541cb0ef41Sopenharmony_ci  void Run() final {
1551cb0ef41Sopenharmony_ci    if (TryRun()) {
1561cb0ef41Sopenharmony_ci      RunInternal();
1571cb0ef41Sopenharmony_ci    }
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  virtual void RunInternal() = 0;
1611cb0ef41Sopenharmony_ci};
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci// Multiple inheritance can be used because IdleTask is a pure interface.
1641cb0ef41Sopenharmony_ciclass CancelableIdleTask : public Cancelable, public IdleTask {
1651cb0ef41Sopenharmony_ci public:
1661cb0ef41Sopenharmony_ci  explicit CancelableIdleTask(Isolate* isolate);
1671cb0ef41Sopenharmony_ci  explicit CancelableIdleTask(CancelableTaskManager* manager);
1681cb0ef41Sopenharmony_ci  CancelableIdleTask(const CancelableIdleTask&) = delete;
1691cb0ef41Sopenharmony_ci  CancelableIdleTask& operator=(const CancelableIdleTask&) = delete;
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  // IdleTask overrides.
1721cb0ef41Sopenharmony_ci  void Run(double deadline_in_seconds) final {
1731cb0ef41Sopenharmony_ci    if (TryRun()) {
1741cb0ef41Sopenharmony_ci      RunInternal(deadline_in_seconds);
1751cb0ef41Sopenharmony_ci    }
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  virtual void RunInternal(double deadline_in_seconds) = 0;
1791cb0ef41Sopenharmony_ci};
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci}  // namespace internal
1821cb0ef41Sopenharmony_ci}  // namespace v8
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci#endif  // V8_TASKS_CANCELABLE_TASK_H_
185