Follow up fix for eventfd shim
This commit is contained in:
parent
b5ae8bdb01
commit
69512c7b1e
@ -1,6 +1,7 @@
|
||||
//! Linux `eventfd` implementation.
|
||||
use std::io;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::mem;
|
||||
|
||||
use rustc_target::abi::Endian;
|
||||
|
||||
@ -9,8 +10,8 @@
|
||||
|
||||
use self::shims::unix::fd::FileDescriptor;
|
||||
|
||||
/// Minimum size of u8 array to hold u64 value.
|
||||
const U64_MIN_ARRAY_SIZE: usize = 8;
|
||||
// We'll only do reads and writes in chunks of size u64.
|
||||
const U64_ARRAY_SIZE: usize = mem::size_of::<u64>();
|
||||
|
||||
/// Maximum value that the eventfd counter can hold.
|
||||
const MAX_COUNTER: u64 = u64::MAX - 1;
|
||||
@ -51,7 +52,7 @@ fn read<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
// Check the size of slice, and return error only if the size of the slice < 8.
|
||||
let Some(bytes) = bytes.first_chunk_mut::<U64_MIN_ARRAY_SIZE>() else {
|
||||
let Some(bytes) = bytes.first_chunk_mut::<U64_ARRAY_SIZE>() else {
|
||||
return Ok(Err(Error::from(ErrorKind::InvalidInput)));
|
||||
};
|
||||
// Block when counter == 0.
|
||||
@ -63,7 +64,7 @@ fn read<'tcx>(
|
||||
throw_unsup_format!("eventfd: blocking is unsupported");
|
||||
}
|
||||
} else {
|
||||
// Prevent false alarm in data race detection when doing synchronisation via eventfd.
|
||||
// Synchronize with all prior `write` calls to this FD.
|
||||
ecx.acquire_clock(&self.clock);
|
||||
// Return the counter in the host endianness using the buffer provided by caller.
|
||||
*bytes = match ecx.tcx.sess.target.endian {
|
||||
@ -71,7 +72,7 @@ fn read<'tcx>(
|
||||
Endian::Big => self.counter.to_be_bytes(),
|
||||
};
|
||||
self.counter = 0;
|
||||
return Ok(Ok(U64_MIN_ARRAY_SIZE));
|
||||
return Ok(Ok(U64_ARRAY_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,7 +95,7 @@ fn write<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
// Check the size of slice, and return error only if the size of the slice < 8.
|
||||
let Some(bytes) = bytes.first_chunk::<U64_MIN_ARRAY_SIZE>() else {
|
||||
let Some(bytes) = bytes.first_chunk::<U64_ARRAY_SIZE>() else {
|
||||
return Ok(Err(Error::from(ErrorKind::InvalidInput)));
|
||||
};
|
||||
// Convert from bytes to int according to host endianness.
|
||||
@ -110,8 +111,10 @@ fn write<'tcx>(
|
||||
// Else, block.
|
||||
match self.counter.checked_add(num) {
|
||||
Some(new_count @ 0..=MAX_COUNTER) => {
|
||||
// Prevent false alarm in data race detection when doing synchronisation via eventfd.
|
||||
self.clock.join(&ecx.release_clock().unwrap());
|
||||
// Future `read` calls will synchronize with this write, so update the FD clock.
|
||||
if let Some(clock) = &ecx.release_clock() {
|
||||
self.clock.join(clock);
|
||||
}
|
||||
self.counter = new_count;
|
||||
}
|
||||
None | Some(u64::MAX) => {
|
||||
@ -123,7 +126,7 @@ fn write<'tcx>(
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(Ok(U64_MIN_ARRAY_SIZE))
|
||||
Ok(Ok(U64_ARRAY_SIZE))
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,9 +166,10 @@ fn eventfd(&mut self, val: &OpTy<'tcx>, flags: &OpTy<'tcx>) -> InterpResult<'tcx
|
||||
}
|
||||
|
||||
let mut is_nonblock = false;
|
||||
// Unload the flag that we support.
|
||||
// Unset the flag that we support.
|
||||
// After unloading, flags != 0 means other flags are used.
|
||||
if flags & efd_cloexec == efd_cloexec {
|
||||
// cloexec is ignored because Miri does not support exec.
|
||||
flags &= !efd_cloexec;
|
||||
}
|
||||
if flags & efd_nonblock == efd_nonblock {
|
||||
@ -173,9 +177,7 @@ fn eventfd(&mut self, val: &OpTy<'tcx>, flags: &OpTy<'tcx>) -> InterpResult<'tcx
|
||||
is_nonblock = true;
|
||||
}
|
||||
if flags != 0 {
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(Scalar::from_i32(-1));
|
||||
throw_unsup_format!("eventfd: encountered unknown unsupported flags {:#x}", flags);
|
||||
}
|
||||
|
||||
let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event {
|
||||
|
@ -1,5 +1,4 @@
|
||||
//@ignore-target-windows: No eventfd on Windows
|
||||
//@ignore-target-apple: No eventfd in macos
|
||||
//@only-target-linux
|
||||
fn main() {
|
||||
// eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0.
|
||||
// This will pass when blocking is implemented.
|
||||
|
@ -1,5 +1,4 @@
|
||||
//@ignore-target-windows: No eventfd on Windows
|
||||
//@ignore-target-apple: No eventfd in macos
|
||||
//@only-target-linux
|
||||
fn main() {
|
||||
// eventfd write will block when EFD_NONBLOCK flag is clear
|
||||
// and the addition caused counter to exceed u64::MAX - 1.
|
||||
|
@ -1,5 +1,4 @@
|
||||
//@ignore-target-windows: No eventfd in windows
|
||||
//@ignore-target-apple: No eventfd in macos
|
||||
//@only-target-linux
|
||||
// test_race depends on a deterministic schedule.
|
||||
//@compile-flags: -Zmiri-preemption-rate=0
|
||||
|
||||
@ -42,9 +41,11 @@ fn test_read_write() {
|
||||
// value -1.
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let res = read_bytes(fd, &mut buf);
|
||||
let e = std::io::Error::last_os_error();
|
||||
assert_eq!(e.raw_os_error(), Some(libc::EAGAIN));
|
||||
assert_eq!(res, -1);
|
||||
|
||||
// Write with supplied buffer that > 8 bytes should be allowed.
|
||||
// Write with supplied buffer bigger than 8 bytes should be allowed.
|
||||
let sized_9_data: [u8; 9];
|
||||
if cfg!(target_endian = "big") {
|
||||
// Adjust the data based on the endianness of host system.
|
||||
@ -55,19 +56,23 @@ fn test_read_write() {
|
||||
let res = write_bytes(fd, sized_9_data);
|
||||
assert_eq!(res, 8);
|
||||
|
||||
// Read with supplied buffer that < 8 bytes should fail with return
|
||||
// Read with supplied buffer smaller than 8 bytes should fail with return
|
||||
// value -1.
|
||||
let mut buf: [u8; 7] = [1; 7];
|
||||
let res = read_bytes(fd, &mut buf);
|
||||
let e = std::io::Error::last_os_error();
|
||||
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
|
||||
assert_eq!(res, -1);
|
||||
|
||||
// Write with supplied buffer that < 8 bytes should fail with return
|
||||
// Write with supplied buffer smaller than 8 bytes should fail with return
|
||||
// value -1.
|
||||
let size_7_data: [u8; 7] = [1; 7];
|
||||
let res = write_bytes(fd, size_7_data);
|
||||
let e = std::io::Error::last_os_error();
|
||||
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
|
||||
assert_eq!(res, -1);
|
||||
|
||||
// Read with supplied buffer > 8 bytes should be allowed.
|
||||
// Read with supplied buffer bigger than 8 bytes should be allowed.
|
||||
let mut buf: [u8; 9] = [1; 9];
|
||||
let res = read_bytes(fd, &mut buf);
|
||||
assert_eq!(res, 8);
|
||||
@ -75,6 +80,8 @@ fn test_read_write() {
|
||||
// Write u64::MAX should fail.
|
||||
let u64_max_bytes: [u8; 8] = [255; 8];
|
||||
let res = write_bytes(fd, u64_max_bytes);
|
||||
let e = std::io::Error::last_os_error();
|
||||
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
|
||||
assert_eq!(res, -1);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user