feat: rwlock instead of mutex for global scope

* Rwlock -> InnerRwLock
* RwLock makes use of InnerRwLock.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2024-12-31 00:43:24 +11:00
parent 1ffd7187ef
commit cfe89f828a
5 changed files with 139 additions and 17 deletions
+1 -1
View File
@@ -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 {
+11 -11
View File
@@ -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();
+1
View File
@@ -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)]
+2 -2
View File
@@ -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 {
+124 -3
View File
@@ -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<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 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)
}
}