1 /*
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 <memory>
15 #include <type_traits>
16 #include <utility>
17 
18 #include "api/task_queue/queued_task.h"
19 #include "api/task_queue/task_queue_base.h"
20 #include "api/units/time_delta.h"
21 #include "api/units/timestamp.h"
22 #include "system_wrappers/include/clock.h"
23 
24 namespace webrtc {
25 
26 class RepeatingTaskHandle;
27 
28 namespace webrtc_repeating_task_impl {
29 class RepeatingTaskBase : public QueuedTask {
30  public:
31   RepeatingTaskBase(TaskQueueBase* task_queue,
32                     TimeDelta first_delay,
33                     Clock* clock);
34   ~RepeatingTaskBase() override;
35 
36   void Stop();
37 
38  private:
39   virtual TimeDelta RunClosure() = 0;
40 
41   bool Run() final;
42 
43   TaskQueueBase* const task_queue_;
44   Clock* const clock_;
45   // This is always finite, except for the special case where it's PlusInfinity
46   // to signal that the task should stop.
47   Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_);
48 };
49 
50 // The template closure pattern is based on rtc::ClosureTask.
51 template <class Closure>
52 class RepeatingTaskImpl final : public RepeatingTaskBase {
53  public:
RepeatingTaskImpl(TaskQueueBase * task_queue,TimeDelta first_delay,Closure && closure,Clock * clock)54   RepeatingTaskImpl(TaskQueueBase* task_queue,
55                     TimeDelta first_delay,
56                     Closure&& closure,
57                     Clock* clock)
58       : RepeatingTaskBase(task_queue, first_delay, clock),
59         closure_(std::forward<Closure>(closure)) {
60     static_assert(
61         std::is_same<TimeDelta,
62                      typename std::result_of<decltype (&Closure::operator())(
63                          Closure)>::type>::value,
64         "");
65   }
66 
67  private:
RunClosure()68   TimeDelta RunClosure() override { return closure_(); }
69 
70   typename std::remove_const<
71       typename std::remove_reference<Closure>::type>::type closure_;
72 };
73 }  // namespace webrtc_repeating_task_impl
74 
75 // Allows starting tasks that repeat themselves on a TaskQueue indefinately
76 // until they are stopped or the TaskQueue is destroyed. It allows starting and
77 // stopping multiple times, but you must stop one task before starting another
78 // and it can only be stopped when in the running state. The public interface is
79 // not thread safe.
80 class RepeatingTaskHandle {
81  public:
82   RepeatingTaskHandle() = default;
83   ~RepeatingTaskHandle() = default;
84   RepeatingTaskHandle(RepeatingTaskHandle&& other);
85   RepeatingTaskHandle& operator=(RepeatingTaskHandle&& other);
86   RepeatingTaskHandle(const RepeatingTaskHandle&) = delete;
87   RepeatingTaskHandle& operator=(const RepeatingTaskHandle&) = delete;
88 
89   // Start can be used to start a task that will be reposted with a delay
90   // determined by the return value of the provided closure. The actual task is
91   // owned by the TaskQueue and will live until it has been stopped or the
92   // TaskQueue is destroyed. Note that this means that trying to stop the
93   // repeating task after the TaskQueue is destroyed is an error. However, it's
94   // perfectly fine to destroy the handle while the task is running, since the
95   // repeated task is owned by the TaskQueue.
96   template <class Closure>
97   static RepeatingTaskHandle Start(TaskQueueBase* task_queue,
98                                    Closure&& closure,
99                                    Clock* clock = Clock::GetRealTimeClock()) {
100     auto repeating_task = std::make_unique<
101         webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
102         task_queue, TimeDelta::Zero(), std::forward<Closure>(closure), clock);
103     auto* repeating_task_ptr = repeating_task.get();
104     task_queue->PostTask(std::move(repeating_task));
105     return RepeatingTaskHandle(repeating_task_ptr);
106   }
107 
108   // DelayedStart is equivalent to Start except that the first invocation of the
109   // closure will be delayed by the given amount.
110   template <class Closure>
111   static RepeatingTaskHandle DelayedStart(
112       TaskQueueBase* task_queue,
113       TimeDelta first_delay,
114       Closure&& closure,
115       Clock* clock = Clock::GetRealTimeClock()) {
116     auto repeating_task = std::make_unique<
117         webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
118         task_queue, first_delay, std::forward<Closure>(closure), clock);
119     auto* repeating_task_ptr = repeating_task.get();
120     task_queue->PostDelayedTask(std::move(repeating_task), first_delay.ms());
121     return RepeatingTaskHandle(repeating_task_ptr);
122   }
123 
124   // Stops future invocations of the repeating task closure. Can only be called
125   // from the TaskQueue where the task is running. The closure is guaranteed to
126   // not be running after Stop() returns unless Stop() is called from the
127   // closure itself.
128   void Stop();
129 
130   // Returns true if Start() or DelayedStart() was called most recently. Returns
131   // false initially and if Stop() or PostStop() was called most recently.
132   bool Running() const;
133 
134  private:
135   explicit RepeatingTaskHandle(
136       webrtc_repeating_task_impl::RepeatingTaskBase* repeating_task);
137   // Owned by the task queue.
138   webrtc_repeating_task_impl::RepeatingTaskBase* repeating_task_ = nullptr;
139 };
140 
141 }  // namespace webrtc
142 #endif  // RTC_BASE_TASK_UTILS_REPEATING_TASK_H_
143