Merge pull request #81 from arihant2math/mutex-timeouts

This commit is contained in:
Matthew Leach
2025-12-24 08:08:20 +00:00
committed by GitHub
9 changed files with 74 additions and 7 deletions

13
Cargo.lock generated
View File

@@ -106,6 +106,17 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
@@ -125,6 +136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-macro",
"futures-sink",
"futures-task",
"pin-project-lite",
@@ -530,6 +542,7 @@ name = "usertest"
version = "0.1.0"
dependencies = [
"libc",
"parking_lot",
]
[[package]]

View File

@@ -20,7 +20,7 @@ async-trait = "0.1.88"
getargs = { version = "0.5.0", default-features = false }
ringbuf = { version = "0.4.8", default-features = false, features = ["alloc"] }
bitflags = "2.9.1"
futures = { version = "0.3.31", default-features = false, features = ["alloc"] }
futures = { version = "0.3.31", default-features = false, features = ["alloc", "async-await"] }
rand = { version = "0.9.2", default-features = false, features = ["small_rng"] }
[profile.release]

View File

@@ -168,6 +168,9 @@ pub enum KernelError {
#[error("No such process")]
NoProcess,
#[error("Operation timed out")]
TimedOut,
#[error("{0}")]
Other(&'static str),
}

View File

@@ -38,6 +38,7 @@ pub const EDOM: isize = -33;
pub const ERANGE: isize = -34;
pub const EWOULDBLOCK: isize = -EAGAIN;
pub const ENOSYS: isize = -38;
pub const ETIMEDOUT: isize = -110;
pub fn kern_err_to_syscall(err: KernelError) -> isize {
match err {
@@ -51,6 +52,7 @@ pub fn kern_err_to_syscall(err: KernelError) -> isize {
KernelError::SeekPipe => ESPIPE,
KernelError::NotSupported => ENOSYS,
KernelError::NoMemory => ENOMEM,
KernelError::TimedOut => ETIMEDOUT,
e => todo!("{e}"),
}
}

View File

@@ -190,7 +190,7 @@ pub async fn handle_syscall() {
TUA::from_value(arg1 as _),
arg2 as _,
arg3 as _,
VA::from_value(arg4 as _),
TUA::from_value(arg4 as _),
TUA::from_value(arg5 as _),
arg6 as _,
)

View File

@@ -1,5 +1,5 @@
use crate::{
drivers::timer::{Instant, now},
drivers::timer::{Instant, now, uptime},
sync::SpinLock,
};
use core::time::Duration;
@@ -14,7 +14,7 @@ pub fn date() -> Duration {
let duraton_since_ep_info = now - ep_info.1;
ep_info.0 + duraton_since_ep_info
} else {
Duration::new(0, 0)
uptime()
}
}

View File

@@ -1,9 +1,15 @@
use crate::clock::realtime::date;
use crate::clock::timespec::TimeSpec;
use crate::drivers::timer::sleep;
use crate::sync::{OnceLock, SpinLock};
use alloc::boxed::Box;
use alloc::{collections::btree_map::BTreeMap, sync::Arc};
use core::time::Duration;
use futures::FutureExt;
use key::FutexKey;
use libkernel::{
error::{KernelError, Result},
memory::address::{TUA, VA},
memory::address::TUA,
sync::waker_set::WakerSet,
};
use wait::FutexWait;
@@ -60,7 +66,7 @@ pub async fn sys_futex(
uaddr: TUA<u32>,
op: i32,
val: u32,
_timeout: VA,
timeout: TUA<TimeSpec>,
_uaddr2: TUA<u32>,
_val3: u32,
) -> Result<usize> {
@@ -74,13 +80,36 @@ pub async fn sys_futex(
};
// TODO: support bitset variants properly
let timeout = if timeout.is_null() {
None
} else {
let timeout = TimeSpec::copy_from_user(timeout).await?;
if matches!(cmd, FUTEX_WAIT_BITSET) {
Some(Duration::from(timeout) - date())
} else {
Some(Duration::from(timeout))
}
};
match cmd {
FUTEX_WAIT | FUTEX_WAIT_BITSET => {
// Obtain (or create) the wait-queue for this futex word.
let slot = get_or_create_queue(key);
// Return 0 on success.
FutexWait::new(uaddr, val, slot).await.map(|_| 0)
if let Some(dur) = timeout {
let mut wait = FutexWait::new(uaddr, val, slot).fuse();
let mut sleep = Box::pin(sleep(dur).fuse());
futures::select_biased! {
res = wait => {
res.map(|_| 0)
},
_ = sleep => {
Err(KernelError::TimedOut)
}
}
} else {
FutexWait::new(uaddr, val, slot).await.map(|_| 0)
}
}
FUTEX_WAKE | FUTEX_WAKE_BITSET => Ok(wake_key(val as _, key)),

View File

@@ -5,3 +5,4 @@ edition = "2024"
[dependencies]
libc = "0.2"
parking_lot = "0.12"

View File

@@ -451,6 +451,24 @@ fn test_rust_mutex() {
println!(" OK");
}
fn test_parking_lot_mutex_timeout() {
print!("Testing parking_lot mutex with timeout ...");
use parking_lot::Mutex;
use std::time::Duration;
let mtx = Arc::new(Mutex::new(()));
let mtx_clone = Arc::clone(&mtx);
let guard = mtx.lock();
// Now try to acquire the lock with a timeout in another thread
let handle = thread::spawn(move || {
let timeout = Duration::from_millis(100);
let result = mtx_clone.try_lock_for(timeout);
assert!(result.is_none(), "Expected to not acquire the lock");
});
handle.join().unwrap();
drop(guard);
println!(" OK");
}
fn run_test(test_fn: fn()) {
// Fork a new process to run the test
unsafe {
@@ -495,6 +513,7 @@ fn main() {
run_test(test_rust_dir);
run_test(test_rust_thread);
run_test(test_rust_mutex);
run_test(test_parking_lot_mutex_timeout);
let end = std::time::Instant::now();
println!("All tests passed in {} ms", (end - start).as_millis());
}