From a245e49e7567f91a9d5fc0a38115df4dc55c15c1 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 7 Jan 2026 14:45:01 +1100 Subject: [PATCH] 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 --- src/syscall/futex.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/syscall/futex.rs b/src/syscall/futex.rs index bb62fc65d1..2659fc8cb7 100644 --- a/src/syscall/futex.rs +++ b/src/syscall/futex.rs @@ -93,12 +93,12 @@ pub fn futex( .map(|buf| unsafe { buf.read_exact::() }) .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(¤t_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)