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