diff --git a/rtc_base/task_utils/BUILD.gn b/rtc_base/task_utils/BUILD.gn index 1882cd9ee8..32f72b87df 100644 --- a/rtc_base/task_utils/BUILD.gn +++ b/rtc_base/task_utils/BUILD.gn @@ -21,6 +21,7 @@ rtc_library("repeating_task") { "../../api/task_queue", "../../api/units:time_delta", "../../api/units:timestamp", + "../../system_wrappers:system_wrappers", "../synchronization:sequence_checker", "//third_party/abseil-cpp/absl/memory", ] diff --git a/rtc_base/task_utils/repeating_task.cc b/rtc_base/task_utils/repeating_task.cc index 3b84701952..574e6331f1 100644 --- a/rtc_base/task_utils/repeating_task.cc +++ b/rtc_base/task_utils/repeating_task.cc @@ -17,11 +17,13 @@ namespace webrtc { namespace webrtc_repeating_task_impl { + RepeatingTaskBase::RepeatingTaskBase(TaskQueueBase* task_queue, - TimeDelta first_delay) + TimeDelta first_delay, + Clock* clock) : task_queue_(task_queue), - next_run_time_(Timestamp::Micros(rtc::TimeMicros()) + first_delay) { -} + clock_(clock), + next_run_time_(clock_->CurrentTime() + first_delay) {} RepeatingTaskBase::~RepeatingTaskBase() = default; @@ -39,7 +41,7 @@ bool RepeatingTaskBase::Run() { return true; RTC_DCHECK(delay.IsFinite()); - TimeDelta lost_time = Timestamp::Micros(rtc::TimeMicros()) - next_run_time_; + TimeDelta lost_time = clock_->CurrentTime() - next_run_time_; next_run_time_ += delay; delay -= lost_time; delay = std::max(delay, TimeDelta::Zero()); diff --git a/rtc_base/task_utils/repeating_task.h b/rtc_base/task_utils/repeating_task.h index f7ae55ee97..487b7d19d4 100644 --- a/rtc_base/task_utils/repeating_task.h +++ b/rtc_base/task_utils/repeating_task.h @@ -19,6 +19,7 @@ #include "api/task_queue/task_queue_base.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "system_wrappers/include/clock.h" namespace webrtc { @@ -27,7 +28,9 @@ class RepeatingTaskHandle; namespace webrtc_repeating_task_impl { class RepeatingTaskBase : public QueuedTask { public: - RepeatingTaskBase(TaskQueueBase* task_queue, TimeDelta first_delay); + RepeatingTaskBase(TaskQueueBase* task_queue, + TimeDelta first_delay, + Clock* clock); ~RepeatingTaskBase() override; void Stop(); @@ -38,6 +41,7 @@ class RepeatingTaskBase : public QueuedTask { bool Run() final; TaskQueueBase* const task_queue_; + Clock* const clock_; // This is always finite, except for the special case where it's PlusInfinity // to signal that the task should stop. Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_); @@ -49,8 +53,9 @@ class RepeatingTaskImpl final : public RepeatingTaskBase { public: RepeatingTaskImpl(TaskQueueBase* task_queue, TimeDelta first_delay, - Closure&& closure) - : RepeatingTaskBase(task_queue, first_delay), + Closure&& closure, + Clock* clock) + : RepeatingTaskBase(task_queue, first_delay, clock), closure_(std::forward(closure)) { static_assert( std::is_same static RepeatingTaskHandle Start(TaskQueueBase* task_queue, - Closure&& closure) { + Closure&& closure, + Clock* clock = Clock::GetRealTimeClock()) { auto repeating_task = std::make_unique< webrtc_repeating_task_impl::RepeatingTaskImpl>( - task_queue, TimeDelta::Zero(), std::forward(closure)); + task_queue, TimeDelta::Zero(), std::forward(closure), clock); auto* repeating_task_ptr = repeating_task.get(); task_queue->PostTask(std::move(repeating_task)); return RepeatingTaskHandle(repeating_task_ptr); @@ -102,12 +108,14 @@ class RepeatingTaskHandle { // DelayedStart is equivalent to Start except that the first invocation of the // closure will be delayed by the given amount. template - static RepeatingTaskHandle DelayedStart(TaskQueueBase* task_queue, - TimeDelta first_delay, - Closure&& closure) { + static RepeatingTaskHandle DelayedStart( + TaskQueueBase* task_queue, + TimeDelta first_delay, + Closure&& closure, + Clock* clock = Clock::GetRealTimeClock()) { auto repeating_task = std::make_unique< webrtc_repeating_task_impl::RepeatingTaskImpl>( - task_queue, first_delay, std::forward(closure)); + task_queue, first_delay, std::forward(closure), clock); auto* repeating_task_ptr = repeating_task.get(); task_queue->PostDelayedTask(std::move(repeating_task), first_delay.ms()); return RepeatingTaskHandle(repeating_task_ptr); diff --git a/rtc_base/task_utils/repeating_task_unittest.cc b/rtc_base/task_utils/repeating_task_unittest.cc index 36d085c4fe..2fb15d1e5a 100644 --- a/rtc_base/task_utils/repeating_task_unittest.cc +++ b/rtc_base/task_utils/repeating_task_unittest.cc @@ -44,6 +44,21 @@ class MockClosure { MOCK_METHOD(void, Delete, ()); }; +class MockTaskQueue : public TaskQueueBase { + public: + MockTaskQueue() : task_queue_setter_(this) {} + + MOCK_METHOD(void, Delete, (), (override)); + MOCK_METHOD(void, PostTask, (std::unique_ptr task), (override)); + MOCK_METHOD(void, + PostDelayedTask, + (std::unique_ptr task, uint32_t milliseconds), + (override)); + + private: + CurrentTaskQueueSetter task_queue_setter_; +}; + class MoveOnlyClosure { public: explicit MoveOnlyClosure(MockClosure* mock) : mock_(mock) {} @@ -228,4 +243,37 @@ TEST(RepeatingTaskTest, Example) { // task queue destruction and running the desctructor closure. } +TEST(RepeatingTaskTest, ClockIntegration) { + std::unique_ptr delayed_task; + uint32_t expected_ms = 0; + SimulatedClock clock(Timestamp::Millis(0)); + + NiceMock task_queue; + ON_CALL(task_queue, PostDelayedTask) + .WillByDefault( + Invoke([&delayed_task, &expected_ms](std::unique_ptr task, + uint32_t milliseconds) { + EXPECT_EQ(milliseconds, expected_ms); + delayed_task = std::move(task); + })); + + expected_ms = 100; + RepeatingTaskHandle handle = RepeatingTaskHandle::DelayedStart( + &task_queue, TimeDelta::Millis(100), + [&clock]() { + EXPECT_EQ(Timestamp::Millis(100), clock.CurrentTime()); + // Simulate work happening for 10ms. + clock.AdvanceTimeMilliseconds(10); + return TimeDelta::Millis(100); + }, + &clock); + + clock.AdvanceTimeMilliseconds(100); + QueuedTask* task_to_run = delayed_task.release(); + expected_ms = 90; + EXPECT_FALSE(task_to_run->Run()); + EXPECT_NE(nullptr, delayed_task.get()); + handle.Stop(); +} + } // namespace webrtc