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 if deadline != zx::BootInstant::INFINITE && deadline <= zx::BootInstant::get() {
86 return error!(ETIMEDOUT);
87 }
88 let waiter = Arc::new(Waiter::new());
89 let timer = zx::BootTimer::create();
90 let signal_handler = SignalHandler {
91 inner: SignalHandlerInner::None,
92 event_handler: EventHandler::None,
93 err_code: Some(errno!(ETIMEDOUT)),
94 };
95 waiter
96 .wake_on_zircon_signals(&timer, zx::Signals::TIMER_SIGNALED, signal_handler)
97 .expect("wait can only fail in OOM conditions");
98 timer
99 .set(deadline, timer_slack)
100 .expect("timer set cannot fail with valid handles and slack");
101 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
102 mask,
103 notifiable: FutexNotifiable::new_internal_boot(Arc::downgrade(&waiter)),
104 });
105 std::mem::drop(state);
106
107 let result = waiter.wait(current_task);
108 self.resolve_wait(result, |state| {
109 state.remove_waiter_from_queue(key, &WaiterMatcher::BootWaiter(&waiter))
110 })
111 }
112
113 pub fn wait(
117 &self,
118 current_task: &CurrentTask,
119 addr: UserAddress,
120 value: u32,
121 mask: u32,
122 deadline: zx::MonotonicInstant,
123 ) -> Result<(), Errno> {
124 let addr = FutexAddress::try_from(addr)?;
125 let _ = current_task.mm()?.atomic_load_u32_acquire(addr)?;
130 let mut state = self.state.lock();
131 let loaded_value = current_task.mm()?.atomic_load_u32_acquire(addr)?;
136 if value != loaded_value {
137 return error!(EAGAIN);
138 }
139
140 let key = Key::get(current_task, addr)?;
141 if deadline != zx::MonotonicInstant::INFINITE && deadline <= zx::MonotonicInstant::get() {
143 return error!(ETIMEDOUT);
144 }
145 let event = InterruptibleEvent::new();
146 let guard = event.begin_wait();
147 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
148 mask,
149 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
150 });
151 std::mem::drop(state);
152
153 let result = current_task.block_until(guard, deadline);
154 self.resolve_wait(result, |state| {
155 state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event))
156 })
157 }
158
159 pub fn wake(
164 &self,
165 task: &Task,
166 addr: UserAddress,
167 count: usize,
168 mask: u32,
169 ) -> Result<usize, Errno> {
170 let addr = FutexAddress::try_from(addr)?;
171 let key = Key::get(task, addr)?;
172 Ok(self.state.lock().wake(key, count, mask))
173 }
174
175 pub fn requeue(
179 &self,
180 current_task: &CurrentTask,
181 addr: UserAddress,
182 wake_count: usize,
183 requeue_count: usize,
184 new_addr: UserAddress,
185 expected_value: Option<u32>,
186 ) -> Result<usize, Errno> {
187 let addr = FutexAddress::try_from(addr)?;
188 let new_addr = FutexAddress::try_from(new_addr)?;
189 if expected_value.is_some() {
190 let _ = current_task.mm()?.atomic_load_u32_acquire(addr)?;
195 }
196 let key = Key::get(current_task, addr)?;
197 let new_key = Key::get(current_task, new_addr)?;
198 let mut state = self.state.lock();
199 if let Some(expected) = expected_value {
200 let value = current_task.mm()?.atomic_load_u32_acquire(addr)?;
203 if value != expected {
204 return error!(EAGAIN);
205 }
206 }
207
208 Ok(state.requeue(key, new_key, wake_count, requeue_count))
209 }
210
211 pub fn lock_pi(
215 &self,
216 current_task: &CurrentTask,
217 addr: UserAddress,
218 deadline: zx::MonotonicInstant,
219 ) -> Result<(), Errno> {
220 let addr = FutexAddress::try_from(addr)?;
221 let mm = current_task.mm()?;
222 if let Ok(current) = mm.atomic_load_u32_relaxed(addr) {
228 let _ = mm.atomic_compare_exchange_u32_acq_rel(addr, current, current);
229 }
230 let mut state = self.state.lock();
231 let key = Key::get(current_task, addr)?;
234
235 let tid = current_task.get_tid() as u32;
236
237 let mut current_value = mm.atomic_load_u32_relaxed(addr)?;
241 let new_owner_tid = loop {
242 let new_owner_tid = current_value & FUTEX_TID_MASK;
243 if new_owner_tid == tid {
244 return error!(EDEADLOCK);
251 }
252
253 if current_value == 0 {
254 match mm.atomic_compare_exchange_weak_u32_acq_rel(addr, current_value, tid) {
257 CompareExchangeResult::Success => return Ok(()),
258 CompareExchangeResult::Stale { observed } => {
259 current_value = observed;
260 continue;
261 }
262 CompareExchangeResult::Error(e) => return Err(e),
263 }
264 }
265
266 let target_value = current_value | FUTEX_WAITERS;
269 match mm.atomic_compare_exchange_u32_acq_rel(addr, current_value, target_value) {
270 CompareExchangeResult::Success => (),
271 CompareExchangeResult::Stale { observed } => {
272 current_value = observed;
273 continue;
274 }
275 CompareExchangeResult::Error(e) => return Err(e),
276 }
277 break new_owner_tid;
278 };
279
280 let event = InterruptibleEvent::new();
281 let guard = event.begin_wait();
282 let notifiable = FutexNotifiable::new_internal(Arc::downgrade(&event));
283 state
284 .get_rt_mutex_waiters_or_default(key.clone())
285 .push_back(RtMutexWaiter { tid, notifiable });
286 std::mem::drop(state);
287
288 let result = current_task
292 .get_task(new_owner_tid as i32)
293 .ok()
294 .and_then(|o| o.running_state().unwrap().thread.get().map(|t| Arc::clone(&t.thread)))
295 .map_or_else(
296 || error!(ESRCH),
297 |owner| current_task.block_with_owner_until(guard, &owner, deadline),
298 );
299
300 self.resolve_wait(result, |state| {
305 state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event))
306 })
307 }
308
309 pub fn unlock_pi(&self, current_task: &CurrentTask, addr: UserAddress) -> Result<(), Errno> {
313 let addr = FutexAddress::try_from(addr)?;
314 let mm = current_task.mm()?;
315 if let Ok(current) = mm.atomic_load_u32_relaxed(addr) {
321 let _ = mm.atomic_compare_exchange_u32_acq_rel(addr, current, current);
322 }
323 let mut state = self.state.lock();
324 let tid = current_task.get_tid() as u32;
325
326 let key = Key::get(current_task, addr)?;
327
328 let mut expected_value = mm.atomic_load_u32_relaxed(addr)?;
332 if expected_value & FUTEX_TID_MASK != tid {
333 return error!(EPERM);
338 }
339
340 loop {
341 let maybe_waiter = state.pop_rt_mutex_waiter(key.clone());
342 let target_value = maybe_waiter.as_ref().map_or(0, |waiter| waiter.tid);
343
344 let handoff =
347 mm.atomic_compare_exchange_u32_acq_rel(addr, expected_value, target_value);
348 if let Err(e) = handoff_result(handoff) {
349 if let Some(waiter) = maybe_waiter {
350 state.unpop_rt_mutex_waiter(key, waiter);
351 }
352 return Err(e);
353 }
354 expected_value = target_value;
357
358 let Some(mut waiter) = maybe_waiter else {
359 break;
361 };
362
363 if waiter.notifiable.notify() {
364 break;
365 }
366
367 }
370
371 Ok(())
372 }
373}
374
375fn handoff_result(result: CompareExchangeResult<u32>) -> Result<(), Errno> {
377 match result {
378 CompareExchangeResult::Success => Ok(()),
379 CompareExchangeResult::Stale { .. } => error!(EINVAL),
388 CompareExchangeResult::Error(_) => error!(EACCES),
392 }
393}
394
395impl FutexTable<SharedFutexKey> {
396 pub fn external_wait(
406 &self,
407 memory: MemoryObject,
408 offset: u64,
409 value: u32,
410 mask: u32,
411 ) -> Result<(Arc<()>, oneshot::Receiver<()>), Errno> {
412 let key = SharedFutexKey::new(&memory, offset);
413 let mut state = self.state.lock();
414 Self::external_check_futex_value(&memory, offset, value)?;
416
417 let token = Arc::new(());
418 let (sender, receiver) = oneshot::channel::<()>();
419 state.get_waiters_or_default(key).add(FutexWaiter {
420 mask,
421 notifiable: FutexNotifiable::new_external(Arc::downgrade(&token), sender),
422 });
423 Ok((token, receiver))
424 }
425
426 pub fn external_wake(
431 &self,
432 memory: MemoryObject,
433 offset: u64,
434 count: usize,
435 mask: u32,
436 ) -> Result<usize, Errno> {
437 Ok(self.state.lock().wake(SharedFutexKey::new(&memory, offset), count, mask))
438 }
439
440 pub fn external_requeue(
441 &self,
442 first_memory: MemoryObject,
443 first_offset: u64,
444 second_memory: Option<MemoryObject>,
445 second_offset: u64,
446 wake_count: usize,
447 requeue_count: usize,
448 expected_value: Option<u32>,
449 ) -> Result<usize, Errno> {
450 let first_key = SharedFutexKey::new(&first_memory, first_offset);
451 let second_key = match second_memory.as_ref() {
452 Some(second_memory) => SharedFutexKey::new(second_memory, second_offset),
453 None => SharedFutexKey::new(&first_memory, second_offset),
454 };
455 let mut state = self.state.lock();
462 if let Some(expected) = expected_value {
463 Self::external_check_futex_value(&first_memory, first_offset, expected)?;
465 }
466 Ok(state.requeue(first_key, second_key, wake_count, requeue_count))
467 }
468
469 fn external_check_futex_value(
470 memory: &MemoryObject,
471 offset: u64,
472 value: u32,
473 ) -> Result<(), Errno> {
474 let loaded_value = {
475 let mut buf = [0u8; 4];
477 memory.read(&mut buf, offset).map_err(|_| errno!(EINVAL))?;
478 u32::from_ne_bytes(buf)
479 };
480 if loaded_value != value {
481 return error!(EAGAIN);
482 }
483 Ok(())
484 }
485}
486
487pub trait FutexKey: Sized + Ord + Hash + Clone {
488 fn get(task: &Task, addr: FutexAddress) -> Result<Self, Errno>;
489 fn get_table_from_task(task: &Task) -> Result<Arc<FutexTable<Self>>, Errno>;
490}
491
492#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
493pub struct PrivateFutexKey {
494 addr: FutexAddress,
495}
496
497impl FutexKey for PrivateFutexKey {
498 fn get(_task: &Task, addr: FutexAddress) -> Result<Self, Errno> {
499 Ok(PrivateFutexKey { addr })
500 }
501
502 fn get_table_from_task(task: &Task) -> Result<Arc<FutexTable<Self>>, Errno> {
503 Ok(task.mm()?.futex.clone())
504 }
505}
506
507#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
508pub struct SharedFutexKey {
509 koid: zx::Koid,
512 offset: u64,
513}
514
515impl FutexKey for SharedFutexKey {
516 fn get(task: &Task, addr: FutexAddress) -> Result<Self, Errno> {
517 let (memory, offset) = task.mm()?.get_mapping_memory(addr.into(), ProtectionFlags::READ)?;
518 Ok(SharedFutexKey::new(&memory, offset))
519 }
520
521 fn get_table_from_task(task: &Task) -> Result<Arc<FutexTable<Self>>, Errno> {
522 Ok(task.kernel().shared_futexes.clone())
523 }
524}
525
526impl SharedFutexKey {
527 fn new(memory: &MemoryObject, offset: u64) -> Self {
528 Self { koid: memory.get_koid(), offset }
529 }
530}
531
532struct FutexTableState<Key: FutexKey> {
533 waiters: HashMap<Key, FutexWaiters>,
534 rt_mutex_waiters: HashMap<Key, VecDeque<RtMutexWaiter>>,
535}
536
537impl<Key: FutexKey> Default for FutexTableState<Key> {
538 fn default() -> Self {
539 Self { waiters: Default::default(), rt_mutex_waiters: Default::default() }
540 }
541}
542
543impl<Key: FutexKey> FutexTableState<Key> {
544 fn get_waiters_or_default(&mut self, key: Key) -> &mut FutexWaiters {
546 self.waiters.entry(key).or_default()
547 }
548
549 fn wake(&mut self, key: Key, count: usize, mask: u32) -> usize {
550 let entry = self.waiters.entry(key);
551 match entry {
552 Entry::Vacant(_) => 0,
553 Entry::Occupied(mut entry) => {
554 let count = entry.get_mut().notify(mask, count);
555 if entry.get().is_empty() {
556 entry.remove();
557 }
558 count
559 }
560 }
561 }
562
563 fn requeue(
564 &mut self,
565 key: Key,
566 new_key: Key,
567 wake_count: usize,
568 requeue_count: usize,
569 ) -> usize {
570 let woken;
571 let to_requeue;
572 match self.waiters.entry(key) {
573 Entry::Vacant(_) => return 0,
574 Entry::Occupied(mut entry) => {
575 woken = entry.get_mut().notify(FUTEX_BITSET_MATCH_ANY, wake_count);
577
578 to_requeue = entry.get_mut().split_for_requeue(requeue_count);
580
581 if entry.get().is_empty() {
582 entry.remove();
583 }
584 }
585 }
586
587 let requeued = to_requeue.0.len();
588 if !to_requeue.is_empty() {
589 self.get_waiters_or_default(new_key).transfer(to_requeue);
590 }
591
592 woken + requeued
593 }
594
595 fn get_rt_mutex_waiters_or_default(&mut self, key: Key) -> &mut VecDeque<RtMutexWaiter> {
598 self.rt_mutex_waiters.entry(key).or_default()
599 }
600
601 fn pop_rt_mutex_waiter(&mut self, key: Key) -> Option<RtMutexWaiter> {
603 let entry = self.rt_mutex_waiters.entry(key);
604 match entry {
605 Entry::Vacant(_) => None,
606 Entry::Occupied(mut entry) => {
607 let mut waiter = entry.get_mut().pop_front();
608 if entry.get().is_empty() {
612 entry.remove();
613 } else if let Some(waiter) = &mut waiter {
614 waiter.tid |= FUTEX_WAITERS;
615 }
616 waiter
617 }
618 }
619 }
620
621 fn unpop_rt_mutex_waiter(&mut self, key: Key, mut waiter: RtMutexWaiter) {
627 waiter.tid &= FUTEX_TID_MASK;
628 self.get_rt_mutex_waiters_or_default(key).push_front(waiter);
629 }
630
631 fn remove_waiter_from_queue(&mut self, key: Key, matcher: &WaiterMatcher<'_>) -> bool {
636 search_and_remove_waiter(&mut self.waiters, key, matcher)
637 }
638
639 fn remove_rt_mutex_waiter_from_queue(&mut self, key: Key, matcher: &WaiterMatcher<'_>) -> bool {
644 search_and_remove_waiter(&mut self.rt_mutex_waiters, key, matcher)
645 }
646}
647
648fn search_and_remove_waiter<Key: FutexKey, Queue: WaiterQueue>(
661 queues: &mut HashMap<Key, Queue>,
662 key: Key,
663 matcher: &WaiterMatcher<'_>,
664) -> bool {
665 if let Entry::Occupied(mut entry) = queues.entry(key) {
666 let found = entry.get_mut().remove_waiter(matcher);
667 if entry.get().is_empty() {
668 entry.remove();
669 }
670 if found {
671 return true;
672 }
673 }
674
675 let mut found = false;
678 queues.retain(|_, waiters| {
679 if !found {
680 found = waiters.remove_waiter(matcher);
681 }
682 !waiters.is_empty()
683 });
684 found
685}
686
687trait WaiterQueue {
689 fn remove_waiter(&mut self, matcher: &WaiterMatcher<'_>) -> bool;
696
697 fn is_empty(&self) -> bool;
699}
700
701enum WaiterMatcher<'a> {
706 Event(&'a Arc<InterruptibleEvent>),
708
709 BootWaiter(&'a Arc<Waiter>),
711}
712
713impl WaiterMatcher<'_> {
714 fn matches(&self, notifiable: &FutexNotifiable) -> bool {
716 match (self, notifiable) {
717 (Self::Event(event), FutexNotifiable::Internal(weak)) => {
718 weak.upgrade().is_some_and(|strong| Arc::ptr_eq(&strong, event))
719 }
720 (Self::BootWaiter(waiter), FutexNotifiable::InternalBoot(weak)) => {
721 weak.upgrade().is_some_and(|strong| Arc::ptr_eq(&strong, waiter))
722 }
723 _ => false,
724 }
725 }
726}
727
728enum FutexNotifiable {
730 Internal(Weak<InterruptibleEvent>),
732 InternalBoot(Weak<Waiter>),
734 External(Weak<()>, Option<oneshot::Sender<()>>),
738}
739
740impl FutexNotifiable {
741 fn new_internal(event: Weak<InterruptibleEvent>) -> Self {
742 Self::Internal(event)
743 }
744
745 fn new_internal_boot(waiter: Weak<Waiter>) -> Self {
746 Self::InternalBoot(waiter)
747 }
748
749 fn new_external(token: Weak<()>, sender: oneshot::Sender<()>) -> Self {
750 Self::External(token, Some(sender))
751 }
752
753 fn notify(&mut self) -> bool {
756 match self {
757 Self::Internal(event) => {
758 if let Some(event) = event.upgrade() {
759 event.notify();
760 true
761 } else {
762 false
763 }
764 }
765 Self::InternalBoot(waiter) => {
766 if let Some(waiter) = waiter.upgrade() {
767 waiter.notify();
768 true
769 } else {
770 false
771 }
772 }
773 Self::External(_, sender) => {
774 if let Some(sender) = sender.take() {
775 sender.send(()).is_ok()
776 } else {
777 false
778 }
779 }
780 }
781 }
782
783 fn is_stale(&self) -> bool {
784 match self {
785 Self::Internal(weak) => weak.strong_count() == 0,
786 Self::External(weak, _) => weak.strong_count() == 0,
787 Self::InternalBoot(weak) => weak.strong_count() == 0,
788 }
789 }
790}
791
792struct FutexWaiter {
793 mask: u32,
794 notifiable: FutexNotifiable,
795}
796
797#[derive(Default)]
798struct FutexWaiters(VecDeque<FutexWaiter>);
799
800impl FutexWaiters {
801 fn add(&mut self, waiter: FutexWaiter) {
802 self.0.push_back(waiter);
803 }
804
805 fn notify(&mut self, mask: u32, count: usize) -> usize {
806 let mut woken = 0;
807 self.0.retain_mut(|waiter| {
808 if woken == count || waiter.mask & mask == 0 {
809 return true;
810 }
811 if waiter.notifiable.notify() {
814 woken += 1;
815 }
816 false
817 });
818 woken
819 }
820
821 fn transfer(&mut self, mut other: Self) {
822 self.0.append(&mut other.0);
823 }
824
825 fn split_for_requeue(&mut self, count: usize) -> Self {
826 let count = std::cmp::min(count, self.0.len());
827 let tail = self.0.split_off(count);
828 let head = std::mem::replace(&mut self.0, tail);
829 FutexWaiters(head)
830 }
831}
832
833trait QueuedWaiter {
835 fn notifiable(&self) -> &FutexNotifiable;
836}
837
838impl QueuedWaiter for FutexWaiter {
839 fn notifiable(&self) -> &FutexNotifiable {
840 &self.notifiable
841 }
842}
843
844impl QueuedWaiter for RtMutexWaiter {
845 fn notifiable(&self) -> &FutexNotifiable {
846 &self.notifiable
847 }
848}
849
850impl<W: QueuedWaiter> WaiterQueue for VecDeque<W> {
851 fn remove_waiter(&mut self, matcher: &WaiterMatcher<'_>) -> bool {
852 let mut found = false;
853 self.retain(|w| {
854 if matcher.matches(w.notifiable()) {
855 found = true;
856 return false;
857 }
858 !w.notifiable().is_stale()
859 });
860 found
861 }
862
863 fn is_empty(&self) -> bool {
864 VecDeque::is_empty(self)
865 }
866}
867
868impl WaiterQueue for FutexWaiters {
869 fn remove_waiter(&mut self, matcher: &WaiterMatcher<'_>) -> bool {
870 self.0.remove_waiter(matcher)
871 }
872
873 fn is_empty(&self) -> bool {
874 self.0.is_empty()
875 }
876}
877
878struct RtMutexWaiter {
879 tid: u32,
881
882 notifiable: FutexNotifiable,
883}
884
885#[cfg(test)]
886mod tests {
887 use super::*;
888 use starnix_sync::InterruptibleEvent;
889 use starnix_uapi::restricted_aspace::RESTRICTED_ASPACE_BASE;
890 use starnix_uapi::user_address::UserAddress;
891
892 #[fuchsia::test]
893 fn test_remove_waiter_simple() {
894 let mut state = FutexTableState::<PrivateFutexKey>::default();
895 let key = PrivateFutexKey {
896 addr: FutexAddress::try_from(UserAddress::from(
897 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
898 ))
899 .unwrap(),
900 };
901 let event = Arc::new(InterruptibleEvent::new());
902
903 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
904 mask: u32::MAX,
905 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
906 });
907
908 assert_eq!(state.waiters.len(), 1);
909 assert!(state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
910 assert_eq!(state.waiters.len(), 0);
911 }
912
913 #[fuchsia::test]
914 fn test_remove_waiter_requeued() {
915 let mut state = FutexTableState::<PrivateFutexKey>::default();
916 let key1 = PrivateFutexKey {
917 addr: FutexAddress::try_from(UserAddress::from(
918 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
919 ))
920 .unwrap(),
921 };
922 let key2 = PrivateFutexKey {
923 addr: FutexAddress::try_from(UserAddress::from(
924 (RESTRICTED_ASPACE_BASE + 0x2000) as u64,
925 ))
926 .unwrap(),
927 };
928 let event = Arc::new(InterruptibleEvent::new());
929
930 state.get_waiters_or_default(key2.clone()).add(FutexWaiter {
931 mask: u32::MAX,
932 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
933 });
934
935 assert_eq!(state.waiters.len(), 1);
936 assert!(state.remove_waiter_from_queue(key1, &WaiterMatcher::Event(&event)));
937 assert_eq!(state.waiters.len(), 0);
938 }
939
940 #[fuchsia::test]
946 fn test_wake_racing_with_interruption_is_not_lost() {
947 let mut state = FutexTableState::<PrivateFutexKey>::default();
948 let key = PrivateFutexKey {
949 addr: FutexAddress::try_from(UserAddress::from(
950 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
951 ))
952 .unwrap(),
953 };
954 let event = InterruptibleEvent::new();
955 let _guard = event.begin_wait();
956
957 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
958 mask: u32::MAX,
959 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
960 });
961
962 event.interrupt();
964
965 assert_eq!(state.wake(key.clone(), 1, FUTEX_BITSET_MATCH_ANY), 1);
967
968 assert!(!state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
971 }
972
973 #[fuchsia::test]
975 fn test_wake_racing_with_boot_waiter_removal_is_not_lost() {
976 let mut state = FutexTableState::<PrivateFutexKey>::default();
977 let key = PrivateFutexKey {
978 addr: FutexAddress::try_from(UserAddress::from(
979 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
980 ))
981 .unwrap(),
982 };
983 let waiter = Arc::new(Waiter::new());
984
985 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
986 mask: u32::MAX,
987 notifiable: FutexNotifiable::new_internal_boot(Arc::downgrade(&waiter)),
988 });
989
990 assert_eq!(state.wake(key.clone(), 1, FUTEX_BITSET_MATCH_ANY), 1);
993
994 assert!(!state.remove_waiter_from_queue(key, &WaiterMatcher::BootWaiter(&waiter)));
995 }
996
997 #[fuchsia::test]
1002 fn test_remove_waiter_ignores_other_waiter_kinds() {
1003 let mut state = FutexTableState::<PrivateFutexKey>::default();
1004 let key = PrivateFutexKey {
1005 addr: FutexAddress::try_from(UserAddress::from(
1006 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1007 ))
1008 .unwrap(),
1009 };
1010 let event = InterruptibleEvent::new();
1011 let waiter = Arc::new(Waiter::new());
1012
1013 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
1014 mask: u32::MAX,
1015 notifiable: FutexNotifiable::new_internal_boot(Arc::downgrade(&waiter)),
1016 });
1017
1018 assert!(!state.remove_waiter_from_queue(key.clone(), &WaiterMatcher::Event(&event)));
1019 assert_eq!(state.waiters.len(), 1);
1020
1021 assert!(state.remove_waiter_from_queue(key, &WaiterMatcher::BootWaiter(&waiter)));
1022 assert_eq!(state.waiters.len(), 0);
1023 }
1024
1025 #[fuchsia::test]
1026 fn test_remove_rt_mutex_waiter() {
1027 let mut state = FutexTableState::<PrivateFutexKey>::default();
1028 let key = PrivateFutexKey {
1029 addr: FutexAddress::try_from(UserAddress::from(
1030 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1031 ))
1032 .unwrap(),
1033 };
1034 let event = Arc::new(InterruptibleEvent::new());
1035
1036 state.get_rt_mutex_waiters_or_default(key.clone()).push_back(RtMutexWaiter {
1037 tid: 1,
1038 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
1039 });
1040
1041 assert_eq!(state.rt_mutex_waiters.len(), 1);
1042 state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event));
1043 assert_eq!(state.rt_mutex_waiters.len(), 0);
1044 }
1045
1046 #[fuchsia::test]
1051 fn test_remove_rt_mutex_waiter_reports_whether_it_was_queued() {
1052 let mut state = FutexTableState::<PrivateFutexKey>::default();
1053 let key = PrivateFutexKey {
1054 addr: FutexAddress::try_from(UserAddress::from(
1055 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1056 ))
1057 .unwrap(),
1058 };
1059 let event = InterruptibleEvent::new();
1060 let queue_waiter = |state: &mut FutexTableState<PrivateFutexKey>| {
1061 state.get_rt_mutex_waiters_or_default(key.clone()).push_back(RtMutexWaiter {
1062 tid: 1,
1063 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&event)),
1064 });
1065 };
1066
1067 queue_waiter(&mut state);
1068 assert!(
1069 state.remove_rt_mutex_waiter_from_queue(key.clone(), &WaiterMatcher::Event(&event))
1070 );
1071
1072 queue_waiter(&mut state);
1074 assert!(state.pop_rt_mutex_waiter(key.clone()).is_some());
1075
1076 assert!(!state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
1077 }
1078
1079 #[fuchsia::test]
1084 fn test_remove_rt_mutex_waiter_stale_cleanup_is_not_a_match() {
1085 let mut state = FutexTableState::<PrivateFutexKey>::default();
1086 let key = PrivateFutexKey {
1087 addr: FutexAddress::try_from(UserAddress::from(
1088 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1089 ))
1090 .unwrap(),
1091 };
1092
1093 {
1094 let dead_event = InterruptibleEvent::new();
1095 state.get_rt_mutex_waiters_or_default(key.clone()).push_back(RtMutexWaiter {
1096 tid: 1,
1097 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&dead_event)),
1098 });
1099 } let event = InterruptibleEvent::new();
1102 assert!(!state.remove_rt_mutex_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
1103 assert_eq!(state.rt_mutex_waiters.len(), 0, "the stale waiter should be collected");
1104 }
1105
1106 #[fuchsia::test]
1109 fn test_remove_waiter_collects_queues_emptied_by_the_scan() {
1110 let mut state = FutexTableState::<PrivateFutexKey>::default();
1111 let stale_key = PrivateFutexKey {
1112 addr: FutexAddress::try_from(UserAddress::from(
1113 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1114 ))
1115 .unwrap(),
1116 };
1117 let key = PrivateFutexKey {
1118 addr: FutexAddress::try_from(UserAddress::from(
1119 (RESTRICTED_ASPACE_BASE + 0x2000) as u64,
1120 ))
1121 .unwrap(),
1122 };
1123
1124 {
1125 let dead_event = InterruptibleEvent::new();
1126 state.get_waiters_or_default(stale_key).add(FutexWaiter {
1127 mask: u32::MAX,
1128 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&dead_event)),
1129 });
1130 } let event = InterruptibleEvent::new();
1134 assert!(!state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&event)));
1135 assert_eq!(state.waiters.len(), 0, "the emptied queue should be collected");
1136 }
1137
1138 #[fuchsia::test]
1139 fn test_split_for_requeue_fairness() {
1140 let mut waiters = FutexWaiters::default();
1141 let e1 = Arc::new(InterruptibleEvent::new());
1142 let e2 = Arc::new(InterruptibleEvent::new());
1143 let e3 = Arc::new(InterruptibleEvent::new());
1144
1145 waiters.add(FutexWaiter {
1146 mask: 1,
1147 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&e1)),
1148 });
1149 waiters.add(FutexWaiter {
1150 mask: 2,
1151 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&e2)),
1152 });
1153 waiters.add(FutexWaiter {
1154 mask: 3,
1155 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&e3)),
1156 });
1157
1158 let split = waiters.split_for_requeue(2);
1159
1160 assert_eq!(split.0.len(), 2);
1161 assert_eq!(split.0[0].mask, 1);
1162 assert_eq!(split.0[1].mask, 2);
1163
1164 assert_eq!(waiters.0.len(), 1);
1165 assert_eq!(waiters.0[0].mask, 3);
1166 }
1167
1168 #[fuchsia::test]
1169 fn test_stale_external_waiter_cleanup() {
1170 let mut state = FutexTableState::<PrivateFutexKey>::default();
1171 let key = PrivateFutexKey {
1172 addr: FutexAddress::try_from(UserAddress::from(
1173 (RESTRICTED_ASPACE_BASE + 0x1000) as u64,
1174 ))
1175 .unwrap(),
1176 };
1177
1178 {
1179 let token = Arc::new(());
1180 let (sender, _receiver) = oneshot::channel::<()>();
1181 state.get_waiters_or_default(key.clone()).add(FutexWaiter {
1182 mask: u32::MAX,
1183 notifiable: FutexNotifiable::new_external(Arc::downgrade(&token), sender),
1184 });
1185 } assert_eq!(state.waiters.len(), 1);
1188
1189 let dummy_event = InterruptibleEvent::new();
1191 state.remove_waiter_from_queue(key, &WaiterMatcher::Event(&dummy_event));
1192
1193 assert_eq!(state.waiters.len(), 0, "Stale external waiter should be removed");
1194 }
1195
1196 #[::fuchsia::test]
1203 async fn test_unlock_pi_hands_over_to_next_waiter_after_a_stale_one() {
1204 use crate::mm::memory::MemoryObject;
1205 use crate::mm::{DesiredAddress, MappingName, MappingOptions, PAGE_SIZE, ProtectionFlags};
1206 use crate::testing::spawn_kernel_and_run;
1207
1208 spawn_kernel_and_run(async move |current_task| {
1209 let mm = current_task.mm().unwrap();
1210 let addr = mm
1211 .map_memory(
1212 DesiredAddress::Any,
1213 Arc::new(MemoryObject::from(zx::Vmo::create(*PAGE_SIZE).unwrap())),
1214 0,
1215 *PAGE_SIZE as usize,
1216 ProtectionFlags::READ | ProtectionFlags::WRITE,
1217 MappingOptions::empty(),
1218 MappingName::None,
1219 )
1220 .expect("map failed");
1221 let futex_addr = FutexAddress::try_from(addr).unwrap();
1222
1223 let owner_tid = current_task.get_tid() as u32;
1225 assert!(matches!(
1226 mm.atomic_compare_exchange_u32_acq_rel(futex_addr, 0, owner_tid | FUTEX_WAITERS),
1227 CompareExchangeResult::Success
1228 ));
1229
1230 const STALE_TID: u32 = 0x111;
1231 const NEXT_OWNER_TID: u32 = 0x222;
1232 let futex_table = FutexTable::<PrivateFutexKey>::default();
1233 let key = PrivateFutexKey::get(current_task, futex_addr).unwrap();
1234 let next_owner_event = InterruptibleEvent::new();
1235 {
1236 let mut state = futex_table.state.lock();
1237 let queue = state.get_rt_mutex_waiters_or_default(key);
1238 {
1239 let dead_event = InterruptibleEvent::new();
1240 queue.push_back(RtMutexWaiter {
1241 tid: STALE_TID,
1242 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&dead_event)),
1243 });
1244 } queue.push_back(RtMutexWaiter {
1246 tid: NEXT_OWNER_TID,
1247 notifiable: FutexNotifiable::new_internal(Arc::downgrade(&next_owner_event)),
1248 });
1249 }
1250
1251 futex_table.unlock_pi(current_task, addr).expect("unlock_pi failed");
1252
1253 assert_eq!(
1254 mm.atomic_load_u32_relaxed(futex_addr).unwrap(),
1255 NEXT_OWNER_TID,
1256 "the mutex should have been handed to the waiter behind the stale one"
1257 );
1258 assert!(futex_table.state.lock().rt_mutex_waiters.is_empty());
1259 })
1260 .await;
1261 }
1262
1263 #[::fuchsia::test]
1264 async fn test_futex_deadlock_with_pager() {
1265 use crate::mm::memory::MemoryObject;
1266 use crate::mm::{DesiredAddress, MappingName, MappingOptions, PAGE_SIZE, ProtectionFlags};
1267 use crate::testing::spawn_kernel_and_run;
1268 use std::sync::atomic::{AtomicBool, Ordering};
1269 use zx::sys::zx_page_request_command_t::ZX_PAGER_VMO_READ;
1270
1271 spawn_kernel_and_run(async move |current_task| {
1272 let mm = current_task.mm().unwrap();
1273
1274 let port = Arc::new(zx::Port::create());
1275 let port_clone = port.clone();
1276 let pager =
1277 Arc::new(zx::Pager::create(zx::PagerOptions::empty()).expect("create failed"));
1278 let pager_clone = pager.clone();
1279
1280 let vmo = Arc::new(
1281 pager
1282 .create_vmo(zx::VmoOptions::RESIZABLE, &port, 1, *PAGE_SIZE)
1283 .expect("create_vmo failed"),
1284 );
1285 let vmo_clone = vmo.clone();
1286
1287 let mapped_addr = mm
1288 .map_memory(
1289 DesiredAddress::Any,
1290 Arc::new(MemoryObject::from(
1291 (*vmo).duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1292 )),
1293 0,
1294 *PAGE_SIZE as usize,
1295 ProtectionFlags::READ | ProtectionFlags::WRITE,
1296 MappingOptions::empty(),
1297 MappingName::None,
1298 )
1299 .expect("map failed");
1300
1301 let futex_table = Arc::new(FutexTable::<PrivateFutexKey>::default());
1302 let futex_table_clone = futex_table.clone();
1303 let task_clone = current_task.task.clone();
1304 let dummy_addr = UserAddress::from((RESTRICTED_ASPACE_BASE + 0x2000) as u64);
1305
1306 let page_requested = Arc::new(AtomicBool::new(false));
1307 let wake_completed = Arc::new(AtomicBool::new(false));
1308
1309 let page_req_clone = page_requested.clone();
1310 let wake_completed_clone = wake_completed.clone();
1311
1312 let pager_thread = std::thread::spawn(move || {
1313 let packet = port_clone.wait(zx::MonotonicInstant::INFINITE).expect("wait failed");
1314 if let zx::PacketContents::Pager(contents) = packet.contents() {
1315 if contents.command() == ZX_PAGER_VMO_READ {
1316 let range = contents.range();
1317 page_req_clone.store(true, Ordering::SeqCst);
1318
1319 let waker = std::thread::spawn(move || {
1321 let _ = futex_table_clone.wake(&task_clone, dummy_addr, 1, u32::MAX);
1322 wake_completed_clone.store(true, Ordering::SeqCst);
1323 });
1324
1325 waker.join().unwrap();
1327 assert!(
1328 wake_completed.load(Ordering::SeqCst),
1329 "Waker thread must NOT be blocked while page fault is in progress!"
1330 );
1331
1332 let source_vmo =
1334 zx::Vmo::create(range.end - range.start).expect("create failed");
1335 pager_clone
1336 .supply_pages(&vmo_clone, range, &source_vmo, 0)
1337 .expect("supply_pages failed");
1338 }
1339 }
1340 });
1341
1342 let _ = futex_table.wait(
1344 current_task,
1345 mapped_addr,
1346 0,
1347 u32::MAX,
1348 zx::MonotonicInstant::from_nanos(1),
1349 );
1350
1351 pager_thread.join().unwrap();
1352 })
1353 .await;
1354 }
1355
1356 #[::fuchsia::test]
1357 async fn test_wait_expired_deadline_returns_etimedout_without_queuing() {
1358 use crate::mm::memory::MemoryObject;
1359 use crate::mm::{DesiredAddress, MappingName, MappingOptions, PAGE_SIZE, ProtectionFlags};
1360 use crate::testing::spawn_kernel_and_run;
1361
1362 spawn_kernel_and_run(async move |current_task| {
1363 let mm = current_task.mm().unwrap();
1364 let addr = mm
1365 .map_memory(
1366 DesiredAddress::Any,
1367 Arc::new(MemoryObject::from(zx::Vmo::create(*PAGE_SIZE).unwrap())),
1368 0,
1369 *PAGE_SIZE as usize,
1370 ProtectionFlags::READ | ProtectionFlags::WRITE,
1371 MappingOptions::empty(),
1372 MappingName::None,
1373 )
1374 .expect("map failed");
1375
1376 let futex_table = FutexTable::<PrivateFutexKey>::default();
1377
1378 assert_eq!(
1379 futex_table.wait(
1380 current_task,
1381 addr,
1382 0,
1383 FUTEX_BITSET_MATCH_ANY,
1384 zx::MonotonicInstant::ZERO,
1385 ),
1386 error!(ETIMEDOUT)
1387 );
1388 assert_eq!(
1389 futex_table.wait(
1390 current_task,
1391 addr,
1392 0,
1393 FUTEX_BITSET_MATCH_ANY,
1394 zx::MonotonicInstant::get(),
1395 ),
1396 error!(ETIMEDOUT)
1397 );
1398 assert_eq!(
1399 futex_table.wait_boot(
1400 current_task,
1401 addr,
1402 0,
1403 FUTEX_BITSET_MATCH_ANY,
1404 zx::BootInstant::ZERO,
1405 zx::BootDuration::ZERO,
1406 ),
1407 error!(ETIMEDOUT)
1408 );
1409 assert_eq!(
1410 futex_table.wait_boot(
1411 current_task,
1412 addr,
1413 0,
1414 FUTEX_BITSET_MATCH_ANY,
1415 zx::BootInstant::get(),
1416 zx::BootDuration::ZERO,
1417 ),
1418 error!(ETIMEDOUT)
1419 );
1420 assert!(futex_table.state.lock().waiters.is_empty());
1421
1422 assert_eq!(
1424 futex_table.wait(
1425 current_task,
1426 addr,
1427 1,
1428 FUTEX_BITSET_MATCH_ANY,
1429 zx::MonotonicInstant::ZERO,
1430 ),
1431 error!(EAGAIN)
1432 );
1433 assert_eq!(
1434 futex_table.wait_boot(
1435 current_task,
1436 addr,
1437 1,
1438 FUTEX_BITSET_MATCH_ANY,
1439 zx::BootInstant::ZERO,
1440 zx::BootDuration::ZERO,
1441 ),
1442 error!(EAGAIN)
1443 );
1444 assert!(futex_table.state.lock().waiters.is_empty());
1445 })
1446 .await;
1447 }
1448}