1use crate::error::Result;
14use crate::sched::thread::{self, Id};
15use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
16
17const UNARMED: usize = 0;
19
20pub struct ParkedWaiter {
21 uid: AtomicUsize,
22}
23
24impl ParkedWaiter {
25 pub const fn new() -> Self {
26 Self {
27 uid: AtomicUsize::new(UNARMED),
28 }
29 }
30
31 pub fn arm(&self, uid: usize) -> Result<()> {
32 if uid == UNARMED {
33 return Err(kerr!(EINVAL, "ParkedWaiter::arm requires non-zero uid"));
34 }
35 self.uid
36 .compare_exchange(UNARMED, uid, Ordering::Release, Ordering::Relaxed)
37 .map(|_| ())
38 .map_err(|_| kerr!(EBUSY, "ParkedWaiter already armed"))
39 }
40
41 pub fn disarm(&self) {
42 self.uid.store(UNARMED, Ordering::Release);
43 }
44
45 pub fn park_current(&self) -> Result<()> {
48 let uid = crate::sched::with(|s| s.current_uid())
49 .ok_or_else(|| kerr!(EINVAL, "park_current with no current thread"))?;
50 if uid == UNARMED {
51 return Err(kerr!(EINVAL, "idle thread cannot park"));
52 }
53 self.park(uid)
54 }
55
56 pub fn park(&self, uid: usize) -> Result<()> {
59 crate::sync::atomic::irq_free(|| -> Result<()> {
63 self.arm(uid)?;
64 let tid = thread::UId::new(uid, thread::Id::new(0, crate::sched::task::UId::new(0)));
65 crate::sched::with(|s| {
66 if s.sleep_until(Some(tid), u64::MAX, crate::time::tick())
67 .is_err()
68 {
69 bug!("park with no current thread despite armed uid");
70 }
71 });
72 Ok(())
73 })?;
74 self.disarm();
75 Ok(())
76 }
77
78 pub fn wake(&self) {
80 let uid = self.uid.load(Ordering::Acquire);
81 if uid != UNARMED {
82 crate::sched::kick_thread(uid as u32);
83 }
84 }
85}