1// Copyright 2017 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_LIBPLATFORM_DEFAULT_FOREGROUND_TASK_RUNNER_H_
6#define V8_LIBPLATFORM_DEFAULT_FOREGROUND_TASK_RUNNER_H_
7
8#include <memory>
9#include <queue>
10
11#include "include/libplatform/libplatform.h"
12#include "include/v8-platform.h"
13#include "src/base/platform/condition-variable.h"
14#include "src/base/platform/mutex.h"
15
16namespace v8 {
17namespace platform {
18
19class V8_PLATFORM_EXPORT DefaultForegroundTaskRunner
20    : public NON_EXPORTED_BASE(TaskRunner) {
21 public:
22  using TimeFunction = double (*)();
23  class V8_NODISCARD RunTaskScope {
24   public:
25    explicit RunTaskScope(
26        std::shared_ptr<DefaultForegroundTaskRunner> task_runner);
27    ~RunTaskScope();
28    RunTaskScope(const RunTaskScope&) = delete;
29    RunTaskScope& operator=(const RunTaskScope&) = delete;
30
31   private:
32    std::shared_ptr<DefaultForegroundTaskRunner> task_runner_;
33  };
34
35  DefaultForegroundTaskRunner(IdleTaskSupport idle_task_support,
36                              TimeFunction time_function);
37
38  void Terminate();
39
40  std::unique_ptr<Task> PopTaskFromQueue(MessageLoopBehavior wait_for_work);
41
42  std::unique_ptr<IdleTask> PopTaskFromIdleQueue();
43
44  double MonotonicallyIncreasingTime();
45
46  // v8::TaskRunner implementation.
47  void PostTask(std::unique_ptr<Task> task) override;
48  void PostDelayedTask(std::unique_ptr<Task> task,
49                       double delay_in_seconds) override;
50
51  void PostIdleTask(std::unique_ptr<IdleTask> task) override;
52  bool IdleTasksEnabled() override;
53
54  void PostNonNestableTask(std::unique_ptr<Task> task) override;
55  void PostNonNestableDelayedTask(std::unique_ptr<Task> task,
56                                  double delay_in_seconds) override;
57  bool NonNestableTasksEnabled() const override;
58
59 private:
60  enum Nestability { kNestable, kNonNestable };
61
62  void WaitForTaskLocked(const base::MutexGuard&);
63
64  // The same as PostTask or PostNonNestableTask, but the lock is already held
65  // by the caller. The {guard} parameter should make sure that the caller is
66  // holding the lock.
67  void PostTaskLocked(std::unique_ptr<Task> task, Nestability nestability,
68                      const base::MutexGuard&);
69
70  // The same as PostDelayedTask or PostNonNestableDelayedTask, but the lock is
71  // already held by the caller. The {guard} parameter should make sure that the
72  // caller is holding the lock.
73  void PostDelayedTaskLocked(std::unique_ptr<Task> task,
74                             double delay_in_seconds, Nestability nestability,
75                             const base::MutexGuard&);
76
77  // A caller of this function has to hold {lock_}. The {guard} parameter should
78  // make sure that the caller is holding the lock.
79  std::unique_ptr<Task> PopTaskFromDelayedQueueLocked(const base::MutexGuard&,
80                                                      Nestability* nestability);
81
82  // A non-nestable task is poppable only if the task runner is not nested,
83  // i.e. if a task is not being run from within a task. A nestable task is
84  // always poppable.
85  bool HasPoppableTaskInQueue() const;
86
87  // Move delayed tasks that hit their deadline to the main queue.
88  void MoveExpiredDelayedTasks(const base::MutexGuard& guard);
89
90  bool terminated_ = false;
91  base::Mutex lock_;
92  base::ConditionVariable event_loop_control_;
93  int nesting_depth_ = 0;
94
95  using TaskQueueEntry = std::pair<Nestability, std::unique_ptr<Task>>;
96  std::deque<TaskQueueEntry> task_queue_;
97
98  IdleTaskSupport idle_task_support_;
99  std::queue<std::unique_ptr<IdleTask>> idle_task_queue_;
100
101  // Some helper constructs for the {delayed_task_queue_}.
102  struct DelayedEntry {
103    double timeout_time;
104    Nestability nestability;
105    std::unique_ptr<Task> task;
106  };
107
108  // Define a comparison operator for the delayed_task_queue_ to make sure
109  // that the unique_ptr in the DelayedEntry is not accessed in the priority
110  // queue. This is necessary because we have to reset the unique_ptr when we
111  // remove a DelayedEntry from the priority queue.
112  struct DelayedEntryCompare {
113    bool operator()(const DelayedEntry& left, const DelayedEntry& right) const {
114      return left.timeout_time > right.timeout_time;
115    }
116  };
117  std::priority_queue<DelayedEntry, std::vector<DelayedEntry>,
118                      DelayedEntryCompare>
119      delayed_task_queue_;
120
121  TimeFunction time_function_;
122};
123
124}  // namespace platform
125}  // namespace v8
126#endif  // V8_LIBPLATFORM_DEFAULT_FOREGROUND_TASK_RUNNER_H_
127