1use crate::{InterruptibleEventRequeueOwnerLock, LockDepMutex};
6use std::sync::Arc;
7use std::sync::atomic::Ordering;
8
9#[derive(Debug)]
55pub struct InterruptibleEvent {
56 futex: zx::Futex,
57 requeue_target: zx::Futex,
58 requeue_owner: LockDepMutex<Option<Arc<zx::Thread>>, InterruptibleEventRequeueOwnerLock>,
75}
76
77const READY: i32 = 0;
82
83const WAITING: i32 = 1;
91
92const NOTIFIED: i32 = 2;
96
97const INTERRUPTED: i32 = 3;
101
102const REQUEUED: i32 = 4;
106
107const WAITING_REQUEUEABLE: i32 = 5;
117
118#[must_use = "call block_until to advance the event state machine"]
123#[derive(Debug)]
124pub struct EventWaitGuard<'a> {
125 event: &'a InterruptibleEvent,
126}
127
128impl Drop for EventWaitGuard<'_> {
129 fn drop(&mut self) {
130 self.event.reset();
131 }
132}
133
134impl<'a> EventWaitGuard<'a> {
135 pub fn event(&self) -> &'a InterruptibleEvent {
137 self.event
138 }
139
140 pub fn get_owner(&self) -> Option<zx::Koid> {
142 self.event.get_owner()
143 }
144
145 pub fn block_until(
148 self,
149 new_owner: Option<&zx::Thread>,
150 deadline: zx::MonotonicInstant,
151 ) -> Result<(), WakeReason> {
152 self.event.block_until_with_clean_delay(new_owner, deadline, crate::STACK_CLEAN_DELAY)
153 }
154
155 #[cfg(test)]
156 fn block_until_with_clean_delay(
157 self,
158 new_owner: Option<&zx::Thread>,
159 deadline: zx::MonotonicInstant,
160 clean_delay: zx::MonotonicDuration,
161 ) -> Result<(), WakeReason> {
162 self.event.block_until_with_clean_delay(new_owner, deadline, clean_delay)
163 }
164}
165
166#[derive(Debug, PartialEq, Eq)]
168pub enum WakeReason {
169 Interrupted,
171
172 DeadlineExpired,
174}
175
176impl Default for InterruptibleEvent {
177 fn default() -> Self {
178 InterruptibleEvent {
179 futex: zx::Futex::new(READY),
180 requeue_target: zx::Futex::new(READY),
181 requeue_owner: LockDepMutex::new(None),
182 }
183 }
184}
185
186struct LoadedState<'a> {
187 futex: &'a zx::Futex,
188 state: i32,
189 is_requeued: bool,
190}
191
192impl InterruptibleEvent {
193 pub fn new() -> Arc<Self> {
194 Arc::new(Self::default())
195 }
196
197 fn load_state(&self) -> LoadedState<'_> {
200 let state = self.futex.load(Ordering::Acquire);
201 if state == REQUEUED {
202 LoadedState {
203 futex: &self.requeue_target,
204 state: self.requeue_target.load(Ordering::Acquire),
205 is_requeued: true,
206 }
207 } else {
208 LoadedState { futex: &self.futex, state, is_requeued: false }
209 }
210 }
211
212 pub fn get_owner(&self) -> Option<zx::Koid> {
214 self.load_state().futex.get_owner()
215 }
216
217 pub fn begin_wait(&self) -> EventWaitGuard<'_> {
243 self.begin_wait_with_state(WAITING)
244 }
245
246 pub fn begin_wait_requeueable(&self) -> EventWaitGuard<'_> {
258 self.begin_wait_with_state(WAITING_REQUEUEABLE)
259 }
260
261 fn begin_wait_with_state(&self, initial_state: i32) -> EventWaitGuard<'_> {
262 self.requeue_target.store(READY, Ordering::Relaxed);
263 self.futex
264 .compare_exchange(READY, initial_state, Ordering::AcqRel, Ordering::Relaxed)
265 .expect("Tried to begin waiting on an event when not ready.");
266 EventWaitGuard { event: self }
267 }
268
269 pub fn assign_new_owner(&self, new_owner: &Arc<zx::Thread>) -> Result<(), zx::Status> {
295 if self.futex.load(Ordering::Relaxed) != WAITING_REQUEUEABLE {
296 return Err(zx::Status::BAD_STATE);
297 }
298 let mut requeue_owner = self.requeue_owner.lock();
304 if self
305 .futex
306 .compare_exchange(WAITING_REQUEUEABLE, REQUEUED, Ordering::AcqRel, Ordering::Relaxed)
307 .is_ok()
308 {
309 *requeue_owner = Some(Arc::clone(new_owner));
310 let res =
311 self.futex.requeue(0, REQUEUED, &self.requeue_target, u32::MAX, Some(new_owner));
312 self.requeue_target.store(WAITING, Ordering::Release);
316 res
317 } else {
318 Err(zx::Status::BAD_STATE)
319 }
320 }
321
322 pub fn is_waiting(&self) -> bool {
325 let LoadedState { state, is_requeued, .. } = self.load_state();
326 matches!(state, WAITING | WAITING_REQUEUEABLE) || (state == READY && is_requeued)
330 }
331
332 fn reset(&self) {
333 let observed = self.futex.load(Ordering::Relaxed);
343 if matches!(observed, WAITING_REQUEUEABLE | REQUEUED) {
344 if self.futex.swap(NOTIFIED, Ordering::AcqRel) == REQUEUED {
345 *self.requeue_owner.lock() = None;
346 }
347 self.requeue_target.store(READY, Ordering::Relaxed);
348 }
349 self.futex.store(READY, Ordering::Release);
352 }
353
354 fn block_until_with_clean_delay(
355 &self,
356 new_owner: Option<&zx::Thread>,
357 deadline: zx::MonotonicInstant,
358 clean_delay: zx::MonotonicDuration,
359 ) -> Result<(), WakeReason> {
360 let mut clean_deadline = crate::initial_clean_deadline(deadline, clean_delay);
363 loop {
364 let LoadedState { futex: target_futex, state, is_requeued } = self.load_state();
365 let expected_state = match state {
366 WAITING | WAITING_REQUEUEABLE => state,
367 READY if is_requeued => WAITING,
371 NOTIFIED => return Ok(()),
372 INTERRUPTED => return Err(WakeReason::Interrupted),
373 other => panic!("Unexpected event state: {other}"),
374 };
375
376 let requeued_owner = if is_requeued { self.requeue_owner.lock().clone() } else { None };
377 let effective_owner = if is_requeued { requeued_owner.as_deref() } else { new_owner };
378
379 match target_futex.wait(expected_state, effective_owner, clean_deadline) {
380 Err(zx::Status::TIMED_OUT) => {
382 if clean_deadline < deadline {
383 starnix_stack::clean_stack();
384 clean_deadline = deadline;
385 } else {
386 return Err(WakeReason::DeadlineExpired);
387 }
388 }
389 Err(zx::Status::BAD_STATE) | Ok(()) => {}
392 Err(e) => panic!("Unexpected error from zx_futex_wait: {e}"),
393 }
394 }
395 }
396
397 pub fn notify(&self) {
405 self.wake(NOTIFIED);
406 }
407
408 pub fn interrupt(&self) {
417 self.wake(INTERRUPTED);
418 }
419
420 fn wake(&self, state: i32) {
421 loop {
429 let LoadedState { futex, state: current_state, is_requeued } = self.load_state();
430 match current_state {
431 NOTIFIED | INTERRUPTED => return,
432 READY if !is_requeued => return,
433 READY => std::thread::yield_now(),
434 WAITING | WAITING_REQUEUEABLE => {
435 if futex
436 .compare_exchange(
437 current_state,
438 state,
439 Ordering::Release,
440 Ordering::Acquire,
441 )
442 .is_ok()
443 {
444 futex.wake_all();
445 return;
446 }
447 }
448 other => panic!("Unexpected event state: {other}"),
449 }
450 }
451 }
452}
453
454#[cfg(test)]
455mod test {
456 use super::*;
457 use std::sync::atomic::AtomicBool;
458
459 #[test]
460 fn test_wait_block_and_notify() {
461 let event = InterruptibleEvent::new();
462
463 let guard = event.begin_wait();
464
465 let other_event = Arc::clone(&event);
466 let thread = std::thread::spawn(move || {
467 other_event.notify();
468 });
469
470 guard.block_until(None, zx::MonotonicInstant::INFINITE).expect("failed to be notified");
471 thread.join().expect("failed to join thread");
472 }
473
474 #[test]
475 fn test_wait_block_and_interrupt() {
476 let event = InterruptibleEvent::new();
477
478 let guard = event.begin_wait();
479
480 let other_event = Arc::clone(&event);
481 let thread = std::thread::spawn(move || {
482 other_event.interrupt();
483 });
484
485 let result = guard.block_until(None, zx::MonotonicInstant::INFINITE);
486 assert_eq!(result, Err(WakeReason::Interrupted));
487 thread.join().expect("failed to join thread");
488 }
489
490 #[test]
491 fn test_wait_block_and_timeout() {
492 let event = InterruptibleEvent::new();
493
494 let guard = event.begin_wait();
495 let result = guard
496 .block_until(None, zx::MonotonicInstant::after(zx::MonotonicDuration::from_millis(20)));
497 assert_eq!(result, Err(WakeReason::DeadlineExpired));
498 }
499
500 #[test]
501 fn futex_ownership_is_transferred() {
502 let event = Arc::new(InterruptibleEvent::new());
503
504 let (root_thread_handle, root_thread_koid) = fuchsia_runtime::with_thread_self(|thread| {
505 (thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(), thread.koid().unwrap())
506 });
507
508 let event_for_blocked_thread = event.clone();
509
510 let blocked_thread = std::thread::spawn(move || {
511 let event = event_for_blocked_thread;
512 let guard = event.begin_wait();
513 guard.block_until(Some(&root_thread_handle), zx::MonotonicInstant::INFINITE).unwrap();
514 });
515
516 while event.get_owner() != Some(root_thread_koid) {
519 std::thread::sleep(std::time::Duration::from_millis(100));
520 }
521
522 event.notify();
523 blocked_thread.join().unwrap();
524 }
525
526 #[test]
527 fn stale_pi_owner_is_noop() {
528 let mut new_owner = None;
529 std::thread::scope(|s| {
530 s.spawn(|| {
531 new_owner = Some(
532 fuchsia_runtime::with_thread_self(|thread| {
533 thread.duplicate_handle(zx::Rights::SAME_RIGHTS)
534 })
535 .unwrap(),
536 );
537 });
538 });
539 let new_owner = new_owner.unwrap();
540
541 let event = InterruptibleEvent::new();
542 let guard = event.begin_wait();
543 let result = guard.block_until(
544 Some(&new_owner),
545 zx::MonotonicInstant::after(zx::MonotonicDuration::from_millis(20)),
546 );
547 assert_eq!(result, Err(WakeReason::DeadlineExpired));
548 }
549
550 #[test]
551 fn futex_ownership_is_transferred_via_requeue() {
552 let event = Arc::new(InterruptibleEvent::new());
553
554 let (root_thread_handle, root_thread_koid) = fuchsia_runtime::with_thread_self(|thread| {
555 (
556 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
557 thread.koid().unwrap(),
558 )
559 });
560
561 let event_for_blocked_thread = event.clone();
562
563 let (tx, rx) = std::sync::mpsc::channel();
564 let blocked_thread = std::thread::spawn(move || {
565 let (thread_handle, _) = fuchsia_runtime::with_thread_self(|thread| {
566 (thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(), thread.koid().unwrap())
567 });
568 tx.send(thread_handle).unwrap();
569 let event = event_for_blocked_thread;
570 let guard = event.begin_wait_requeueable();
571 guard.block_until(None, zx::MonotonicInstant::INFINITE).unwrap();
572 });
573
574 let blocked_thread_handle = rx.recv().unwrap();
576 while blocked_thread_handle.info().unwrap().state
577 != zx::ThreadState::Blocked(zx::ThreadBlockType::Futex)
578 {
579 std::thread::sleep(std::time::Duration::from_millis(10));
580 }
581
582 event.assign_new_owner(&root_thread_handle).unwrap();
584
585 while event.get_owner() != Some(root_thread_koid) {
587 std::thread::sleep(std::time::Duration::from_millis(50));
588 }
589
590 event.notify();
591 blocked_thread.join().unwrap();
592 }
593
594 #[test]
595 fn concurrent_wait_wake_assign_new_owner_stress_test() {
596 let root_thread_handle = fuchsia_runtime::with_thread_self(|thread| {
597 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
598 });
599
600 for _ in 0..200 {
601 let event = Arc::new(InterruptibleEvent::new());
602 let barrier = Arc::new(std::sync::Barrier::new(2));
603
604 let event_waiter = event.clone();
605 let event_assign = event.clone();
606 let event_waker = event.clone();
607 let barrier_assign = barrier.clone();
608 let barrier_waker = barrier.clone();
609 let thread_handle = Arc::clone(&root_thread_handle);
610
611 let waiter = std::thread::spawn(move || {
612 let guard = event_waiter.begin_wait_requeueable();
613 let _ = guard.block_until(None, zx::MonotonicInstant::INFINITE);
614 });
615
616 while event.futex.load(Ordering::Relaxed) != WAITING_REQUEUEABLE {
617 std::thread::yield_now();
618 }
619
620 let assigner = std::thread::spawn(move || {
621 barrier_assign.wait();
622 let _ = event_assign.assign_new_owner(&thread_handle);
623 });
624
625 let waker = std::thread::spawn(move || {
626 barrier_waker.wait();
627 event_waker.notify();
628 });
629
630 assigner.join().unwrap();
631 waker.join().unwrap();
632 waiter.join().unwrap();
633 }
634 }
635
636 #[test]
637 fn futex_ownership_is_transferred_when_requeued_before_block() {
638 let event = InterruptibleEvent::new();
639
640 let (root_thread_handle, root_thread_koid) = fuchsia_runtime::with_thread_self(|thread| {
641 (
642 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
643 thread.koid().unwrap(),
644 )
645 });
646
647 let event_for_blocked_thread = Arc::clone(&event);
648 let (ready_tx, ready_rx) = std::sync::mpsc::channel();
649 let (go_tx, go_rx) = std::sync::mpsc::channel();
650 let blocked_thread = std::thread::spawn(move || {
651 let guard = event_for_blocked_thread.begin_wait_requeueable();
652 ready_tx.send(()).unwrap();
653 go_rx.recv().unwrap();
654 guard.block_until(None, zx::MonotonicInstant::INFINITE).unwrap();
655 });
656
657 ready_rx.recv().unwrap();
659 event.assign_new_owner(&root_thread_handle).unwrap();
660 go_tx.send(()).unwrap();
661
662 while event.get_owner() != Some(root_thread_koid) {
663 std::thread::sleep(std::time::Duration::from_millis(5));
664 }
665
666 event.notify();
667 blocked_thread.join().unwrap();
668 }
669
670 #[test]
671 fn test_wait_clean_stack_then_notify() {
672 let event = InterruptibleEvent::new();
673 let guard = event.begin_wait();
674
675 let other_event = Arc::clone(&event);
676 let thread = std::thread::spawn(move || {
677 std::thread::sleep(std::time::Duration::from_millis(30));
678 other_event.notify();
679 });
680
681 guard
682 .block_until_with_clean_delay(
683 None,
684 zx::MonotonicInstant::INFINITE,
685 zx::MonotonicDuration::from_millis(10),
686 )
687 .expect("failed to be notified after clean_stack");
688 thread.join().expect("failed to join thread");
689 }
690
691 #[test]
692 fn test_wait_clean_stack_then_timeout() {
693 let event = InterruptibleEvent::new();
694 let guard = event.begin_wait();
695 let deadline = zx::MonotonicInstant::after(zx::MonotonicDuration::from_millis(30));
696
697 let result = guard.block_until_with_clean_delay(
698 None,
699 deadline,
700 zx::MonotonicDuration::from_millis(10),
701 );
702 assert_eq!(result, Err(WakeReason::DeadlineExpired));
703 assert!(zx::MonotonicInstant::get() >= deadline);
704 }
705
706 #[test]
707 fn futex_requeue_owner_is_preserved_across_clean_stack() {
708 let event = InterruptibleEvent::new();
709
710 let (root_thread_handle, root_thread_koid) = fuchsia_runtime::with_thread_self(|thread| {
711 (
712 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
713 thread.koid().unwrap(),
714 )
715 });
716
717 let event_for_blocked_thread = Arc::clone(&event);
718 let (ready_tx, ready_rx) = std::sync::mpsc::channel();
719 let (go_tx, go_rx) = std::sync::mpsc::channel();
720 let blocked_thread = std::thread::spawn(move || {
721 let thread_handle = fuchsia_runtime::with_thread_self(|thread| {
722 thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()
723 });
724 let guard = event_for_blocked_thread.begin_wait_requeueable();
725 ready_tx.send(thread_handle).unwrap();
726 go_rx.recv().unwrap();
727 guard
728 .block_until_with_clean_delay(
729 None,
730 zx::MonotonicInstant::INFINITE,
731 zx::MonotonicDuration::from_millis(25),
732 )
733 .unwrap();
734 });
735
736 let blocked_thread_handle = ready_rx.recv().unwrap();
740 event.assign_new_owner(&root_thread_handle).unwrap();
741 go_tx.send(()).unwrap();
742
743 while event.get_owner() != Some(root_thread_koid) {
744 std::thread::sleep(std::time::Duration::from_millis(5));
745 }
746
747 std::thread::sleep(std::time::Duration::from_millis(50));
750 while blocked_thread_handle.info().unwrap().state
751 != zx::ThreadState::Blocked(zx::ThreadBlockType::Futex)
752 {
753 std::thread::sleep(std::time::Duration::from_millis(5));
754 }
755 assert_eq!(event.get_owner(), Some(root_thread_koid));
756
757 event.notify();
758 blocked_thread.join().unwrap();
759 }
760
761 #[test]
762 fn test_stack_allocated_wait_notify_and_interrupt() {
763 let event = InterruptibleEvent::default();
764 let guard = event.begin_wait();
765 std::thread::scope(|s| {
766 s.spawn(|| {
767 event.notify();
768 });
769 guard.block_until(None, zx::MonotonicInstant::INFINITE).expect("failed to be notified");
770 });
771
772 let guard = event.begin_wait();
773 std::thread::scope(|s| {
774 s.spawn(|| {
775 event.interrupt();
776 });
777 let result = guard.block_until(None, zx::MonotonicInstant::INFINITE);
778 assert_eq!(result, Err(WakeReason::Interrupted));
779 });
780 }
781
782 #[test]
783 fn test_is_waiting_during_requeue_transition() {
784 let event = InterruptibleEvent::new();
785 assert!(!event.is_waiting());
786
787 let guard = event.begin_wait_requeueable();
788 assert!(event.is_waiting());
789
790 event.futex.store(REQUEUED, Ordering::Release);
793 assert_eq!(event.requeue_target.load(Ordering::Relaxed), READY);
794 assert!(event.is_waiting());
795
796 drop(guard);
797 assert!(!event.is_waiting());
798
799 let guard = event.begin_wait();
800 event.notify();
801 guard.block_until(None, zx::MonotonicInstant::INFINITE).unwrap();
802 assert!(!event.is_waiting());
803 }
804
805 #[test]
806 fn test_dropping_wait_guard_resets_event() {
807 let event = InterruptibleEvent::new();
808 assert!(!event.is_waiting());
809 {
810 let _guard = event.begin_wait();
811 assert!(event.is_waiting());
812 }
813 assert!(!event.is_waiting());
814
815 let guard = event.begin_wait();
816 event.notify();
817 guard.block_until(None, zx::MonotonicInstant::INFINITE).unwrap();
818 assert!(!event.is_waiting());
819 }
820
821 #[test]
822 fn test_dropping_requeued_wait_guard_releases_owner() {
823 let event = InterruptibleEvent::new();
824 let owner = fuchsia_runtime::with_thread_self(|thread| {
825 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
826 });
827 assert_eq!(Arc::strong_count(&owner), 1);
828
829 {
830 let _guard = event.begin_wait_requeueable();
831 event.assign_new_owner(&owner).unwrap();
832 assert!(event.is_waiting());
833 assert_eq!(Arc::strong_count(&owner), 2);
834 }
835
836 assert!(!event.is_waiting());
837 assert_eq!(Arc::strong_count(&owner), 1);
838 assert_eq!(event.get_owner(), None);
839
840 let guard = event.begin_wait();
841 event.notify();
842 guard.block_until(None, zx::MonotonicInstant::INFINITE).unwrap();
843 assert!(!event.is_waiting());
844 }
845
846 #[test]
847 fn test_notify_before_block_resets_event_for_reuse() {
848 let event = InterruptibleEvent::new();
849
850 let guard = event.begin_wait();
851 event.notify();
852 assert!(!event.is_waiting());
853 guard.block_until(None, zx::MonotonicInstant::INFINITE).unwrap();
854 assert!(!event.is_waiting());
855
856 let guard = event.begin_wait();
857 event.notify();
858 guard.block_until(None, zx::MonotonicInstant::INFINITE).unwrap();
859 assert!(!event.is_waiting());
860 }
861
862 #[test]
863 fn test_reuse_after_requeued_block() {
864 const POLL_INTERVAL: std::time::Duration = std::time::Duration::from_millis(5);
865
866 let event = InterruptibleEvent::new();
867 let (owner, owner_koid) = fuchsia_runtime::with_thread_self(|thread| {
868 (
869 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
870 thread.koid().unwrap(),
871 )
872 });
873 assert_eq!(Arc::strong_count(&owner), 1);
874
875 let event_for_waiter = Arc::clone(&event);
877 let (thread_tx, thread_rx) = std::sync::mpsc::channel();
878 let waiter = std::thread::spawn(move || {
879 let thread_handle = fuchsia_runtime::with_thread_self(|thread| {
880 thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()
881 });
882 let guard = event_for_waiter.begin_wait_requeueable();
883 thread_tx.send(thread_handle).unwrap();
884 guard.block_until(None, zx::MonotonicInstant::INFINITE)
885 });
886
887 let waiter_handle = thread_rx.recv().unwrap();
888 while waiter_handle.info().unwrap().state
889 != zx::ThreadState::Blocked(zx::ThreadBlockType::Futex)
890 {
891 std::thread::sleep(POLL_INTERVAL);
892 }
893
894 event.assign_new_owner(&owner).unwrap();
895 assert_eq!(Arc::strong_count(&owner), 2);
896 assert_eq!(event.get_owner(), Some(owner_koid));
897
898 event.notify();
899 assert_eq!(waiter.join().unwrap(), Ok(()));
900 assert!(!event.is_waiting());
901 assert_eq!(Arc::strong_count(&owner), 1);
902 assert_eq!(event.get_owner(), None);
903
904 let event_for_waiter = Arc::clone(&event);
906 let (thread_tx, thread_rx) = std::sync::mpsc::channel();
907 let waiter = std::thread::spawn(move || {
908 let thread_handle = fuchsia_runtime::with_thread_self(|thread| {
909 thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()
910 });
911 let guard = event_for_waiter.begin_wait_requeueable();
912 thread_tx.send(thread_handle).unwrap();
913 guard.block_until(None, zx::MonotonicInstant::INFINITE)
914 });
915
916 let waiter_handle = thread_rx.recv().unwrap();
917 while waiter_handle.info().unwrap().state
918 != zx::ThreadState::Blocked(zx::ThreadBlockType::Futex)
919 {
920 std::thread::sleep(POLL_INTERVAL);
921 }
922
923 event.assign_new_owner(&owner).unwrap();
924 assert_eq!(Arc::strong_count(&owner), 2);
925 assert_eq!(event.get_owner(), Some(owner_koid));
926
927 event.interrupt();
928 assert_eq!(waiter.join().unwrap(), Err(WakeReason::Interrupted));
929 assert!(!event.is_waiting());
930 assert_eq!(Arc::strong_count(&owner), 1);
931 assert_eq!(event.get_owner(), None);
932 }
933
934 #[test]
935 fn test_reuse_after_timeout_and_interrupt() {
936 const SHORT_TIMEOUT: zx::MonotonicDuration = zx::MonotonicDuration::from_millis(20);
937
938 let event = InterruptibleEvent::new();
939
940 let (owner_tx, owner_rx) = std::sync::mpsc::channel();
942 let (stop_tx, stop_rx) = std::sync::mpsc::channel::<()>();
943 let owner_thread = std::thread::spawn(move || {
944 let handle = fuchsia_runtime::with_thread_self(|thread| {
945 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
946 });
947 owner_tx.send(handle).unwrap();
948 let _ = stop_rx.recv();
949 });
950 let owner = owner_rx.recv().unwrap();
951 assert_eq!(Arc::strong_count(&owner), 1);
952
953 let guard = event.begin_wait();
955 assert_eq!(
956 guard.block_until(None, zx::MonotonicInstant::after(SHORT_TIMEOUT)),
957 Err(WakeReason::DeadlineExpired)
958 );
959 assert!(!event.is_waiting());
960
961 let guard = event.begin_wait_requeueable();
963 event.assign_new_owner(&owner).unwrap();
964 assert_eq!(Arc::strong_count(&owner), 2);
965 assert_eq!(
966 guard.block_until(None, zx::MonotonicInstant::after(SHORT_TIMEOUT)),
967 Err(WakeReason::DeadlineExpired)
968 );
969 assert!(!event.is_waiting());
970 assert_eq!(Arc::strong_count(&owner), 1);
971 assert_eq!(event.get_owner(), None);
972
973 let guard = event.begin_wait();
975 let other_event = Arc::clone(&event);
976 let interrupter = std::thread::spawn(move || {
977 other_event.interrupt();
978 });
979 assert_eq!(
980 guard.block_until(None, zx::MonotonicInstant::INFINITE),
981 Err(WakeReason::Interrupted)
982 );
983 interrupter.join().unwrap();
984 assert!(!event.is_waiting());
985
986 let guard = event.begin_wait();
988 let other_event = Arc::clone(&event);
989 let notifier = std::thread::spawn(move || {
990 other_event.notify();
991 });
992 assert_eq!(guard.block_until(None, zx::MonotonicInstant::INFINITE), Ok(()));
993 notifier.join().unwrap();
994 assert!(!event.is_waiting());
995
996 drop(stop_tx);
997 owner_thread.join().unwrap();
998 }
999
1000 #[test]
1001 fn test_concurrent_notify_during_reuse() {
1002 const REUSE_ITERATIONS: usize = 500;
1003
1004 let event = InterruptibleEvent::new();
1005 let done = AtomicBool::new(false);
1006 std::thread::scope(|scope| {
1007 let notifier_event = &event;
1008 let done_ref = &done;
1009 scope.spawn(move || {
1010 while !done_ref.load(Ordering::Relaxed) {
1011 notifier_event.notify();
1012 }
1013 });
1014 scopeguard::defer! {
1015 done.store(true, Ordering::Relaxed);
1016 }
1017 for i in 0..REUSE_ITERATIONS {
1018 let guard = event.begin_wait();
1019 if i % 4 == 0 {
1020 drop(guard);
1021 } else {
1022 assert_eq!(guard.block_until(None, zx::MonotonicInstant::INFINITE), Ok(()));
1023 }
1024 }
1025 });
1026 assert!(!event.is_waiting());
1027 }
1028
1029 #[test]
1030 fn test_concurrent_interrupt_and_requeue_during_reuse() {
1031 const REUSE_ITERATIONS: usize = 500;
1032
1033 let event = InterruptibleEvent::new();
1034 let (owner_tx, owner_rx) = std::sync::mpsc::channel();
1035 let (stop_tx, stop_rx) = std::sync::mpsc::channel::<()>();
1036 let owner_thread = std::thread::spawn(move || {
1037 let handle = fuchsia_runtime::with_thread_self(|thread| {
1038 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
1039 });
1040 owner_tx.send(handle).unwrap();
1041 let _ = stop_rx.recv();
1042 });
1043 let owner = owner_rx.recv().unwrap();
1044 assert_eq!(Arc::strong_count(&owner), 1);
1045
1046 let done = AtomicBool::new(false);
1047 std::thread::scope(|scope| {
1048 let interrupter_event = &event;
1049 let assigner_event = &event;
1050 let owner_ref = &owner;
1051 let done_ref = &done;
1052 scope.spawn(move || {
1053 while !done_ref.load(Ordering::Relaxed) {
1054 interrupter_event.interrupt();
1055 }
1056 });
1057 scope.spawn(move || {
1058 while !done_ref.load(Ordering::Relaxed) {
1059 let _ = assigner_event.assign_new_owner(owner_ref);
1060 }
1061 });
1062 scopeguard::defer! {
1063 done.store(true, Ordering::Relaxed);
1064 }
1065 for i in 0..REUSE_ITERATIONS {
1066 let guard =
1067 if i % 2 == 0 { event.begin_wait_requeueable() } else { event.begin_wait() };
1068 if i % 4 == 0 {
1069 drop(guard);
1070 } else {
1071 assert_eq!(
1072 guard.block_until(None, zx::MonotonicInstant::INFINITE),
1073 Err(WakeReason::Interrupted)
1074 );
1075 }
1076 }
1077 });
1078
1079 assert!(!event.is_waiting());
1080 assert_eq!(Arc::strong_count(&owner), 1);
1081 assert_eq!(event.get_owner(), None);
1082
1083 drop(stop_tx);
1084 owner_thread.join().unwrap();
1085 }
1086
1087 #[test]
1088 fn test_non_requeueable_wait_rejects_assign_new_owner() {
1089 const POLL_INTERVAL: std::time::Duration = std::time::Duration::from_millis(5);
1090
1091 let event = InterruptibleEvent::new();
1092 let (known_owner, known_owner_koid) = fuchsia_runtime::with_thread_self(|thread| {
1093 (
1094 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1095 thread.koid().unwrap(),
1096 )
1097 });
1098
1099 let (other_owner_tx, other_owner_rx) = std::sync::mpsc::channel();
1100 let (stop_tx, stop_rx) = std::sync::mpsc::channel::<()>();
1101 let other_owner_thread = std::thread::spawn(move || {
1102 let handle = fuchsia_runtime::with_thread_self(|thread| {
1103 Arc::new(thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
1104 });
1105 other_owner_tx.send(handle).unwrap();
1106 let _ = stop_rx.recv();
1107 });
1108 let other_owner = other_owner_rx.recv().unwrap();
1109
1110 drop(event.begin_wait_requeueable());
1113
1114 std::thread::scope(|s| {
1117 let (tx, rx) = std::sync::mpsc::channel();
1118 let event_ref = &event;
1119 let known_owner_ref = &known_owner;
1120 s.spawn(move || {
1121 let guard = event_ref.begin_wait();
1122 let waiter_handle = fuchsia_runtime::with_thread_self(|thread| {
1123 thread.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()
1124 });
1125 tx.send(waiter_handle).unwrap();
1126 guard.block_until(Some(known_owner_ref), zx::MonotonicInstant::INFINITE).unwrap();
1127 });
1128 scopeguard::defer! {
1129 event.notify();
1130 }
1131
1132 let waiter_handle = rx.recv().unwrap();
1133 while waiter_handle.info().unwrap().state
1134 != zx::ThreadState::Blocked(zx::ThreadBlockType::Futex)
1135 {
1136 std::thread::sleep(POLL_INTERVAL);
1137 }
1138 assert_eq!(event.get_owner(), Some(known_owner_koid));
1139
1140 assert_eq!(event.assign_new_owner(&other_owner), Err(zx::Status::BAD_STATE));
1141 assert_eq!(Arc::strong_count(&other_owner), 1);
1142 assert_eq!(event.get_owner(), Some(known_owner_koid));
1143 });
1144
1145 drop(stop_tx);
1146 other_owner_thread.join().unwrap();
1147 }
1148}