blob: ee6035cad09b0cac5096e83d9c74f23cdbf5db29 [file] [log] [blame]
Sebastian Janssonecb68972019-01-18 10:30:54 +01001/*
2 * Copyright 2019 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifndef RTC_BASE_TASK_UTILS_REPEATING_TASK_H_
12#define RTC_BASE_TASK_UTILS_REPEATING_TASK_H_
13
14#include <type_traits>
15#include <utility>
16
17#include "absl/memory/memory.h"
Danil Chapovalov4423c362019-03-06 18:41:39 +010018#include "api/task_queue/queued_task.h"
19#include "api/task_queue/task_queue_base.h"
Sebastian Janssonecb68972019-01-18 10:30:54 +010020#include "api/units/time_delta.h"
21#include "api/units/timestamp.h"
22#include "rtc_base/sequenced_task_checker.h"
Sebastian Janssonecb68972019-01-18 10:30:54 +010023#include "rtc_base/thread_checker.h"
24
25namespace webrtc {
26
27class RepeatingTaskHandle;
28
29namespace webrtc_repeating_task_impl {
Danil Chapovalov4423c362019-03-06 18:41:39 +010030class RepeatingTaskBase : public QueuedTask {
Sebastian Janssonecb68972019-01-18 10:30:54 +010031 public:
Danil Chapovalov4423c362019-03-06 18:41:39 +010032 RepeatingTaskBase(TaskQueueBase* task_queue, TimeDelta first_delay);
Sebastian Janssonecb68972019-01-18 10:30:54 +010033 ~RepeatingTaskBase() override;
34 virtual TimeDelta RunClosure() = 0;
35
36 private:
37 friend class ::webrtc::RepeatingTaskHandle;
38
39 bool Run() final;
40 void Stop() RTC_RUN_ON(task_queue_);
41 void PostStop();
42
Danil Chapovalov4423c362019-03-06 18:41:39 +010043 TaskQueueBase* const task_queue_;
Sebastian Janssonecb68972019-01-18 10:30:54 +010044 // This is always finite, except for the special case where it's PlusInfinity
45 // to signal that the task should stop.
46 Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_);
47};
48
49// The template closure pattern is based on rtc::ClosureTask.
50template <class Closure>
51class RepeatingTaskImpl final : public RepeatingTaskBase {
52 public:
Danil Chapovalov4423c362019-03-06 18:41:39 +010053 RepeatingTaskImpl(TaskQueueBase* task_queue,
Sebastian Janssonecb68972019-01-18 10:30:54 +010054 TimeDelta first_delay,
55 Closure&& closure)
56 : RepeatingTaskBase(task_queue, first_delay),
57 closure_(std::forward<Closure>(closure)) {
58 static_assert(
59 std::is_same<TimeDelta,
60 typename std::result_of<decltype (&Closure::operator())(
61 Closure)>::type>::value,
62 "");
63 }
64
65 TimeDelta RunClosure() override { return closure_(); }
66
67 private:
68 typename std::remove_const<
69 typename std::remove_reference<Closure>::type>::type closure_;
70};
71} // namespace webrtc_repeating_task_impl
72
73// Allows starting tasks that repeat themselves on a TaskQueue indefinately
74// until they are stopped or the TaskQueue is destroyed. It allows starting and
75// stopping multiple times, but you must stop one task before starting another
76// and it can only be stopped when in the running state. The public interface is
77// not thread safe.
78class RepeatingTaskHandle {
79 public:
80 RepeatingTaskHandle();
81 ~RepeatingTaskHandle();
82 RepeatingTaskHandle(RepeatingTaskHandle&& other);
83 RepeatingTaskHandle& operator=(RepeatingTaskHandle&& other);
84 RepeatingTaskHandle(const RepeatingTaskHandle&) = delete;
85 RepeatingTaskHandle& operator=(const RepeatingTaskHandle&) = delete;
86
87 // Start can be used to start a task that will be reposted with a delay
88 // determined by the return value of the provided closure. The actual task is
89 // owned by the TaskQueue and will live until it has been stopped or the
90 // TaskQueue is destroyed. Note that this means that trying to stop the
91 // repeating task after the TaskQueue is destroyed is an error. However, it's
92 // perfectly fine to destroy the handle while the task is running, since the
93 // repeated task is owned by the TaskQueue.
94 template <class Closure>
Danil Chapovalov4423c362019-03-06 18:41:39 +010095 static RepeatingTaskHandle Start(TaskQueueBase* task_queue,
Sebastian Janssonecb68972019-01-18 10:30:54 +010096 Closure&& closure) {
97 auto repeating_task = absl::make_unique<
98 webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
99 task_queue, TimeDelta::Zero(), std::forward<Closure>(closure));
100 auto* repeating_task_ptr = repeating_task.get();
101 task_queue->PostTask(std::move(repeating_task));
102 return RepeatingTaskHandle(repeating_task_ptr);
103 }
104 template <class Closure>
105 static RepeatingTaskHandle Start(Closure&& closure) {
Danil Chapovalov4423c362019-03-06 18:41:39 +0100106 return Start(TaskQueueBase::Current(), std::forward<Closure>(closure));
Sebastian Janssonecb68972019-01-18 10:30:54 +0100107 }
108
109 // DelayedStart is equivalent to Start except that the first invocation of the
110 // closure will be delayed by the given amount.
111 template <class Closure>
Danil Chapovalov4423c362019-03-06 18:41:39 +0100112 static RepeatingTaskHandle DelayedStart(TaskQueueBase* task_queue,
Sebastian Janssonecb68972019-01-18 10:30:54 +0100113 TimeDelta first_delay,
114 Closure&& closure) {
115 auto repeating_task = absl::make_unique<
116 webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
117 task_queue, first_delay, std::forward<Closure>(closure));
118 auto* repeating_task_ptr = repeating_task.get();
119 task_queue->PostDelayedTask(std::move(repeating_task), first_delay.ms());
120 return RepeatingTaskHandle(repeating_task_ptr);
121 }
122 template <class Closure>
123 static RepeatingTaskHandle DelayedStart(TimeDelta first_delay,
124 Closure&& closure) {
Danil Chapovalov4423c362019-03-06 18:41:39 +0100125 return DelayedStart(TaskQueueBase::Current(), first_delay,
Sebastian Janssonecb68972019-01-18 10:30:54 +0100126 std::forward<Closure>(closure));
127 }
128
129 // Stops future invocations of the repeating task closure. Can only be called
130 // from the TaskQueue where the task is running. The closure is guaranteed to
131 // not be running after Stop() returns unless Stop() is called from the
132 // closure itself.
133 void Stop();
134
135 // Stops future invocations of the repeating task closure. The closure might
136 // still be running when PostStop() returns, but there will be no future
137 // invocation.
138 void PostStop();
139
140 // Returns true if Start() or DelayedStart() was called most recently. Returns
141 // false initially and if Stop() or PostStop() was called most recently.
142 bool Running() const;
143
144 private:
145 explicit RepeatingTaskHandle(
146 webrtc_repeating_task_impl::RepeatingTaskBase* repeating_task);
147 rtc::SequencedTaskChecker sequence_checker_;
148 // Owned by the task queue.
149 webrtc_repeating_task_impl::RepeatingTaskBase* repeating_task_
150 RTC_GUARDED_BY(sequence_checker_) = nullptr;
151};
152
153} // namespace webrtc
154#endif // RTC_BASE_TASK_UTILS_REPEATING_TASK_H_