Skip to content

Commit

Permalink
pw_async2: Add TimeProvider
Browse files Browse the repository at this point in the history
Change-Id: Iacbd442622d963e1a5a47127149023bebb8c5674
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/232411
Reviewed-by: Aaron Green <[email protected]>
Commit-Queue: Taylor Cramer <[email protected]>
Lint: Lint 🤖 <[email protected]>
  • Loading branch information
cramertj authored and CQ Bot Account committed Aug 30, 2024
1 parent f35a192 commit 1d56596
Show file tree
Hide file tree
Showing 21 changed files with 866 additions and 11 deletions.
3 changes: 3 additions & 0 deletions docs/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ _doxygen_input_files = [ # keep-sorted: start
"$dir_pw_async2/public/pw_async2/pend_func_task.h",
"$dir_pw_async2/public/pw_async2/pendable_as_task.h",
"$dir_pw_async2/public/pw_async2/poll.h",
"$dir_pw_async2/public/pw_async2/simulated_time_provider.h",
"$dir_pw_async2/public/pw_async2/system_time_provider.h",
"$dir_pw_async2/public/pw_async2/time_provider.h",
"$dir_pw_async2_basic/public_overrides/pw_async2/dispatcher_native.h",
"$dir_pw_async_basic/public/pw_async_basic/dispatcher.h",
"$dir_pw_base64/public/pw_base64/base64.h",
Expand Down
71 changes: 71 additions & 0 deletions pw_async2/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,74 @@ pw_cc_test(
"//pw_allocator:testing",
],
)

cc_library(
name = "time_provider",
srcs = [
"time_provider.cc",
],
hdrs = [
"public/pw_async2/time_provider.h",
],
includes = ["public"],
deps = [
":dispatcher",
"//pw_containers:intrusive_list",
"//pw_sync:interrupt_spin_lock",
"//pw_toolchain:no_destructor",
],
)

cc_library(
name = "system_time_provider",
srcs = [
"system_time_provider.cc",
],
hdrs = [
"public/pw_async2/system_time_provider.h",
],
implementation_deps = [
"//pw_chrono:system_timer",
"//pw_toolchain:no_destructor",
],
includes = ["public"],
deps = [
":time_provider",
"//pw_chrono:system_clock",
],
)

pw_cc_test(
name = "system_time_provider_test",
srcs = [
"system_time_provider_test.cc",
],
deps = [
":system_time_provider",
"//pw_unit_test",
],
)

cc_library(
name = "simulated_time_provider",
hdrs = [
"public/pw_async2/simulated_time_provider.h",
],
includes = ["public"],
deps = [
":time_provider",
"//pw_sync:interrupt_spin_lock",
],
)

pw_cc_test(
name = "simulated_time_provider_test",
srcs = [
"simulated_time_provider_test.cc",
],
deps = [
":simulated_time_provider",
"//pw_chrono:system_clock",
"//pw_unit_test",
],
)
58 changes: 58 additions & 0 deletions pw_async2/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,62 @@ if (pw_toolchain_CXX_STANDARD >= pw_toolchain_STANDARD.CXX20) {
}
}

pw_source_set("time_provider") {
public = [ "public/pw_async2/time_provider.h" ]
sources = [ "time_provider.cc" ]
public_configs = [ ":public_include_path" ]
public_deps = [
":dispatcher",
"$dir_pw_containers:intrusive_list",
"$dir_pw_sync:interrupt_spin_lock",
"$dir_pw_toolchain:no_destructor",
]
}

pw_source_set("system_time_provider") {
public = [ "public/pw_async2/system_time_provider.h" ]
public_configs = [ ":public_include_path" ]
public_deps = [
":time_provider",
"$dir_pw_chrono:system_clock",
]
sources = [ "system_time_provider.cc" ]
deps = [
"$dir_pw_chrono:system_timer",
"$dir_pw_toolchain:no_destructor",
]
}

pw_test("system_time_provider_test") {
enable_if =
pw_async2_DISPATCHER_BACKEND != "" &&
pw_chrono_SYSTEM_CLOCK_BACKEND != "" &&
pw_sync_INTERRUPT_SPIN_LOCK_BACKEND != "" && pw_thread_YIELD_BACKEND != ""
sources = [ "system_time_provider_test.cc" ]
deps = [ ":system_time_provider" ]
}

pw_source_set("simulated_time_provider") {
public = [ "public/pw_async2/simulated_time_provider.h" ]
public_configs = [ ":public_include_path" ]
public_deps = [
":time_provider",
"$dir_pw_sync:interrupt_spin_lock",
]
}

pw_test("simulated_time_provider_test") {
enable_if =
pw_async2_DISPATCHER_BACKEND != "" &&
pw_chrono_SYSTEM_CLOCK_BACKEND != "" &&
pw_sync_INTERRUPT_SPIN_LOCK_BACKEND != "" && pw_thread_YIELD_BACKEND != ""
sources = [ "simulated_time_provider_test.cc" ]
deps = [
":simulated_time_provider",
"$dir_pw_chrono:system_clock",
]
}

