Skip to content

Commit 37cefa3

Browse files
committed
Add support for FUTEX_WAIT_BITSET(bitset=MAX).
1 parent fb01df5 commit 37cefa3

File tree

1 file changed

+40
-9
lines changed

1 file changed

+40
-9
lines changed

src/shims/posix/linux/sync.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub fn futex<'tcx>(
3636

3737
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
3838
let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
39+
let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?;
3940
let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;
4041
let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?;
4142

@@ -45,12 +46,32 @@ pub fn futex<'tcx>(
4546
// FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
4647
// Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
4748
// or *timeout expires. `timeout == null` for an infinite timeout.
48-
op if op & !futex_realtime == futex_wait => {
49-
if args.len() < 5 {
50-
throw_ub_format!(
51-
"incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5",
52-
args.len()
53-
);
49+
//
50+
// FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset)
51+
// When bitset is u32::MAX, this is identical to FUTEX_WAIT, except the timeout is absolute rather than relative.
52+
op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => {
53+
let wait_bitset = op & !futex_realtime == futex_wait_bitset;
54+
55+
if wait_bitset {
56+
if args.len() != 7 {
57+
throw_ub_format!(
58+
"incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7",
59+
args.len()
60+
);
61+
}
62+
63+
let bitset = this.read_scalar(&args[6])?.to_u32()?;
64+
65+
if bitset != u32::MAX {
66+
throw_unsup_format!("Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX");
67+
}
68+
} else {
69+
if args.len() < 5 {
70+
throw_ub_format!(
71+
"incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5",
72+
args.len()
73+
);
74+
}
5475
}
5576

5677
// `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!).
@@ -70,10 +91,20 @@ pub fn futex<'tcx>(
7091
return Ok(());
7192
}
7293
};
73-
Some(if op & futex_realtime != 0 {
74-
Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
94+
Some(if wait_bitset {
95+
// FUTEX_WAIT_BITSET uses an absolute timestamp.
96+
if op & futex_realtime != 0 {
97+
Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap())
98+
} else {
99+
Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap())
100+
}
75101
} else {
76-
Time::Monotonic(Instant::now().checked_add(duration).unwrap())
102+
// FUTEX_WAIT uses a relative timestamp.
103+
if op & futex_realtime != 0 {
104+
Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
105+
} else {
106+
Time::Monotonic(Instant::now().checked_add(duration).unwrap())
107+
}
77108
})
78109
};
79110
// Check the pointer for alignment and validity.

0 commit comments

Comments
 (0)