From cfe89f828a718b45fe108ec2003bef495bd36f52 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 31 Dec 2024 00:43:24 +1100 Subject: [PATCH] feat: rwlock instead of mutex for global scope * Rwlock -> InnerRwLock * RwLock makes use of InnerRwLock. Signed-off-by: Anhad Singh --- src/header/pthread/rwlock.rs | 2 +- src/ld_so/linker.rs | 22 +++--- src/lib.rs | 1 + src/platform/redox/clone.rs | 4 +- src/sync/rwlock.rs | 127 ++++++++++++++++++++++++++++++++++- 5 files changed, 139 insertions(+), 17 deletions(-) diff --git a/src/header/pthread/rwlock.rs b/src/header/pthread/rwlock.rs index e11ea88128..5c9502580b 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/ld_so/linker.rs b/src/ld_so/linker.rs index 1ac0b59e92..f704751b3b 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 = Mutex::new(Scope::global()); +static GLOBAL_SCOPE: RwLock = 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 64cc935b53..76fd2b7818 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 017696ce6b..22d8e15053 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -7,13 +7,13 @@ use syscall::{ SetSighandlerData, SIGCONT, }; -use crate::sync::rwlock::Rwlock; +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); +static CLONE_LOCK: RwLock = RwLock::new(crate::pthread::Pshared::Private); struct Guard; impl Drop for Guard { diff --git a/src/sync/rwlock.rs b/src/sync/rwlock.rs index b787a8e857..524bfd94a2 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,119 @@ impl Rwlock { } } } + +pub struct RwLock { + inner: InnerRwLock, + data: UnsafeCell, +} + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +impl RwLock { + pub const fn new(val: T) -> Self { + Self { + inner: InnerRwLock::new(Pshared::Private), + data: UnsafeCell::new(val), + } + } +} + +impl RwLock { + 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 struct ReadGuard<'a, T: ?Sized + 'a> { + lock: &'a RwLock, +} + +impl !Send for ReadGuard<'_, T> {} +unsafe impl Sync for ReadGuard<'_, T> {} + +impl<'a, T: ?Sized> ReadGuard<'a, T> { + unsafe fn new(lock: &'a RwLock) -> 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, +} + +impl !Send for WriteGuard<'_, T> {} +unsafe impl Sync for WriteGuard<'_, T> {} + +impl<'a, T: ?Sized> WriteGuard<'a, T> { + unsafe fn new(lock: &'a RwLock) -> 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) + } +}