From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- library/std/src/sys/hermit/condvar.rs | 90 +++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 library/std/src/sys/hermit/condvar.rs (limited to 'library/std/src/sys/hermit/condvar.rs') diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs new file mode 100644 index 000000000..22059ca0d --- /dev/null +++ b/library/std/src/sys/hermit/condvar.rs @@ -0,0 +1,90 @@ +use crate::ffi::c_void; +use crate::ptr; +use crate::sync::atomic::{AtomicUsize, Ordering::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 +// "Implementing Condition Variables with Semaphores" + +pub struct Condvar { + counter: AtomicUsize, + sem1: *const c_void, + sem2: *const c_void, +} + +pub(crate) type MovableCondvar = LazyBox; + +impl LazyInit for Condvar { + fn init() -> Box { + Box::new(Self::new()) + } +} + +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); + } + condvar + } + + 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); + } + } + + pub unsafe fn notify_all(&self) { + let counter = self.counter.swap(0, SeqCst); + for _ in 0..counter { + abi::sem_post(self.sem1); + } + for _ in 0..counter { + abi::sem_timedwait(self.sem2, 0); + } + } + + pub unsafe fn wait(&self, mutex: &Mutex) { + self.counter.fetch_add(1, SeqCst); + mutex.unlock(); + abi::sem_timedwait(self.sem1, 0); + abi::sem_post(self.sem2); + mutex.lock(); + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + self.counter.fetch_add(1, SeqCst); + 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) + }; + + abi::sem_post(self.sem2); + mutex.lock(); + res == 0 + } +} + +impl Drop for Condvar { + fn drop(&mut self) { + unsafe { + let _ = abi::sem_destroy(self.sem1); + let _ = abi::sem_destroy(self.sem2); + } + } +} -- cgit v1.2.3