Implement clockid_t handling to pthread_rwlock timeout

This commit is contained in:
Wildan M
2026-03-29 10:51:04 +07:00
parent e589a94c6d
commit 928a446f12
2 changed files with 81 additions and 23 deletions
+41 -15
View File
@@ -2,7 +2,7 @@ use super::*;
use crate::header::errno::{EBUSY, EINVAL};
use crate::pthread::Pshared;
use crate::{error::ResultExt, header::time::CLOCK_REALTIME, pthread::Pshared};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_init(
@@ -23,27 +23,52 @@ pub unsafe extern "C" fn pthread_rwlock_init(
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_rdlock(rwlock: *mut pthread_rwlock_t) -> c_int {
unsafe { get(rwlock) }.acquire_read_lock(None);
0
unsafe { get(rwlock) }
.acquire_read_lock(None)
.map(|_| 0)
.or_minus_one_errno()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_clockrdlock(
rwlock: *mut pthread_rwlock_t,
clock_id: clockid_t,
abstime: *const timespec,
) -> c_int {
unsafe { get(rwlock) }
.acquire_read_lock(Some((unsafe { &*abstime }, clock_id)))
.map(|_| 0)
.or_minus_one_errno()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_timedrdlock(
rwlock: *mut pthread_rwlock_t,
timeout: *const timespec,
abstime: *const timespec,
) -> c_int {
unsafe { get(rwlock) }.acquire_read_lock(Some(unsafe { &*timeout }));
0
unsafe { get(rwlock) }
.acquire_read_lock(Some((unsafe { &*abstime }, CLOCK_REALTIME)))
.map(|_| 0)
.or_minus_one_errno()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_clockwrlock(
rwlock: *mut pthread_rwlock_t,
clock_id: clockid_t,
abstime: *const timespec,
) -> c_int {
unsafe { get(rwlock) }
.acquire_write_lock(Some((unsafe { &*abstime }, clock_id)))
.map(|_| 0)
.or_minus_one_errno()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_timedwrlock(
rwlock: *mut pthread_rwlock_t,
timeout: *const timespec,
abstime: *const timespec,
) -> c_int {
unsafe { get(rwlock) }.acquire_write_lock(Some(unsafe { &*timeout }));
0
unsafe { get(rwlock) }
.acquire_write_lock(Some((unsafe { &*abstime }, CLOCK_REALTIME)))
.map(|_| 0)
.or_minus_one_errno()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rwlock: *mut pthread_rwlock_t) -> c_int {
@@ -67,9 +92,10 @@ pub unsafe extern "C" fn pthread_rwlock_unlock(rwlock: *mut pthread_rwlock_t) ->
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_rwlock_wrlock(rwlock: *mut pthread_rwlock_t) -> c_int {
unsafe { get(rwlock) }.acquire_write_lock(None);
0
unsafe { get(rwlock) }
.acquire_write_lock(None)
.map(|_| 0)
.or_minus_one_errno()
}
#[unsafe(no_mangle)]
+40 -8
View File
@@ -4,7 +4,16 @@ use core::{
sync::atomic::{AtomicU32, Ordering},
};
use crate::{header::bits_time::timespec, pthread::Pshared};
use crate::{
error::{Errno, Result},
header::{
bits_time::timespec,
errno::EINVAL,
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec_realtime_to_monotonic},
},
platform::types::clockid_t,
pthread::Pshared,
};
pub struct InnerRwLock {
state: AtomicU32,
@@ -25,7 +34,25 @@ impl InnerRwLock {
state: AtomicU32::new(0),
}
}
pub fn acquire_write_lock(&self, deadline: Option<&timespec>) {
fn translate_timeout(deadline: Option<(&timespec, i32)>) -> Result<Option<timespec>, Errno> {
let relative = match deadline {
// FUTEX expect monotonic clock
Some((abstime, CLOCK_MONOTONIC)) => Some(abstime.clone()),
Some((abstime, CLOCK_REALTIME)) => {
Some(timespec_realtime_to_monotonic(abstime.clone())?)
}
None => None,
_ => {
return Err(Errno(EINVAL));
}
};
Ok(relative)
}
pub fn acquire_write_lock(
&self,
deadline: Option<(&timespec, clockid_t)>,
) -> Result<(), Errno> {
let relative = Self::translate_timeout(deadline)?;
let mut waiting_wr = self.state.load(Ordering::Relaxed) & WAITING_WR;
loop {
@@ -35,7 +62,7 @@ impl InnerRwLock {
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => return,
Ok(_) => break,
Err(actual) => {
let expected = actual;
let expected = if actual & COUNT_MASK != EXCLUSIVE {
@@ -50,7 +77,7 @@ impl InnerRwLock {
waiting_wr = expected & WAITING_WR;
if actual & COUNT_MASK > 0 {
let _ = crate::sync::futex_wait(&self.state, expected, deadline);
let _ = crate::sync::futex_wait(&self.state, expected, relative.as_ref());
} else {
// We must avoid blocking indefinitely in our `futex_wait()`, in this case
// where it's possible that `self.state == expected` but our futex might
@@ -61,12 +88,17 @@ impl InnerRwLock {
}
}
}
Ok(())
}
pub fn acquire_read_lock(&self, deadline: Option<&timespec>) {
pub fn acquire_read_lock(&self, deadline: Option<(&timespec, clockid_t)>) -> Result<(), Errno> {
let relative = Self::translate_timeout(deadline)?;
// TODO: timeout
while let Err(old) = self.try_acquire_read_lock() {
crate::sync::futex_wait(&self.state, old, deadline);
crate::sync::futex_wait(&self.state, old, relative.as_ref());
}
Ok(())
}
pub fn try_acquire_read_lock(&self) -> Result<(), u32> {
let mut cached = self.state.load(Ordering::Acquire);
@@ -167,12 +199,12 @@ impl<T> RwLock<T> {
impl<T: ?Sized> RwLock<T> {
pub fn read(&self) -> ReadGuard<'_, T> {
self.inner.acquire_read_lock(None);
let _ = self.inner.acquire_read_lock(None);
unsafe { ReadGuard::new(self) }
}
pub fn write(&self) -> WriteGuard<'_, T> {
self.inner.acquire_write_lock(None);
let _ = self.inner.acquire_write_lock(None);
unsafe { WriteGuard::new(self) }
}