about summary refs log tree commit diff
path: root/library/std/src/sys_common
diff options
context:
space:
mode:
authorjoboet <jonasboettiger@icloud.com>2024-04-23 11:49:37 +0200
committerjoboet <jonasboettiger@icloud.com>2024-05-02 12:38:26 +0200
commita56fd370fc3e6b5cfbd9eb0b96f533d0bcca0b1f (patch)
treea1fc69d5c82808c6018e0500d1f77bafdf002b85 /library/std/src/sys_common
parentfcc06c894b17f4d0c80b8934ea5f27faa894c960 (diff)
std: move thread parking to `sys::sync`
Diffstat (limited to 'library/std/src/sys_common')
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--library/std/src/sys_common/thread_parking/futex.rs97
-rw-r--r--library/std/src/sys_common/thread_parking/id.rs103
-rw-r--r--library/std/src/sys_common/thread_parking/mod.rs24
4 files changed, 0 insertions, 225 deletions
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index cc21560fff5..3a38ba1100f 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -26,7 +26,6 @@ pub mod io;
 pub mod lazy_box;
 pub mod process;
 pub mod thread_local_dtor;
-pub mod thread_parking;
 pub mod wstr;
 pub mod wtf8;
 
diff --git a/library/std/src/sys_common/thread_parking/futex.rs b/library/std/src/sys_common/thread_parking/futex.rs
deleted file mode 100644
index 588e7b27826..00000000000
--- a/library/std/src/sys_common/thread_parking/futex.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-use crate::pin::Pin;
-use crate::sync::atomic::AtomicU32;
-use crate::sync::atomic::Ordering::{Acquire, Release};
-use crate::sys::futex::{futex_wait, futex_wake};
-use crate::time::Duration;
-
-const PARKED: u32 = u32::MAX;
-const EMPTY: u32 = 0;
-const NOTIFIED: u32 = 1;
-
-pub struct Parker {
-    state: AtomicU32,
-}
-
-// Notes about memory ordering:
-//
-// Memory ordering is only relevant for the relative ordering of operations
-// between different variables. Even Ordering::Relaxed guarantees a
-// monotonic/consistent order when looking at just a single atomic variable.
-//
-// So, since this parker is just a single atomic variable, we only need to look
-// at the ordering guarantees we need to provide to the 'outside world'.
-//
-// The only memory ordering guarantee that parking and unparking provide, is
-// that things which happened before unpark() are visible on the thread
-// returning from park() afterwards. Otherwise, it was effectively unparked
-// before unpark() was called while still consuming the 'token'.
-//
-// In other words, unpark() needs to synchronize with the part of park() that
-// consumes the token and returns.
-//
-// This is done with a release-acquire synchronization, by using
-// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
-// Ordering::Acquire when checking for this state in park().
-impl Parker {
-    /// Construct the futex parker. The UNIX parker implementation
-    /// requires this to happen in-place.
-    pub unsafe fn new_in_place(parker: *mut Parker) {
-        parker.write(Self { state: AtomicU32::new(EMPTY) });
-    }
-
-    // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`.
-    pub unsafe fn park(self: Pin<&Self>) {
-        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
-        // first case.
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-        loop {
-            // Wait for something to happen, assuming it's still set to PARKED.
-            futex_wait(&self.state, PARKED, None);
-            // Change NOTIFIED=>EMPTY and return in that case.
-            if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Acquire).is_ok() {
-                return;
-            } else {
-                // Spurious wake up. We loop to try again.
-            }
-        }
-    }
-
-    // Assumes this is only called by the thread that owns the Parker,
-    // which means that `self.state != PARKED`. This implementation doesn't
-    // require `Pin`, but other implementations do.
-    pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
-        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
-        // first case.
-        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
-            return;
-        }
-        // Wait for something to happen, assuming it's still set to PARKED.
-        futex_wait(&self.state, PARKED, Some(timeout));
-        // This is not just a store, because we need to establish a
-        // release-acquire ordering with unpark().
-        if self.state.swap(EMPTY, Acquire) == NOTIFIED {
-            // Woke up because of unpark().
-        } else {
-            // Timeout or spurious wake up.
-            // We return either way, because we can't easily tell if it was the
-            // timeout or not.
-        }
-    }
-
-    // This implementation doesn't require `Pin`, but other implementations do.
-    #[inline]
-    pub fn unpark(self: Pin<&Self>) {
-        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
-        // wake the thread in the first case.
-        //
-        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
-        // purpose, to make sure every unpark() has a release-acquire ordering
-        // with park().
-        if self.state.swap(NOTIFIED, Release) == PARKED {
-            futex_wake(&self.state);
-        }
-    }
-}
diff --git a/library/std/src/sys_common/thread_parking/id.rs b/library/std/src/sys_common/thread_parking/id.rs
deleted file mode 100644
index 04667439660..00000000000
--- a/library/std/src/sys_common/thread_parking/id.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-//! Thread parking using thread ids.
-//!
-//! Some platforms (notably NetBSD) have thread parking primitives whose semantics
-//! match those offered by `thread::park`, with the difference that the thread to
-//! be unparked is referenced by a platform-specific thread id. Since the thread
-//! parker is constructed before that id is known, an atomic state variable is used
-//! to manage the park state and propagate the thread id. This also avoids platform
-//! calls in the case where `unpark` is called before `park`.
-
-use crate::cell::UnsafeCell;
-use crate::pin::Pin;
-use crate::sync::atomic::{
-    fence, AtomicI8,
-    Ordering::{Acquire, Relaxed, Release},
-};
-use crate::sys::thread_parking::{current, park, park_timeout, unpark, ThreadId};
-use crate::time::Duration;
-
-pub struct Parker {
-    state: AtomicI8,
-    tid: UnsafeCell<Option<ThreadId>>,
-}
-
-const PARKED: i8 = -1;
-const EMPTY: i8 = 0;
-const NOTIFIED: i8 = 1;
-
-impl Parker {
-    pub fn new() -> Parker {
-        Parker { state: AtomicI8::new(EMPTY), tid: UnsafeCell::new(None) }
-    }
-
-    /// Create a new thread parker. UNIX requires this to happen in-place.
-    pub unsafe fn new_in_place(parker: *mut Parker) {
-        parker.write(Parker::new())
-    }
-
-    /// # Safety
-    /// * must always be called from the same thread
-    /// * must be called before the state is set to PARKED
-    unsafe fn init_tid(&self) {
-        // The field is only ever written to from this thread, so we don't need
-        // synchronization to read it here.
-        if self.tid.get().read().is_none() {
-            // Because this point is only reached once, before the state is set
-            // to PARKED for the first time, the non-atomic write here can not
-            // conflict with reads by other threads.
-            self.tid.get().write(Some(current()));
-            // Ensure that the write can be observed by all threads reading the
-            // state. Synchronizes with the acquire barrier in `unpark`.
-            fence(Release);
-        }
-    }
-
-    pub unsafe fn park(self: Pin<&Self>) {
-        self.init_tid();
-
-        // Changes NOTIFIED to EMPTY and EMPTY to PARKED.
-        let state = self.state.fetch_sub(1, Acquire);
-        if state == EMPTY {
-            // Loop to guard against spurious wakeups.
-            // The state must be reset with acquire ordering to ensure that all
-            // calls to `unpark` synchronize with this thread.
-            while self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed).is_err() {
-                park(self.state.as_ptr().addr());
-            }
-        }
-    }
-
-    pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
-        self.init_tid();
-
-        let state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
-        if state == PARKED {
-            park_timeout(dur, self.state.as_ptr().addr());
-            // Swap to ensure that we observe all state changes with acquire
-            // ordering.
-            self.state.swap(EMPTY, Acquire);
-        }
-    }
-
-    pub fn unpark(self: Pin<&Self>) {
-        let state = self.state.swap(NOTIFIED, Release);
-        if state == PARKED {
-            // Synchronize with the release fence in `init_tid` to observe the
-            // write to `tid`.
-            fence(Acquire);
-            // # Safety
-            // The thread id is initialized before the state is set to `PARKED`
-            // for the first time and is not written to from that point on
-            // (negating the need for an atomic read).
-            let tid = unsafe { self.tid.get().read().unwrap_unchecked() };
-            // It is possible that the waiting thread woke up because of a timeout
-            // and terminated before this call is made. This call then returns an
-            // error or wakes up an unrelated thread. The platform API and
-            // environment does allow this, however.
-            unpark(tid, self.state.as_ptr().addr());
-        }
-    }
-}
-
-unsafe impl Send for Parker {}
-unsafe impl Sync for Parker {}
diff --git a/library/std/src/sys_common/thread_parking/mod.rs b/library/std/src/sys_common/thread_parking/mod.rs
deleted file mode 100644
index c4d3f9ea2f4..00000000000
--- a/library/std/src/sys_common/thread_parking/mod.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-cfg_if::cfg_if! {
-    if #[cfg(any(
-        target_os = "linux",
-        target_os = "android",
-        all(target_arch = "wasm32", target_feature = "atomics"),
-        target_os = "freebsd",
-        target_os = "openbsd",
-        target_os = "dragonfly",
-        target_os = "fuchsia",
-        target_os = "hermit",
-    ))] {
-        mod futex;
-        pub use futex::Parker;
-    } else if #[cfg(any(
-        target_os = "netbsd",
-        all(target_vendor = "fortanix", target_env = "sgx"),
-        target_os = "solid_asp3",
-    ))] {
-        mod id;
-        pub use id::Parker;
-    } else {
-        pub use crate::sys::thread_parking::Parker;
-    }
-}