Add ability to specify delayed task precision in RepeatingTaskHandle.
See go/postdelayedtask-precision-in-webrtc for context of which use
cases are considered "high" or "low". Most use cases are "low" which
is the default, but this CL allows opting in to "high".
Will be used by FrameBuffer2.
Bug: webrtc:13604
Change-Id: Iebf6eea44779873e78746da749a39e1101b92819
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/248861
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35776}
diff --git a/rtc_base/task_utils/repeating_task.cc b/rtc_base/task_utils/repeating_task.cc
index b9bfdd8..c07df45 100644
--- a/rtc_base/task_utils/repeating_task.cc
+++ b/rtc_base/task_utils/repeating_task.cc
@@ -21,10 +21,12 @@
RepeatingTaskBase::RepeatingTaskBase(
TaskQueueBase* task_queue,
+ TaskQueueBase::DelayPrecision precision,
TimeDelta first_delay,
Clock* clock,
rtc::scoped_refptr<PendingTaskSafetyFlag> alive_flag)
: task_queue_(task_queue),
+ precision_(precision),
clock_(clock),
next_run_time_(clock_->CurrentTime() + first_delay),
alive_flag_(std::move(alive_flag)) {}
@@ -51,7 +53,8 @@
delay -= lost_time;
delay = std::max(delay, TimeDelta::Zero());
- task_queue_->PostDelayedTask(absl::WrapUnique(this), delay.ms());
+ task_queue_->PostDelayedTaskWithPrecision(precision_, absl::WrapUnique(this),
+ delay.ms());
// Return false to tell the TaskQueue to not destruct this object since we
// have taken ownership with absl::WrapUnique.
diff --git a/rtc_base/task_utils/repeating_task.h b/rtc_base/task_utils/repeating_task.h
index 4c9983c..20f28d5 100644
--- a/rtc_base/task_utils/repeating_task.h
+++ b/rtc_base/task_utils/repeating_task.h
@@ -34,6 +34,7 @@
class RepeatingTaskBase : public QueuedTask {
public:
RepeatingTaskBase(TaskQueueBase* task_queue,
+ TaskQueueBase::DelayPrecision precision,
TimeDelta first_delay,
Clock* clock,
rtc::scoped_refptr<PendingTaskSafetyFlag> alive_flag);
@@ -45,6 +46,7 @@
bool Run() final;
TaskQueueBase* const task_queue_;
+ const TaskQueueBase::DelayPrecision precision_;
Clock* const clock_;
// This is always finite.
Timestamp next_run_time_ RTC_GUARDED_BY(task_queue_);
@@ -60,11 +62,13 @@
class RepeatingTaskImpl final : public RepeatingTaskBase {
public:
RepeatingTaskImpl(TaskQueueBase* task_queue,
+ TaskQueueBase::DelayPrecision precision,
TimeDelta first_delay,
Closure&& closure,
Clock* clock,
rtc::scoped_refptr<PendingTaskSafetyFlag> alive_flag)
: RepeatingTaskBase(task_queue,
+ precision,
first_delay,
clock,
std::move(alive_flag)),
@@ -106,17 +110,20 @@
// owned by the TaskQueue and will live until it has been stopped or the
// TaskQueue deletes it. It's perfectly fine to destroy the handle while the
// task is running, since the repeated task is owned by the TaskQueue.
+ // The tasks are scheduled onto the task queue using the specified precision.
template <class Closure>
static RepeatingTaskHandle Start(TaskQueueBase* task_queue,
Closure&& closure,
+ TaskQueueBase::DelayPrecision precision =
+ TaskQueueBase::DelayPrecision::kLow,
Clock* clock = Clock::GetRealTimeClock()) {
auto alive_flag = PendingTaskSafetyFlag::CreateDetached();
webrtc_repeating_task_impl::RepeatingTaskHandleDTraceProbeStart();
task_queue->PostTask(
std::make_unique<
webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
- task_queue, TimeDelta::Zero(), std::forward<Closure>(closure),
- clock, alive_flag));
+ task_queue, precision, TimeDelta::Zero(),
+ std::forward<Closure>(closure), clock, alive_flag));
return RepeatingTaskHandle(std::move(alive_flag));
}
@@ -127,14 +134,17 @@
TaskQueueBase* task_queue,
TimeDelta first_delay,
Closure&& closure,
+ TaskQueueBase::DelayPrecision precision =
+ TaskQueueBase::DelayPrecision::kLow,
Clock* clock = Clock::GetRealTimeClock()) {
auto alive_flag = PendingTaskSafetyFlag::CreateDetached();
webrtc_repeating_task_impl::RepeatingTaskHandleDTraceProbeDelayedStart();
- task_queue->PostDelayedTask(
+ task_queue->PostDelayedTaskWithPrecision(
+ precision,
std::make_unique<
webrtc_repeating_task_impl::RepeatingTaskImpl<Closure>>(
- task_queue, first_delay, std::forward<Closure>(closure), clock,
- alive_flag),
+ task_queue, precision, first_delay, std::forward<Closure>(closure),
+ clock, alive_flag),
first_delay.ms());
return RepeatingTaskHandle(std::move(alive_flag));
}
diff --git a/rtc_base/task_utils/repeating_task_unittest.cc b/rtc_base/task_utils/repeating_task_unittest.cc
index 1d26ee6..d6ab920 100644
--- a/rtc_base/task_utils/repeating_task_unittest.cc
+++ b/rtc_base/task_utils/repeating_task_unittest.cc
@@ -64,12 +64,22 @@
void Delete() override {}
void PostTask(std::unique_ptr<QueuedTask> task) override {
- PostDelayedTask(std::move(task), 0);
+ last_task_ = std::move(task);
+ last_precision_ = absl::nullopt;
+ last_delay_ = 0;
}
void PostDelayedTask(std::unique_ptr<QueuedTask> task,
uint32_t milliseconds) override {
last_task_ = std::move(task);
+ last_precision_ = TaskQueueBase::DelayPrecision::kLow;
+ last_delay_ = milliseconds;
+ }
+
+ void PostDelayedHighPrecisionTask(std::unique_ptr<QueuedTask> task,
+ uint32_t milliseconds) override {
+ last_task_ = std::move(task);
+ last_precision_ = TaskQueueBase::DelayPrecision::kHigh;
last_delay_ = milliseconds;
}
@@ -94,11 +104,16 @@
return last_delay_.value_or(-1);
}
+ absl::optional<TaskQueueBase::DelayPrecision> last_precision() const {
+ return last_precision_;
+ }
+
private:
CurrentTaskQueueSetter task_queue_setter_;
SimulatedClock* clock_;
std::unique_ptr<QueuedTask> last_task_;
absl::optional<uint32_t> last_delay_;
+ absl::optional<TaskQueueBase::DelayPrecision> last_precision_;
};
// NOTE: Since this utility class holds a raw pointer to a variable that likely
@@ -165,7 +180,7 @@
clock.AdvanceTime(kSleepDuration);
return kRepeatInterval;
},
- &clock);
+ TaskQueueBase::DelayPrecision::kLow, &clock);
EXPECT_EQ(task_queue.last_delay(), 0u);
EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
@@ -188,7 +203,7 @@
clock.AdvanceTime(TimeDelta::Millis(100));
return TimeDelta::Millis(300);
},
- &clock);
+ TaskQueueBase::DelayPrecision::kLow, &clock);
// Expect instant post task.
EXPECT_EQ(task_queue.last_delay(), 0u);
@@ -338,7 +353,7 @@
clock.AdvanceTimeMilliseconds(10);
return TimeDelta::Millis(100);
},
- &clock);
+ TaskQueueBase::DelayPrecision::kLow, &clock);
clock.AdvanceTimeMilliseconds(100);
QueuedTask* task_to_run = delayed_task.release();
@@ -366,4 +381,66 @@
handle.Stop();
}
+TEST(RepeatingTaskTest, DefaultPrecisionIsLow) {
+ SimulatedClock clock(Timestamp::Zero());
+ FakeTaskQueue task_queue(&clock);
+ // Closure that repeats twice.
+ MockFunction<TimeDelta()> closure;
+ EXPECT_CALL(closure, Call())
+ .WillOnce(Return(TimeDelta::Millis(1)))
+ .WillOnce(Return(TimeDelta::PlusInfinity()));
+ RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction());
+ // Initial task is a PostTask().
+ EXPECT_FALSE(task_queue.last_precision().has_value());
+ EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
+ // Repeated task is a delayed task with the default precision: low.
+ EXPECT_TRUE(task_queue.last_precision().has_value());
+ EXPECT_EQ(task_queue.last_precision().value(),
+ TaskQueueBase::DelayPrecision::kLow);
+ // No more tasks.
+ EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
+}
+
+TEST(RepeatingTaskTest, CanSpecifyToPostTasksWithLowPrecision) {
+ SimulatedClock clock(Timestamp::Zero());
+ FakeTaskQueue task_queue(&clock);
+ // Closure that repeats twice.
+ MockFunction<TimeDelta()> closure;
+ EXPECT_CALL(closure, Call())
+ .WillOnce(Return(TimeDelta::Millis(1)))
+ .WillOnce(Return(TimeDelta::PlusInfinity()));
+ RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction(),
+ TaskQueueBase::DelayPrecision::kLow);
+ // Initial task is a PostTask().
+ EXPECT_FALSE(task_queue.last_precision().has_value());
+ EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
+ // Repeated task is a delayed task with the specified precision.
+ EXPECT_TRUE(task_queue.last_precision().has_value());
+ EXPECT_EQ(task_queue.last_precision().value(),
+ TaskQueueBase::DelayPrecision::kLow);
+ // No more tasks.
+ EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
+}
+
+TEST(RepeatingTaskTest, CanSpecifyToPostTasksWithHighPrecision) {
+ SimulatedClock clock(Timestamp::Zero());
+ FakeTaskQueue task_queue(&clock);
+ // Closure that repeats twice.
+ MockFunction<TimeDelta()> closure;
+ EXPECT_CALL(closure, Call())
+ .WillOnce(Return(TimeDelta::Millis(1)))
+ .WillOnce(Return(TimeDelta::PlusInfinity()));
+ RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction(),
+ TaskQueueBase::DelayPrecision::kHigh);
+ // Initial task is a PostTask().
+ EXPECT_FALSE(task_queue.last_precision().has_value());
+ EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
+ // Repeated task is a delayed task with the specified precision.
+ EXPECT_TRUE(task_queue.last_precision().has_value());
+ EXPECT_EQ(task_queue.last_precision().value(),
+ TaskQueueBase::DelayPrecision::kHigh);
+ // No more tasks.
+ EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
+}
+
} // namespace webrtc