Split unix-specific function into UnixFileDescription
This commit is contained in:
parent
374397f1bb
commit
035777d477
7 changed files with 190 additions and 155 deletions
|
|
@ -7,15 +7,9 @@ use std::rc::{Rc, Weak};
|
|||
|
||||
use rustc_abi::Size;
|
||||
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub(crate) enum FlockOp {
|
||||
SharedLock { nonblocking: bool },
|
||||
ExclusiveLock { nonblocking: bool },
|
||||
Unlock,
|
||||
}
|
||||
|
||||
/// Represents an open file description.
|
||||
pub trait FileDescription: std::fmt::Debug + Any {
|
||||
fn name(&self) -> &'static str;
|
||||
|
|
@ -50,37 +44,6 @@ pub trait FileDescription: std::fmt::Debug + Any {
|
|||
throw_unsup_format!("cannot write to {}", self.name());
|
||||
}
|
||||
|
||||
/// Reads as much as possible into the given buffer `ptr` from a given offset.
|
||||
/// `len` indicates how many bytes we should try to read.
|
||||
/// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error.
|
||||
fn pread<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
_offset: u64,
|
||||
_ptr: Pointer,
|
||||
_len: usize,
|
||||
_dest: &MPlaceTy<'tcx>,
|
||||
_ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
throw_unsup_format!("cannot pread from {}", self.name());
|
||||
}
|
||||
|
||||
/// Writes as much as possible from the given buffer `ptr` starting at a given offset.
|
||||
/// `ptr` is the pointer to the user supplied read buffer.
|
||||
/// `len` indicates how many bytes we should try to write.
|
||||
/// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error.
|
||||
fn pwrite<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
_ptr: Pointer,
|
||||
_len: usize,
|
||||
_offset: u64,
|
||||
_dest: &MPlaceTy<'tcx>,
|
||||
_ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
throw_unsup_format!("cannot pwrite to {}", self.name());
|
||||
}
|
||||
|
||||
/// Seeks to the given offset (which can be relative to the beginning, end, or current position).
|
||||
/// Returns the new position from the start of the stream.
|
||||
fn seek<'tcx>(
|
||||
|
|
@ -99,25 +62,14 @@ pub trait FileDescription: std::fmt::Debug + Any {
|
|||
throw_unsup_format!("cannot close {}", self.name());
|
||||
}
|
||||
|
||||
fn flock<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
_op: FlockOp,
|
||||
) -> InterpResult<'tcx, io::Result<()>> {
|
||||
throw_unsup_format!("cannot flock {}", self.name());
|
||||
}
|
||||
|
||||
fn is_tty(&self, _communicate_allowed: bool) -> bool {
|
||||
// Most FDs are not tty's and the consequence of a wrong `false` are minor,
|
||||
// so we use a default impl here.
|
||||
false
|
||||
}
|
||||
|
||||
/// Check the readiness of file description.
|
||||
fn get_epoll_ready_events<'tcx>(
|
||||
&self,
|
||||
) -> InterpResult<'tcx, crate::shims::unix::linux::epoll::EpollReadyEvents> {
|
||||
throw_unsup_format!("{}: epoll does not support this file description", self.name());
|
||||
fn as_unix(&self) -> &dyn UnixFileDescription {
|
||||
panic!("Not a unix file descriptor: {}", self.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,71 @@
|
|||
//! General management of file descriptors, and support for
|
||||
//! standard file descriptors (stdin/stdout/stderr).
|
||||
|
||||
use std::io;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
use rustc_abi::Size;
|
||||
|
||||
use crate::helpers::check_min_arg_count;
|
||||
use crate::shims::files::FlockOp;
|
||||
use crate::shims::files::FileDescription;
|
||||
use crate::shims::unix::linux_like::epoll::EpollReadyEvents;
|
||||
use crate::shims::unix::*;
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub(crate) enum FlockOp {
|
||||
SharedLock { nonblocking: bool },
|
||||
ExclusiveLock { nonblocking: bool },
|
||||
Unlock,
|
||||
}
|
||||
|
||||
/// Represents unix-specific file descriptions.
|
||||
pub trait UnixFileDescription: FileDescription {
|
||||
/// Reads as much as possible into the given buffer `ptr` from a given offset.
|
||||
/// `len` indicates how many bytes we should try to read.
|
||||
/// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error.
|
||||
fn pread<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
_offset: u64,
|
||||
_ptr: Pointer,
|
||||
_len: usize,
|
||||
_dest: &MPlaceTy<'tcx>,
|
||||
_ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
throw_unsup_format!("cannot pread from {}", self.name());
|
||||
}
|
||||
|
||||
/// Writes as much as possible from the given buffer `ptr` starting at a given offset.
|
||||
/// `ptr` is the pointer to the user supplied read buffer.
|
||||
/// `len` indicates how many bytes we should try to write.
|
||||
/// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error.
|
||||
fn pwrite<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
_ptr: Pointer,
|
||||
_len: usize,
|
||||
_offset: u64,
|
||||
_dest: &MPlaceTy<'tcx>,
|
||||
_ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
throw_unsup_format!("cannot pwrite to {}", self.name());
|
||||
}
|
||||
|
||||
fn flock<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
_op: FlockOp,
|
||||
) -> InterpResult<'tcx, io::Result<()>> {
|
||||
throw_unsup_format!("cannot flock {}", self.name());
|
||||
}
|
||||
|
||||
/// Check the readiness of file description.
|
||||
fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> {
|
||||
throw_unsup_format!("{}: epoll does not support this file description", self.name());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn dup(&mut self, old_fd_num: i32) -> InterpResult<'tcx, Scalar> {
|
||||
|
|
@ -66,7 +121,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
throw_unsup_format!("unsupported flags {:#x}", op);
|
||||
};
|
||||
|
||||
let result = fd.flock(this.machine.communicate(), parsed_op)?;
|
||||
let result = fd.as_unix().flock(this.machine.communicate(), parsed_op)?;
|
||||
drop(fd);
|
||||
// return `0` if flock is successful
|
||||
let result = result.map(|()| 0i32);
|
||||
|
|
@ -196,7 +251,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let Ok(offset) = u64::try_from(offset) else {
|
||||
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
};
|
||||
fd.pread(communicate, offset, buf, count, dest, this)?
|
||||
fd.as_unix().pread(communicate, offset, buf, count, dest, this)?
|
||||
}
|
||||
};
|
||||
interp_ok(())
|
||||
|
|
@ -236,7 +291,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let Ok(offset) = u64::try_from(offset) else {
|
||||
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
};
|
||||
fd.pwrite(communicate, buf, count, offset, dest, this)?
|
||||
fd.as_unix().pwrite(communicate, buf, count, offset, dest, this)?
|
||||
}
|
||||
};
|
||||
interp_ok(())
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
|
||||
use self::shims::time::system_time_to_duration;
|
||||
use crate::helpers::check_min_arg_count;
|
||||
use crate::shims::files::{EvalContextExt as _, FileDescription, FileDescriptionRef, FlockOp};
|
||||
use crate::shims::files::{EvalContextExt as _, FileDescription, FileDescriptionRef};
|
||||
use crate::shims::os_str::bytes_to_os_str;
|
||||
use crate::shims::unix::fd::{FlockOp, UnixFileDescription};
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -64,6 +65,51 @@ impl FileDescription for FileHandle {
|
|||
}
|
||||
}
|
||||
|
||||
fn seek<'tcx>(
|
||||
&self,
|
||||
communicate_allowed: bool,
|
||||
offset: SeekFrom,
|
||||
) -> InterpResult<'tcx, io::Result<u64>> {
|
||||
assert!(communicate_allowed, "isolation should have prevented even opening a file");
|
||||
interp_ok((&mut &self.file).seek(offset))
|
||||
}
|
||||
|
||||
fn close<'tcx>(
|
||||
self: Box<Self>,
|
||||
communicate_allowed: bool,
|
||||
_ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<()>> {
|
||||
assert!(communicate_allowed, "isolation should have prevented even opening a file");
|
||||
// We sync the file if it was opened in a mode different than read-only.
|
||||
if self.writable {
|
||||
// `File::sync_all` does the checks that are done when closing a file. We do this to
|
||||
// to handle possible errors correctly.
|
||||
let result = self.file.sync_all();
|
||||
// Now we actually close the file and return the result.
|
||||
drop(*self);
|
||||
interp_ok(result)
|
||||
} else {
|
||||
// We drop the file, this closes it but ignores any errors
|
||||
// produced when closing it. This is done because
|
||||
// `File::sync_all` cannot be done over files like
|
||||
// `/dev/urandom` which are read-only. Check
|
||||
// https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
|
||||
// for a deeper discussion.
|
||||
drop(*self);
|
||||
interp_ok(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn is_tty(&self, communicate_allowed: bool) -> bool {
|
||||
communicate_allowed && self.file.is_terminal()
|
||||
}
|
||||
|
||||
fn as_unix(&self) -> &dyn UnixFileDescription {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl UnixFileDescription for FileHandle {
|
||||
fn pread<'tcx>(
|
||||
&self,
|
||||
communicate_allowed: bool,
|
||||
|
|
@ -126,41 +172,6 @@ impl FileDescription for FileHandle {
|
|||
}
|
||||
}
|
||||
|
||||
fn seek<'tcx>(
|
||||
&self,
|
||||
communicate_allowed: bool,
|
||||
offset: SeekFrom,
|
||||
) -> InterpResult<'tcx, io::Result<u64>> {
|
||||
assert!(communicate_allowed, "isolation should have prevented even opening a file");
|
||||
interp_ok((&mut &self.file).seek(offset))
|
||||
}
|
||||
|
||||
fn close<'tcx>(
|
||||
self: Box<Self>,
|
||||
communicate_allowed: bool,
|
||||
_ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<()>> {
|
||||
assert!(communicate_allowed, "isolation should have prevented even opening a file");
|
||||
// We sync the file if it was opened in a mode different than read-only.
|
||||
if self.writable {
|
||||
// `File::sync_all` does the checks that are done when closing a file. We do this to
|
||||
// to handle possible errors correctly.
|
||||
let result = self.file.sync_all();
|
||||
// Now we actually close the file and return the result.
|
||||
drop(*self);
|
||||
interp_ok(result)
|
||||
} else {
|
||||
// We drop the file, this closes it but ignores any errors
|
||||
// produced when closing it. This is done because
|
||||
// `File::sync_all` cannot be done over files like
|
||||
// `/dev/urandom` which are read-only. Check
|
||||
// https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
|
||||
// for a deeper discussion.
|
||||
drop(*self);
|
||||
interp_ok(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn flock<'tcx>(
|
||||
&self,
|
||||
communicate_allowed: bool,
|
||||
|
|
@ -255,10 +266,6 @@ impl FileDescription for FileHandle {
|
|||
compile_error!("flock is supported only on UNIX and Windows hosts");
|
||||
}
|
||||
}
|
||||
|
||||
fn is_tty(&self, communicate_allowed: bool) -> bool {
|
||||
communicate_allowed && self.file.is_terminal()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExtPrivate<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::time::Duration;
|
|||
|
||||
use crate::concurrency::VClock;
|
||||
use crate::shims::files::{FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef};
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::*;
|
||||
|
||||
/// An `Epoll` file descriptor connects file handles and epoll events
|
||||
|
|
@ -151,8 +152,14 @@ impl FileDescription for Epoll {
|
|||
) -> InterpResult<'tcx, io::Result<()>> {
|
||||
interp_ok(Ok(()))
|
||||
}
|
||||
|
||||
fn as_unix(&self) -> &dyn UnixFileDescription {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl UnixFileDescription for Epoll {}
|
||||
|
||||
/// The table of all EpollEventInterest.
|
||||
/// The BTreeMap key is the FdId of an active file description registered with
|
||||
/// any epoll instance. The value is a list of EpollEventInterest associated
|
||||
|
|
@ -594,7 +601,7 @@ fn check_and_update_one_event_interest<'tcx>(
|
|||
ecx: &MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
// Get the bitmask of ready events for a file description.
|
||||
let ready_events_bitmask = fd_ref.get_epoll_ready_events()?.get_event_bitmask(ecx);
|
||||
let ready_events_bitmask = fd_ref.as_unix().get_epoll_ready_events()?.get_event_bitmask(ecx);
|
||||
let epoll_event_interest = interest.borrow();
|
||||
// This checks if any of the events specified in epoll_event_interest.events
|
||||
// match those in ready_events.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use std::io::ErrorKind;
|
|||
|
||||
use crate::concurrency::VClock;
|
||||
use crate::shims::files::{FileDescription, FileDescriptionRef, WeakFileDescriptionRef};
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::shims::unix::linux_like::epoll::{EpollReadyEvents, EvalContextExt as _};
|
||||
use crate::*;
|
||||
|
||||
|
|
@ -36,17 +37,6 @@ impl FileDescription for Event {
|
|||
"event"
|
||||
}
|
||||
|
||||
fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> {
|
||||
// We only check the status of EPOLLIN and EPOLLOUT flags for eventfd. If other event flags
|
||||
// need to be supported in the future, the check should be added here.
|
||||
|
||||
interp_ok(EpollReadyEvents {
|
||||
epollin: self.counter.get() != 0,
|
||||
epollout: self.counter.get() != MAX_COUNTER,
|
||||
..EpollReadyEvents::new()
|
||||
})
|
||||
}
|
||||
|
||||
fn close<'tcx>(
|
||||
self: Box<Self>,
|
||||
_communicate_allowed: bool,
|
||||
|
|
@ -120,6 +110,23 @@ impl FileDescription for Event {
|
|||
let weak_eventfd = self_ref.downgrade();
|
||||
eventfd_write(num, buf_place, dest, weak_eventfd, ecx)
|
||||
}
|
||||
|
||||
fn as_unix(&self) -> &dyn UnixFileDescription {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl UnixFileDescription for Event {
|
||||
fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> {
|
||||
// We only check the status of EPOLLIN and EPOLLOUT flags for eventfd. If other event flags
|
||||
// need to be supported in the future, the check should be added here.
|
||||
|
||||
interp_ok(EpollReadyEvents {
|
||||
epollin: self.counter.get() != 0,
|
||||
epollout: self.counter.get() != MAX_COUNTER,
|
||||
..EpollReadyEvents::new()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ mod unnamed_socket;
|
|||
|
||||
mod android;
|
||||
mod freebsd;
|
||||
mod linux;
|
||||
pub mod linux;
|
||||
mod linux_like;
|
||||
mod macos;
|
||||
mod solarish;
|
||||
|
||||
// All the Unix-specific extension traits
|
||||
pub use self::env::{EvalContextExt as _, UnixEnvVars};
|
||||
pub use self::fd::EvalContextExt as _;
|
||||
pub use self::fd::{EvalContextExt as _, UnixFileDescription};
|
||||
pub use self::fs::{DirTable, EvalContextExt as _};
|
||||
pub use self::linux_like::epoll::EpollInterestTable;
|
||||
pub use self::mem::EvalContextExt as _;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use crate::concurrency::VClock;
|
|||
use crate::shims::files::{
|
||||
EvalContextExt as _, FileDescription, FileDescriptionRef, WeakFileDescriptionRef,
|
||||
};
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::shims::unix::linux_like::epoll::{EpollReadyEvents, EvalContextExt as _};
|
||||
use crate::*;
|
||||
|
||||
|
|
@ -61,52 +62,6 @@ impl FileDescription for AnonSocket {
|
|||
"socketpair"
|
||||
}
|
||||
|
||||
fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> {
|
||||
// We only check the status of EPOLLIN, EPOLLOUT, EPOLLHUP and EPOLLRDHUP flags.
|
||||
// If other event flags need to be supported in the future, the check should be added here.
|
||||
|
||||
let mut epoll_ready_events = EpollReadyEvents::new();
|
||||
|
||||
// Check if it is readable.
|
||||
if let Some(readbuf) = &self.readbuf {
|
||||
if !readbuf.borrow().buf.is_empty() {
|
||||
epoll_ready_events.epollin = true;
|
||||
}
|
||||
} else {
|
||||
// Without a read buffer, reading never blocks, so we are always ready.
|
||||
epoll_ready_events.epollin = true;
|
||||
}
|
||||
|
||||
// Check if is writable.
|
||||
if let Some(peer_fd) = self.peer_fd().upgrade() {
|
||||
if let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf {
|
||||
let data_size = writebuf.borrow().buf.len();
|
||||
let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(data_size);
|
||||
if available_space != 0 {
|
||||
epoll_ready_events.epollout = true;
|
||||
}
|
||||
} else {
|
||||
// Without a write buffer, writing never blocks.
|
||||
epoll_ready_events.epollout = true;
|
||||
}
|
||||
} else {
|
||||
// Peer FD has been closed. This always sets both the RDHUP and HUP flags
|
||||
// as we do not support `shutdown` that could be used to partially close the stream.
|
||||
epoll_ready_events.epollrdhup = true;
|
||||
epoll_ready_events.epollhup = true;
|
||||
// Since the peer is closed, even if no data is available reads will return EOF and
|
||||
// writes will return EPIPE. In other words, they won't block, so we mark this as ready
|
||||
// for read and write.
|
||||
epoll_ready_events.epollin = true;
|
||||
epoll_ready_events.epollout = true;
|
||||
// If there is data lost in peer_fd, set EPOLLERR.
|
||||
if self.peer_lost_data.get() {
|
||||
epoll_ready_events.epollerr = true;
|
||||
}
|
||||
}
|
||||
interp_ok(epoll_ready_events)
|
||||
}
|
||||
|
||||
fn close<'tcx>(
|
||||
self: Box<Self>,
|
||||
_communicate_allowed: bool,
|
||||
|
|
@ -211,6 +166,10 @@ impl FileDescription for AnonSocket {
|
|||
}
|
||||
anonsocket_write(available_space, &peer_fd, ptr, len, dest, ecx)
|
||||
}
|
||||
|
||||
fn as_unix(&self) -> &dyn UnixFileDescription {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Write to AnonSocket based on the space available and return the written byte size.
|
||||
|
|
@ -290,6 +249,54 @@ fn anonsocket_read<'tcx>(
|
|||
ecx.return_read_success(ptr, bytes, actual_read_size, dest)
|
||||
}
|
||||
|
||||
impl UnixFileDescription for AnonSocket {
|
||||
fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> {
|
||||
// We only check the status of EPOLLIN, EPOLLOUT, EPOLLHUP and EPOLLRDHUP flags.
|
||||
// If other event flags need to be supported in the future, the check should be added here.
|
||||
|
||||
let mut epoll_ready_events = EpollReadyEvents::new();
|
||||
|
||||
// Check if it is readable.
|
||||
if let Some(readbuf) = &self.readbuf {
|
||||
if !readbuf.borrow().buf.is_empty() {
|
||||
epoll_ready_events.epollin = true;
|
||||
}
|
||||
} else {
|
||||
// Without a read buffer, reading never blocks, so we are always ready.
|
||||
epoll_ready_events.epollin = true;
|
||||
}
|
||||
|
||||
// Check if is writable.
|
||||
if let Some(peer_fd) = self.peer_fd().upgrade() {
|
||||
if let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf {
|
||||
let data_size = writebuf.borrow().buf.len();
|
||||
let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(data_size);
|
||||
if available_space != 0 {
|
||||
epoll_ready_events.epollout = true;
|
||||
}
|
||||
} else {
|
||||
// Without a write buffer, writing never blocks.
|
||||
epoll_ready_events.epollout = true;
|
||||
}
|
||||
} else {
|
||||
// Peer FD has been closed. This always sets both the RDHUP and HUP flags
|
||||
// as we do not support `shutdown` that could be used to partially close the stream.
|
||||
epoll_ready_events.epollrdhup = true;
|
||||
epoll_ready_events.epollhup = true;
|
||||
// Since the peer is closed, even if no data is available reads will return EOF and
|
||||
// writes will return EPIPE. In other words, they won't block, so we mark this as ready
|
||||
// for read and write.
|
||||
epoll_ready_events.epollin = true;
|
||||
epoll_ready_events.epollout = true;
|
||||
// If there is data lost in peer_fd, set EPOLLERR.
|
||||
if self.peer_lost_data.get() {
|
||||
epoll_ready_events.epollerr = true;
|
||||
}
|
||||
}
|
||||
interp_ok(epoll_ready_events)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
/// For more information on the arguments see the socketpair manpage:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue