1 use crate::sync::atomic::AtomicI32;
2 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
3 use crate::time::Duration;
5 const PARKED: i32 = -1;
7 const NOTIFIED: i32 = 1;
15 pub const fn new() -> Self {
16 Parker { state: AtomicI32::new(EMPTY) }
19 // Assumes this is only called by the thread that owns the Parker,
20 // which means that `self.state != PARKED`.
21 pub unsafe fn park(&self) {
22 // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
24 if self.state.fetch_sub(1, Acquire) == NOTIFIED {
28 // Wait for something to happen, assuming it's still set to PARKED.
29 futex_wait(&self.state, PARKED, None);
30 // Change NOTIFIED=>EMPTY and return in that case.
31 if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
34 // Spurious wake up. We loop to try again.
39 // Assumes this is only called by the thread that owns the Parker,
40 // which means that `self.state != PARKED`.
41 pub unsafe fn park_timeout(&self, timeout: Duration) {
42 // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
44 if self.state.fetch_sub(1, Acquire) == NOTIFIED {
47 // Wait for something to happen, assuming it's still set to PARKED.
48 futex_wait(&self.state, PARKED, Some(timeout));
49 // This is not just a store, because we need to establish a
50 // release-acquire ordering with unpark().
51 if self.state.swap(EMPTY, Acquire) == NOTIFIED {
52 // Woke up because of unpark().
54 // Timeout or spurious wake up.
55 // We return either way, because we can't easily tell if it was the
61 pub fn unpark(&self) {
62 // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
63 // wake the thread in the first case.
65 // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
66 // purpose, to make sure every unpark() has a release-acquire ordering
68 if self.state.swap(NOTIFIED, Release) == PARKED {
69 futex_wake(&self.state);
74 fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
76 let timespec_ptr = match timeout {
78 timespec = libc::timespec {
79 tv_sec: timeout.as_secs() as _,
80 tv_nsec: timeout.subsec_nanos() as _,
82 ×pec as *const libc::timespec
84 None => crate::ptr::null(),
89 futex as *const AtomicI32,
90 libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
97 fn futex_wake(futex: &AtomicI32) {
101 futex as *const AtomicI32,
102 libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,