Various futex fixes

This commit is contained in:
Jacob Lorentzon
2024-04-05 20:31:06 +00:00
committed by Jeremy Soller
parent 7cf68bc8ee
commit 1fba2ef10a
10 changed files with 216 additions and 68 deletions
+5 -9
View File
@@ -74,7 +74,7 @@ impl Cond {
unlock: impl FnOnce() -> Result<()>,
lock: impl FnOnce() -> Result<()>,
lock_with_timeout: impl FnOnce(&timespec) -> Result<()>,
timeout: Option<&timespec>,
deadline: Option<&timespec>,
) -> Result<(), Errno> {
// TODO: Error checking for certain types (i.e. robust and errorcheck) of mutexes, e.g. if the
// mutex is not locked.
@@ -83,14 +83,10 @@ impl Cond {
unlock();
match timeout {
Some(timeout) => {
crate::sync::futex_wait(
&self.cur,
current,
timespec::subtract(*timeout, crate::sync::rttime()).as_ref(),
);
lock_with_timeout(timeout);
match deadline {
Some(deadline) => {
crate::sync::futex_wait(&self.cur, current, Some(&deadline));
lock_with_timeout(deadline);
}
None => {
crate::sync::futex_wait(&self.cur, current, None);
+35 -18
View File
@@ -16,8 +16,12 @@ pub use self::{
};
use crate::{
header::time::timespec,
header::{
errno::{EAGAIN, ETIMEDOUT},
time::timespec,
},
platform::{types::*, Pal, Sys},
pthread::Errno,
};
use core::{
mem::MaybeUninit,
@@ -36,7 +40,7 @@ pub enum AttemptStatus {
}
pub trait FutexTy {
fn conv(self) -> i32;
fn conv(self) -> u32;
}
pub trait FutexAtomicTy {
type Ty: FutexTy;
@@ -44,13 +48,13 @@ pub trait FutexAtomicTy {
fn ptr(&self) -> *mut Self::Ty;
}
impl FutexTy for u32 {
fn conv(self) -> i32 {
self as i32
fn conv(self) -> u32 {
self
}
}
impl FutexTy for i32 {
fn conv(self) -> i32 {
self
fn conv(self) -> u32 {
self as u32
}
}
impl FutexAtomicTy for AtomicU32 {
@@ -91,20 +95,26 @@ impl FutexAtomicTy for AtomicI32 {
pub unsafe fn futex_wake_ptr(ptr: *mut impl FutexTy, n: i32) -> usize {
// TODO: unwrap_unchecked?
Sys::futex(ptr.cast(), FUTEX_WAKE, n, 0).unwrap() as usize
Sys::futex_wake(ptr.cast(), n as u32).unwrap() as usize
}
pub unsafe fn futex_wait_ptr<T: FutexTy>(
ptr: *mut T,
value: T,
timeout_opt: Option<&timespec>,
) -> bool {
// TODO: unwrap_unchecked?
Sys::futex(
deadline_opt: Option<&timespec>,
) -> FutexWaitResult {
match Sys::futex_wait(
ptr.cast(),
FUTEX_WAIT,
value.conv(),
timeout_opt.map_or(0, |t| t as *const _ as usize),
) == Ok(0)
deadline_opt.map_or(core::ptr::null(), |t| t as *const _),
) {
Ok(()) => FutexWaitResult::Waited,
Err(Errno(EAGAIN)) => FutexWaitResult::Stale,
Err(Errno(ETIMEDOUT)) if deadline_opt.is_some() => FutexWaitResult::TimedOut,
Err(other) => {
eprintln!("futex failed: {}", other.0);
FutexWaitResult::Waited
}
}
}
pub fn futex_wake(atomic: &impl FutexAtomicTy, n: i32) -> usize {
unsafe { futex_wake_ptr(atomic.ptr(), n) }
@@ -112,9 +122,16 @@ pub fn futex_wake(atomic: &impl FutexAtomicTy, n: i32) -> usize {
pub fn futex_wait<T: FutexAtomicTy>(
atomic: &T,
value: T::Ty,
timeout_opt: Option<&timespec>,
) -> bool {
unsafe { futex_wait_ptr(atomic.ptr(), value, timeout_opt) }
deadline_opt: Option<&timespec>,
) -> FutexWaitResult {
unsafe { futex_wait_ptr(atomic.ptr(), value, deadline_opt) }
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FutexWaitResult {
Waited, // possibly spurious
Stale, // outdated value
TimedOut,
}
pub fn rttime() -> timespec {
@@ -187,7 +204,7 @@ impl AtomicLock {
pub fn wait_if(&self, value: c_int, timeout_opt: Option<&timespec>) {
self.wait_if_raw(value, timeout_opt);
}
pub fn wait_if_raw(&self, value: c_int, timeout_opt: Option<&timespec>) -> bool {
pub fn wait_if_raw(&self, value: c_int, timeout_opt: Option<&timespec>) -> FutexWaitResult {
futex_wait(&self.atomic, value, timeout_opt)
}
+7 -1
View File
@@ -10,6 +10,8 @@ use crate::{
use crate::platform::{types::*, Pal, Sys};
use super::FutexWaitResult;
pub struct RlctMutex {
// Actual locking word.
inner: AtomicUint,
@@ -123,7 +125,11 @@ impl RlctMutex {
// If the mutex is not robust, simply futex_wait until unblocked.
//crate::sync::futex_wait(&self.inner, inner | WAITING_BIT, None);
crate::sync::futex_wait(&self.inner, thread, None);
if crate::sync::futex_wait(&self.inner, thread, deadline)
== FutexWaitResult::TimedOut
{
return Err(Errno(ETIMEDOUT));
}
}
}
}
+4 -5
View File
@@ -21,7 +21,7 @@ impl Rwlock {
state: AtomicU32::new(0),
}
}
pub fn acquire_write_lock(&self, _timeout: Option<&timespec>) {
pub fn acquire_write_lock(&self, deadline: Option<&timespec>) {
let mut waiting_wr = self.state.load(Ordering::Relaxed) & WAITING_WR;
loop {
@@ -45,16 +45,15 @@ impl Rwlock {
};
waiting_wr = expected & WAITING_WR;
// TODO: timeout
let _ = crate::sync::futex_wait(&self.state, expected, None);
let _ = crate::sync::futex_wait(&self.state, expected, deadline);
}
}
}
}
pub fn acquire_read_lock(&self, _timeout: Option<&timespec>) {
pub fn acquire_read_lock(&self, deadline: Option<&timespec>) {
// TODO: timeout
while let Err(old) = self.try_acquire_read_lock() {
crate::sync::futex_wait(&self.state, old, None);
crate::sync::futex_wait(&self.state, old, deadline);
}
}
pub fn try_acquire_read_lock(&self) -> Result<(), u32> {