Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
887c130
solarish platform add supports for available-parallelism.
devnexen May 24, 2024
d3974fa
reorder code
RalfJung May 26, 2024
b531ca7
Auto merge of #3629 - devnexen:illumos_num_cpus, r=RalfJung
bors May 26, 2024
38870cf
avoid using macro_use
RalfJung May 26, 2024
da6c08e
Auto merge of #3634 - RalfJung:macro_use, r=RalfJung
bors May 26, 2024
d562cec
Preparing for merge from rustc
RalfJung May 27, 2024
8058933
Merge from rustc
RalfJung May 27, 2024
84f70ab
fmt
RalfJung May 27, 2024
79c30b6
Auto merge of #3635 - RalfJung:rustup, r=RalfJung
bors May 27, 2024
fcb4cf5
avoid repeating the Provenance parameter everywhere
RalfJung May 27, 2024
98a3ac9
also add type aliases for the pointer types
RalfJung May 27, 2024
2c1a5a7
Auto merge of #3636 - RalfJung:provenance-type-aliases, r=RalfJung
bors May 27, 2024
4277ddf
Preparing for merge from rustc
May 28, 2024
54db9aa
Merge from rustc
May 28, 2024
ef86cbd
Auto merge of #3639 - rust-lang:rustup-2024-05-28, r=RalfJung
bors May 28, 2024
4991fd9
move ./miri environment variables to CONTRIBUTING
RalfJung May 28, 2024
9d162eb
Auto merge of #3641 - RalfJung:env-vars, r=RalfJung
bors May 28, 2024
d5235f9
Fix "local crate" detection
narpfel May 28, 2024
483485e
Add a benchmark for creating large uninit allocations
saethlin May 27, 2024
ec5327d
Auto merge of #3638 - saethlin:big-alloc-bench, r=RalfJung
bors May 29, 2024
a963103
add tests for local crate detection
narpfel May 28, 2024
5bf7832
Preparing for merge from rustc
May 30, 2024
8faa34e
Merge from rustc
May 30, 2024
a200d38
fmt
May 30, 2024
daeb68a
make env/var test deterministic
RalfJung May 30, 2024
8a7338a
Auto merge of #3645 - rust-lang:rustup-2024-05-30, r=RalfJung
bors May 30, 2024
00644c1
add a comment
RalfJung May 30, 2024
58f3894
Auto merge of #3644 - narpfel:local-crates-metadata-format-update, r=…
bors May 30, 2024
0453f37
Preparing for merge from rustc
Jun 5, 2024
7950562
Merge from rustc
Jun 5, 2024
9a77692
fmt
Jun 5, 2024
56438c3
Auto merge of #3648 - rust-lang:rustup-2024-06-05, r=RalfJung
bors Jun 5, 2024
14f65cb
Preparing for merge from rustc
Jun 7, 2024
f0ea91c
Merge from rustc
Jun 7, 2024
60f7aab
Auto merge of #3652 - rust-lang:rustup-2024-06-07, r=RalfJung
bors Jun 7, 2024
27d9a46
Fix stage in contributing
Noratrieb Jun 7, 2024
dce1bbf
Remove --stage entirely from contributing
Noratrieb Jun 7, 2024
4c18f2a
Auto merge of #3654 - Nilstrieb:patch-1, r=RalfJung
bors Jun 7, 2024
a269cf5
Add eventfd shim
tiif Jun 8, 2024
20b3527
Auto merge of #3650 - tiif:feat/eventfd, r=oli-obk
bors Jun 8, 2024
3fa1d47
add support for `pclmulqdq`
folkertdev May 28, 2024
ea73f00
comment nits
RalfJung Jun 8, 2024
4d5fd11
Auto merge of #3640 - folkertdev:add-pclmulqdq, r=RalfJung
bors Jun 8, 2024
ca3d93a
portable-simd: add test for non-power-of-2 bitmask
RalfJung Jun 8, 2024
1f1dd65
Auto merge of #3655 - RalfJung:simd-bitmask, r=RalfJung
bors Jun 8, 2024
1ae0053
Preparing for merge from rustc
RalfJung Jun 8, 2024
5367235
Merge from rustc
RalfJung Jun 8, 2024
989dfb1
Auto merge of #3656 - RalfJung:rustup, r=RalfJung
bors Jun 8, 2024
a13a9ab
simd_bitmask: nicer error when the mask is too big
RalfJung Jun 9, 2024
d5fa08c
Auto merge of #3659 - RalfJung:bitmask-too-large, r=RalfJung
bors Jun 9, 2024
91e53aa
simd_select_bitmask: fix intrinsic name in error
RalfJung Jun 9, 2024
773415d
Auto merge of #3660 - RalfJung:wrong-error, r=RalfJung
bors Jun 9, 2024
110b092
simd_bitmask: work correctly for sizes like 24
RalfJung Jun 9, 2024
ba45198
use strict ops in some places
RalfJung Jun 9, 2024
de822dc
Auto merge of #3662 - RalfJung:simd-bitmask, r=RalfJung
bors Jun 9, 2024
844450a
First attempt
tiif Jun 7, 2024
0bca4e1
Convert u128 to nanosecond
tiif Jun 7, 2024
9f60709
Remove test
tiif Jun 7, 2024
9cf04b5
Use modulo operation to convert nanosecond to Duration
tiif Jun 7, 2024
aa83235
Move duration division out
tiif Jun 7, 2024
d0fb350
Add comment for u128 to u64 conversion.
tiif Jun 9, 2024
e85c521
Checked add for duration update
tiif Jun 9, 2024
21d66af
Saturate to u64::MAX
tiif Jun 9, 2024
40182be
Run cargo fmt
tiif Jun 9, 2024
509eec1
Auto merge of #3653 - tiif:bug/futex_ice, r=RalfJung
bors Jun 9, 2024
87c4d29
don't panic if time computaton overflows
RalfJung Jun 9, 2024
b5ae8bd
Auto merge of #3663 - RalfJung:timeouts, r=RalfJung
bors Jun 9, 2024
69512c7
Follow up fix for eventfd shim
tiif Jun 9, 2024
ad85a20
Auto merge of #3661 - tiif:fix/eventfd, r=RalfJung
bors Jun 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add eventfd shim
  • Loading branch information
