1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
use crate::shims::unix::fs::FileDescriptor;
use rustc_const_eval::interpret::InterpResult;
use rustc_middle::ty::TyCtxt;
use rustc_target::abi::Endian;
use std::cell::Cell;
use std::io;
/// 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
/// with a file descriptor. For more information see the man
/// page below:
///
/// <https://man.netbsd.org/eventfd.2>
#[derive(Debug)]
pub 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.
pub val: Cell<u64>,
}
impl FileDescriptor for Event {
fn name(&self) -> &'static str {
"event"
}
fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> {
Ok(Box::new(Event { val: self.val.clone() }))
}
fn close<'tcx>(
self: Box<Self>,
_communicate_allowed: bool,
) -> InterpResult<'tcx, io::Result<i32>> {
Ok(Ok(0))
}
/// A write call adds the 8-byte integer value supplied in
/// its buffer (in native endianess) to the counter. The maximum value that may be
/// stored in the counter is the largest unsigned 64-bit value
/// minus 1 (i.e., 0xfffffffffffffffe). If the addition would
/// cause the counter's value to exceed the maximum, then the
/// write either blocks until a read is performed on the
/// file descriptor, or fails with the error EAGAIN if the
/// file descriptor has been made nonblocking.
/// A write fails with the error EINVAL if the size of the
/// supplied buffer is less than 8 bytes, or if an attempt is
/// made to write the value 0xffffffffffffffff.
fn write<'tcx>(
&self,
_communicate_allowed: bool,
bytes: &[u8],
tcx: TyCtxt<'tcx>,
) -> InterpResult<'tcx, io::Result<usize>> {
let v1 = self.val.get();
let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
// Convert from target endianess to host endianess.
let num = match tcx.sess.target.endian {
Endian::Little => u64::from_le_bytes(bytes),
Endian::Big => u64::from_be_bytes(bytes),
};
// FIXME handle blocking when addition results in exceeding the max u64 value
// or fail with EAGAIN if the file descriptor is nonblocking.
let v2 = v1.checked_add(num).unwrap();
self.val.set(v2);
assert_eq!(8, bytes.len());
Ok(Ok(8))
}
}