fuchsia_sync/
completion.rs1use std::time::Duration;
8use zx::sys;
9
10unsafe extern "C" {
11 fn sync_completion_wait(
12 completion: *const sys::zx_futex_t,
13 timeout: sys::zx_duration_mono_t,
14 ) -> sys::zx_status_t;
15 fn sync_completion_wait_deadline(
16 completion: *const sys::zx_futex_t,
17 deadline: sys::zx_instant_mono_t,
18 ) -> sys::zx_status_t;
19 fn sync_completion_signal(completion: *const sys::zx_futex_t);
20 fn sync_completion_reset(completion: *const sys::zx_futex_t);
21 fn sync_completion_signaled(completion: *const sys::zx_futex_t) -> bool;
22}
23
24const SYNC_COMPLETION_INIT: i32 = 0;
25
26#[repr(transparent)]
33pub struct Completion(sys::zx_futex_t);
34
35unsafe impl Send for Completion {}
38
39unsafe impl Sync for Completion {}
42
43impl Completion {
44 pub const fn new() -> Self {
46 Self(sys::zx_futex_t::new(SYNC_COMPLETION_INIT))
47 }
48
49 #[inline]
50 fn as_futex_ptr(&self) -> *const sys::zx_futex_t {
51 std::ptr::addr_of!(self.0)
52 }
53
54 pub fn wait(&self) {
56 let signaled = self.wait_until(zx::MonotonicInstant::INFINITE);
57 assert!(signaled, "sync_completion_wait with infinite deadline failed");
58 }
59
60 pub fn wait_for(&self, timeout: Duration) -> bool {
63 let nanos = zx::MonotonicDuration::from(timeout).into_nanos();
64 let status = unsafe { sync_completion_wait(self.as_futex_ptr(), nanos) };
67 status == sys::ZX_OK
68 }
69
70 pub fn wait_until(&self, deadline: zx::MonotonicInstant) -> bool {
73 let status =
76 unsafe { sync_completion_wait_deadline(self.as_futex_ptr(), deadline.into_nanos()) };
77 status == sys::ZX_OK
78 }
79
80 pub fn signal(&self) {
82 unsafe {
85 sync_completion_signal(self.as_futex_ptr());
86 }
87 }
88
89 pub fn reset(&self) {
91 unsafe {
94 sync_completion_reset(self.as_futex_ptr());
95 }
96 }
97
98 pub fn is_signaled(&self) -> bool {
100 unsafe { sync_completion_signaled(self.as_futex_ptr()) }
103 }
104}
105
106impl Default for Completion {
107 fn default() -> Self {
108 Self::new()
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use std::sync::Arc;
116 use std::time::Duration;
117
118 #[test]
119 fn test_completion_signal_then_wait() {
120 let c = Completion::new();
121 assert!(!c.is_signaled());
122 c.signal();
123 assert!(c.is_signaled());
124 c.wait();
125 assert!(c.is_signaled());
126 }
127
128 #[test]
129 fn test_completion_wait_then_signal() {
130 let c = Arc::new(Completion::new());
131 let c_clone = c.clone();
132 let handle = std::thread::spawn(move || {
133 std::thread::sleep(Duration::from_millis(10));
134 c_clone.signal();
135 });
136 c.wait();
137 handle.join().unwrap();
138 assert!(c.is_signaled());
139 }
140
141 #[test]
142 fn test_completion_reset() {
143 let c = Completion::new();
144 c.signal();
145 assert!(c.is_signaled());
146 c.reset();
147 assert!(!c.is_signaled());
148 }
149
150 #[test]
151 fn test_completion_multiple_waiters() {
152 let c = Arc::new(Completion::new());
153 let mut handles = vec![];
154 for _ in 0..5 {
155 let c_clone = c.clone();
156 handles.push(std::thread::spawn(move || {
157 c_clone.wait();
158 }));
159 }
160 std::thread::sleep(Duration::from_millis(10));
161 c.signal();
162 for handle in handles {
163 handle.join().unwrap();
164 }
165 }
166
167 #[test]
168 fn test_completion_wait_for() {
169 let c = Completion::new();
170 assert!(!c.wait_for(Duration::from_millis(10)));
171
172 c.signal();
173 assert!(c.wait_for(Duration::from_millis(10)));
174 }
175
176 #[test]
177 fn test_completion_wait_for_signal() {
178 let c = Arc::new(Completion::new());
179 let c_clone = c.clone();
180 let handle = std::thread::spawn(move || {
181 std::thread::sleep(Duration::from_millis(10));
182 c_clone.signal();
183 });
184 assert!(c.wait_for(Duration::from_secs(5)));
185 handle.join().unwrap();
186 assert!(c.is_signaled());
187 }
188
189 #[test]
190 fn test_completion_wait_until() {
191 let c = Completion::new();
192 assert!(!c.wait_until(zx::MonotonicInstant::after(zx::MonotonicDuration::from_millis(10))));
193
194 c.signal();
195 assert!(c.wait_until(zx::MonotonicInstant::from_nanos(0)));
196 }
197
198 #[test]
199 fn test_completion_wait_until_signal() {
200 let c = Arc::new(Completion::new());
201 let c_clone = c.clone();
202 let handle = std::thread::spawn(move || {
203 std::thread::sleep(Duration::from_millis(10));
204 c_clone.signal();
205 });
206 assert!(c.wait_until(zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(5))));
207 handle.join().unwrap();
208 assert!(c.is_signaled());
209 }
210}