about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-09 12:15:39 +0000
committerbors <bors@rust-lang.org>2024-06-09 12:15:39 +0000
commitad85a200310c439437f0ae0f92a4737c86b8695c (patch)
treef3d40ce9935fecb0aae705a77b9f4eee1e001e51
parentb5ae8bdb01bccf103d89503b28cfda5837e36223 (diff)
parent69512c7b1e000da54aba7e4f8aa1c64473dff9c0 (diff)
downloadrust-ad85a200310c439437f0ae0f92a4737c86b8695c.tar.gz
rust-ad85a200310c439437f0ae0f92a4737c86b8695c.zip
Auto merge of #3661 - tiif:fix/eventfd, r=RalfJung
Follow up PR for eventfd shim

Follow up of https://github.com/rust-lang/miri/pull/3650
-rw-r--r--src/tools/miri/src/shims/unix/linux/eventfd.rs28
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs19
4 files changed, 30 insertions, 23 deletions
diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs
index 3080d5b8d07..cae5abca3bd 100644
--- a/src/tools/miri/src/shims/unix/linux/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs
@@ -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 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;
+// 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 @@ impl FileDescription for Event {
         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 @@ impl FileDescription for Event {
                 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 @@ impl FileDescription for Event {
                 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 @@ impl FileDescription for Event {
         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 @@ impl FileDescription for Event {
         // 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 @@ impl FileDescription for Event {
                 }
             }
         };
-        Ok(Ok(U64_MIN_ARRAY_SIZE))
+        Ok(Ok(U64_ARRAY_SIZE))
     }
 }
 
@@ -163,9 +166,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'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 {
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs
index b24635f9340..fb9a23206c6 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs
@@ -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.
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs
index 32ca4a919f7..2037a516dea 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs
@@ -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.
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
index 6af195316e8..a3567eeb7cb 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
@@ -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);
 }