Thread parker
This commit is contained in:
parent
7f7a1c3314
commit
eee2f8995a
66
src/sync.rs
66
src/sync.rs
|
@ -129,6 +129,7 @@ impl Lock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// from parking_lot_core
|
||||||
pub struct SpinWait {
|
pub struct SpinWait {
|
||||||
counter: u32,
|
counter: u32,
|
||||||
}
|
}
|
||||||
|
@ -180,3 +181,68 @@ impl SpinWait {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// taken from `std`
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Parker {
|
||||||
|
mutex: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parker {
|
||||||
|
const PARKED: u32 = u32::MAX;
|
||||||
|
const EMPTY: u32 = 0;
|
||||||
|
const NOTIFIED: u32 = 1;
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
mutex: AtomicU32::new(Self::EMPTY),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *mut u32 {
|
||||||
|
self.mutex.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn from_ptr<'a>(ptr: *mut u32) -> &'a Self {
|
||||||
|
// SAFETY: The caller must ensure that `ptr` is not aliased, and lasts
|
||||||
|
// for the lifetime of the `Parker`.
|
||||||
|
unsafe { mem::transmute(AtomicU32::from_ptr(ptr)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_parked(&self) -> bool {
|
||||||
|
self.mutex.load(Ordering::Acquire) == Self::PARKED
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn park(&self) {
|
||||||
|
if self.mutex.fetch_sub(1, Ordering::Acquire) == Self::NOTIFIED {
|
||||||
|
// The thread was notified, so we can return immediately.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
atomic_wait::wait(&self.mutex, Self::PARKED);
|
||||||
|
|
||||||
|
// We check whether we were notified or woke up spuriously with
|
||||||
|
// acquire ordering in order to make-visible any writes made by the
|
||||||
|
// thread that notified us.
|
||||||
|
if self.mutex.swap(Self::EMPTY, Ordering::Acquire) == Self::NOTIFIED {
|
||||||
|
// The thread was notified, so we can return immediately.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// spurious wakeup, so we need to re-park.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unpark(&self) {
|
||||||
|
// write with Release ordering to ensure that any writes made by this
|
||||||
|
// thread are made-available to the unparked thread.
|
||||||
|
if self.mutex.swap(Self::NOTIFIED, Ordering::Release) == Self::PARKED {
|
||||||
|
// The thread was parked, so we need to notify it.
|
||||||
|
atomic_wait::wake_one(&self.mutex);
|
||||||
|
} else {
|
||||||
|
// The thread was not parked, so we don't need to do anything.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue