diff --git a/src/header/pthread/rwlock.rs b/src/header/pthread/rwlock.rs index e11ea881282ce4207067d75772d0f139da78e4af..5c9502580b786dfc4e632dbab98284e3382f4679 100644 --- a/src/header/pthread/rwlock.rs +++ b/src/header/pthread/rwlock.rs @@ -114,7 +114,7 @@ pub unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut pthread_rwlock_t) - 0 } -pub(crate) type RlctRwlock = crate::sync::rwlock::Rwlock; +pub(crate) type RlctRwlock = crate::sync::rwlock::InnerRwLock; #[derive(Clone, Copy, Default)] pub(crate) struct RlctRwlockAttr { diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 86852d3fe751fc49bc5d14698ef2631e26b100ab..8a4132c3c35e86b833f217fcccb7afd625e458c1 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 6d78d6c0cc2a0a4598a6a67340cd9cec879d4447..5b272bb52c1c018968fb740c4b82af72daafcb92 100644 --- a/src/header/stdlib/rand48.rs +++ b/src/header/stdlib/rand48.rs @@ -2,7 +2,10 @@ 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 +122,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<Params> = Mutex::<Params>::new(Params::new()); +static PARAMS: RwLock<Params> = RwLock::<Params>::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/ld_so/linker.rs b/src/ld_so/linker.rs index 1ac0b59e9219f3626b78f549bfa88a45960e5289..f704751b3b1df97606fab1a23fc26cab8f3b5c4a 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -29,7 +29,7 @@ use crate::{ types::{c_char, c_int, c_uint, c_void}, Pal, Sys, }, - sync::Mutex, + sync::rwlock::RwLock, }; use super::{ @@ -49,7 +49,7 @@ use super::{ // do better errors than just goblin::Error::Malformed // TODO: rwlock? -static GLOBAL_SCOPE: Mutex<Scope> = Mutex::new(Scope::global()); +static GLOBAL_SCOPE: RwLock<Scope> = RwLock::new(Scope::global()); /// Same as [`crate::fs::File`], but does not touch [`crate::platform::ERRNO`] as the dynamic /// linker does not have thread-local storage. @@ -371,7 +371,7 @@ impl Linker { eprintln!("[ld.so]: moving {} into the global scope", obj.name); } - let mut global_scope = GLOBAL_SCOPE.lock(); + let mut global_scope = GLOBAL_SCOPE.write(); obj.scope.move_into(&mut global_scope); } @@ -419,8 +419,8 @@ impl Linker { if let Some(handle) = handle.as_ref() { &handle.as_ref().scope } else { - guard = GLOBAL_SCOPE.lock(); - &*guard + guard = GLOBAL_SCOPE.read(); + &guard } .get_sym(name) .map(|(symbol, _, obj)| { @@ -454,7 +454,7 @@ impl Linker { // objects map. if Arc::strong_count(&obj) == 2 { // Remove from the global scope. - match *GLOBAL_SCOPE.lock() { + match *GLOBAL_SCOPE.write() { Scope::Global { ref mut objs } => { objs.retain(|o| !Weak::ptr_eq(o, &Arc::downgrade(&obj))); } @@ -713,10 +713,10 @@ impl Linker { if let Some(dependent) = dependent { match scope { ObjectScope::Local => dependent.scope.add(&obj), - ObjectScope::Global => GLOBAL_SCOPE.lock().add(&obj), + ObjectScope::Global => GLOBAL_SCOPE.write().add(&obj), } } else if let ObjectScope::Global = scope { - GLOBAL_SCOPE.lock().add(&obj); + GLOBAL_SCOPE.write().add(&obj); } objects_data.push(data); @@ -817,7 +817,7 @@ impl Linker { )))?; let resolved = GLOBAL_SCOPE - .lock() + .read() .get_sym(name) .or_else(|| obj.scope.get_sym(name)) .map(|(sym, _, _)| sym.as_ptr()) @@ -869,7 +869,7 @@ impl Linker { )))?; let symbol = GLOBAL_SCOPE - .lock() + .read() .get_sym(name) .or_else(|| obj.scope.get_sym(name)) .map(|(sym, _, obj)| (sym, obj.tls_offset)); @@ -1067,7 +1067,7 @@ extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) -> ) }; - let resolved = resolve_sym(name.to_str().unwrap(), &[&GLOBAL_SCOPE.lock(), &obj.scope]) + let resolved = resolve_sym(name.to_str().unwrap(), &[&GLOBAL_SCOPE.read(), &obj.scope]) .expect(&format!("symbol '{}' not found", name.to_str().unwrap())) .as_ptr(); diff --git a/src/lib.rs b/src/lib.rs index 64cc935b53f17c20542d32b829c2e0f1de167b1a..76fd2b781855cac32aff10d587b3e0f73486d71b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ #![feature(sync_unsafe_cell)] #![feature(thread_local)] #![feature(vec_into_raw_parts)] +#![feature(negative_impls)] #![allow(clippy::cast_lossless)] #![allow(clippy::cast_ptr_alignment)] #![allow(clippy::derive_hash_xor_eq)] diff --git a/src/platform/redox/clone.rs b/src/platform/redox/clone.rs index 017696ce6b15869d626c9cef28aa2400a5f3ffd6..3c78230fa7241debcbc8bab536a8798fc87c9917 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -7,29 +7,6 @@ use syscall::{ SetSighandlerData, SIGCONT, }; -use crate::sync::rwlock::Rwlock; - use redox_rt::{proc::FdGuard, signal::sighandler_function}; -pub use redox_rt::proc::*; - -static CLONE_LOCK: Rwlock = Rwlock::new(crate::pthread::Pshared::Private); - -struct Guard; -impl Drop for Guard { - fn drop(&mut self) { - CLONE_LOCK.unlock() - } -} - -pub fn rdlock() -> impl Drop { - CLONE_LOCK.acquire_read_lock(None); - - Guard -} -pub fn wrlock() -> impl Drop { - CLONE_LOCK.acquire_write_lock(None); - - Guard -} -pub use redox_rt::thread::*; +pub use redox_rt::{proc::*, thread::*}; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 2c6c2e9b3f965f88919934898afadfdd9bb29683..628dfb734e0a32160bb5da817ef660c58eff80f9 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -34,6 +34,7 @@ use crate::{ unistd::{F_OK, R_OK, W_OK, X_OK}, }, io::{self, prelude::*, BufReader}, + sync::rwlock::RwLock, }; pub use redox_rt::proc::FdGuard; @@ -75,6 +76,8 @@ macro_rules! path_from_c_str { use self::{exec::Executable, path::canonicalize}; +static CLONE_LOCK: RwLock<()> = RwLock::new(()); + /// Redox syscall implementation of the platform abstraction layer. pub struct Sys; @@ -260,7 +263,7 @@ impl Pal for Sys { unsafe fn fork() -> Result<pid_t> { // TODO: Find way to avoid lock. - let _guard = clone::wrlock(); + let _guard = CLONE_LOCK.write(); Ok(clone::fork_impl()? as pid_t) } @@ -726,7 +729,7 @@ impl Pal for Sys { } unsafe fn rlct_clone(stack: *mut usize) -> Result<crate::pthread::OsTid> { - let _guard = clone::rdlock(); + let _guard = CLONE_LOCK.read(); let res = clone::rlct_clone_impl(stack); res.map(|mut fd| crate::pthread::OsTid { diff --git a/src/sync/rwlock.rs b/src/sync/rwlock.rs index b787a8e85747f9e531d574e422bbde90b927368b..58c279f26e4d55b1e13283113fd6040a6eeb34a1 100644 --- a/src/sync/rwlock.rs +++ b/src/sync/rwlock.rs @@ -1,8 +1,13 @@ -use core::sync::atomic::{AtomicU32, Ordering}; +use core::{ + cell::UnsafeCell, + fmt, ops, + ptr::NonNull, + sync::atomic::{AtomicU32, Ordering}, +}; use crate::{header::time::timespec, pthread::Pshared}; -pub struct Rwlock { +pub struct InnerRwLock { state: AtomicU32, } // PTHREAD_RWLOCK_INITIALIZER is defined as "all zeroes". @@ -15,7 +20,7 @@ const EXCLUSIVE: u32 = COUNT_MASK; // supporting timeouts. // TODO: Add futex ops that use bitmasks. -impl Rwlock { +impl InnerRwLock { pub const fn new(_pshared: Pshared) -> Self { Self { state: AtomicU32::new(0), @@ -143,3 +148,135 @@ impl Rwlock { } } } + +pub struct RwLock<T: ?Sized> { + inner: InnerRwLock, + data: UnsafeCell<T>, +} + +unsafe impl<T: ?Sized + Send> Send for RwLock<T> {} +unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} + +impl<T> RwLock<T> { + pub const fn new(val: T) -> Self { + Self { + inner: InnerRwLock::new(Pshared::Private), + data: UnsafeCell::new(val), + } + } +} + +impl<T: ?Sized> RwLock<T> { + pub fn read(&self) -> ReadGuard<'_, T> { + self.inner.acquire_read_lock(None); + unsafe { ReadGuard::new(self) } + } + + pub fn write(&self) -> WriteGuard<'_, T> { + self.inner.acquire_write_lock(None); + unsafe { WriteGuard::new(self) } + } + + pub fn try_read(&self) -> Option<ReadGuard<'_, T>> { + if self.inner.try_acquire_read_lock().is_ok() { + Some(unsafe { ReadGuard::new(self) }) + } else { + None + } + } + + pub fn try_write(&self) -> Option<WriteGuard<'_, T>> { + if self.inner.try_acquire_write_lock().is_ok() { + Some(unsafe { WriteGuard::new(self) }) + } else { + None + } + } +} + +pub struct ReadGuard<'a, T: ?Sized + 'a> { + lock: &'a RwLock<T>, +} + +impl<T: ?Sized> !Send for ReadGuard<'_, T> {} +unsafe impl<T: ?Sized + Sync> Sync for ReadGuard<'_, T> {} + +impl<'a, T: ?Sized> ReadGuard<'a, T> { + unsafe fn new(lock: &'a RwLock<T>) -> Self { + Self { lock } + } +} + +impl<'a, T: ?Sized> ops::Deref for ReadGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: We have shared reference to the data. + unsafe { &*self.lock.data.get() } + } +} + +impl<'a, T: ?Sized> Drop for ReadGuard<'a, T> { + fn drop(&mut self) { + self.lock.inner.unlock(); + } +} + +impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for ReadGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, T: ?Sized + fmt::Display> fmt::Display for ReadGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +pub struct WriteGuard<'a, T: ?Sized + 'a> { + lock: &'a RwLock<T>, +} + +impl<T: ?Sized> !Send for WriteGuard<'_, T> {} +unsafe impl<T: ?Sized + Sync> Sync for WriteGuard<'_, T> {} + +impl<'a, T: ?Sized> WriteGuard<'a, T> { + unsafe fn new(lock: &'a RwLock<T>) -> Self { + Self { lock } + } +} + +impl<'a, T: ?Sized> ops::Deref for WriteGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: We have exclusive reference to the data. + unsafe { &*self.lock.data.get() } + } +} + +impl<'a, T: ?Sized> ops::DerefMut for WriteGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: We have exclusive reference to the data. + unsafe { &mut *self.lock.data.get() } + } +} + +impl<'a, T: ?Sized> Drop for WriteGuard<'a, T> { + fn drop(&mut self) { + self.lock.inner.unlock(); + } +} + +impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for WriteGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, T: ?Sized + fmt::Display> fmt::Display for WriteGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} diff --git a/tests/expected/bins_dynamic/ptrace.stdout b/tests/expected/bins_dynamic/ptrace.stdout index c2e762dd87797f57166ae0277711391a9e072d64..824e89accd2a60dfb40609fd63b82c6ccda56547 100644 --- a/tests/expected/bins_dynamic/ptrace.stdout +++ b/tests/expected/bins_dynamic/ptrace.stdout @@ -1,30 +1,5 @@ ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs -Post-syscall -Wait... Child exited with status 0 diff --git a/tests/expected/bins_static/ptrace.stdout b/tests/expected/bins_static/ptrace.stdout index c2e762dd87797f57166ae0277711391a9e072d64..824e89accd2a60dfb40609fd63b82c6ccda56547 100644 --- a/tests/expected/bins_static/ptrace.stdout +++ b/tests/expected/bins_static/ptrace.stdout @@ -1,30 +1,5 @@ ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs Set regs -Post-syscall -Wait... ------ Pre-syscall ----- -Wait... -Get regs -Post-syscall -Wait... Child exited with status 0 diff --git a/tests/ptrace.c b/tests/ptrace.c index ef01252b452e3bcfe55d377824c92c9bb3655c85..40123f47b16040951b5c78e1eb3c56e0b946588a 100644 --- a/tests/ptrace.c +++ b/tests/ptrace.c @@ -48,17 +48,18 @@ int main() { int status; while (true) { - puts("----- Pre-syscall -----"); + // puts("----- Pre-syscall -----"); result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); ERROR_IF(ptrace, result, == -1); UNEXP_IF(ptrace, result, != 0); - puts("Wait..."); + // puts("Wait..."); result = waitpid(pid, &status, 0); ERROR_IF(waitpid, result, == -1); - if (WIFEXITED(status)) { break; } + if (WIFEXITED(status)) + break; struct user_regs_struct regs; - puts("Get regs"); + // puts("Get regs"); result = ptrace(PTRACE_GETREGS, pid, NULL, ®s); ERROR_IF(ptrace, result, == -1); @@ -69,14 +70,15 @@ int main() { ERROR_IF(ptrace, result, == -1); } - puts("Post-syscall"); + // puts("Post-syscall"); result = ptrace(PTRACE_SYSCALL, pid, NULL, NULL); ERROR_IF(ptrace, result, == -1); UNEXP_IF(ptrace, result, != 0); - puts("Wait..."); + // puts("Wait..."); result = waitpid(pid, &status, 0); ERROR_IF(waitpid, result, == -1); - if (WIFEXITED(status)) { break; } + if (WIFEXITED(status)) + break; } printf("Child exited with status %d\n", WEXITSTATUS(status)); }