mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-15 06:24:01 +00:00
Move from libc read/write to nix read/write
Replace std from_raw_fd/into_raw_fd dance with nix write Fixup notifyd build
This commit is contained in:
parent
65cf6ada56
commit
f3e8272c5d
11 changed files with 107 additions and 119 deletions
|
@ -285,13 +285,14 @@ fn read_in_chunks(fd: RawFd, buff: &mut WString, split_null: bool, do_seek: bool
|
||||||
|
|
||||||
while !finished {
|
while !finished {
|
||||||
let mut inbuf = [0_u8; READ_CHUNK_SIZE];
|
let mut inbuf = [0_u8; READ_CHUNK_SIZE];
|
||||||
let bytes_read = read_blocked(fd, &mut inbuf);
|
|
||||||
|
|
||||||
if bytes_read <= 0 {
|
let bytes_read = match read_blocked(fd, &mut inbuf) {
|
||||||
|
Ok(0) | Err(_) => {
|
||||||
eof = true;
|
eof = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let bytes_read = bytes_read as usize;
|
Ok(read) => read,
|
||||||
|
};
|
||||||
|
|
||||||
let bytes_consumed = inbuf[..bytes_read]
|
let bytes_consumed = inbuf[..bytes_read]
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -352,10 +353,13 @@ fn read_one_char_at_a_time(
|
||||||
|
|
||||||
while !finished {
|
while !finished {
|
||||||
let mut b = [0_u8; 1];
|
let mut b = [0_u8; 1];
|
||||||
if read_blocked(fd, &mut b) <= 0 {
|
match read_blocked(fd, &mut b) {
|
||||||
|
Ok(0) | Err(_) => {
|
||||||
eof = true;
|
eof = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
let b = b[0];
|
let b = b[0];
|
||||||
|
|
||||||
nbytes += 1;
|
nbytes += 1;
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::wutil::encoding::{mbrtowc, wcrtomb, zero_mbstate, AT_LEAST_MB_LEN_MAX
|
||||||
use crate::wutil::fish_iswalnum;
|
use crate::wutil::fish_iswalnum;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use libc::{EINTR, EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
use libc::{EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -1469,10 +1469,10 @@ fn can_be_encoded(wc: char) -> bool {
|
||||||
|
|
||||||
/// Call read, blocking and repeating on EINTR. Exits on EAGAIN.
|
/// Call read, blocking and repeating on EINTR. Exits on EAGAIN.
|
||||||
/// \return the number of bytes read, or 0 on EOF. On EAGAIN, returns -1 if nothing was read.
|
/// \return the number of bytes read, or 0 on EOF. On EAGAIN, returns -1 if nothing was read.
|
||||||
pub fn read_blocked(fd: RawFd, buf: &mut [u8]) -> isize {
|
pub fn read_blocked(fd: RawFd, buf: &mut [u8]) -> nix::Result<usize> {
|
||||||
loop {
|
loop {
|
||||||
let res = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) };
|
let res = nix::unistd::read(fd, buf);
|
||||||
if res < 0 && errno::errno().0 == EINTR {
|
if let Err(nix::Error::EINTR) = res {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -1496,16 +1496,17 @@ pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
let fd = fd.as_raw_fd();
|
let fd = fd.as_raw_fd();
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
while total < buf.len() {
|
while total < buf.len() {
|
||||||
let written =
|
match nix::unistd::write(fd, &buf[total..]) {
|
||||||
unsafe { libc::write(fd, buf[total..].as_ptr() as *const _, buf.len() - total) };
|
Ok(written) => {
|
||||||
if written < 0 {
|
total += written;
|
||||||
let errno = errno::errno().0;
|
}
|
||||||
if matches!(errno, libc::EAGAIN | libc::EINTR) {
|
Err(err) => {
|
||||||
|
if matches!(err, nix::Error::EAGAIN | nix::Error::EINTR) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return Err(std::io::Error::from_raw_os_error(errno));
|
return Err(std::io::Error::from(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
total += written as usize;
|
|
||||||
}
|
}
|
||||||
Ok(total)
|
Ok(total)
|
||||||
}
|
}
|
||||||
|
@ -1517,15 +1518,17 @@ pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
pub fn read_loop<Fd: AsRawFd>(fd: &Fd, buf: &mut [u8]) -> std::io::Result<usize> {
|
pub fn read_loop<Fd: AsRawFd>(fd: &Fd, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
let fd = fd.as_raw_fd();
|
let fd = fd.as_raw_fd();
|
||||||
loop {
|
loop {
|
||||||
let read = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) };
|
match nix::unistd::read(fd, buf) {
|
||||||
if read < 0 {
|
Ok(read) => {
|
||||||
let errno = errno::errno().0;
|
return Ok(read);
|
||||||
if matches!(errno, libc::EAGAIN | libc::EINTR) {
|
}
|
||||||
|
Err(err) => {
|
||||||
|
if matches!(err, nix::Error::EAGAIN | nix::Error::EINTR) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return Err(std::io::Error::from_raw_os_error(errno));
|
return Err(std::io::Error::from(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Ok(read as usize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,22 +120,23 @@ impl FdEventSignaller {
|
||||||
let c = 1_u8;
|
let c = 1_u8;
|
||||||
let mut ret;
|
let mut ret;
|
||||||
loop {
|
loop {
|
||||||
ret = unsafe {
|
let bytes = c.to_ne_bytes();
|
||||||
libc::write(
|
ret = nix::unistd::write(self.write_fd(), &bytes);
|
||||||
self.write_fd(),
|
|
||||||
&c as *const _ as *const c_void,
|
match ret {
|
||||||
std::mem::size_of_val(&c),
|
Ok(_) => break,
|
||||||
)
|
Err(nix::Error::EINTR) => continue,
|
||||||
};
|
Err(_) => break,
|
||||||
if ret >= 0 || errno().0 != EINTR {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(err) = ret {
|
||||||
// EAGAIN occurs if either the pipe buffer is full or the eventfd overflows (very unlikely).
|
// EAGAIN occurs if either the pipe buffer is full or the eventfd overflows (very unlikely).
|
||||||
if ret < 0 && ![EAGAIN, EWOULDBLOCK].contains(&errno().0) {
|
if ![nix::Error::EAGAIN, nix::Error::EWOULDBLOCK].contains(&err) {
|
||||||
perror("write");
|
perror("write");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform a poll to see if an event is received.
|
/// Perform a poll to see if an event is received.
|
||||||
/// If \p wait is set, wait until it is readable; this does not consume the event
|
/// If \p wait is set, wait until it is readable; this does not consume the event
|
||||||
|
|
14
src/fds.rs
14
src/fds.rs
|
@ -33,23 +33,13 @@ pub struct AutoCloseFd {
|
||||||
|
|
||||||
impl Read for AutoCloseFd {
|
impl Read for AutoCloseFd {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
unsafe {
|
nix::unistd::read(self.as_raw_fd(), buf).map_err(std::io::Error::from)
|
||||||
match libc::read(self.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len()) {
|
|
||||||
-1 => Err(std::io::Error::from_raw_os_error(errno::errno().0)),
|
|
||||||
bytes => Ok(bytes as usize),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Write for AutoCloseFd {
|
impl Write for AutoCloseFd {
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
unsafe {
|
nix::unistd::write(self.as_raw_fd(), buf).map_err(std::io::Error::from)
|
||||||
match libc::write(self.as_raw_fd(), buf.as_ptr() as *const _, buf.len()) {
|
|
||||||
-1 => Err(std::io::Error::from_raw_os_error(errno::errno().0)),
|
|
||||||
bytes => Ok(bytes as usize),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) -> std::io::Result<()> {
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
|
|
@ -84,9 +84,7 @@ pub fn flog_impl_async_safe(fd: i32, s: impl FloggableDisplayAsyncSafe) {
|
||||||
let bytes: &[u8] = s.to_flog_str_async_safe(&mut storage);
|
let bytes: &[u8] = s.to_flog_str_async_safe(&mut storage);
|
||||||
// Note we deliberately do not retry on signals, etc.
|
// Note we deliberately do not retry on signals, etc.
|
||||||
// This is used to report error messages after fork() in the child process.
|
// This is used to report error messages after fork() in the child process.
|
||||||
unsafe {
|
let _ = nix::unistd::write(fd, bytes);
|
||||||
let _ = libc::write(fd, bytes.as_ptr() as *const libc::c_void, bytes.len());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Variant of FLOG which is async-safe to use after fork().
|
/// Variant of FLOG which is async-safe to use after fork().
|
||||||
|
|
|
@ -7,10 +7,9 @@ use std::{
|
||||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use errno::errno;
|
|
||||||
use libc::{
|
use libc::{
|
||||||
c_void, lseek, mmap, munmap, EINTR, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ,
|
lseek, mmap, munmap, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, PROT_WRITE, SEEK_END,
|
||||||
PROT_WRITE, SEEK_END, SEEK_SET,
|
SEEK_SET,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{HistoryItem, PersistenceMode};
|
use super::{HistoryItem, PersistenceMode};
|
||||||
|
@ -137,7 +136,7 @@ impl HistoryFileContents {
|
||||||
if unsafe { lseek(fd, 0, SEEK_SET) } != 0 {
|
if unsafe { lseek(fd, 0, SEEK_SET) } != 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if !read_from_fd(fd, region.as_mut()) {
|
if read_from_fd(fd, region.as_mut()).is_err() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,25 +229,19 @@ fn should_mmap() -> bool {
|
||||||
|
|
||||||
/// Read from `fd` to fill `dest`, zeroing any unused space.
|
/// Read from `fd` to fill `dest`, zeroing any unused space.
|
||||||
// Return true on success, false on failure.
|
// Return true on success, false on failure.
|
||||||
fn read_from_fd(fd: RawFd, dest: &mut [u8]) -> bool {
|
fn read_from_fd(fd: RawFd, mut dest: &mut [u8]) -> nix::Result<()> {
|
||||||
let mut remaining = dest.len();
|
while !dest.is_empty() {
|
||||||
let mut nread = 0;
|
match nix::unistd::read(fd, dest) {
|
||||||
while remaining > 0 {
|
Ok(0) => break,
|
||||||
let amt =
|
Ok(amt) => {
|
||||||
unsafe { libc::read(fd, (&mut dest[nread]) as *mut u8 as *mut c_void, remaining) };
|
dest = &mut dest[amt..];
|
||||||
if amt < 0 {
|
|
||||||
if errno().0 != EINTR {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} else if amt == 0 {
|
Err(nix::Error::EINTR) => continue,
|
||||||
break;
|
Err(err) => return Err(err),
|
||||||
} else {
|
|
||||||
remaining -= amt as usize;
|
|
||||||
nread += amt as usize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dest[nread..].fill(0u8);
|
dest.fill(0u8);
|
||||||
true
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_all(s: &mut Vec<u8>, needle: &[u8], replacement: &[u8]) {
|
fn replace_all(s: &mut Vec<u8>, needle: &[u8], replacement: &[u8]) {
|
||||||
|
|
|
@ -294,7 +294,7 @@ fn readb(in_fd: RawFd) -> ReadbResult {
|
||||||
// Check stdin.
|
// Check stdin.
|
||||||
if fdset.test(in_fd) {
|
if fdset.test(in_fd) {
|
||||||
let mut arr: [u8; 1] = [0];
|
let mut arr: [u8; 1] = [0];
|
||||||
if read_blocked(in_fd, &mut arr) != 1 {
|
if read_blocked(in_fd, &mut arr) != Ok(1) {
|
||||||
// The terminal has been closed.
|
// The terminal has been closed.
|
||||||
return ReadbResult::Eof;
|
return ReadbResult::Eof;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
//! end of the list is reached, at which point regular searching will commence.
|
//! end of the list is reached, at which point regular searching will commence.
|
||||||
|
|
||||||
use libc::{
|
use libc::{
|
||||||
c_char, c_int, c_void, EAGAIN, ECHO, EINTR, EIO, EISDIR, ENOTTY, EPERM, ESRCH, EWOULDBLOCK,
|
c_char, c_int, ECHO, EINTR, EIO, EISDIR, ENOTTY, EPERM, ESRCH, ICANON, ICRNL, IEXTEN, INLCR,
|
||||||
ICANON, ICRNL, IEXTEN, INLCR, IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN,
|
IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, STDIN_FILENO, STDOUT_FILENO,
|
||||||
STDIN_FILENO, STDOUT_FILENO, S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE,
|
S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE,
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
@ -688,18 +688,21 @@ fn read_ni(parser: &Parser, fd: RawFd, io: &IoChain) -> i32 {
|
||||||
let mut fd_contents = Vec::with_capacity(usize::try_from(buf.st_size).unwrap());
|
let mut fd_contents = Vec::with_capacity(usize::try_from(buf.st_size).unwrap());
|
||||||
loop {
|
loop {
|
||||||
let mut buff = [0_u8; 4096];
|
let mut buff = [0_u8; 4096];
|
||||||
let amt = unsafe { libc::read(fd, &mut buff[0] as *mut _ as *mut c_void, buff.len()) };
|
|
||||||
if amt > 0 {
|
match nix::unistd::read(fd, &mut buff) {
|
||||||
fd_contents.extend_from_slice(&buff[..usize::try_from(amt).unwrap()]);
|
Ok(0) => {
|
||||||
} else if amt == 0 {
|
|
||||||
// EOF.
|
// EOF.
|
||||||
break;
|
break;
|
||||||
} else {
|
}
|
||||||
assert!(amt == -1);
|
Ok(amt) => {
|
||||||
let err = errno();
|
fd_contents.extend_from_slice(&buff[..amt]);
|
||||||
if err.0 == EINTR {
|
}
|
||||||
|
Err(err) => {
|
||||||
|
if err == nix::Error::EINTR {
|
||||||
continue;
|
continue;
|
||||||
} else if err.0 == EAGAIN || err.0 == EWOULDBLOCK && make_fd_blocking(fd).is_ok() {
|
} else if err == nix::Error::EAGAIN
|
||||||
|
|| err == nix::Error::EWOULDBLOCK && make_fd_blocking(fd).is_ok()
|
||||||
|
{
|
||||||
// We succeeded in making the fd blocking, keep going.
|
// We succeeded in making the fd blocking, keep going.
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -712,6 +715,7 @@ fn read_ni(parser: &Parser, fd: RawFd, io: &IoChain) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut s = str2wcstring(&fd_contents);
|
let mut s = str2wcstring(&fd_contents);
|
||||||
|
|
||||||
|
|
|
@ -76,9 +76,8 @@ impl ItemMaker {
|
||||||
}
|
}
|
||||||
ItemWakeReason::Readable => {
|
ItemWakeReason::Readable => {
|
||||||
let mut buf = [0u8; 1024];
|
let mut buf = [0u8; 1024];
|
||||||
let amt =
|
let res = nix::unistd::read(fd.as_raw_fd(), &mut buf);
|
||||||
unsafe { libc::read(fd.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len()) };
|
let amt = res.expect("read error!");
|
||||||
assert_ne!(amt, -1, "read error!");
|
|
||||||
self.length_read.fetch_add(amt as usize, Ordering::Relaxed);
|
self.length_read.fetch_add(amt as usize, Ordering::Relaxed);
|
||||||
was_closed = amt == 0;
|
was_closed = amt == 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,16 +114,16 @@ impl UniversalNotifier for NotifydNotifier {
|
||||||
let mut read_something = false;
|
let mut read_something = false;
|
||||||
let mut buff: [u8; 64] = [0; 64];
|
let mut buff: [u8; 64] = [0; 64];
|
||||||
loop {
|
loop {
|
||||||
let amt_read = unsafe {
|
let res = nix::unistd::read(self.notify_fd, &mut buff);
|
||||||
libc::read(
|
|
||||||
self.notify_fd,
|
if let Ok(amt_read) = res {
|
||||||
buff.as_mut_ptr() as *mut libc::c_void,
|
read_something |= amt_read > 0;
|
||||||
buff.len(),
|
}
|
||||||
)
|
|
||||||
};
|
match res {
|
||||||
read_something = read_something || amt_read > 0;
|
Ok(amt_read) if amt_read != buff.len() => break,
|
||||||
if amt_read != buff.len() as isize {
|
Err(_) => break,
|
||||||
break;
|
_ => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FLOGF!(
|
FLOGF!(
|
||||||
|
|
|
@ -401,12 +401,8 @@ pub fn wrename(old_name: &wstr, new_name: &wstr) -> libc::c_int {
|
||||||
unsafe { libc::rename(old_narrow.as_ptr(), new_narrow.as_ptr()) }
|
unsafe { libc::rename(old_narrow.as_ptr(), new_narrow.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to_fd(input: &[u8], fd: RawFd) -> std::io::Result<usize> {
|
pub fn write_to_fd(input: &[u8], fd: RawFd) -> nix::Result<usize> {
|
||||||
let mut file = unsafe { std::fs::File::from_raw_fd(fd) };
|
nix::unistd::write(fd, input)
|
||||||
let amt = file.write(input);
|
|
||||||
// Ensure the file is not closed.
|
|
||||||
file.into_raw_fd();
|
|
||||||
amt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write a wide string to a file descriptor. This avoids doing any additional allocation.
|
/// Write a wide string to a file descriptor. This avoids doing any additional allocation.
|
||||||
|
|
Loading…
Reference in a new issue