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 #[inline(always)]
59 pub const fn new(timer: Arc<dyn Timer>) -> Self {
60 Self { timer }
61 }
62
63 /// Returns the timer composed by this adapter.
64 ///
65 /// # Returns
66 ///
67 /// The timer used to register blocking sleeps.
68 #[must_use]
69 #[inline(always)]
70 pub fn timer(&self) -> &dyn Timer {
71 self.timer.as_ref()
72 }
73
74 /// Blocks the current thread until an absolute deadline is reached.
75 ///
76 /// # Parameters
77 ///
78 /// * `deadline` - Deadline in the composed timer's clock domain.
79 ///
80 /// # Returns
81 ///
82 /// `Ok(())` after the deadline future completes.
83 ///
84 /// # Errors
85 ///
86 /// Returns any error produced while registering or completing the
87 /// deadline.
88 ///
89 /// # Panics
90 ///
91 /// Panics when the composed timer panics during registration or its
92 /// returned future panics while being polled.
93 ///
94 /// # Blocking
95 ///
96 /// Parks the calling thread while the composed timer is pending. The timer
97 /// backend must be driven independently during that interval.
98 #[inline(always)]
99 pub fn sleep_until(
100 &self,
101 deadline: MonotonicInstant,
102 ) -> Result<(), TimeError> {
103 let future = self.timer.at(deadline)?;
104 Self::block_on(future)
105 }
106
107 /// Blocks the current thread for a relative duration.
108 ///
109 /// The timer fixes the absolute deadline before this method begins polling
110 /// and parking.
111 ///
112 /// # Parameters
113 ///
114 /// * `duration` - Duration measured by the composed timer's clock.
115 ///
116 /// # Returns
117 ///
118 /// `Ok(())` after the deadline future completes.
119 ///
120 /// # Errors
121 ///
122 /// Returns deadline overflow, registration failure, or a backend failure
123 /// reported while waiting.
124 ///
125 /// # Panics
126 ///
127 /// Panics when the composed timer panics during registration or its
128 /// returned future panics while being polled.
129 ///
130 /// # Blocking
131 ///
132 /// Parks the calling thread while the composed timer is pending. The timer
133 /// backend must be driven independently during that interval.
134 #[inline(always)]
135 pub fn sleep_for(&self, duration: Duration) -> Result<(), TimeError> {
136 let future = self.timer.after(duration)?;
137 Self::block_on(future)
138 }
139
140 /// Polls one timer future, parking between incomplete polls.
141 ///
142 /// # Parameters
143 ///
144 /// * `future` - Eagerly registered timer future to drive to completion.
145 ///
146 /// # Returns
147 ///
148 /// The completion result produced by `future`.
149 ///
150 /// # Errors
151 ///
152 /// Returns the completion error reported by `future`.
153 ///
154 /// # Panics
155 ///
156 /// Panics when polling the timer future panics.
157 fn block_on(mut future: TimerFuture) -> Result<(), TimeError> {
158 let thread_waker = Arc::new(ThreadWaker::new(std::thread::current()));
159 let waker = Waker::from(Arc::clone(&thread_waker));
160 let mut context = Context::from_waker(&waker);
161 loop {
162 thread_waker.clear_notification();
163 if let Poll::Ready(result) = future.as_mut().poll(&mut context) {
164 return result;
165 }
166 while !thread_waker.take_notification() {
167 std::thread::park();
168 }
169 }
170 }
171}
172
173impl std::fmt::Debug for BlockingSleeper {
174 /// Formats this adapter without requiring the timer trait object to be
175 /// debug-formattable.
176 ///
177 /// # Parameters
178 ///
179 /// * `formatter` - Destination formatter.
180 ///
181 /// # Returns
182 ///
183 /// `Ok(())` when formatting succeeds.
184 ///
185 /// # Errors
186 ///
187 /// Returns [`std::fmt::Error`] when the destination rejects output.
188 #[inline]
189 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 formatter
191 .debug_struct("BlockingSleeper")
192 .finish_non_exhaustive()
193 }
194}