Skip to main content

qubit_clock/sleep/
blocking_sleeper.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Defines a blocking adapter over the asynchronous Timer capability.
9
10use super::internal::ThreadWaker;
11use crate::{
12    MonotonicInstant,
13    TimeError,
14    Timer,
15    TimerFuture,
16};
17use std::sync::Arc;
18use std::task::{
19    Context,
20    Poll,
21    Waker,
22};
23use std::time::Duration;
24
25/// Adapts any [`Timer`] into synchronous blocking sleep operations.
26///
27/// This type owns no clock or scheduling policy of its own. It composes a
28/// shared timer and blocks only the calling thread while polling the timer's
29/// future. Clones share that same timer.
30///
31/// # Progress
32///
33/// The timer backend must still make progress after the calling thread parks.
34/// [`StdTimer`](crate::StdTimer) has its own worker. A
35/// [`ManualTimer`](crate::ManualTimer) requires another thread or controller to
36/// advance its clock. A `TokioTimer` requires its retained runtime to remain
37/// alive and be driven independently. Blocking the sole driver thread of a
38/// current-thread Tokio runtime while waiting on that same runtime's timer
39/// prevents the deadline from completing.
40#[derive(Clone)]
41pub struct BlockingSleeper {
42    /// Timer providing eager deadline registration and completion futures.
43    timer: Arc<dyn Timer>,
44}
45
46impl BlockingSleeper {
47    /// Creates a blocking adapter over a shared timer.
48    ///
49    /// # Parameters
50    ///
51    /// * `timer` - Timer used for every blocking deadline. Its backend must
52    ///   progress independently while the calling thread is parked.
53    ///
54    /// # Returns
55    ///
56    /// A cloneable blocking sleeper composing `timer`.
57    #[must_use]
58    pub const fn new(timer: Arc<dyn Timer>) -> Self {
59        Self { timer }
60    }
61
62    /// Returns the timer composed by this adapter.
63    ///
64    /// # Returns
65    ///
66    /// The timer used to register blocking sleeps.
67    #[must_use]
68    pub fn timer(&self) -> &dyn Timer {
69        self.timer.as_ref()
70    }
71
72    /// Blocks the current thread until an absolute deadline is reached.
73    ///
74    /// # Parameters
75    ///
76    /// * `deadline` - Deadline in the composed timer's clock domain.
77    ///
78    /// # Returns
79    ///
80    /// `Ok(())` after the deadline future completes.
81    ///
82    /// # Errors
83    ///
84    /// Returns any error produced while registering or completing the
85    /// deadline.
86    ///
87    /// # Panics
88    ///
89    /// Panics when the composed timer panics during registration or its
90    /// returned future panics while being polled.
91    ///
92    /// # Blocking
93    ///
94    /// Parks the calling thread while the composed timer is pending. The timer
95    /// backend must be driven independently during that interval.
96    pub fn sleep_until(
97        &self,
98        deadline: MonotonicInstant,
99    ) -> Result<(), TimeError> {
100        let future = self.timer.at(deadline)?;
101        Self::block_on(future)
102    }
103
104    /// Blocks the current thread for a relative duration.
105    ///
106    /// The timer fixes the absolute deadline before this method begins polling
107    /// and parking.
108    ///
109    /// # Parameters
110    ///
111    /// * `duration` - Duration measured by the composed timer's clock.
112    ///
113    /// # Returns
114    ///
115    /// `Ok(())` after the deadline future completes.
116    ///
117    /// # Errors
118    ///
119    /// Returns deadline overflow, registration failure, or a backend failure
120    /// reported while waiting.
121    ///
122    /// # Panics
123    ///
124    /// Panics when the composed timer panics during registration or its
125    /// returned future panics while being polled.
126    ///
127    /// # Blocking
128    ///
129    /// Parks the calling thread while the composed timer is pending. The timer
130    /// backend must be driven independently during that interval.
131    pub fn sleep_for(&self, duration: Duration) -> Result<(), TimeError> {
132        let future = self.timer.after(duration)?;
133        Self::block_on(future)
134    }
135
136    /// Polls one timer future, parking between incomplete polls.
137    ///
138    /// # Parameters
139    ///
140    /// * `future` - Eagerly registered timer future to drive to completion.
141    ///
142    /// # Returns
143    ///
144    /// The completion result produced by `future`.
145    ///
146    /// # Errors
147    ///
148    /// Returns the completion error reported by `future`.
149    ///
150    /// # Panics
151    ///
152    /// Panics when polling the timer future panics.
153    fn block_on(mut future: TimerFuture) -> Result<(), TimeError> {
154        let thread_waker = Arc::new(ThreadWaker::new(std::thread::current()));
155        let waker = Waker::from(Arc::clone(&thread_waker));
156        let mut context = Context::from_waker(&waker);
157        loop {
158            thread_waker.clear_notification();
159            if let Poll::Ready(result) = future.as_mut().poll(&mut context) {
160                return result;
161            }
162            while !thread_waker.take_notification() {
163                std::thread::park();
164            }
165        }
166    }
167}
168
169impl std::fmt::Debug for BlockingSleeper {
170    /// Formats this adapter without requiring the timer trait object to be
171    /// debug-formattable.
172    ///
173    /// # Parameters
174    ///
175    /// * `formatter` - Destination formatter.
176    ///
177    /// # Returns
178    ///
179    /// `Ok(())` when formatting succeeds.
180    ///
181    /// # Errors
182    ///
183    /// Returns [`std::fmt::Error`] when the destination rejects output.
184    #[inline]
185    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186        formatter
187            .debug_struct("BlockingSleeper")
188            .finish_non_exhaustive()
189    }
190}