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