tiif committed Jun 8, 2024
commit a269cf5657262e8a1dcd1377b116db6223f1f54a
113 changes: 94 additions & 19 deletions src/tools/miri/src/shims/unix/linux/eventfd.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
//! Linux `eventfd` implementation.
//! Currently just a stub.
use std::io;
use std::io::{Error, ErrorKind};

use rustc_target::abi::Endian;

use crate::shims::unix::*;
use crate::*;
use crate::{concurrency::VClock, *};

use self::shims::unix::fd::FileDescriptor;

/// Minimum size of u8 array to hold u64 value.
const U64_MIN_ARRAY_SIZE: usize = 8;

/// Maximum value that the eventfd counter can hold.
const MAX_COUNTER: u64 = u64::MAX - 1;

/// A kind of file descriptor created by `eventfd`.
/// The `Event` type isn't currently written to by `eventfd`.
/// The interface is meant to keep track of objects associated
Expand All @@ -20,7 +26,9 @@ use self::shims::unix::fd::FileDescriptor;
struct Event {
/// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the
/// kernel. This counter is initialized with the value specified in the argument initval.
val: u64,
counter: u64,
is_nonblock: bool,
clock: VClock,
}

impl FileDescription for Event {
Expand All @@ -35,6 +43,38 @@ impl FileDescription for Event {
Ok(Ok(()))
}

/// Read the counter in the buffer and return the counter if succeeded.
fn read<'tcx>(
&mut self,
_communicate_allowed: bool,
bytes: &mut [u8],
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 {
return Ok(Err(Error::from(ErrorKind::InvalidInput)));
};
// Block when counter == 0.
if self.counter == 0 {
if self.is_nonblock {
return Ok(Err(Error::from(ErrorKind::WouldBlock)));
} else {
//FIXME: blocking is not supported
throw_unsup_format!("eventfd: blocking is unsupported");
}
} else {
// Prevent false alarm in data race detection when doing synchronisation via eventfd.
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 {
Endian::Little => self.counter.to_le_bytes(),
Endian::Big => self.counter.to_be_bytes(),
};
self.counter = 0;
return Ok(Ok(U64_MIN_ARRAY_SIZE));
}
}

