pw_async2: Derive TimeFuture from Future
As part of this, removes the `Reset` function from `TimeFuture`. A new
future should be acquired from the `TimeProvider` instead.
Change-Id: I236760eda4560448a293e6f3357775ca0fffc570
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/324492
Docs-Not-Needed: Alexei Frolov <frolv@google.com>
Reviewed-by: Lloyd Pique <lpique@google.com>
Commit-Queue: Alexei Frolov <frolv@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/pw_async2/public/pw_async2/time_provider.h b/pw_async2/public/pw_async2/time_provider.h
index 479e284..5ded953 100644
--- a/pw_async2/public/pw_async2/time_provider.h
+++ b/pw_async2/public/pw_async2/time_provider.h
@@ -19,6 +19,7 @@
#include <mutex>
#include "pw_async2/dispatcher.h"
+#include "pw_async2/future.h"
#include "pw_chrono/virtual_clock.h"
#include "pw_containers/intrusive_list.h"
#include "pw_sync/interrupt_spin_lock.h"
@@ -119,7 +120,9 @@
/// used with any `TimeProvider` with a compatible `Clock` type.
template <typename Clock>
class [[nodiscard]] TimeFuture
- : public IntrusiveForwardList<TimeFuture<Clock>>::Item {
+ : public experimental::Future<TimeFuture<Clock>,
+ typename Clock::time_point>,
+ public IntrusiveForwardList<TimeFuture<Clock>>::Item {
public:
TimeFuture() : provider_(nullptr) {}
TimeFuture(const TimeFuture&) = delete;
@@ -157,28 +160,6 @@
/// Destruction is thread-safe, but not necessarily interrupt-safe.
~TimeFuture() { Unlist(); }
- Poll<typename Clock::time_point> Pend(Context& cx)
- PW_LOCKS_EXCLUDED(internal::time_lock()) {
- std::lock_guard lock(internal::time_lock());
- if (this->unlisted()) {
- return Ready(expiration_);
- }
- // NOTE: this is done under the lock in order to ensure that `provider_` is
- // not set to unlisted between it being initially read and `waker_` being
- // set.
- PW_ASYNC_STORE_WAKER(cx, waker_, "TimeFuture is waiting for a time_point");
- return Pending();
- }
-
- /// Resets ``TimeFuture`` to expire at ``expiration``.
- void Reset(typename Clock::time_point expiration)
- PW_LOCKS_EXCLUDED(internal::time_lock()) {
- std::lock_guard lock(internal::time_lock());
- UnlistLocked();
- expiration_ = expiration;
- EnlistLocked();
- }
-
// Returns the provider associated with this timer.
//
// NOTE: this method must not be called before initializing the timer.
@@ -200,8 +181,34 @@
}
private:
+ using Base =
+ experimental::Future<TimeFuture<Clock>, typename Clock::time_point>;
+ friend Base;
friend class TimeProvider<Clock>;
+ Poll<typename Clock::time_point> DoPend(Context& cx)
+ PW_LOCKS_EXCLUDED(internal::time_lock()) {
+ std::lock_guard lock(internal::time_lock());
+ if (this->unlisted()) {
+ return Ready(expiration_);
+ }
+ // NOTE: this is done under the lock in order to ensure that `provider_` is
+ // not set to unlisted between it being initially read and `waker_` being
+ // set.
+ PW_ASYNC_STORE_WAKER(cx, waker_, "TimeFuture is waiting for a time_point");
+ return Pending();
+ }
+
+ void DoMarkComplete() {
+ std::lock_guard lock(internal::time_lock());
+ provider_ = nullptr;
+ }
+
+ // SAFETY: It is safe to read `provider_` without holding the lock.
+ bool DoIsComplete() const PW_NO_LOCK_SAFETY_ANALYSIS {
+ return provider_ == nullptr;
+ }
+
/// Constructs a `Timer` from a `TimeProvider` and a `time_point`.
TimeFuture(TimeProvider<Clock>& provider,
typename Clock::time_point expiration)
diff --git a/pw_async2/simulated_time_provider_test.cc b/pw_async2/simulated_time_provider_test.cc
index 8c191df..f0fe7e0 100644
--- a/pw_async2/simulated_time_provider_test.cc
+++ b/pw_async2/simulated_time_provider_test.cc
@@ -120,20 +120,6 @@
EXPECT_FALSE(tp.TimeUntilNextExpiration().has_value());
}
-TEST(SimulatedTimeProvider, ResetSetsTimerBackToPendingAndFiresAgain) {
- SimulatedTimeProvider<SystemClock> tp;
- Dispatcher dispatcher;
-
- auto timer = tp.WaitFor(1h);
- EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsPending());
- tp.AdvanceTime(90min);
- EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsReady());
- timer.Reset(timer.expiration() + 40min);
- EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsPending());
- tp.AdvanceTime(90min);
- EXPECT_TRUE(dispatcher.RunPendableUntilStalled(timer).IsReady());
-}
-
TEST(SimulatedTimeProvider, TimerWithPastExpirationExpiresImmediately) {
SimulatedTimeProvider<SystemClock> tp;
auto start = tp.now();