From 902b55457aa073730a0b996f2ff3c8e0368e42ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= Date: Mon, 17 Jan 2022 15:20:24 +0100 Subject: [PATCH] Let a RepeatingTask stop itself by returning a delay of PlusInfinity. Bug: none Change-Id: I5bf87e236019d156ffe85c5b91ce09f5f4042937 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/247160 Reviewed-by: Evan Shrubsole Reviewed-by: Tomas Gunnarsson Commit-Queue: Niels Moller Cr-Commit-Position: refs/heads/main@{#35710} --- rtc_base/task_utils/repeating_task.cc | 9 ++++--- rtc_base/task_utils/repeating_task.h | 5 +++- .../task_utils/repeating_task_unittest.cc | 25 +++++++++++++------ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/rtc_base/task_utils/repeating_task.cc b/rtc_base/task_utils/repeating_task.cc index 1f3eb1d064..b9bfdd87a4 100644 --- a/rtc_base/task_utils/repeating_task.cc +++ b/rtc_base/task_utils/repeating_task.cc @@ -38,13 +38,14 @@ bool RepeatingTaskBase::Run() { return true; TimeDelta delay = RunClosure(); + RTC_DCHECK_GE(delay, TimeDelta::Zero()); - // The closure might have stopped this task, in which case we return true to - // destruct this object. - if (!alive_flag_->alive()) + // A delay of +infinity means that the task should not be run again. + // Alternatively, the closure might have stopped this task. In either which + // case we return true to destruct this object. + if (delay.IsPlusInfinity() || !alive_flag_->alive()) return true; - RTC_DCHECK(delay.IsFinite()); TimeDelta lost_time = clock_->CurrentTime() - next_run_time_; next_run_time_ += delay; delay -= lost_time; diff --git a/rtc_base/task_utils/repeating_task.h b/rtc_base/task_utils/repeating_task.h index 91a40e0714..4c9983c349 100644 --- a/rtc_base/task_utils/repeating_task.h +++ b/rtc_base/task_utils/repeating_task.h @@ -52,7 +52,10 @@ class RepeatingTaskBase : public QueuedTask { RTC_GUARDED_BY(task_queue_); }; -// The template closure pattern is based on rtc::ClosureTask. +// The template closure pattern is based on rtc::ClosureTask. The provided +// closure should have a TimeDelta return value, specifing the desired +// non-negative interval to next repetition, or TimeDelta::PlusInfinity to +// indicate that the task should be deleted and not called again. template class RepeatingTaskImpl final : public RepeatingTaskBase { public: diff --git a/rtc_base/task_utils/repeating_task_unittest.cc b/rtc_base/task_utils/repeating_task_unittest.cc index ac0520a2e0..1d26ee62dc 100644 --- a/rtc_base/task_utils/repeating_task_unittest.cc +++ b/rtc_base/task_utils/repeating_task_unittest.cc @@ -239,34 +239,43 @@ TEST(RepeatingTaskTest, TaskCanStopItself) { EXPECT_EQ(counter.load(), 1); } +TEST(RepeatingTaskTest, TaskCanStopItselfByReturningInfinity) { + std::atomic_int counter(0); + SimulatedClock clock(Timestamp::Zero()); + FakeTaskQueue task_queue(&clock); + RepeatingTaskHandle handle = RepeatingTaskHandle::Start(&task_queue, [&] { + ++counter; + return TimeDelta::PlusInfinity(); + }); + EXPECT_EQ(task_queue.last_delay(), 0u); + // Task cancelled itself so wants to be released. + EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask()); + EXPECT_EQ(counter.load(), 1); +} + TEST(RepeatingTaskTest, ZeroReturnValueRepostsTheTask) { NiceMock closure; rtc::Event done; - RepeatingTaskHandle handle; EXPECT_CALL(closure, Call()) .WillOnce(Return(TimeDelta::Zero())) .WillOnce(Invoke([&] { done.Set(); - handle.Stop(); - return kTimeout; + return TimeDelta::PlusInfinity(); })); TaskQueueForTest task_queue("queue"); - handle = - RepeatingTaskHandle::Start(task_queue.Get(), MoveOnlyClosure(&closure)); + RepeatingTaskHandle::Start(task_queue.Get(), MoveOnlyClosure(&closure)); EXPECT_TRUE(done.Wait(kTimeout.ms())); } TEST(RepeatingTaskTest, StartPeriodicTask) { MockFunction closure; rtc::Event done; - RepeatingTaskHandle handle; EXPECT_CALL(closure, Call()) .WillOnce(Return(TimeDelta::Millis(20))) .WillOnce(Return(TimeDelta::Millis(20))) .WillOnce(Invoke([&] { done.Set(); - handle.Stop(); - return kTimeout; + return TimeDelta::PlusInfinity(); })); TaskQueueForTest task_queue("queue"); RepeatingTaskHandle::Start(task_queue.Get(), closure.AsStdFunction());