1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
base / task / thread_pool / delayed_task_manager.h [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TASK_THREAD_POOL_DELAYED_TASK_MANAGER_H_
#define BASE_TASK_THREAD_POOL_DELAYED_TASK_MANAGER_H_
#include <functional>
#include <optional>
#include "base/base_export.h"
#include "base/containers/intrusive_heap.h"
#include "base/functional/callback.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/synchronization/atomic_flag.h"
#include "base/task/common/checked_lock.h"
#include "base/task/delay_policy.h"
#include "base/task/task_features.h"
#include "base/task/thread_pool/task.h"
#include "base/thread_annotations.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
namespace base {
class SequencedTaskRunner;
namespace internal {
// The DelayedTaskManager forwards tasks to post task callbacks when they become
// ripe for execution. Tasks are not forwarded before Start() is called. This
// class is thread-safe.
class BASE_EXPORT DelayedTaskManager {
public:
// Posts |task| for execution immediately.
using PostTaskNowCallback = OnceCallback<void(Task task)>;
// |tick_clock| can be specified for testing.
DelayedTaskManager(
const TickClock* tick_clock = DefaultTickClock::GetInstance());
DelayedTaskManager(const DelayedTaskManager&) = delete;
DelayedTaskManager& operator=(const DelayedTaskManager&) = delete;
~DelayedTaskManager();
// Starts the delayed task manager, allowing past and future tasks to be
// forwarded to their callbacks as they become ripe for execution.
// |service_thread_task_runner| posts tasks to the ThreadPool service
// thread.
void Start(scoped_refptr<SequencedTaskRunner> service_thread_task_runner);
// Schedules a call to |post_task_now_callback| with |task| as argument when
// |task| is ripe for execution.
void AddDelayedTask(Task task, PostTaskNowCallback post_task_now_callback);
// Pop and post all the ripe tasks in the delayed task queue.
void ProcessRipeTasks();
// Returns the |delayed_run_time| of the next scheduled task, if any.
std::optional<TimeTicks> NextScheduledRunTime() const;
// Returns the DelayPolicy for the next delayed task.
subtle::DelayPolicy TopTaskDelayPolicyForTesting() const;
// Must be invoked before deleting the delayed task manager. The caller must
// flush tasks posted to the service thread by this before deleting the
// delayed task manager.
void Shutdown();
private:
struct DelayedTask {
DelayedTask();
DelayedTask(Task task, PostTaskNowCallback callback);
DelayedTask(DelayedTask&& other);
DelayedTask(const DelayedTask&) = delete;
DelayedTask& operator=(const DelayedTask&) = delete;
~DelayedTask();
// Required by IntrusiveHeap::insert().
DelayedTask& operator=(DelayedTask&& other);
// Used for a min-heap.
bool operator>(const DelayedTask& other) const;
Task task;
PostTaskNowCallback callback;
// Mark the delayed task as scheduled. Since the sort key is
// |task.delayed_run_time|, it does not alter sort order when it is called.
void SetScheduled();
// Required by IntrusiveHeap.
void SetHeapHandle(const HeapHandle& handle) {}
// Required by IntrusiveHeap.
void ClearHeapHandle() {}
// Required by IntrusiveHeap.
HeapHandle GetHeapHandle() const { return HeapHandle::Invalid(); }
};
// Get the time at which to schedule the next |ProcessRipeTasks()| execution,
// or TimeTicks::Max() if none needs to be scheduled (i.e. no task, or next
// task already scheduled).
std::pair<TimeTicks, subtle::DelayPolicy>
GetTimeAndDelayPolicyToScheduleProcessRipeTasksLockRequired()
EXCLUSIVE_LOCKS_REQUIRED(queue_lock_);
// Schedule |ProcessRipeTasks()| on the service thread to be executed when
// the next task is ripe.
void ScheduleProcessRipeTasksOnServiceThread();
const RepeatingClosure process_ripe_tasks_closure_;
const RepeatingClosure schedule_process_ripe_tasks_closure_;
const raw_ptr<const TickClock> tick_clock_;
// Synchronizes access to |delayed_task_queue_| and the setting of
// |service_thread_task_runner_|. Once |service_thread_task_runner_| is set,
// it is never modified. It is therefore safe to access
// |service_thread_task_runner_| without synchronization once it is observed
// that it is non-null.
mutable CheckedLock queue_lock_{UniversalSuccessor()};
scoped_refptr<SequencedTaskRunner> service_thread_task_runner_;
DelayedTaskHandle delayed_task_handle_ GUARDED_BY_CONTEXT(sequence_checker_);
IntrusiveHeap<DelayedTask, std::greater<>> delayed_task_queue_
GUARDED_BY(queue_lock_);
base::TimeDelta max_precise_delay GUARDED_BY(queue_lock_) =
kDefaultMaxPreciseDelay;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace internal
} // namespace base
#endif // BASE_TASK_THREAD_POOL_DELAYED_TASK_MANAGER_H_