diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs index 22059ca0dbe10..647bbed071fd4 100644 --- a/library/std/src/sys/hermit/condvar.rs +++ b/library/std/src/sys/hermit/condvar.rs @@ -1,9 +1,12 @@ use crate::ffi::c_void; +use crate::mem::MaybeUninit; use crate::ptr; -use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +use crate::sync::atomic::{ + AtomicPtr, AtomicUsize, + Ordering::{Acquire, Release, SeqCst}, +}; use crate::sys::hermit::abi; use crate::sys::locks::Mutex; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; // The implementation is inspired by Andrew D. Birrell's paper @@ -11,70 +14,95 @@ use crate::time::Duration; pub struct Condvar { counter: AtomicUsize, - sem1: *const c_void, - sem2: *const c_void, + sem1: AtomicPtr, + sem2: AtomicPtr, } -pub(crate) type MovableCondvar = LazyBox; +pub(crate) type MovableCondvar = Condvar; -impl LazyInit for Condvar { - fn init() -> Box { - Box::new(Self::new()) +#[cold] +fn init_semaphore(sem: &AtomicPtr) -> *mut c_void { + let new = unsafe { + let mut new = MaybeUninit::uninit(); + let _ = abi::sem_init(new.as_mut_ptr(), 0); + new.assume_init() as *mut c_void + }; + + match sem.compare_exchange(ptr::null_mut(), new, Release, Acquire) { + Ok(_) => new, + Err(sem) => unsafe { + let _ = abi::sem_destroy(new); + sem + }, } } -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - impl Condvar { - pub fn new() -> Self { - let mut condvar = - Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }; - unsafe { - let _ = abi::sem_init(&mut condvar.sem1, 0); - let _ = abi::sem_init(&mut condvar.sem2, 0); + #[inline] + pub const fn new() -> Self { + Self { + counter: AtomicUsize::new(0), + sem1: AtomicPtr::new(ptr::null_mut()), + sem2: AtomicPtr::new(ptr::null_mut()), } - condvar + } + + #[inline] + fn semaphores(&self) -> (*const c_void, *const c_void) { + let mut sem1 = self.sem1.load(Acquire); + if sem1.is_null() { + sem1 = init_semaphore(&self.sem1); + } + + let mut sem2 = self.sem2.load(Acquire); + if sem2.is_null() { + sem2 = init_semaphore(&self.sem2); + } + + (sem1, sem2) } pub unsafe fn notify_one(&self) { if self.counter.load(SeqCst) > 0 { self.counter.fetch_sub(1, SeqCst); - abi::sem_post(self.sem1); - abi::sem_timedwait(self.sem2, 0); + let (sem1, sem2) = self.semaphores(); + unsafe { + abi::sem_post(sem1); + abi::sem_timedwait(sem2, 0); + } } } pub unsafe fn notify_all(&self) { let counter = self.counter.swap(0, SeqCst); + let (sem1, sem2) = self.semaphores(); for _ in 0..counter { - abi::sem_post(self.sem1); + unsafe { abi::sem_post(sem1) }; } for _ in 0..counter { - abi::sem_timedwait(self.sem2, 0); + unsafe { abi::sem_timedwait(sem2, 0) }; } } pub unsafe fn wait(&self, mutex: &Mutex) { self.counter.fetch_add(1, SeqCst); + let (sem1, sem2) = self.semaphores(); mutex.unlock(); - abi::sem_timedwait(self.sem1, 0); - abi::sem_post(self.sem2); + abi::sem_timedwait(sem1, 0); + abi::sem_post(sem2); mutex.lock(); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { self.counter.fetch_add(1, SeqCst); + let (sem1, sem2) = self.semaphores(); mutex.unlock(); - let millis = dur.as_millis().min(u32::MAX as u128) as u32; - let res = if millis > 0 { - abi::sem_timedwait(self.sem1, millis) - } else { - abi::sem_trywait(self.sem1) - }; + let millis = dur.as_millis().min(u32::MAX as u128) as u32; + let res = + if millis > 0 { abi::sem_timedwait(sem1, millis) } else { abi::sem_trywait(sem1) }; - abi::sem_post(self.sem2); + abi::sem_post(sem2); mutex.lock(); res == 0 } @@ -83,8 +111,14 @@ impl Condvar { impl Drop for Condvar { fn drop(&mut self) { unsafe { - let _ = abi::sem_destroy(self.sem1); - let _ = abi::sem_destroy(self.sem2); + let sem1 = *self.sem1.get_mut(); + let sem2 = *self.sem2.get_mut(); + if !sem1.is_null() { + let _ = abi::sem_destroy(sem1); + } + if !sem2.is_null() { + let _ = abi::sem_destroy(sem2); + } } } } diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index eb15a04ffcffb..d7b7a0bb0568f 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -2,7 +2,6 @@ use crate::cell::UnsafeCell; use crate::collections::VecDeque; use crate::hint; use crate::ops::{Deref, DerefMut, Drop}; -use crate::ptr; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::hermit::abi; diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index 9701bab1f660b..1adf0b2be6b73 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -1,6 +1,5 @@ use crate::cell::UnsafeCell; use crate::sys::locks::{MovableCondvar, Mutex}; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct RwLock { lock: Mutex,