@@ -29,28 +29,43 @@ Future<bool> Delay(boost::asio::any_io_executor executor,
2929 Promise<bool > promise;
3030 auto future = promise.GetFuture ();
3131
32- // cancel() is dispatched through post() rather than called directly to
33- // satisfy ASIO's thread-safety requirement: steady_timer operations must
34- // not be called concurrently from multiple threads.
35- //
36- // The callback is registered after async_wait is in flight so that an
37- // already-cancelled token cancels the in-progress operation rather than
38- // firing before async_wait has been called.
39- //
40- // The CancellationCallback is captured by the async_wait handler so its
41- // lifetime matches the timer's; it is released (and deregistered) when
42- // the handler fires.
43- auto cb = std::make_shared<CancellationCallback>(
44- std::move (token), [timer, executor] {
45- boost::asio::post (executor, [timer] { timer->cancel (); });
46- });
47-
48- timer->async_wait ([p = std::move (promise), timer,
49- cb](boost::system::error_code code) mutable {
50- cb.reset ();
32+ // This code is tricky because there are a few constraints that conflict.
33+ // 1. We need to make sure timer->cancel isn't called _before_
34+ // timer->async_wait, or else it'll just be ignored.
35+ // 2. The cancellation_callback has to be created _before_
36+ // timer->async_wait, because it has to be captured by async_wait's
37+ // handler, because it is an RAII type, and once it is destroyed, it
38+ // deregisters itself. It has to stay alive as long as the timer needs to
39+ // be cancellable.
40+
41+ Promise<std::monostate> timer_started_promise;
42+ Future<std::monostate> timer_started_future =
43+ timer_started_promise.GetFuture ();
44+
45+ auto cancel_timer = [timer, executor,
46+ timer_started_future =
47+ std::move (timer_started_future)]() mutable {
48+ timer_started_future.Then (
49+ [timer](auto const &) -> std::monostate {
50+ timer->cancel ();
51+ return {};
52+ },
53+ [executor](Continuation<void ()> f) {
54+ boost::asio::post (executor, f);
55+ });
56+ };
57+
58+ auto cancellation_callback =
59+ std::make_shared<CancellationCallback>(std::move (token), cancel_timer);
60+
61+ timer->async_wait ([p = std::move (promise), timer, cancellation_callback](
62+ boost::system::error_code code) mutable {
63+ cancellation_callback.reset ();
5164 p.Resolve (code != boost::asio::error::operation_aborted);
5265 });
5366
67+ timer_started_promise.Resolve ({});
68+
5469 return future;
5570}
5671
0 commit comments