1use smallvec::SmallVec;
6use std::sync::Arc;
7use std::sync::atomic::{AtomicU8, Ordering};
8
9#[derive(Debug)]
46pub struct ObjectWaiter {
47 event: zx::Event,
54
55 state: AtomicU8,
57}
58
59const IDLE: u8 = 0;
63
64const WAITING: u8 = 1;
69
70const INTERRUPTING: u8 = 2;
74
75const INTERRUPTED: u8 = 3;
79
80const INTERRUPTED_SIGNAL: zx::Signals = zx::Signals::EVENT_SIGNALED;
82
83const WAIT_ITEMS_COMMON_SIZE: usize = 4;
86
87#[must_use = "call wait_many to block until the objects are signaled or the wait is interrupted"]
91#[derive(Debug)]
92pub struct ObjectWaitGuard<'a> {
93 waiter: &'a Arc<ObjectWaiter>,
94}
95
96#[derive(Debug, PartialEq, Eq)]
98pub enum ObjectWaitError {
99 Interrupted,
101
102 DeadlineExpired,
104
105 Failed(zx::Status),
108}
109
110impl ObjectWaiter {
111 pub fn new() -> Arc<Self> {
112 Arc::new(Self { event: zx::Event::create(), state: AtomicU8::new(IDLE) })
113 }
114
115 pub fn begin_wait<'a>(self: &'a Arc<Self>) -> ObjectWaitGuard<'a> {
124 self.state
128 .compare_exchange(IDLE, WAITING, Ordering::AcqRel, Ordering::Relaxed)
129 .expect("Tried to begin waiting on an ObjectWaiter that is already waiting.");
130 ObjectWaitGuard { waiter: self }
131 }
132
133 pub fn interrupt(&self) {
139 if self
143 .state
144 .compare_exchange(WAITING, INTERRUPTING, Ordering::Acquire, Ordering::Relaxed)
145 .is_ok()
146 {
147 let _ = self.event.signal(zx::Signals::NONE, INTERRUPTED_SIGNAL);
149 self.state.store(INTERRUPTED, Ordering::Release);
152 }
153 }
154
155 fn end_wait(&self) -> bool {
160 loop {
161 match self.state.compare_exchange(WAITING, IDLE, Ordering::Release, Ordering::Acquire) {
162 Ok(_) => return false,
164 Err(INTERRUPTING) => std::thread::yield_now(),
168 Err(INTERRUPTED) => {
169 let _ = self.event.signal(INTERRUPTED_SIGNAL, zx::Signals::NONE);
171 self.state.store(IDLE, Ordering::Release);
172 return true;
173 }
174 Err(state) => unreachable!("Unexpected ObjectWaiter state: {state}"),
175 }
176 }
177 }
178}
179
180impl<'a> ObjectWaitGuard<'a> {
181 pub fn waiter(&self) -> &'a Arc<ObjectWaiter> {
183 self.waiter
184 }
185
186 pub fn wait_many<const N: usize>(
201 self,
202 items: [zx::WaitItem<'_>; N],
203 deadline: zx::MonotonicInstant,
204 ) -> Result<[zx::Signals; N], ObjectWaitError> {
205 self.wait_many_with_clean_delay(items, deadline, crate::STACK_CLEAN_DELAY)
206 }
207
208 fn wait_many_with_clean_delay<const N: usize>(
209 self,
210 items: [zx::WaitItem<'_>; N],
211 deadline: zx::MonotonicInstant,
212 clean_delay: zx::MonotonicDuration,
213 ) -> Result<[zx::Signals; N], ObjectWaitError> {
214 const { assert!(N < zx::sys::ZX_WAIT_MANY_MAX_ITEMS, "Too many items to wait for") };
215
216 let waiter = self.waiter;
220 let mut all_items: SmallVec<[zx::WaitItem<'_>; WAIT_ITEMS_COMMON_SIZE]> =
221 SmallVec::with_capacity(N + 1);
222 all_items.extend(items);
223 all_items.push(waiter.event.wait_item(INTERRUPTED_SIGNAL));
224
225 let mut clean_deadline = crate::initial_clean_deadline(deadline, clean_delay);
227 let result = loop {
228 match zx::object_wait_many(&mut all_items, clean_deadline) {
229 Err(zx::Status::TIMED_OUT) if clean_deadline < deadline => {
230 starnix_stack::clean_stack();
231 clean_deadline = deadline;
232 }
233 result => break result,
234 }
235 };
236
237 if self.end() {
241 return Err(ObjectWaitError::Interrupted);
242 }
243 match result {
244 Ok(_) => Ok(std::array::from_fn(|i| all_items[i].pending())),
247 Err(zx::Status::TIMED_OUT) => Err(ObjectWaitError::DeadlineExpired),
248 Err(status) => Err(ObjectWaitError::Failed(status)),
249 }
250 }
251
252 fn end(self) -> bool {
254 let waiter = self.waiter;
255 std::mem::forget(self);
256 waiter.end_wait()
257 }
258}
259
260impl Drop for ObjectWaitGuard<'_> {
261 fn drop(&mut self) {
262 self.waiter.end_wait();
263 }
264}
265
266#[cfg(test)]
267mod test {
268 use super::*;
269 use std::sync::atomic::AtomicBool;
270
271 fn signal(event: &zx::Event) {
272 event.signal(zx::Signals::NONE, zx::Signals::USER_0).expect("failed to signal event");
273 }
274
275 fn wait_for(
278 guard: ObjectWaitGuard<'_>,
279 event: &zx::Event,
280 deadline: zx::MonotonicInstant,
281 ) -> Result<[zx::Signals; 1], ObjectWaitError> {
282 guard.wait_many([event.wait_item(zx::Signals::USER_0)], deadline)
283 }
284
285 fn spawn_when_blocked(f: impl FnOnce() + Send + 'static) -> std::thread::JoinHandle<()> {
287 let waiting_thread = fuchsia_runtime::with_thread_self(|thread| {
288 thread.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle")
289 });
290 std::thread::spawn(move || {
291 while waiting_thread.info().expect("info").state
292 != zx::ThreadState::Blocked(zx::ThreadBlockType::WaitMany)
293 {
294 std::thread::sleep(std::time::Duration::from_millis(1));
295 }
296 f();
297 })
298 }
299
300 fn is_event_signaled(waiter: &ObjectWaiter) -> bool {
302 waiter.event.wait_one(INTERRUPTED_SIGNAL, zx::MonotonicInstant::INFINITE_PAST).is_ok()
303 }
304
305 #[test]
306 fn test_wait_block_and_signal() {
307 let waiter = ObjectWaiter::new();
308 let event = zx::Event::create();
309 let other_event = event.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
310 let thread = spawn_when_blocked(move || signal(&other_event));
311
312 let result = wait_for(waiter.begin_wait(), &event, zx::MonotonicInstant::INFINITE);
313 assert_eq!(result, Ok([zx::Signals::USER_0]));
314 thread.join().expect("failed to join thread");
315 }
316
317 #[test]
318 fn test_wait_block_and_interrupt() {
319 let waiter = ObjectWaiter::new();
320 let event = zx::Event::create();
321 let other_waiter = Arc::clone(&waiter);
322 let thread = spawn_when_blocked(move || other_waiter.interrupt());
323
324 let result = wait_for(waiter.begin_wait(), &event, zx::MonotonicInstant::INFINITE);
325 assert_eq!(result, Err(ObjectWaitError::Interrupted));
326 thread.join().expect("failed to join thread");
327 assert!(!is_event_signaled(&waiter));
329 }
330
331 #[test]
332 fn test_wait_block_and_timeout() {
333 let waiter = ObjectWaiter::new();
334 let event = zx::Event::create();
335 let deadline = zx::MonotonicInstant::after(zx::MonotonicDuration::from_millis(20));
336
337 let result = wait_for(waiter.begin_wait(), &event, deadline);
338 assert_eq!(result, Err(ObjectWaitError::DeadlineExpired));
339 assert!(zx::MonotonicInstant::get() >= deadline);
340 }
341
342 #[test]
343 fn test_poll_with_past_deadline() {
344 let waiter = ObjectWaiter::new();
345 let event = zx::Event::create();
346 let deadline = zx::MonotonicInstant::INFINITE_PAST;
347
348 let result = wait_for(waiter.begin_wait(), &event, deadline);
349 assert_eq!(result, Err(ObjectWaitError::DeadlineExpired));
350 signal(&event);
351 assert_eq!(wait_for(waiter.begin_wait(), &event, deadline), Ok([zx::Signals::USER_0]));
352 }
353
354 #[test]
355 fn test_wait_returns_pending_signals_in_order() {
356 let waiter = ObjectWaiter::new();
357 let event = zx::Event::create();
358 let (channel, peer) = zx::Channel::create();
359 std::mem::drop(peer);
360
361 let result = waiter.begin_wait().wait_many(
362 [
363 event.wait_item(zx::Signals::USER_0),
364 channel.wait_item(zx::Signals::CHANNEL_PEER_CLOSED),
365 ],
366 zx::MonotonicInstant::INFINITE,
367 );
368 let [event_signals, channel_signals] = result.expect("failed to wait");
369 assert_eq!(event_signals, zx::Signals::NONE);
370 assert!(channel_signals.contains(zx::Signals::CHANNEL_PEER_CLOSED));
371 }
372
373 #[test]
374 fn test_wait_without_items() {
375 let waiter = ObjectWaiter::new();
376
377 let result = waiter.begin_wait().wait_many([], zx::MonotonicInstant::INFINITE_PAST);
378 assert_eq!(result, Err(ObjectWaitError::DeadlineExpired));
379 let guard = waiter.begin_wait();
380 waiter.interrupt();
381 let result = guard.wait_many([], zx::MonotonicInstant::INFINITE);
382 assert_eq!(result, Err(ObjectWaitError::Interrupted));
383 }
384
385 #[test]
386 fn test_wait_fails_without_wait_right() {
387 let waiter = ObjectWaiter::new();
388 let event = zx::Event::create().duplicate_handle(zx::Rights::TRANSFER).unwrap();
389
390 let result = wait_for(waiter.begin_wait(), &event, zx::MonotonicInstant::INFINITE);
391 assert_eq!(result, Err(ObjectWaitError::Failed(zx::Status::ACCESS_DENIED)));
392 }
393
394 #[test]
395 fn test_interrupt_outside_wait_is_ignored() {
396 let waiter = ObjectWaiter::new();
397 let event = zx::Event::create();
398
399 for _ in 0..2 {
402 waiter.interrupt();
403 assert!(!is_event_signaled(&waiter));
404 let result = wait_for(waiter.begin_wait(), &event, zx::MonotonicInstant::INFINITE_PAST);
405 assert_eq!(result, Err(ObjectWaitError::DeadlineExpired));
406 }
407 }
408
409 #[test]
410 fn test_interrupt_before_block_ends_wait() {
411 let waiter = ObjectWaiter::new();
412 let event = zx::Event::create();
413
414 let guard = waiter.begin_wait();
416 waiter.interrupt();
417 let result = wait_for(guard, &event, zx::MonotonicInstant::INFINITE);
418 assert_eq!(result, Err(ObjectWaitError::Interrupted));
419
420 signal(&event);
422 let guard = waiter.begin_wait();
423 waiter.interrupt();
424 let result = wait_for(guard, &event, zx::MonotonicInstant::INFINITE);
425 assert_eq!(result, Err(ObjectWaitError::Interrupted));
426
427 let result = wait_for(waiter.begin_wait(), &event, zx::MonotonicInstant::INFINITE);
429 assert_eq!(result, Ok([zx::Signals::USER_0]));
430 }
431
432 #[test]
433 fn test_interrupt_signals_event_once() {
434 let waiter = ObjectWaiter::new();
435
436 let guard = waiter.begin_wait();
437 assert!(!is_event_signaled(&waiter));
438 waiter.interrupt();
439 assert!(is_event_signaled(&waiter));
440 waiter.interrupt();
442 assert!(is_event_signaled(&waiter));
443
444 std::mem::drop(guard);
446 assert!(!is_event_signaled(&waiter));
447 std::mem::drop(waiter.begin_wait());
448 }
449
450 #[test]
451 fn test_interrupt_in_progress_ends_wait() {
452 let waiter = ObjectWaiter::new();
453 let event = zx::Event::create();
454 signal(&event);
455
456 let guard = waiter.begin_wait();
460 waiter.state.store(INTERRUPTING, Ordering::Relaxed);
461 let other_waiter = Arc::clone(&waiter);
462 let thread = std::thread::spawn(move || {
463 std::thread::sleep(std::time::Duration::from_millis(10));
464 other_waiter.event.signal(zx::Signals::NONE, INTERRUPTED_SIGNAL).expect("signal");
466 other_waiter.state.store(INTERRUPTED, Ordering::Release);
467 });
468
469 let result = wait_for(guard, &event, zx::MonotonicInstant::INFINITE);
471 assert_eq!(result, Err(ObjectWaitError::Interrupted));
472 thread.join().expect("failed to join thread");
473 assert!(!is_event_signaled(&waiter));
474 }
475
476 #[test]
477 fn test_interrupt_races_with_end_of_wait() {
478 let waiter = ObjectWaiter::new();
479 let event = zx::Event::create();
480 signal(&event);
481 let done = Arc::new(AtomicBool::new(false));
482 let interrupter = std::thread::spawn({
483 let (waiter, done) = (Arc::clone(&waiter), Arc::clone(&done));
484 move || {
485 while !done.load(Ordering::Relaxed) {
486 waiter.interrupt();
487 }
488 }
489 });
490
491 for _ in 0..1000 {
494 let result = wait_for(waiter.begin_wait(), &event, zx::MonotonicInstant::INFINITE);
495 assert!(
496 result == Ok([zx::Signals::USER_0]) || result == Err(ObjectWaitError::Interrupted),
497 "Unexpected result: {result:?}"
498 );
499 assert!(!is_event_signaled(&waiter));
500 }
501 done.store(true, Ordering::Relaxed);
502 interrupter.join().expect("failed to join thread");
503 }
504
505 #[test]
506 #[should_panic(expected = "Tried to begin waiting on an ObjectWaiter that is already waiting.")]
507 fn test_concurrent_begin_wait_panics() {
508 let waiter = ObjectWaiter::new();
509 let _guard = waiter.begin_wait();
510 let _ = waiter.begin_wait();
511 }
512
513 #[test]
514 fn test_wait_clean_stack() {
515 let waiter = ObjectWaiter::new();
516 let event = zx::Event::create();
517 let wait = |guard: ObjectWaitGuard<'_>, deadline| {
518 guard.wait_many_with_clean_delay(
519 [event.wait_item(zx::Signals::USER_0)],
520 deadline,
521 zx::MonotonicDuration::from_millis(10),
522 )
523 };
524
525 let deadline = zx::MonotonicInstant::after(zx::MonotonicDuration::from_millis(30));
527 assert_eq!(wait(waiter.begin_wait(), deadline), Err(ObjectWaitError::DeadlineExpired));
528 assert!(zx::MonotonicInstant::get() >= deadline);
529
530 let guard = waiter.begin_wait();
532 let other_waiter = Arc::clone(&waiter);
533 let thread = std::thread::spawn(move || {
534 std::thread::sleep(std::time::Duration::from_millis(30));
535 other_waiter.interrupt();
536 });
537 let result = wait(guard, zx::MonotonicInstant::INFINITE);
538 assert_eq!(result, Err(ObjectWaitError::Interrupted));
539 thread.join().expect("failed to join thread");
540
541 let other_event = event.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
543 let thread = std::thread::spawn(move || {
544 std::thread::sleep(std::time::Duration::from_millis(30));
545 signal(&other_event);
546 });
547 let result = wait(waiter.begin_wait(), zx::MonotonicInstant::INFINITE);
548 assert_eq!(result, Ok([zx::Signals::USER_0]));
549 thread.join().expect("failed to join thread");
550 }
551}