about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/src/shims/unix/linux/eventfd.rs79
1 files changed, 30 insertions, 49 deletions
diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs
index e1531fc2fa8..d1d461daa99 100644
--- a/src/tools/miri/src/shims/unix/linux/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs
@@ -2,16 +2,12 @@
 use std::cell::{Cell, RefCell};
 use std::io;
 use std::io::{Error, ErrorKind};
-use std::mem;
 
 use crate::shims::unix::fd::FileDescriptionRef;
 use crate::shims::unix::linux::epoll::{EpollReadyEvents, EvalContextExt as _};
 use crate::shims::unix::*;
 use crate::{concurrency::VClock, *};
 
-// 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;
 
@@ -65,35 +61,45 @@ impl FileDescription for Event {
         dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx> {
-        // eventfd read at the size of u64.
-        let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ecx.machine.layouts.u64);
+        // We're treating the buffer as a `u64`.
+        let ty = ecx.machine.layouts.u64;
         // Check the size of slice, and return error only if the size of the slice < 8.
-        if len < U64_ARRAY_SIZE {
-            let result = Err(Error::from(ErrorKind::InvalidInput));
-            return return_read_bytes_and_count_ev(&buf_place, None, result, dest, ecx);
+        if len < ty.size.bytes_usize() {
+            ecx.set_last_error_from_io_error(Error::from(ErrorKind::InvalidInput))?;
+            ecx.write_int(-1, dest)?;
+            return Ok(());
         }
 
+        // eventfd read at the size of u64.
+        let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
+
         // Block when counter == 0.
         let counter = self.counter.get();
         if counter == 0 {
             if self.is_nonblock {
-                let result = Err(Error::from(ErrorKind::WouldBlock));
-                return return_read_bytes_and_count_ev(&buf_place, None, result, dest, ecx);
-            } else {
-                //FIXME: blocking is not supported
-                throw_unsup_format!("eventfd: blocking is unsupported");
+                ecx.set_last_error_from_io_error(Error::from(ErrorKind::WouldBlock))?;
+                ecx.write_int(-1, dest)?;
+                return Ok(());
             }
+
+            throw_unsup_format!("eventfd: blocking is unsupported");
         } else {
             // Synchronize with all prior `write` calls to this FD.
             ecx.acquire_clock(&self.clock.borrow());
-            let result = Ok(U64_ARRAY_SIZE);
+
+            // Give old counter value to userspace, and set counter value to 0.
+            ecx.write_int(counter, &buf_place)?;
             self.counter.set(0);
+
             // When any of the event happened, we check and update the status of all supported event
             // types for current file description.
             ecx.check_and_update_readiness(self_ref)?;
 
-            return_read_bytes_and_count_ev(&buf_place, Some(counter), result, dest, ecx)
+            // Tell userspace how many bytes we wrote.
+            ecx.write_int(buf_place.layout.size.bytes(), dest)?;
         }
+
+        Ok(())
     }
 
     /// A write call adds the 8-byte integer value supplied in
@@ -117,14 +123,16 @@ impl FileDescription for Event {
         dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx> {
+        // We're treating the buffer as a `u64`.
+        let ty = ecx.machine.layouts.u64;
         // Check the size of slice, and return error only if the size of the slice < 8.
-        if len < U64_ARRAY_SIZE {
+        if len < ty.layout.size.bytes_usize() {
             let result = Err(Error::from(ErrorKind::InvalidInput));
             return ecx.return_written_byte_count_or_error(result, dest);
         }
 
         // Read the user supplied value from the pointer.
-        let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ecx.machine.layouts.u64);
+        let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
         let num = ecx.read_scalar(&buf_place)?.to_u64()?;
 
         // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
@@ -142,22 +150,20 @@ impl FileDescription for Event {
                 }
                 self.counter.set(new_count);
             }
-            None | Some(u64::MAX) => {
+            None | Some(u64::MAX) =>
                 if self.is_nonblock {
                     let result = Err(Error::from(ErrorKind::WouldBlock));
                     return ecx.return_written_byte_count_or_error(result, dest);
                 } else {
-                    //FIXME: blocking is not supported
                     throw_unsup_format!("eventfd: blocking is unsupported");
-                }
-            }
+                },
         };
         // When any of the event happened, we check and update the status of all supported event
         // types for current file description.
         ecx.check_and_update_readiness(self_ref)?;
 
-        let result = Ok(U64_ARRAY_SIZE);
-        ecx.return_written_byte_count_or_error(result, dest)
+        // Return how many bytes we read.
+        ecx.write_int(buf_place.layout.size.bytes(), dest)
     }
 }
 
@@ -222,28 +228,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         Ok(Scalar::from_i32(fd_value))
     }
 }
-
-/// This function either writes to the user supplied buffer and to dest place, or sets the
-/// last libc error and writes -1 to dest. This is only used by eventfd.
-fn return_read_bytes_and_count_ev<'tcx>(
-    buf_place: &MPlaceTy<'tcx>,
-    read_val: Option<u64>,
-    result: io::Result<usize>,
-    dest: &MPlaceTy<'tcx>,
-    ecx: &mut MiriInterpCx<'tcx>,
-) -> InterpResult<'tcx> {
-    match result.map(|c| i64::try_from(c).unwrap()) {
-        Ok(read_bytes) => {
-            // Write to the user supplied buffer.
-            ecx.write_int(read_val.unwrap(), buf_place)?;
-            // Write to the function return value place.
-            ecx.write_int(read_bytes, dest)?;
-            return Ok(());
-        }
-        Err(e) => {
-            ecx.set_last_error_from_io_error(e)?;
-            ecx.write_int(-1, dest)?;
-            return Ok(());
-        }
-    }
-}