fix(syscalls/futex): premature timeout

Previously, if a futex with a timeout was woken up (even via
`futex_wake`), it was treated as though the timeout had expired. When
the timeout expires, the scheduler sets `wake` to `None` and unblocks
the process. Hence if `wake` is `None` and if a timeout was given to
futex, it has expired. Otherwise the process was woken up by
`futex_wake`.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2026-01-07 14:45:01 +11:00
parent 5ccd2414af
commit a245e49e75
+8 -5
View File
@@ -93,12 +93,12 @@ pub fn futex(
.map(|buf| unsafe { buf.read_exact::<TimeSpec>() })
.transpose()?;
let context_lock = context::current();
{
let mut futexes = FUTEXES.lock(token.token());
let (futexes, mut token) = futexes.token_split();
let context_lock = context::current();
let (fetched, expected) = if op == FUTEX_WAIT {
// Must be aligned, otherwise it could cross a page boundary and mess up the
// (simpler) validation we did in the first place.
@@ -160,7 +160,7 @@ pub fn futex(
.or_insert_with(|| Vec::new())
.push(FutexEntry {
target_virtaddr,
context_lock,
context_lock: context_lock.clone(),
addr_space: Arc::downgrade(&current_addrsp),
});
}
@@ -169,8 +169,11 @@ pub fn futex(
context::switch(token);
if timeout_opt.is_some() {
context::current().write(token.token()).wake = None;
let context = context_lock.read(token.token());
// The scheduler clears `wake` on timeout. Hence if a timeout was
// set and `wake` is now `None`, we timed out.
if context.wake.is_none() && timeout_opt.is_some() {
Err(Error::new(ETIMEDOUT))
} else {
Ok(0)