/// A write call adds the 8-byte integer value supplied in
/// its buffer (in native endianness) to the counter. The maximum value that may be
/// stored in the counter is the largest unsigned 64-bit value
Expand All @@ -53,16 +93,37 @@ impl FileDescription for Event {
bytes: &[u8],
ecx: &mut MiriInterpCx<'tcx>,
) -> InterpResult<'tcx, io::Result<usize>> {
let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
// Convert from target endianness to host endianness.
// 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 {
return Ok(Err(Error::from(ErrorKind::InvalidInput)));
};
// Convert from bytes to int according to host endianness.
let num = match ecx.tcx.sess.target.endian {
Endian::Little => u64::from_le_bytes(bytes),
Endian::Big => u64::from_be_bytes(bytes),
Endian::Little => u64::from_le_bytes(*bytes),
Endian::Big => u64::from_be_bytes(*bytes),
};
// u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
if num == u64::MAX {
return Ok(Err(Error::from(ErrorKind::InvalidInput)));
}
// If the addition does not let the counter to exceed the maximum value, update the counter.
// 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());
self.counter = new_count;
}
None | Some(u64::MAX) => {
if self.is_nonblock {
return Ok(Err(Error::from(ErrorKind::WouldBlock)));
} else {
//FIXME: blocking is not supported
throw_unsup_format!("eventfd: blocking is unsupported");
}
}
};
// FIXME handle blocking when addition results in exceeding the max u64 value
// or fail with EAGAIN if the file descriptor is nonblocking.
self.val = self.val.checked_add(num).unwrap();
Ok(Ok(8))
Ok(Ok(U64_MIN_ARRAY_SIZE))
}
}

Expand All @@ -87,27 +148,41 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn eventfd(&mut self, val: &OpTy<'tcx>, flags: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();

// eventfd is Linux specific.
this.assert_target_os("linux", "eventfd");

let val = this.read_scalar(val)?.to_u32()?;
let flags = this.read_scalar(flags)?.to_i32()?;
let mut flags = this.read_scalar(flags)?.to_i32()?;

let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC");
let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK");
let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE");

if flags & (efd_cloexec | efd_nonblock | efd_semaphore) != flags {
throw_unsup_format!("eventfd: flag {flags:#x} is unsupported");
if flags & efd_semaphore == efd_semaphore {
throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported");
}

let mut is_nonblock = false;
// Unload the flag that we support.
// After unloading, flags != 0 means other flags are used.
if flags & efd_cloexec == efd_cloexec {
// cloexec does nothing as we don't support `exec`
flags &= !efd_cloexec;
}
if flags & efd_nonblock == efd_nonblock {
// FIXME remember the nonblock flag
flags &= !efd_nonblock;
is_nonblock = true;
}
if flags & efd_semaphore == efd_semaphore {
throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported");
if flags != 0 {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
return Ok(Scalar::from_i32(-1));
}

let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { val: val.into() }));
let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event {
counter: val.into(),
is_nonblock,
clock: VClock::default(),
}));
Ok(Scalar::from_i32(fd))
}
}
12 changes: 12 additions & 0 deletions src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//@ignore-target-windows: No eventfd on Windows
//@ignore-target-apple: No eventfd in macos
fn main() {
// eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0.
// This will pass when blocking is implemented.
let flags = libc::EFD_CLOEXEC;
let fd = unsafe { libc::eventfd(0, flags) };
let mut buf: [u8; 8] = [0; 8];
let _res: i32 = unsafe {
libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap() //~ERROR: blocking is unsupported
};
}
14 changes: 14 additions & 0 deletions src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: unsupported operation: eventfd: blocking is unsupported
--> $DIR/libc_eventfd_read_block.rs:LL:CC
|
LL | libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
= note: BACKTRACE:
= note: inside `main` at $DIR/libc_eventfd_read_block.rs:LL:CC

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

