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::wutil::perror;
use libc::EINTR;
use libc::O_CLOEXEC;
use libc::{fcntl, F_GETFL, F_SETFL, O_CLOEXEC, O_NONBLOCK};
use nix::unistd;
use std::ffi::CStr;
use std::io::{Read, Write};
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
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!("wcstring_list_ffi_t")
generate!("make_fd_nonblocking")
generate!("wperror")
generate_pod!("pipes_ffi_t")

View File

@ -3,8 +3,9 @@ use crate::common::{str2wcstring, wcs2string, EMPTY_STRING};
use crate::fd_monitor::{
FdMonitor, FdMonitorItem, FdMonitorItemId, ItemWakeReason, NativeCallback,
};
use crate::fds::{make_autoclose_pipes, wopen_cloexec, AutoCloseFd, PIPE_ERROR};
use crate::ffi;
use crate::fds::{
make_autoclose_pipes, make_fd_nonblocking, wopen_cloexec, AutoCloseFd, PIPE_ERROR,
};
use crate::flog::{should_flog, FLOG, FLOGF};
use crate::global_safety::RelaxedAtomicBool;
use crate::job_group::JobGroup;
@ -13,7 +14,7 @@ use crate::redirection::{RedirectionMode, RedirectionSpecList};
use crate::signal::SigChecker;
use crate::topic_monitor::topic_t;
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 libc::{EAGAIN, EEXIST, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, O_EXCL, STDERR_FILENO};
use std::cell::UnsafeCell;
@ -343,11 +344,14 @@ impl IoBufferfill {
// 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
// from direct buffer transfers.
if ffi::make_fd_nonblocking(autocxx::c_int(pipes.read.fd())).0 != 0 {
match make_fd_nonblocking(&pipes.read.fd()) {
Ok(_) => (),
Err(e) => {
FLOG!(warning, PIPE_ERROR);
perror("fcntl");
perror_io("fcntl", &e);
return None;
}
}
// 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)));
begin_filling(&mut buffer, pipes.read);

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::fds::{self, AutoClosePipes};
use crate::ffi::{self as ffi, c_int};
use crate::fds::{self, make_fd_nonblocking, AutoClosePipes};
use crate::flog::{FloggableDebug, FLOG};
use crate::wchar::WString;
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
// (so reads will never block) and use select() to poll it.
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 {