From d7741a93ac0a1acd4402a849ad63d64112286394 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Sep 2024 16:49:21 +0200 Subject: [PATCH] simplify eventfd handling a bit --- src/shims/unix/linux/eventfd.rs | 79 +++++++++++++-------------------- 1 file changed, 30 insertions(+), 49 deletions(-) diff --git a/src/shims/unix/linux/eventfd.rs b/src/shims/unix/linux/eventfd.rs index e1531fc2fa..d1d461daa9 100644 --- a/src/shims/unix/linux/eventfd.rs +++ b/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::(); - /// 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, - result: io::Result, - 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(()); - } - } -}