22 changes: 22 additions & 0 deletions src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//@ignore-target-windows: No eventfd on Windows
//@ignore-target-apple: No eventfd in macos
fn main() {
// eventfd write will block when EFD_NONBLOCK flag is clear
// and the addition caused counter to exceed u64::MAX - 1.
// This will pass when blocking is implemented.
let flags = libc::EFD_CLOEXEC;
let fd = unsafe { libc::eventfd(0, flags) };
// Write u64 - 1.
let mut sized_8_data: [u8; 8] = (u64::MAX - 1).to_ne_bytes();
let res: i64 = unsafe {
libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
};
assert_eq!(res, 8);

// Write 1.
sized_8_data = 1_u64.to_ne_bytes();
// Write 1 to the counter.
let _res: i64 = unsafe {
libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() //~ERROR: blocking is unsupported
};
}
14 changes: 14 additions & 0 deletions src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: unsupported operation: eventfd: blocking is unsupported
--> $DIR/libc_eventfd_write_block.rs:LL:CC
|
LL | libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported
|
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
= note: BACKTRACE:
= note: inside `main` at $DIR/libc_eventfd_write_block.rs:LL:CC

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

101 changes: 101 additions & 0 deletions src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//@ignore-target-windows: No eventfd in windows
//@ignore-target-apple: No eventfd in macos
// test_race depends on a deterministic schedule.
//@compile-flags: -Zmiri-preemption-rate=0

use std::thread;

fn main() {
test_read_write();
test_race();
}

fn read_bytes<const N: usize>(fd: i32, buf: &mut [u8; N]) -> i32 {
let res: i32 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), N).try_into().unwrap() };
return res;
}

fn write_bytes<const N: usize>(fd: i32, data: [u8; N]) -> i32 {
let res: i32 =
unsafe { libc::write(fd, data.as_ptr() as *const libc::c_void, N).try_into().unwrap() };
return res;
}

fn test_read_write() {
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
let fd = unsafe { libc::eventfd(0, flags) };
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
// Write 1 to the counter.
let res = write_bytes(fd, sized_8_data);
assert_eq!(res, 8);

// Read 1 from the counter.
let mut buf: [u8; 8] = [0; 8];
let res = read_bytes(fd, &mut buf);
// Read returns number of bytes has been read, which is always 8.
assert_eq!(res, 8);
// Check the value of counter read.
let counter = u64::from_ne_bytes(buf);
assert_eq!(counter, 1);

// After read, the counter is currently 0, read counter 0 should fail with return
// value -1.
let mut buf: [u8; 8] = [0; 8];
let res = read_bytes(fd, &mut buf);
assert_eq!(res, -1);

// Write with supplied buffer that > 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.
sized_9_data = [0, 0, 0, 0, 0, 0, 0, 1, 0];
} else {
sized_9_data = [1, 0, 0, 0, 0, 0, 0, 0, 0];
}
let res = write_bytes(fd, sized_9_data);
assert_eq!(res, 8);

// Read with supplied buffer that < 8 bytes should fail with return
// value -1.
let mut buf: [u8; 7] = [1; 7];
let res = read_bytes(fd, &mut buf);
assert_eq!(res, -1);

// Write with supplied buffer that < 8 bytes should fail with return
// value -1.
let size_7_data: [u8; 7] = [1; 7];
let res = write_bytes(fd, size_7_data);
assert_eq!(res, -1);

// Read with supplied buffer > 8 bytes should be allowed.
let mut buf: [u8; 9] = [1; 9];
let res = read_bytes(fd, &mut buf);
assert_eq!(res, 8);

// Write u64::MAX should fail.
let u64_max_bytes: [u8; 8] = [255; 8];
let res = write_bytes(fd, u64_max_bytes);
assert_eq!(res, -1);
}

fn test_race() {
static mut VAL: u8 = 0;
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
let fd = unsafe { libc::eventfd(0, flags) };
let thread1 = thread::spawn(move || {
let mut buf: [u8; 8] = [0; 8];
let res = read_bytes(fd, &mut buf);
// read returns number of bytes has been read, which is always 8.
assert_eq!(res, 8);
let counter = u64::from_ne_bytes(buf);
assert_eq!(counter, 1);
unsafe { assert_eq!(VAL, 1) };
});
unsafe { VAL = 1 };
let data: [u8; 8] = 1_u64.to_ne_bytes();
let res = write_bytes(fd, data);
// write returns number of bytes written, which is always 8.
assert_eq!(res, 8);
thread::yield_now();
thread1.join().unwrap();
}