1use crate::mm::memory::MemoryObject;
6use crate::mm::{CompareExchangeResult, ProtectionFlags};
7use crate::task::{CurrentTask, EventHandler, SignalHandler, SignalHandlerInner, Task, Waiter};
8use futures::channel::oneshot;
9use starnix_sync::{FutexTableStateLock, InterruptibleEvent, LockDepMutex};
10use starnix_types::futex_address::FutexAddress;
11use starnix_uapi::errors::Errno;
12use starnix_uapi::user_address::UserAddress;
13use starnix_uapi::{FUTEX_BITSET_MATCH_ANY, FUTEX_TID_MASK, FUTEX_WAITERS, errno, error};
14use std::collections::hash_map::Entry;
15use std::collections::{HashMap, VecDeque};
16use std::hash::Hash;
17use std::sync::{Arc, Weak};
18
19pub struct FutexTable<Key: FutexKey> {
25 state: LockDepMutex<FutexTableState<Key>, FutexTableStateLock>,
29}
30
31impl<Key: FutexKey> Default for FutexTable<Key> {
32 fn default() -> Self {
33 Self { state: LockDepMutex::new(FutexTableState::default()) }
34 }
35}
36
37impl<Key: FutexKey> FutexTable<Key> {
38 fn resolve_wait(
48 &self,
49 result: Result<(), Errno>,
50 remove: impl FnOnce(&mut FutexTableState<Key>) -> bool,
51 ) -> Result<(), Errno> {
52 result.or_else(|e| if remove(&mut self.state.lock()) { Err(e) } else { Ok(()) })
53 }
54
55 pub fn wait_boot(
59 &self,
60 current_task: &CurrentTask,
61 addr: UserAddress,
62 value: u32,
63 mask: u32,
64 deadline: zx::BootInstant,
65 timer_slack: zx::BootDuration,
66 ) -> Result<(), Errno> {
67 let addr = FutexAddress::try_from(addr)?;
68 let _ = current_task.mm()?.atomic_load_u32_acquire(addr)?;
73 let mut state = self.state.lock();
74 let loaded_value = current_task.mm()?.atomic_load_u32_acquire(addr)?;
79 if value != loaded_value {
80 return error!(EAGAIN);
81 }
82
83 let key = Key::get(current_task, addr)?;
84 let waiter = Arc::new(Waiter::new());
85 let timer = zx::BootTimer::create();
86 let signal_handler = SignalHandler {
87 inner: SignalHandlerInner::None,
88 event_handler: EventHandler::None,
89 err_code: Some(errno!(ETIMEDOUT)),
90 };
91 waiter
92 .wake_on_zircon_signals(&timer, zx::Signals::TIMER_SIGNALED, signal_handler)
93 .expect("wait can only fail in OOM conditions");
94 timer
95 .set(deadline, timer_slack)
96 .expect("timer set cannot fail with valid handles and slack");
97 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
98 mask,
99 notifiable: FutexNotifiable::new_internal_boot(Arc::downgrade(&waiter)),
100 });
101 std::mem::drop(state);
102
103 let result = waiter.wait(current_task);
104 self.resolve_wait(result, |state| {
105 state.remove_waiter_from_queue(key, &WaiterMatcher::BootWaiter(&waiter))
106 })
107 }
108
109 pub fn wait(
113 &self,
114 current_task: &CurrentTask,
115 addr: UserAddress,
116 value: u32,
117 mask: u32,
118 deadline: zx::MonotonicInstant,
119 ) -> Result<(), Errno> {
120 let addr = FutexAddress::try_from(addr)?;
121 let _ = current_task.mm()?.atomic_load_u32_acquire(addr)?;
126 let mut state = self.state.lock();
127 let loaded_value = current_task.mm()?.atomic_load_u32_acquire(addr)?;
132 if value != loaded_value {
133 return error!(EAGAIN);
134 }
135
136 let key = Key::get(current_task, addr)?;
137 let event = InterruptibleEvent::new();
138 let guard = event.begin_wait();
139 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
140 mask,
141 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
142 });
143 std::mem::drop(state);
144
145 let result = current_task.block_until(guard, deadline);
146 self.resolve_wait(result, |state| {
147 state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event))
148 })
149 }
150
151 pub fn wake(
156 &self,
157 task: &Task,
158 addr: UserAddress,
159 count: usize,
160 mask: u32,
161 ) -> Result<usize, Errno> {
162 let addr = FutexAddress::try_from(addr)?;
163 let key = Key::get(task, addr)?;
164 Ok(self.state.lock().wake(key, count, mask))
165 }
166
167 pub fn requeue(
171 &self,
172 current_task: &CurrentTask,
173 addr: UserAddress,
174 wake_count: usize,
175 requeue_count: usize,
176 new_addr: UserAddress,
177 expected_value: Option<u32>,
178 ) -> Result<usize, Errno> {
179 let addr = FutexAddress::try_from(addr)?;
180 let new_addr = FutexAddress::try_from(new_addr)?;
181 if expected_value.is_some() {
182 let _ = current_task.mm()?.atomic_load_u32_acquire(addr)?;
187 }
188 let key = Key::get(current_task, addr)?;
189 let new_key = Key::get(current_task, new_addr)?;
190 let mut state = self.state.lock();
191 if let Some(expected) = expected_value {
192 let value = current_task.mm()?.atomic_load_u32_acquire(addr)?;
195 if value != expected {
196 return error!(EAGAIN);
197 }
198 }
199
200 Ok(state.requeue(key, new_key, wake_count, requeue_count))
201 }
202
203 pub fn lock_pi(
207 &self,
208 current_task: &CurrentTask,
209 addr: UserAddress,
210 deadline: zx::MonotonicInstant,
211 ) -> Result<(), Errno> {
212 let addr = FutexAddress::try_from(addr)?;
213 let mm = current_task.mm()?;
214 if let Ok(current) = mm.atomic_load_u32_relaxed(addr) {
220 let _ = mm.atomic_compare_exchange_u32_acq_rel(addr, current, current);
221 }
222 let mut state = self.state.lock();
223 let key = Key::get(current_task, addr)?;
226
227 let tid = current_task.get_tid() as u32;
228
229 let mut current_value = mm.atomic_load_u32_relaxed(addr)?;
233 let new_owner_tid = loop {
234 let new_owner_tid = current_value & FUTEX_TID_MASK;
235 if new_owner_tid == tid {
236 return error!(EDEADLOCK);
243 }
244
245 if current_value == 0 {
246 match mm.atomic_compare_exchange_weak_u32_acq_rel(addr, current_value, tid) {
249 CompareExchangeResult::Success => return Ok(()),
250 CompareExchangeResult::Stale { observed } => {
251 current_value = observed;
252 continue;
253 }
254 CompareExchangeResult::Error(e) => return Err(e),
255 }
256 }
257
258 let target_value = current_value | FUTEX_WAITERS;
261 match mm.atomic_compare_exchange_u32_acq_rel(addr, current_value, target_value) {
262 CompareExchangeResult::Success => (),
263 CompareExchangeResult::Stale { observed } => {
264 current_value = observed;
265 continue;
266 }
267 CompareExchangeResult::Error(e) => return Err(e),
268 }
269 break new_owner_tid;
270 };
271
272 let event = InterruptibleEvent::new();
273 let guard = event.begin_wait();
274 let notifiable = FutexNotifiable::new_internal(Arc::downgrade(&event));
275 state
276 .get_rt_mutex_waiters_or_default(key.clone())
277 .push_back(RtMutexWaiter { tid, notifiable });
278 std::mem::drop(state);
279
280 let result = current_task
284 .get_task(new_owner_tid as i32)
285 .ok()
286 .and_then(|o| o.running_state().unwrap().thread.get().map(|t| Arc::clone(&t.thread)))
287 .map_or_else(
288 || error!(ESRCH),
289 |owner| current_task.block_with_owner_until(guard, &owner, deadline),
290 );
291
292 self.resolve_wait(result, |state| {
297 state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event))
298 })
299 }
300
301 pub fn unlock_pi(&self, current_task: &CurrentTask, addr: UserAddress) -> Result<(), Errno> {
305 let addr = FutexAddress::try_from(addr)?;
306 let mm = current_task.mm()?;
307 if let Ok(current) = mm.atomic_load_u32_relaxed(addr) {
313 let _ = mm.atomic_compare_exchange_u32_acq_rel(addr, current, current);
314 }
315 let mut state = self.state.lock();
316 let tid = current_task.get_tid() as u32;
317
318 let key = Key::get(current_task, addr)?;
319
320 let mut expected_value = mm.atomic_load_u32_relaxed(addr)?;
324 if expected_value & FUTEX_TID_MASK != tid {
325 return error!(EPERM);
330 }
331
332 loop {
333 let maybe_waiter = state.pop_rt_mutex_waiter(key.clone());
334 let target_value = maybe_waiter.as_ref().map_or(0, |waiter| waiter.tid);
335
336 let handoff =
339 mm.atomic_compare_exchange_u32_acq_rel(addr, expected_value, target_value);
340 if let Err(e) = handoff_result(handoff) {
341 if let Some(waiter) = maybe_waiter {
342 state.unpop_rt_mutex_waiter(key, waiter);
343 }
344 return Err(e);
345 }
346 expected_value = target_value;
349
350 let Some(mut waiter) = maybe_waiter else {
351 break;
353 };
354
355 if waiter.notifiable.notify() {
356 break;
357 }
358
359 }
362
363 Ok(())
364 }
365}
366
367fn handoff_result(result: CompareExchangeResult<u32>) -> Result<(), Errno> {
369 match result {
370 CompareExchangeResult::Success => Ok(()),
371 CompareExchangeResult::Stale { .. } => error!(EINVAL),
380 CompareExchangeResult::Error(_) => error!(EACCES),
384 }
385}
386
387impl FutexTable<SharedFutexKey> {
388 pub fn external_wait(
398 &self,
399 memory: MemoryObject,
400 offset: u64,
401 value: u32,
402 mask: u32,
403 ) -> Result<(Arc<()>, oneshot::Receiver<()>), Errno> {
404 let key = SharedFutexKey::new(&memory, offset);
405 let mut state = self.state.lock();
406 Self::external_check_futex_value(&memory, offset, value)?;
408
409 let token = Arc::new(());
410 let (sender, receiver) = oneshot::channel::<()>();
411 state.get_waiters_or_default(key).add(FutexWaiter {
412 mask,
413 notifiable: FutexNotifiable::new_external(Arc::downgrade(&token), sender),
414 });
415 Ok((token, receiver))
416 }
417
418 pub fn external_wake(
423 &self,
424 memory: MemoryObject,
425 offset: u64,
426 count: usize,
427 mask: u32,
428 ) -> Result<usize, Errno> {
429 Ok(self.state.lock().wake(SharedFutexKey::new(&memory, offset), count, mask))
430 }
431
432 pub fn external_requeue(
433 &self,
434 first_memory: MemoryObject,
435 first_offset: u64,
436 second_memory: Option<MemoryObject>,
437 second_offset: u64,
438 wake_count: usize,
439 requeue_count: usize,
440 expected_value: Option<u32>,
441 ) -> Result<usize, Errno> {
442 let first_key = SharedFutexKey::new(&first_memory, first_offset);
443 let second_key = match second_memory.as_ref() {
444 Some(second_memory) => SharedFutexKey::new(second_memory, second_offset),
445 None => SharedFutexKey::new(&first_memory, second_offset),
446 };
447 let mut state = self.state.lock();
454 if let Some(expected) = expected_value {
455 Self::external_check_futex_value(&first_memory, first_offset, expected)?;
457 }
458 Ok(state.requeue(first_key, second_key, wake_count, requeue_count))
459 }
460
461 fn external_check_futex_value(
462 memory: &MemoryObject,
463 offset: u64,
464 value: u32,
465 ) -> Result<(), Errno> {
466 let loaded_value = {
467 let mut buf = [0u8; 4];
469 memory.read(&mut buf, offset).map_err(|_| errno!(EINVAL))?;
470 u32::from_ne_bytes(buf)
471 };
472 if loaded_value != value {
473 return error!(EAGAIN);
474 }
475 Ok(())
476 }
477}
478
479pub trait FutexKey: Sized + Ord + Hash + Clone {
480 fn get(task: &Task, addr: FutexAddress) -> Result<Self, Errno>;
481 fn get_table_from_task(task: &Task) -> Result<Arc<FutexTable<Self>>, Errno>;
482}
483
484#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
485pub struct PrivateFutexKey {
486 addr: FutexAddress,
487}
488
489impl FutexKey for PrivateFutexKey {
490 fn get(_task: &Task, addr: FutexAddress) -> Result<Self, Errno> {
491 Ok(PrivateFutexKey { addr })
492 }
493
494 fn get_table_from_task(task: &Task) -> Result<Arc<FutexTable<Self>>, Errno> {
495 Ok(task.mm()?.futex.clone())
496 }
497}
498
499#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
500pub struct SharedFutexKey {
501 koid: zx::Koid,
504 offset: u64,
505}
506
507impl FutexKey for SharedFutexKey {
508 fn get(task: &Task, addr: FutexAddress) -> Result<Self, Errno> {
509 let (memory, offset) = task.mm()?.get_mapping_memory(addr.into(), ProtectionFlags::READ)?;
510 Ok(SharedFutexKey::new(&memory, offset))
511 }
512
513 fn get_table_from_task(task: &Task) -> Result<Arc<FutexTable<Self>>, Errno> {
514 Ok(task.kernel().shared_futexes.clone())
515 }
516}
517
518impl SharedFutexKey {
519 fn new(memory: &MemoryObject, offset: u64) -> Self {
520 Self { koid: memory.get_koid(), offset }
521 }
522}
523
524struct FutexTableState<Key: FutexKey> {
525 waiters: HashMap<Key, FutexWaiters>,
526 rt_mutex_waiters: HashMap<Key, VecDeque<RtMutexWaiter>>,
527}
528
529impl<Key: FutexKey> Default for FutexTableState<Key> {
530 fn default() -> Self {
531 Self { waiters: Default::default(), rt_mutex_waiters: Default::default() }
532 }
533}
534
535impl<Key: FutexKey> FutexTableState<Key> {
536 fn get_waiters_or_default(&mut self, key: Key) -> &mut FutexWaiters {
538 self.waiters.entry(key).or_default()
539 }
540
541 fn wake(&mut self, key: Key, count: usize, mask: u32) -> usize {
542 let entry = self.waiters.entry(key);
543 match entry {
544 Entry::Vacant(_) => 0,
545 Entry::Occupied(mut entry) => {
546 let count = entry.get_mut().notify(mask, count);
547 if entry.get().is_empty() {
548 entry.remove();
549 }
550 count
551 }
552 }
553 }
554
555 fn requeue(
556 &mut self,
557 key: Key,
558 new_key: Key,
559 wake_count: usize,
560 requeue_count: usize,
561 ) -> usize {
562 let woken;
563 let to_requeue;
564 match self.waiters.entry(key) {
565 Entry::Vacant(_) => return 0,
566 Entry::Occupied(mut entry) => {
567 woken = entry.get_mut().notify(FUTEX_BITSET_MATCH_ANY, wake_count);
569
570 to_requeue = entry.get_mut().split_for_requeue(requeue_count);
572
573 if entry.get().is_empty() {
574 entry.remove();
575 }
576 }
577 }
578
579 let requeued = to_requeue.0.len();
580 if !to_requeue.is_empty() {
581 self.get_waiters_or_default(new_key).transfer(to_requeue);
582 }
583
584 woken + requeued
585 }
586
587 fn get_rt_mutex_waiters_or_default(&mut self, key: Key) -> &mut VecDeque<RtMutexWaiter> {
590 self.rt_mutex_waiters.entry(key).or_default()
591 }
592
593 fn pop_rt_mutex_waiter(&mut self, key: Key) -> Option<RtMutexWaiter> {
595 let entry = self.rt_mutex_waiters.entry(key);
596 match entry {
597 Entry::Vacant(_) => None,
598 Entry::Occupied(mut entry) => {
599 let mut waiter = entry.get_mut().pop_front();
600 if entry.get().is_empty() {
604 entry.remove();
605 } else if let Some(waiter) = &mut waiter {
606 waiter.tid |= FUTEX_WAITERS;
607 }
608 waiter
609 }
610 }
611 }
612
613 fn unpop_rt_mutex_waiter(&mut self, key: Key, mut waiter: RtMutexWaiter) {
619 waiter.tid &= FUTEX_TID_MASK;
620 self.get_rt_mutex_waiters_or_default(key).push_front(waiter);
621 }
622
623 fn remove_waiter_from_queue(&mut self, key: Key, matcher: &WaiterMatcher<'_>) -> bool {
628 search_and_remove_waiter(&mut self.waiters, key, matcher)
629 }
630
631 fn remove_rt_mutex_waiter_from_queue(&mut self, key: Key, matcher: &WaiterMatcher<'_>) -> bool {
636 search_and_remove_waiter(&mut self.rt_mutex_waiters, key, matcher)
637 }
638}
639
640fn search_and_remove_waiter<Key: FutexKey, Queue: WaiterQueue>(
653 queues: &mut HashMap<Key, Queue>,
654 key: Key,
655 matcher: &WaiterMatcher<'_>,
656) -> bool {
657 if let Entry::Occupied(mut entry) = queues.entry(key) {
658 let found = entry.get_mut().remove_waiter(matcher);
659 if entry.get().is_empty() {
660 entry.remove();
661 }
662 if found {
663 return true;
664 }
665 }
666
667 let mut found = false;
670 queues.retain(|_, waiters| {
671 if !found {
672 found = waiters.remove_waiter(matcher);
673 }
674 !waiters.is_empty()
675 });
676 found
677}
678
679trait WaiterQueue {
681 fn remove_waiter(&mut self, matcher: &WaiterMatcher<'_>) -> bool;
688
689 fn is_empty(&self) -> bool;
691}
692
693enum WaiterMatcher<'a> {
698 Event(&'a Arc<InterruptibleEvent>),
700
701 BootWaiter(&'a Arc<Waiter>),
703}
704
705impl WaiterMatcher<'_> {
706 fn matches(&self, notifiable: &FutexNotifiable) -> bool {
708 match (self, notifiable) {
709 (Self::Event(event), FutexNotifiable::Internal(weak)) => {
710 weak.upgrade().is_some_and(|strong| Arc::ptr_eq(&strong, event))
711 }
712 (Self::BootWaiter(waiter), FutexNotifiable::InternalBoot(weak)) => {
713 weak.upgrade().is_some_and(|strong| Arc::ptr_eq(&strong, waiter))
714 }
715 _ => false,
716 }
717 }
718}
719
720enum FutexNotifiable {
722 Internal(Weak<InterruptibleEvent>),
724 InternalBoot(Weak<Waiter>),
726 External(Weak<()>, Option<oneshot::Sender<()>>),
730}
731
732impl FutexNotifiable {
733 fn new_internal(event: Weak<InterruptibleEvent>) -> Self {
734 Self::Internal(event)
735 }
736
737 fn new_internal_boot(waiter: Weak<Waiter>) -> Self {
738 Self::InternalBoot(waiter)
739 }
740
741 fn new_external(token: Weak<()>, sender: oneshot::Sender<()>) -> Self {
742 Self::External(token, Some(sender))
743 }
744
745 fn notify(&mut self) -> bool {
748 match self {
749 Self::Internal(event) => {
750 if let Some(event) = event.upgrade() {
751 event.notify();
752 true
753 } else {
754 false
755 }
756 }
757 Self::InternalBoot(waiter) => {
758 if let Some(waiter) = waiter.upgrade() {
759 waiter.notify();
760 true
761 } else {
762 false
763 }
764 }
765 Self::External(_, sender) => {
766 if let Some(sender) = sender.take() {
767 sender.send(()).is_ok()
768 } else {
769 false
770 }
771 }
772 }
773 }
774
775 fn is_stale(&self) -> bool {
776 match self {
777 Self::Internal(weak) => weak.strong_count() == 0,
778 Self::External(weak, _) => weak.strong_count() == 0,
779 Self::InternalBoot(weak) => weak.strong_count() == 0,
780 }
781 }
782}
783
784struct FutexWaiter {
785 mask: u32,
786 notifiable: FutexNotifiable,
787}
788
789#[derive(Default)]
790struct FutexWaiters(VecDeque<FutexWaiter>);
791
792impl FutexWaiters {
793 fn add(&mut self, waiter: FutexWaiter) {
794 self.0.push_back(waiter);
795 }
796
797 fn notify(&mut self, mask: u32, count: usize) -> usize {
798 let mut woken = 0;
799 self.0.retain_mut(|waiter| {
800 if woken == count || waiter.mask & mask == 0 {
801 return true;
802 }
803 if waiter.notifiable.notify() {
806 woken += 1;
807 }
808 false
809 });
810 woken
811 }
812
813 fn transfer(&mut self, mut other: Self) {
814 self.0.append(&mut other.0);
815 }
816
817 fn split_for_requeue(&mut self, count: usize) -> Self {
818 let count = std::cmp::min(count, self.0.len());
819 let tail = self.0.split_off(count);
820 let head = std::mem::replace(&mut self.0, tail);
821 FutexWaiters(head)
822 }
823}
824
825trait QueuedWaiter {
827 fn notifiable(&self) -> &FutexNotifiable;
828}
829
830impl QueuedWaiter for FutexWaiter {
831 fn notifiable(&self) -> &FutexNotifiable {
832 &self.notifiable
833 }
834}
835
836impl QueuedWaiter for RtMutexWaiter {
837 fn notifiable(&self) -> &FutexNotifiable {
838 &self.notifiable
839 }
840}
841
842impl<W: QueuedWaiter> WaiterQueue for VecDeque<W> {
843 fn remove_waiter(&mut self, matcher: &WaiterMatcher<'_>) -> bool {
844 let mut found = false;
845 self.retain(|w| {
846 if matcher.matches(w.notifiable()) {
847 found = true;
848 return false;
849 }
850 !w.notifiable().is_stale()
851 });
852 found
853 }
854
855 fn is_empty(&self) -> bool {
856 VecDeque::is_empty(self)
857 }
858}
859
860impl WaiterQueue for FutexWaiters {
861 fn remove_waiter(&mut self, matcher: &WaiterMatcher<'_>) -> bool {
862 self.0.remove_waiter(matcher)
863 }
864
865 fn is_empty(&self) -> bool {
866 self.0.is_empty()
867 }
868}
869
870struct RtMutexWaiter {
871 tid: u32,
873
874 notifiable: FutexNotifiable,
875}
876
877#[cfg(test)]
878mod tests {
879 use super::*;
880 use starnix_sync::InterruptibleEvent;
881 use starnix_uapi::restricted_aspace::RESTRICTED_ASPACE_BASE;
882 use starnix_uapi::user_address::UserAddress;
883
884 #[fuchsia::test]
885 fn test_remove_waiter_simple() {
886 let mut state = FutexTableState::<PrivateFutexKey>::default();
887 let key = PrivateFutexKey {
888 addr: FutexAddress::try_from(UserAddress::from(
889 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
890 ))
891 .unwrap(),
892 };
893 let event = Arc::new(InterruptibleEvent::new());
894
895 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
896 mask: u32::MAX,
897 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
898 });
899
900 assert_eq!(state.waiters.len(), 1);
901 assert!(state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
902 assert_eq!(state.waiters.len(), 0);
903 }
904
905 #[fuchsia::test]
906 fn test_remove_waiter_requeued() {
907 let mut state = FutexTableState::<PrivateFutexKey>::default();
908 let key1 = PrivateFutexKey {
909 addr: FutexAddress::try_from(UserAddress::from(
910 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
911 ))
912 .unwrap(),
913 };
914 let key2 = PrivateFutexKey {
915 addr: FutexAddress::try_from(UserAddress::from(
916 (RESTRICTED_ASPACE_BASE + 0x2000) as u64,
917 ))
918 .unwrap(),
919 };
920 let event = Arc::new(InterruptibleEvent::new());
921
922 state.get_waiters_or_default(key2.clone()).add(FutexWaiter {
923 mask: u32::MAX,
924 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
925 });
926
927 assert_eq!(state.waiters.len(), 1);
928 assert!(state.remove_waiter_from_queue(key1, &WaiterMatcher::Event(&event)));
929 assert_eq!(state.waiters.len(), 0);
930 }
931
932 #[fuchsia::test]
938 fn test_wake_racing_with_interruption_is_not_lost() {
939 let mut state = FutexTableState::<PrivateFutexKey>::default();
940 let key = PrivateFutexKey {
941 addr: FutexAddress::try_from(UserAddress::from(
942 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
943 ))
944 .unwrap(),
945 };
946 let event = InterruptibleEvent::new();
947 let _guard = event.begin_wait();
948
949 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
950 mask: u32::MAX,
951 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
952 });
953
954 event.interrupt();
956
957 assert_eq!(state.wake(key.clone(), 1, FUTEX_BITSET_MATCH_ANY), 1);
959
960 assert!(!state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
963 }
964
965 #[fuchsia::test]
967 fn test_wake_racing_with_boot_waiter_removal_is_not_lost() {
968 let mut state = FutexTableState::<PrivateFutexKey>::default();
969 let key = PrivateFutexKey {
970 addr: FutexAddress::try_from(UserAddress::from(
971 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
972 ))
973 .unwrap(),
974 };
975 let waiter = Arc::new(Waiter::new());
976
977 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
978 mask: u32::MAX,
979 notifiable: FutexNotifiable::new_internal_boot(Arc::downgrade(&waiter)),
980 });
981
982 assert_eq!(state.wake(key.clone(), 1, FUTEX_BITSET_MATCH_ANY), 1);
985
986 assert!(!state.remove_waiter_from_queue(key, &WaiterMatcher::BootWaiter(&waiter)));
987 }
988
989 #[fuchsia::test]
994 fn test_remove_waiter_ignores_other_waiter_kinds() {
995 let mut state = FutexTableState::<PrivateFutexKey>::default();
996 let key = PrivateFutexKey {
997 addr: FutexAddress::try_from(UserAddress::from(
998 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
999 ))
1000 .unwrap(),
1001 };
1002 let event = InterruptibleEvent::new();
1003 let waiter = Arc::new(Waiter::new());
1004
1005 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
1006 mask: u32::MAX,
1007 notifiable: FutexNotifiable::new_internal_boot(Arc::downgrade(&waiter)),
1008 });
1009
1010 assert!(!state.remove_waiter_from_queue(key.clone(), &WaiterMatcher::Event(&event)));
1011 assert_eq!(state.waiters.len(), 1);
1012
1013 assert!(state.remove_waiter_from_queue(key, &WaiterMatcher::BootWaiter(&waiter)));
1014 assert_eq!(state.waiters.len(), 0);
1015 }
1016
1017 #[fuchsia::test]
1018 fn test_remove_rt_mutex_waiter() {
1019 let mut state = FutexTableState::<PrivateFutexKey>::default();
1020 let key = PrivateFutexKey {
1021 addr: FutexAddress::try_from(UserAddress::from(
1022 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1023 ))
1024 .unwrap(),
1025 };
1026 let event = Arc::new(InterruptibleEvent::new());
1027
1028 state.get_rt_mutex_waiters_or_default(key.clone()).push_back(RtMutexWaiter {
1029 tid: 1,
1030 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
1031 });
1032
1033 assert_eq!(state.rt_mutex_waiters.len(), 1);
1034 state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event));
1035 assert_eq!(state.rt_mutex_waiters.len(), 0);
1036 }
1037
1038 #[fuchsia::test]
1043 fn test_remove_rt_mutex_waiter_reports_whether_it_was_queued() {
1044 let mut state = FutexTableState::<PrivateFutexKey>::default();
1045 let key = PrivateFutexKey {
1046 addr: FutexAddress::try_from(UserAddress::from(
1047 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1048 ))
1049 .unwrap(),
1050 };
1051 let event = InterruptibleEvent::new();
1052 let queue_waiter = |state: &mut FutexTableState<PrivateFutexKey>| {
1053 state.get_rt_mutex_waiters_or_default(key.clone()).push_back(RtMutexWaiter {
1054 tid: 1,
1055 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
1056 });
1057 };
1058
1059 queue_waiter(&mut state);
1060 assert!(
1061 state.remove_rt_mutex_waiter_from_queue(key.clone(), &WaiterMatcher::Event(&event))
1062 );
1063
1064 queue_waiter(&mut state);
1066 assert!(state.pop_rt_mutex_waiter(key.clone()).is_some());
1067
1068 assert!(!state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
1069 }
1070
1071 #[fuchsia::test]
1076 fn test_remove_rt_mutex_waiter_stale_cleanup_is_not_a_match() {
1077 let mut state = FutexTableState::<PrivateFutexKey>::default();
1078 let key = PrivateFutexKey {
1079 addr: FutexAddress::try_from(UserAddress::from(
1080 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1081 ))
1082 .unwrap(),
1083 };
1084
1085 {
1086 let dead_event = InterruptibleEvent::new();
1087 state.get_rt_mutex_waiters_or_default(key.clone()).push_back(RtMutexWaiter {
1088 tid: 1,
1089 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&dead_event)),
1090 });
1091 } let event = InterruptibleEvent::new();
1094 assert!(!state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
1095 assert_eq!(state.rt_mutex_waiters.len(), 0, "the stale waiter should be collected");
1096 }
1097
1098 #[fuchsia::test]
1101 fn test_remove_waiter_collects_queues_emptied_by_the_scan() {
1102 let mut state = FutexTableState::<PrivateFutexKey>::default();
1103 let stale_key = PrivateFutexKey {
1104 addr: FutexAddress::try_from(UserAddress::from(
1105 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1106 ))
1107 .unwrap(),
1108 };
1109 let key = PrivateFutexKey {
1110 addr: FutexAddress::try_from(UserAddress::from(
1111 (RESTRICTED_ASPACE_BASE + 0x2000) as u64,
1112 ))
1113 .unwrap(),
1114 };
1115
1116 {
1117 let dead_event = InterruptibleEvent::new();
1118 state.get_waiters_or_default(stale_key).add(FutexWaiter {
1119 mask: u32::MAX,
1120 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&dead_event)),
1121 });
1122 } let event = InterruptibleEvent::new();
1126 assert!(!state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
1127 assert_eq!(state.waiters.len(), 0, "the emptied queue should be collected");
1128 }
1129
1130 #[fuchsia::test]
1131 fn test_split_for_requeue_fairness() {
1132 let mut waiters = FutexWaiters::default();
1133 let e1 = Arc::new(InterruptibleEvent::new());
1134 let e2 = Arc::new(InterruptibleEvent::new());
1135 let e3 = Arc::new(InterruptibleEvent::new());
1136
1137 waiters.add(FutexWaiter {
1138 mask: 1,
1139 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&e1)),
1140 });
1141 waiters.add(FutexWaiter {
1142 mask: 2,
1143 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&e2)),
1144 });
1145 waiters.add(FutexWaiter {
1146 mask: 3,
1147 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&e3)),
1148 });
1149
1150 let split = waiters.split_for_requeue(2);
1151
1152 assert_eq!(split.0.len(), 2);
1153 assert_eq!(split.0[0].mask, 1);
1154 assert_eq!(split.0[1].mask, 2);
1155
1156 assert_eq!(waiters.0.len(), 1);
1157 assert_eq!(waiters.0[0].mask, 3);
1158 }
1159
1160 #[fuchsia::test]
1161 fn test_stale_external_waiter_cleanup() {
1162 let mut state = FutexTableState::<PrivateFutexKey>::default();
1163 let key = PrivateFutexKey {
1164 addr: FutexAddress::try_from(UserAddress::from(
1165 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1166 ))
1167 .unwrap(),
1168 };
1169
1170 {
1171 let token = Arc::new(());
1172 let (sender, _receiver) = oneshot::channel::<()>();
1173 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
1174 mask: u32::MAX,
1175 notifiable: FutexNotifiable::new_external(Arc::downgrade(&token), sender),
1176 });
1177 } assert_eq!(state.waiters.len(), 1);
1180
1181 let dummy_event = InterruptibleEvent::new();
1183 state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&dummy_event));
1184
1185 assert_eq!(state.waiters.len(), 0, "Stale external waiter should be removed");
1186 }
1187
1188 #[::fuchsia::test]
1195 async fn test_unlock_pi_hands_over_to_next_waiter_after_a_stale_one() {
1196 use crate::mm::memory::MemoryObject;
1197 use crate::mm::{DesiredAddress, MappingName, MappingOptions, PAGE_SIZE, ProtectionFlags};
1198 use crate::testing::spawn_kernel_and_run;
1199
1200 spawn_kernel_and_run(async move |current_task| {
1201 let mm = current_task.mm().unwrap();
1202 let addr = mm
1203 .map_memory(
1204 DesiredAddress::Any,
1205 Arc::new(MemoryObject::from(zx::Vmo::create(*PAGE_SIZE).unwrap())),
1206 0,
1207 *PAGE_SIZE as usize,
1208 ProtectionFlags::READ | ProtectionFlags::WRITE,
1209 MappingOptions::empty(),
1210 MappingName::None,
1211 )
1212 .expect("map failed");
1213 let futex_addr = FutexAddress::try_from(addr).unwrap();
1214
1215 let owner_tid = current_task.get_tid() as u32;
1217 assert!(matches!(
1218 mm.atomic_compare_exchange_u32_acq_rel(futex_addr, 0, owner_tid | FUTEX_WAITERS),
1219 CompareExchangeResult::Success
1220 ));
1221
1222 const STALE_TID: u32 = 0x111;
1223 const NEXT_OWNER_TID: u32 = 0x222;
1224 let futex_table = FutexTable::<PrivateFutexKey>::default();
1225 let key = PrivateFutexKey::get(current_task, futex_addr).unwrap();
1226 let next_owner_event = InterruptibleEvent::new();
1227 {
1228 let mut state = futex_table.state.lock();
1229 let queue = state.get_rt_mutex_waiters_or_default(key);
1230 {
1231 let dead_event = InterruptibleEvent::new();
1232 queue.push_back(RtMutexWaiter {
1233 tid: STALE_TID,
1234 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&dead_event)),
1235 });
1236 } queue.push_back(RtMutexWaiter {
1238 tid: NEXT_OWNER_TID,
1239 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&next_owner_event)),
1240 });
1241 }
1242
1243 futex_table.unlock_pi(current_task, addr).expect("unlock_pi failed");
1244
1245 assert_eq!(
1246 mm.atomic_load_u32_relaxed(futex_addr).unwrap(),
1247 NEXT_OWNER_TID,
1248 "the mutex should have been handed to the waiter behind the stale one"
1249 );
1250 assert!(futex_table.state.lock().rt_mutex_waiters.is_empty());
1251 })
1252 .await;
1253 }
1254
1255 #[::fuchsia::test]
1256 async fn test_futex_deadlock_with_pager() {
1257 use crate::mm::memory::MemoryObject;
1258 use crate::mm::{DesiredAddress, MappingName, MappingOptions, PAGE_SIZE, ProtectionFlags};
1259 use crate::testing::spawn_kernel_and_run;
1260 use std::sync::atomic::{AtomicBool, Ordering};
1261 use zx::sys::zx_page_request_command_t::ZX_PAGER_VMO_READ;
1262
1263 spawn_kernel_and_run(async move |current_task| {
1264 let mm = current_task.mm().unwrap();
1265
1266 let port = Arc::new(zx::Port::create());
1267 let port_clone = port.clone();
1268 let pager =
1269 Arc::new(zx::Pager::create(zx::PagerOptions::empty()).expect("create failed"));
1270 let pager_clone = pager.clone();
1271
1272 let vmo = Arc::new(
1273 pager
1274 .create_vmo(zx::VmoOptions::RESIZABLE, &port, 1, *PAGE_SIZE)
1275 .expect("create_vmo failed"),
1276 );
1277 let vmo_clone = vmo.clone();
1278
1279 let mapped_addr = mm
1280 .map_memory(
1281 DesiredAddress::Any,
1282 Arc::new(MemoryObject::from(
1283 (*vmo).duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1284 )),
1285 0,
1286 *PAGE_SIZE as usize,
1287 ProtectionFlags::READ | ProtectionFlags::WRITE,
1288 MappingOptions::empty(),
1289 MappingName::None,
1290 )
1291 .expect("map failed");
1292
1293 let futex_table = Arc::new(FutexTable::<PrivateFutexKey>::default());
1294 let futex_table_clone = futex_table.clone();
1295 let task_clone = current_task.task.clone();
1296 let dummy_addr = UserAddress::from((RESTRICTED_ASPACE_BASE + 0x2000) as u64);
1297
1298 let page_requested = Arc::new(AtomicBool::new(false));
1299 let wake_completed = Arc::new(AtomicBool::new(false));
1300
1301 let page_req_clone = page_requested.clone();
1302 let wake_completed_clone = wake_completed.clone();
1303
1304 let pager_thread = std::thread::spawn(move || {
1305 let packet = port_clone.wait(zx::MonotonicInstant::INFINITE).expect("wait failed");
1306 if let zx::PacketContents::Pager(contents) = packet.contents() {
1307 if contents.command() == ZX_PAGER_VMO_READ {
1308 let range = contents.range();
1309 page_req_clone.store(true, Ordering::SeqCst);
1310
1311 let waker = std::thread::spawn(move || {
1313 let _ = futex_table_clone.wake(&task_clone, dummy_addr, 1, u32::MAX);
1314 wake_completed_clone.store(true, Ordering::SeqCst);
1315 });
1316
1317 waker.join().unwrap();
1319 assert!(
1320 wake_completed.load(Ordering::SeqCst),
1321 "Waker thread must NOT be blocked while page fault is in progress!"
1322 );
1323
1324 let source_vmo =
1326 zx::Vmo::create(range.end - range.start).expect("create failed");
1327 pager_clone
1328 .supply_pages(&vmo_clone, range, &source_vmo, 0)
1329 .expect("supply_pages failed");
1330 }
1331 }
1332 });
1333
1334 let _ = futex_table.wait(
1336 current_task,
1337 mapped_addr,
1338 0,
1339 u32::MAX,
1340 zx::MonotonicInstant::from_nanos(1),
1341 );
1342
1343 pager_thread.join().unwrap();
1344 })
1345 .await;
1346 }
1347}