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:
@@ -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(¤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)
|
||||
|
||||
Reference in New Issue
Block a user