|  | /* | 
|  | *  Copyright 2019 The WebRTC Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "rtc_base/task_utils/repeating_task.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <utility> | 
|  |  | 
|  | #include "absl/functional/any_invocable.h" | 
|  | #include "api/location.h" | 
|  | #include "api/scoped_refptr.h" | 
|  | #include "api/sequence_checker.h" | 
|  | #include "api/task_queue/pending_task_safety_flag.h" | 
|  | #include "api/task_queue/task_queue_base.h" | 
|  | #include "api/units/time_delta.h" | 
|  | #include "api/units/timestamp.h" | 
|  | #include "rtc_base/checks.h" | 
|  | #include "rtc_base/thread_annotations.h" | 
|  | #include "system_wrappers/include/clock.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace { | 
|  |  | 
|  | class RepeatingTask { | 
|  | public: | 
|  | RepeatingTask(TaskQueueBase* task_queue, | 
|  | TaskQueueBase::DelayPrecision precision, | 
|  | TimeDelta first_delay, | 
|  | absl::AnyInvocable<TimeDelta()> task, | 
|  | Clock* clock, | 
|  | scoped_refptr<PendingTaskSafetyFlag> alive_flag, | 
|  | const Location& location); | 
|  | RepeatingTask(RepeatingTask&&) = default; | 
|  | RepeatingTask& operator=(RepeatingTask&&) = delete; | 
|  | ~RepeatingTask() = default; | 
|  |  | 
|  | void operator()() &&; | 
|  |  | 
|  | private: | 
|  | TaskQueueBase* const task_queue_; | 
|  | const TaskQueueBase::DelayPrecision precision_; | 
|  | Clock* const clock_; | 
|  | const Location location_; | 
|  | absl::AnyInvocable<TimeDelta()> task_; | 
|  | // This is always finite. | 
|  | Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_); | 
|  | scoped_refptr<PendingTaskSafetyFlag> alive_flag_ RTC_GUARDED_BY(task_queue_); | 
|  | }; | 
|  |  | 
|  | RepeatingTask::RepeatingTask(TaskQueueBase* task_queue, | 
|  | TaskQueueBase::DelayPrecision precision, | 
|  | TimeDelta first_delay, | 
|  | absl::AnyInvocable<TimeDelta()> task, | 
|  | Clock* clock, | 
|  | scoped_refptr<PendingTaskSafetyFlag> alive_flag, | 
|  | const Location& location) | 
|  | : task_queue_(task_queue), | 
|  | precision_(precision), | 
|  | clock_(clock), | 
|  | location_(location), | 
|  | task_(std::move(task)), | 
|  | next_run_time_(clock_->CurrentTime() + first_delay), | 
|  | alive_flag_(std::move(alive_flag)) {} | 
|  |  | 
|  | void RepeatingTask::operator()() && { | 
|  | RTC_DCHECK_RUN_ON(task_queue_); | 
|  | if (!alive_flag_->alive()) | 
|  | return; | 
|  |  | 
|  | webrtc_repeating_task_impl::RepeatingTaskImplDTraceProbeRun(); | 
|  | TimeDelta delay = task_(); | 
|  | RTC_DCHECK_GE(delay, TimeDelta::Zero()); | 
|  |  | 
|  | // A delay of +infinity means that the task should not be run again. | 
|  | // Alternatively, the closure might have stopped this task. | 
|  | if (delay.IsPlusInfinity() || !alive_flag_->alive()) | 
|  | return; | 
|  |  | 
|  | TimeDelta lost_time = clock_->CurrentTime() - next_run_time_; | 
|  | next_run_time_ += delay; | 
|  | delay -= lost_time; | 
|  | delay = std::max(delay, TimeDelta::Zero()); | 
|  |  | 
|  | task_queue_->PostDelayedTaskWithPrecision(precision_, std::move(*this), delay, | 
|  | location_); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | RepeatingTaskHandle RepeatingTaskHandle::Start( | 
|  | TaskQueueBase* task_queue, | 
|  | absl::AnyInvocable<TimeDelta()> closure, | 
|  | TaskQueueBase::DelayPrecision precision, | 
|  | Clock* clock, | 
|  | const Location& location) { | 
|  | auto alive_flag = PendingTaskSafetyFlag::CreateDetached(); | 
|  | webrtc_repeating_task_impl::RepeatingTaskHandleDTraceProbeStart(); | 
|  | task_queue->PostTask( | 
|  | RepeatingTask(task_queue, precision, TimeDelta::Zero(), | 
|  | std::move(closure), clock, alive_flag, location), | 
|  | location); | 
|  | return RepeatingTaskHandle(std::move(alive_flag)); | 
|  | } | 
|  |  | 
|  | // DelayedStart is equivalent to Start except that the first invocation of the | 
|  | // closure will be delayed by the given amount. | 
|  | RepeatingTaskHandle RepeatingTaskHandle::DelayedStart( | 
|  | TaskQueueBase* task_queue, | 
|  | TimeDelta first_delay, | 
|  | absl::AnyInvocable<TimeDelta()> closure, | 
|  | TaskQueueBase::DelayPrecision precision, | 
|  | Clock* clock, | 
|  | const Location& location) { | 
|  | auto alive_flag = PendingTaskSafetyFlag::CreateDetached(); | 
|  | webrtc_repeating_task_impl::RepeatingTaskHandleDTraceProbeDelayedStart(); | 
|  | task_queue->PostDelayedTaskWithPrecision( | 
|  | precision, | 
|  | RepeatingTask(task_queue, precision, first_delay, std::move(closure), | 
|  | clock, alive_flag, location), | 
|  | first_delay, location); | 
|  | return RepeatingTaskHandle(std::move(alive_flag)); | 
|  | } | 
|  |  | 
|  | void RepeatingTaskHandle::Stop() { | 
|  | if (repeating_task_) { | 
|  | repeating_task_->SetNotAlive(); | 
|  | repeating_task_ = nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool RepeatingTaskHandle::Running() const { | 
|  | return repeating_task_ != nullptr; | 
|  | } | 
|  |  | 
|  | namespace webrtc_repeating_task_impl { | 
|  | // These methods are empty, but can be externally equipped with actions using | 
|  | // dtrace. | 
|  | void RepeatingTaskHandleDTraceProbeStart() {} | 
|  | void RepeatingTaskHandleDTraceProbeDelayedStart() {} | 
|  | void RepeatingTaskImplDTraceProbeRun() {} | 
|  | }  // namespace webrtc_repeating_task_impl | 
|  | }  // namespace webrtc |