fds: add make_fd_{,non}blocking implementations in Rust

This commit is contained in:
David Adam 2023-07-20 23:38:54 +08:00
parent 0b291355b2
commit 35aa7636eb
4 changed files with 41 additions and 13 deletions

View File

@ -3,10 +3,10 @@ use crate::ffi;
use crate::wchar::{wstr, L}; use crate::wchar::{wstr, L};
use crate::wutil::perror; use crate::wutil::perror;
use libc::EINTR; use libc::EINTR;
use libc::O_CLOEXEC; use libc::{fcntl, F_GETFL, F_SETFL, O_CLOEXEC, O_NONBLOCK};
use nix::unistd; use nix::unistd;
use std::ffi::CStr; use std::ffi::CStr;
use std::io::{Read, Write}; use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
pub const PIPE_ERROR: &wstr = L!("An error occurred while setting up pipe"); pub const PIPE_ERROR: &wstr = L!("An error occurred while setting up pipe");
@ -187,3 +187,29 @@ pub fn exec_close(fd: RawFd) {
} }
} }
} }
/// Mark an fd as nonblocking
pub fn make_fd_nonblocking(fd: RawFd) -> Result<(), io::Error> {
let flags = unsafe { fcntl(fd, F_GETFL, 0) };
let nonblocking = (flags & O_NONBLOCK) == O_NONBLOCK;
if !nonblocking {
match unsafe { fcntl(fd, F_SETFL, flags | O_NONBLOCK) } {
0 => return Ok(()),
_ => return Err(io::Error::last_os_error()),
};
}
Ok(())
}
/// Mark an fd as blocking
pub fn make_fd_blocking(fd: RawFd) -> Result<(), io::Error> {
let flags = unsafe { fcntl(fd, F_GETFL, 0) };
let nonblocking = (flags & O_NONBLOCK) == O_NONBLOCK;
if nonblocking {
match unsafe { fcntl(fd, F_SETFL, flags & !O_NONBLOCK) } {
0 => return Ok(()),
_ => return Err(io::Error::last_os_error()),
};
}
Ok(())
}

View File

@ -55,7 +55,6 @@ include_cpp! {
generate_pod!("wcharz_t") generate_pod!("wcharz_t")
generate!("wcstring_list_ffi_t") generate!("wcstring_list_ffi_t")
generate!("make_fd_nonblocking")
generate!("wperror") generate!("wperror")
generate_pod!("pipes_ffi_t") generate_pod!("pipes_ffi_t")

View File

@ -3,8 +3,9 @@ use crate::common::{str2wcstring, wcs2string, EMPTY_STRING};
use crate::fd_monitor::{ use crate::fd_monitor::{
FdMonitor, FdMonitorItem, FdMonitorItemId, ItemWakeReason, NativeCallback, FdMonitor, FdMonitorItem, FdMonitorItemId, ItemWakeReason, NativeCallback,
}; };
use crate::fds::{make_autoclose_pipes, wopen_cloexec, AutoCloseFd, PIPE_ERROR}; use crate::fds::{
use crate::ffi; make_autoclose_pipes, make_fd_nonblocking, wopen_cloexec, AutoCloseFd, PIPE_ERROR,
};
use crate::flog::{should_flog, FLOG, FLOGF}; use crate::flog::{should_flog, FLOG, FLOGF};
use crate::global_safety::RelaxedAtomicBool; use crate::global_safety::RelaxedAtomicBool;
use crate::job_group::JobGroup; use crate::job_group::JobGroup;
@ -13,7 +14,7 @@ use crate::redirection::{RedirectionMode, RedirectionSpecList};
use crate::signal::SigChecker; use crate::signal::SigChecker;
use crate::topic_monitor::topic_t; use crate::topic_monitor::topic_t;
use crate::wchar::{wstr, WString, L}; use crate::wchar::{wstr, WString, L};
use crate::wutil::{perror, wdirname, wstat, wwrite_to_fd}; use crate::wutil::{perror, perror_io, wdirname, wstat, wwrite_to_fd};
use errno::Errno; use errno::Errno;
use libc::{EAGAIN, EEXIST, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, O_EXCL, STDERR_FILENO}; use libc::{EAGAIN, EEXIST, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, O_EXCL, STDERR_FILENO};
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
@ -343,10 +344,13 @@ impl IoBufferfill {
// Our buffer will read from the read end of the pipe. This end must be non-blocking. This is // Our buffer will read from the read end of the pipe. This end must be non-blocking. This is
// because our fillthread needs to poll to decide if it should shut down, and also accept input // because our fillthread needs to poll to decide if it should shut down, and also accept input
// from direct buffer transfers. // from direct buffer transfers.
if ffi::make_fd_nonblocking(autocxx::c_int(pipes.read.fd())).0 != 0 { match make_fd_nonblocking(&pipes.read.fd()) {
FLOG!(warning, PIPE_ERROR); Ok(_) => (),
perror("fcntl"); Err(e) => {
return None; FLOG!(warning, PIPE_ERROR);
perror_io("fcntl", &e);
return None;
}
} }
// Our fillthread gets the read end of the pipe; out_pipe gets the write end. // Our fillthread gets the read end of the pipe; out_pipe gets the write end.
let mut buffer = Arc::new(RwLock::new(IoBuffer::new(buffer_limit))); let mut buffer = Arc::new(RwLock::new(IoBuffer::new(buffer_limit)));

View File

@ -21,8 +21,7 @@ set. This is the real power of topics: you can wait for a sigchld signal OR a th
*/ */
use crate::fd_readable_set::fd_readable_set_t; use crate::fd_readable_set::fd_readable_set_t;
use crate::fds::{self, AutoClosePipes}; use crate::fds::{self, make_fd_nonblocking, AutoClosePipes};
use crate::ffi::{self as ffi, c_int};
use crate::flog::{FloggableDebug, FLOG}; use crate::flog::{FloggableDebug, FLOG};
use crate::wchar::WString; use crate::wchar::WString;
use crate::wutil::perror; use crate::wutil::perror;
@ -213,7 +212,7 @@ impl binary_semaphore_t {
// receive SIGCHLD and so deadlock. So if tsan is enabled, we mark our fd as non-blocking // receive SIGCHLD and so deadlock. So if tsan is enabled, we mark our fd as non-blocking
// (so reads will never block) and use select() to poll it. // (so reads will never block) and use select() to poll it.
if cfg!(feature = "FISH_TSAN_WORKAROUNDS") { if cfg!(feature = "FISH_TSAN_WORKAROUNDS") {
ffi::make_fd_nonblocking(c_int(pipes_.read.fd())); let _ = make_fd_nonblocking(&pipes_.read.fd());
} }
} }
binary_semaphore_t { binary_semaphore_t {