pw_test_group("tests") {
tests = [
":allocate_task_test",
Expand All @@ -220,6 +276,8 @@ pw_test_group("tests") {
":pend_func_task_test",
":pendable_as_task_test",
":once_sender_test",
":simulated_time_provider_test",
":system_time_provider_test",
]
if (pw_toolchain_CXX_STANDARD >= pw_toolchain_STANDARD.CXX20) {
tests += [
Expand Down
66 changes: 66 additions & 0 deletions pw_async2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,70 @@ if(NOT "cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
)
endif()


pw_add_library(pw_async2.time_provider STATIC
HEADERS
public/pw_async2/time_provider.h
SOURCES
time_provider.cc
PUBLIC_DEPS
pw_async2.dispatcher
pw_containers.intrusive_list
pw_sync.interrupt_spin_lock
PUBLIC_INCLUDES
public
)

pw_add_library(pw_async2.system_time_provider STATIC
HEADERS
public/pw_async2/system_time_provider.h
SOURCES
system_time_provider.cc
PUBLIC_DEPS
pw_chrono.system_clock
pw_async2.time_provider
PRIVATE_DEPS
pw_chrono.system_timer
pw_toolchain.no_destructor
PUBLIC_INCLUDES
public
)

if((NOT "${pw_chrono.system_clock_BACKEND}" STREQUAL "") AND
(NOT "${pw_sync.interrupt_spin_lock_BACKEND}" STREQUAL ""))
pw_add_test(pw_async2.system_time_provider_test
SOURCES
system_time_provider_test.cc
PRIVATE_DEPS
pw_async2.system_time_provider
pw_chrono.system_clock
GROUPS
modules
pw_async2
)
endif()

pw_add_library(pw_async2.simulated_time_provider INTERFACE
HEADERS
public/pw_async2/simulated_time_provider.h
PUBLIC_DEPS
pw_async2.time_provider
pw_sync.interrupt_spin_lock
)

if((NOT "${pw_chrono.system_clock_BACKEND}" STREQUAL "") AND
(NOT "${pw_sync.interrupt_spin_lock_BACKEND}" STREQUAL ""))
pw_add_test(pw_async2.simulated_time_provider_test
SOURCES
simulated_time_provider_test.cc
PRIVATE_DEPS
pw_async2.simulated_time_provider
pw_chrono.system_clock
GROUPS
modules
pw_async2
)
endif()


add_subdirectory(examples)
4 changes: 2 additions & 2 deletions pw_async2/dispatcher_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -209,20 +209,20 @@ void DispatcherBase::RemoveTaskFromList(Task& task) {
}

void DispatcherBase::RemoveWokenTaskLocked(Task& task) {
RemoveTaskFromList(task);
if (first_woken_ == &task) {
first_woken_ = task.next_;
}
if (last_woken_ == &task) {
last_woken_ = task.prev_;
}
RemoveTaskFromList(task);
}

void DispatcherBase::RemoveSleepingTaskLocked(Task& task) {
RemoveTaskFromList(task);
if (sleeping_ == &task) {
sleeping_ = task.next_;
}
RemoveTaskFromList(task);
}

void DispatcherBase::AddTaskToWokenList(Task& task) {
Expand Down
5 changes: 5 additions & 0 deletions pw_async2/dispatcher_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ TEST(Dispatcher, RunUntilStalledDoesNotPendSleepingTask) {
EXPECT_EQ(task.destroyed, 1);
}

TEST(Dispatcher, RunUntilStalledWithNoTasksReturnsReady) {
Dispatcher dispatcher;
EXPECT_TRUE(dispatcher.RunUntilStalled().IsReady());
}

TEST(Dispatcher, RunUntilCompletePendsMultipleTasks) {
class CounterTask : public Task {
public:
Expand Down
27 changes: 27 additions & 0 deletions pw_async2/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,33 @@ used instead.
For a more detailed explanation of Pigweed's coroutine support, see the
documentation on the :cpp:class:`pw::async2::Coro<T>` type.

------
Timing
------
When using ``pw::async2``, timing functionality should be injected
by accepting a :cpp:class:`pw::async2::TimeProvider` (most commonly
``TimeProvider<SystemClock>`` when using the system's built-in `time_point`
and `duration` types).

:cpp:class:`pw::async2::TimeProvider` allows for easily waiting
for a timeout or deadline using the
:cpp:func:`pw::async2::TimePoint::WaitFor` and
:cpp:func:`pw::async2::TimePoint::WaitUntil` methods.

Additionally, code which uses :cpp:class:`pw::async2::TimeProvider` for timing
can be tested with simulated time using
:cpp:class:`pw::async2::SimulatedTimeProvider`. Doing so helps avoid
timing-dependent test flakes, as well as ensure that tests are fast since they
don't need to wait for real-world time to elapse.

.. doxygenclass:: pw::async2::TimeProvider
:members:

.. doxygenfunction:: pw::async2::GetSystemTimeProvider

.. doxygenclass:: pw::async2::SimulatedTimeProvider
:members:

-----------------
C++ API reference
-----------------
Expand Down
5 changes: 4 additions & 1 deletion pw_async2/public/pw_async2/dispatcher_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,12 @@ class Task {
/// This identifier may be stored for debugging purposes.
class WaitReason {
public:
/// Indicates that the wait is happen for an unspecified reason.
/// Indicates that the wait is happening for an unspecified reason.
static WaitReason Unspecified() { return WaitReason(); }

/// Indicates that the wait is happening until a timeout expires.
static WaitReason Timeout() { return WaitReason(); }

private:
WaitReason() {}
};
Expand Down
4 changes: 2 additions & 2 deletions pw_async2/public/pw_async2/poll.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ constexpr Poll<T> Ready(std::in_place_t, Args&&... args) {

/// Returns a value indicating completion with some result.
template <typename T>
constexpr Poll<T> Ready(T&& value) {
return Poll<T>(std::forward<T>(value));
constexpr Poll<std::remove_reference_t<T>> Ready(T&& value) {
return Poll<std::remove_reference_t<T>>(std::forward<T>(value));
}

/// Returns a value indicating that an operation was not yet able to complete.
Expand Down
Loading

0 comments on commit 1d56596

Please sign in to comment.