diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 86852d3fe7..8a4132c3c3 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -297,7 +297,7 @@ pub extern "C" fn div(numer: c_int, denom: c_int) -> div_t { /// state. #[no_mangle] pub extern "C" fn drand48() -> c_double { - let params = rand48::params_lock(); + let params = rand48::params(); let mut xsubi = rand48::xsubi_lock(); *xsubi = params.step(*xsubi); xsubi.get_f64() @@ -330,7 +330,7 @@ pub extern "C" fn ecvt( /// state. #[no_mangle] pub unsafe extern "C" fn erand48(xsubi: *mut c_ushort) -> c_double { - let params = rand48::params_lock(); + let params = rand48::params(); let xsubi_mut: &mut [c_ushort; 3] = slice::from_raw_parts_mut(xsubi, 3).try_into().unwrap(); let new_xsubi_value = params.step(xsubi_mut.into()); *xsubi_mut = new_xsubi_value.into(); @@ -521,7 +521,7 @@ pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: size_ /// state. #[no_mangle] pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long { - let params = rand48::params_lock(); + let params = rand48::params(); let xsubi_mut: &mut [c_ushort; 3] = slice::from_raw_parts_mut(xsubi, 3).try_into().unwrap(); let new_xsubi_value = params.step(xsubi_mut.into()); *xsubi_mut = new_xsubi_value.into(); @@ -586,7 +586,7 @@ pub extern "C" fn labs(i: c_long) -> c_long { #[no_mangle] pub unsafe extern "C" fn lcong48(param: *mut c_ushort) { let mut xsubi = rand48::xsubi_lock(); - let mut params = rand48::params_lock(); + let mut params = rand48::params_mut(); let param_slice = slice::from_raw_parts(param, 7); @@ -643,7 +643,7 @@ pub extern "C" fn lldiv(numer: c_longlong, denom: c_longlong) -> lldiv_t { /// state. #[no_mangle] pub extern "C" fn lrand48() -> c_long { - let params = rand48::params_lock(); + let params = rand48::params(); let mut xsubi = rand48::xsubi_lock(); *xsubi = params.step(*xsubi); xsubi.get_u31() @@ -843,7 +843,7 @@ pub unsafe extern "C" fn mktemp(name: *mut c_char) -> *mut c_char { /// state. #[no_mangle] pub extern "C" fn mrand48() -> c_long { - let params = rand48::params_lock(); + let params = rand48::params(); let mut xsubi = rand48::xsubi_lock(); *xsubi = params.step(*xsubi); xsubi.get_i32() @@ -860,7 +860,7 @@ pub extern "C" fn mrand48() -> c_long { /// state. #[no_mangle] pub unsafe extern "C" fn nrand48(xsubi: *mut c_ushort) -> c_long { - let params = rand48::params_lock(); + let params = rand48::params(); let xsubi_mut: &mut [c_ushort; 3] = slice::from_raw_parts_mut(xsubi, 3).try_into().unwrap(); let new_xsubi_value = params.step(xsubi_mut.into()); *xsubi_mut = new_xsubi_value.into(); @@ -1196,7 +1196,7 @@ pub unsafe extern "C" fn secure_getenv(name: *const c_char) -> *mut c_char { pub unsafe extern "C" fn seed48(seed16v: *mut c_ushort) -> *mut c_ushort { static mut BUFFER: [c_ushort; 3] = [0; 3]; - let mut params = rand48::params_lock(); + let mut params = rand48::params_mut(); let mut xsubi = rand48::xsubi_lock(); let seed16v_ref: &[c_ushort; 3] = slice::from_raw_parts(seed16v, 3).try_into().unwrap(); @@ -1296,7 +1296,7 @@ pub unsafe extern "C" fn srand(seed: c_uint) { /// state. #[no_mangle] pub extern "C" fn srand48(seedval: c_long) { - let mut params = rand48::params_lock(); + let mut params = rand48::params_mut(); let mut xsubi = rand48::xsubi_lock(); params.reset(); diff --git a/src/header/stdlib/rand48.rs b/src/header/stdlib/rand48.rs index 6d78d6c0cc..cb91aacc4c 100644 --- a/src/header/stdlib/rand48.rs +++ b/src/header/stdlib/rand48.rs @@ -2,7 +2,7 @@ use crate::{ platform::types::*, - sync::{Mutex, MutexGuard}, + sync::{rwlock::{self, RwLock}, Mutex, MutexGuard}, }; /// A 48-bit integer, used for the 48-bit arithmetic in these functions. @@ -119,13 +119,19 @@ impl Params { } } -// TODO: consider using rwlock instead of mutex for more fine-grained access -/// Immediately get the global Params lock, or panic if unsuccessful. -pub fn params_lock<'a>() -> MutexGuard<'a, Params> { - static PARAMS: Mutex = Mutex::::new(Params::new()); +static PARAMS: RwLock = RwLock::::new(Params::new()); +/// Immediately get the global [`Params`] lock for reading, or panic if unsuccessful. +pub fn params<'a>() -> rwlock::ReadGuard<'a, Params> { PARAMS - .try_lock() + .try_read() + .expect("unable to acquire LCG parameter lock") +} + +/// Immediately get the global [`Params`] lock for writing, or panic if unsuccessful. +pub fn params_mut<'a>() -> rwlock::WriteGuard<'a, Params> { + PARAMS + .try_write() .expect("unable to acquire LCG parameter lock") } diff --git a/src/sync/rwlock.rs b/src/sync/rwlock.rs index 524bfd94a2..58c279f26e 100644 --- a/src/sync/rwlock.rs +++ b/src/sync/rwlock.rs @@ -176,6 +176,22 @@ impl RwLock { self.inner.acquire_write_lock(None); unsafe { WriteGuard::new(self) } } + + pub fn try_read(&self) -> Option> { + if self.inner.try_acquire_read_lock().is_ok() { + Some(unsafe { ReadGuard::new(self) }) + } else { + None + } + } + + pub fn try_write(&self) -> Option> { + if self.inner.try_acquire_write_lock().is_ok() { + Some(unsafe { WriteGuard::new(self) }) + } else { + None + } + } } pub struct ReadGuard<'a, T: ?Sized + 'a> {