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}