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}