From 158a376b73c737d1bbc87c07a29919c7b21b5fc2 Mon Sep 17 00:00:00 2001 From: Ben Date: Thu, 2 Feb 2023 22:46:21 +0000 Subject: pw_async: Implement VirtualSystemClock for Dispatchers Implement VirtualSystemClock in BasicDispatcher and TestDispatcher. Bug: b/254532947 Change-Id: I50861ea67d833d01b7af377b2e739526397ec53c Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/126930 Reviewed-by: Erik Gilling Commit-Queue: Ben Lawson --- pw_async/BUILD.gn | 5 ++++- pw_async/dispatcher_basic.cc | 16 ++++++++-------- pw_async/dispatcher_test.cc | 2 +- pw_async/public/pw_async/dispatcher.h | 13 ++++++++----- pw_async/public/pw_async/dispatcher_basic.h | 12 +++++++----- pw_async/public_test/pw_async/test_dispatcher.h | 6 ++++-- pw_async/test_dispatcher.cc | 10 +++++----- 7 files changed, 37 insertions(+), 27 deletions(-) diff --git a/pw_async/BUILD.gn b/pw_async/BUILD.gn index 42f1dc367..ebed69fd9 100644 --- a/pw_async/BUILD.gn +++ b/pw_async/BUILD.gn @@ -41,7 +41,10 @@ pw_source_set("task") { pw_source_set("dispatcher") { public_configs = [ ":public_include_path" ] - public_deps = [ ":task" ] + public_deps = [ + ":task", + "$dir_pw_chrono:system_clock", + ] public = [ "public/pw_async/dispatcher.h" ] visibility = [ ":*" ] + pw_async_EXPERIMENTAL_MODULE_VISIBILITY } diff --git a/pw_async/dispatcher_basic.cc b/pw_async/dispatcher_basic.cc index 03394fec4..2425b11a8 100644 --- a/pw_async/dispatcher_basic.cc +++ b/pw_async/dispatcher_basic.cc @@ -39,23 +39,23 @@ void BasicDispatcher::RunUntilIdle() { void BasicDispatcher::RunUntil(chrono::SystemClock::time_point end_time) { lock_.lock(); - while (end_time < Now()) { + while (end_time < now()) { RunLoopOnce(); } lock_.unlock(); } void BasicDispatcher::RunFor(chrono::SystemClock::duration duration) { - RunUntil(Now() + duration); + RunUntil(now() + duration); } void BasicDispatcher::RunLoopOnce() { - if (task_queue_.empty() || DueTime(task_queue_.front()) > Now()) { + if (task_queue_.empty() || DueTime(task_queue_.front()) > now()) { // Sleep until a notification is received or until the due time of the // next task. Notifications are sent when tasks are posted or 'stop' is // requested. chrono::SystemClock::time_point wake_time = - task_queue_.empty() ? Now() + SLEEP_DURATION + task_queue_.empty() ? now() + SLEEP_DURATION : DueTime(task_queue_.front()); lock_.unlock(); @@ -66,7 +66,7 @@ void BasicDispatcher::RunLoopOnce() { return; } - while (!task_queue_.empty() && DueTime(task_queue_.front()) <= Now()) { + while (!task_queue_.empty() && DueTime(task_queue_.front()) <= now()) { Task& task = task_queue_.front(); task_queue_.pop_front(); @@ -90,11 +90,11 @@ void BasicDispatcher::RequestStop() { timed_notification_.release(); } -void BasicDispatcher::PostTask(Task& task) { PostTaskForTime(task, Now()); } +void BasicDispatcher::PostTask(Task& task) { PostTaskForTime(task, now()); } void BasicDispatcher::PostDelayedTask(Task& task, chrono::SystemClock::duration delay) { - PostTaskForTime(task, Now() + delay); + PostTaskForTime(task, now() + delay); } void BasicDispatcher::PostTaskForTime(Task& task, @@ -107,7 +107,7 @@ void BasicDispatcher::PostTaskForTime(Task& task, void BasicDispatcher::SchedulePeriodicTask( Task& task, chrono::SystemClock::duration interval) { - SchedulePeriodicTask(task, interval, Now()); + SchedulePeriodicTask(task, interval, now()); } void BasicDispatcher::SchedulePeriodicTask( diff --git a/pw_async/dispatcher_test.cc b/pw_async/dispatcher_test.cc index b37a3aef6..dba072313 100644 --- a/pw_async/dispatcher_test.cc +++ b/pw_async/dispatcher_test.cc @@ -141,7 +141,7 @@ TEST(TestDispatcher, PeriodicTasks) { TestPrimitives tp; Task periodic_task([&tp]([[maybe_unused]] Context& c) { ++tp.count; }); - dispatcher.SchedulePeriodicTask(periodic_task, 20ms, dispatcher.Now() + 50ms); + dispatcher.SchedulePeriodicTask(periodic_task, 20ms, dispatcher.now() + 50ms); // Cancel periodic task after it has run thrice, at +50ms, +70ms, and +90ms. Task cancel_task( diff --git a/pw_async/public/pw_async/dispatcher.h b/pw_async/public/pw_async/dispatcher.h index df449200f..bdd6e192f 100644 --- a/pw_async/public/pw_async/dispatcher.h +++ b/pw_async/public/pw_async/dispatcher.h @@ -14,20 +14,23 @@ #pragma once #include "pw_async/task.h" +#include "pw_chrono/system_clock.h" namespace pw::async { // Asynchronous Dispatcher abstract class. A default implementation is provided // in dispatcher_basic.h. -class Dispatcher { +// +// Dispatcher implements VirtualSystemClock so the Dispatcher's time can be +// injected into other modules under test. This is useful for consistently +// simulating time when using TestDispatcher (rather than using +// chrono::SimulatedSystemClock separately). +class Dispatcher : public chrono::VirtualSystemClock { public: - virtual ~Dispatcher() = default; + ~Dispatcher() override = default; virtual void RequestStop() = 0; - // Returns the current time as viewed by the Dispatcher. - virtual chrono::SystemClock::time_point Now() = 0; - // Post caller owned |task|. virtual void PostTask(Task& task) = 0; diff --git a/pw_async/public/pw_async/dispatcher_basic.h b/pw_async/public/pw_async/dispatcher_basic.h index 482990c20..51efc91b5 100644 --- a/pw_async/public/pw_async/dispatcher_basic.h +++ b/pw_async/public/pw_async/dispatcher_basic.h @@ -28,11 +28,6 @@ class BasicDispatcher final : public Dispatcher, public thread::ThreadCore { void RequestStop() override PW_LOCKS_EXCLUDED(lock_); - // Returns the current time as viewed by the BasicDispatcher. - chrono::SystemClock::time_point Now() override { - return chrono::SystemClock::now(); - } - // Post caller owned |task|. void PostTask(Task& task) override; @@ -68,6 +63,13 @@ class BasicDispatcher final : public Dispatcher, public thread::ThreadCore { void RunUntil(chrono::SystemClock::time_point end_time) override; void RunFor(chrono::SystemClock::duration duration) override; + // VirtualSystemClock overrides: + + // Returns the current time as viewed by the BasicDispatcher. + chrono::SystemClock::time_point now() override { + return chrono::SystemClock::now(); + } + private: // TestDispatcher uses BasicDispatcher methods operating on Task state. friend class TestDispatcher; diff --git a/pw_async/public_test/pw_async/test_dispatcher.h b/pw_async/public_test/pw_async/test_dispatcher.h index 0c86026f1..2a396cb67 100644 --- a/pw_async/public_test/pw_async/test_dispatcher.h +++ b/pw_async/public_test/pw_async/test_dispatcher.h @@ -22,8 +22,6 @@ class TestDispatcher final : public Dispatcher { explicit TestDispatcher() {} ~TestDispatcher() override { RequestStop(); } - chrono::SystemClock::time_point Now() override { return now_; } - void RequestStop() override; // Post caller owned |task|. @@ -64,6 +62,10 @@ class TestDispatcher final : public Dispatcher { // come due in that period. void RunFor(chrono::SystemClock::duration duration) override; + // VirtualSystemClock overrides: + + chrono::SystemClock::time_point now() override { return now_; } + private: // Insert |task| into task_queue_ maintaining its min-heap property, keyed by // |time_due|. diff --git a/pw_async/test_dispatcher.cc b/pw_async/test_dispatcher.cc index 66da26a69..64b484ab7 100644 --- a/pw_async/test_dispatcher.cc +++ b/pw_async/test_dispatcher.cc @@ -42,12 +42,12 @@ void TestDispatcher::RunUntil(chrono::SystemClock::time_point end_time) { } void TestDispatcher::RunFor(chrono::SystemClock::duration duration) { - RunUntil(Now() + duration); + RunUntil(now() + duration); } void TestDispatcher::RunLoopOnce() { while (!task_queue_.empty() && - BasicDispatcher::DueTime(task_queue_.front()) <= Now()) { + BasicDispatcher::DueTime(task_queue_.front()) <= now()) { Task& task = task_queue_.front(); task_queue_.pop_front(); @@ -67,11 +67,11 @@ void TestDispatcher::RequestStop() { task_queue_.clear(); } -void TestDispatcher::PostTask(Task& task) { PostTaskForTime(task, Now()); } +void TestDispatcher::PostTask(Task& task) { PostTaskForTime(task, now()); } void TestDispatcher::PostDelayedTask(Task& task, chrono::SystemClock::duration delay) { - PostTaskForTime(task, Now() + delay); + PostTaskForTime(task, now() + delay); } void TestDispatcher::PostTaskForTime(Task& task, @@ -82,7 +82,7 @@ void TestDispatcher::PostTaskForTime(Task& task, void TestDispatcher::SchedulePeriodicTask( Task& task, chrono::SystemClock::duration interval) { - SchedulePeriodicTask(task, interval, Now()); + SchedulePeriodicTask(task, interval, now()); } void TestDispatcher::SchedulePeriodicTask( -- cgit v1.2.3