Files
RedBear-OS/src/header/pthread/rwlock.rs
T

155 lines
4.7 KiB
Rust

use super::*;
use core::sync::atomic::{AtomicI32 as AtomicInt, Ordering};
use crate::header::errno::EBUSY;
// PTHREAD_RWLOCK_INITIALIZER
// TODO: Optimize for short waits and long waits, using AtomicLock::wait_until, but still
// supporting timeouts.
// TODO: Add futex ops that use bitmasks.
const EXCLUSIVE: u32 = (1 << (u32::BITS - 1)) - 1;
// Separate "waiting for wrlocks" and "waiting for rdlocks"?
//const WAITING: u32 = 1 << (u32::BITS - 1);
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut pthread_rwlock_t) -> c_int {
// (Informing the compiler that this pointer is valid, might improve optimizations.)
let _rwlock: &pthread_rwlock_t = &*rwlock;
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_init(rwlock: *mut pthread_rwlock_t, attr: *const pthread_rwlockattr_t) -> c_int {
let attr = attr.cast::<RlctRwlockAttr>().as_ref();
rwlock.cast::<RlctRwlock>().write(RlctRwlock {
state: AtomicInt::new(0),
});
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_rdlock(rwlock: *mut pthread_rwlock_t) -> c_int {
pthread_rwlock_timedrdlock(rwlock, core::ptr::null())
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_timedrdlock(rwlock: *mut pthread_rwlock_t, timeout: *const timespec) -> c_int {
let rwlock = &*rwlock.cast::<RlctRwlock>();
let timeout = timeout.as_ref();
loop {
if pthread_rwlock_tryrdlock(rwlock as *const _ as *mut _) == EBUSY {
crate::sync::futex_wait(&rwlock.state, EXCLUSIVE as i32, timeout);
}
return 0;
}
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_timedwrlock(rwlock: *mut pthread_rwlock_t, timeout: *const timespec) -> c_int {
let rwlock = &*rwlock.cast::<RlctRwlock>();
let timeout = timeout.as_ref();
/*loop {
if pthread_rwlock_trywrlock(rwlock as *const _ as *mut _) == EBUSY {
crate::sync::futex_wait(&rwlock.state, EXCLUSIVE as i32, timeout);
}
return 0;
}*/
loop {
match rwlock.state.compare_exchange(0, EXCLUSIVE as i32, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => return 0,
Err(value) => {
// TODO: More than just forwarding the timeout.
crate::sync::futex_wait(&rwlock.state, value, timeout);
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rwlock: *mut pthread_rwlock_t) -> c_int {
let rwlock = &*rwlock.cast::<RlctRwlock>();
let mut cached = rwlock.state.load(Ordering::Acquire) as u32;
loop {
let old = if cached == EXCLUSIVE { 0 } else { cached };
let new = old + 1;
assert_ne!(new, EXCLUSIVE, "overflow");
match rwlock.state.compare_exchange_weak(cached as i32, new as i32, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => return 0,
Err(value) if value as u32 == EXCLUSIVE => return EBUSY,
Err(value) => {
cached = value as u32;
core::hint::spin_loop();
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_trywrlock(rwlock: *mut pthread_rwlock_t) -> c_int {
let rwlock = &*rwlock.cast::<RlctRwlock>();
match rwlock.state.compare_exchange(0, EXCLUSIVE as i32, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => 0,
Err(_) => EBUSY,
}
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_unlock(rwlock: *const pthread_rwlock_t) -> c_int {
let rwlock = &*rwlock.cast::<RlctRwlock>();
let old = rwlock.state.swap(0, Ordering::Release) as u32;
if old == EXCLUSIVE {
crate::sync::futex_wake(&rwlock.state, i32::MAX);
}
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlock_wrlock(rwlock: *mut pthread_rwlock_t) -> c_int {
pthread_rwlock_timedwrlock(rwlock, core::ptr::null())
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t) -> c_int {
let _attr = &mut *attr.cast::<RlctRwlockAttr>();
// No-op
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, pshared: *mut c_int) -> c_int {
core::ptr::write(pshared, (*attr.cast::<RlctRwlockAttr>()).pshared);
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int {
attr.cast::<RlctRwlockAttr>().write(RlctRwlockAttr {
// Default according to POSIX.
pshared: PTHREAD_PROCESS_PRIVATE,
});
0
}
#[no_mangle]
pub unsafe extern "C" fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, pshared: c_int) -> c_int {
(*attr.cast::<RlctRwlockAttr>()).pshared = pshared;
0
}
pub(crate) struct RlctRwlockAttr {
pub pshared: c_int,
}
pub(crate) struct RlctRwlock {
pub state: AtomicInt,
}