diff options
Diffstat (limited to 'library/std/src/sys_common/thread_parking/id.rs')
| -rw-r--r-- | library/std/src/sys_common/thread_parking/id.rs | 103 |
1 files changed, 0 insertions, 103 deletions
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 {} |
