Handle EINTR throughout libnative

Closes #11214
This commit is contained in:
Alex Crichton 2014-01-03 23:49:56 -08:00
parent a1cb8dc30c
commit 674d24e2e6
4 changed files with 108 additions and 70 deletions

View File

@ -20,7 +20,7 @@ use std::rt::rtio;
use std::unstable::intrinsics;
use std::vec;
use super::IoResult;
use io::{IoResult, retry};
#[cfg(windows)] use std::os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
#[cfg(windows)] use std::ptr;
@ -143,8 +143,8 @@ impl rtio::RtioFileStream for FileDesc {
overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
match libc::ReadFile(handle, buf as libc::LPVOID,
amt as libc::DWORD,
&mut bytes_read, &mut overlap) {
amt as libc::DWORD,
&mut bytes_read, &mut overlap) {
0 => Err(super::last_error()),
_ => Ok(bytes_read as int)
}
@ -153,10 +153,10 @@ impl rtio::RtioFileStream for FileDesc {
#[cfg(unix)]
fn os_pread(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult<int> {
match unsafe {
match retry(|| unsafe {
libc::pread(fd, buf as *libc::c_void, amt as libc::size_t,
offset as libc::off_t)
} {
offset as libc::off_t) as libc::c_int
}) {
-1 => Err(super::last_error()),
n => Ok(n as int)
}
@ -184,10 +184,10 @@ impl rtio::RtioFileStream for FileDesc {
#[cfg(unix)]
fn os_pwrite(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult<()> {
super::mkerr_libc(unsafe {
super::mkerr_libc(retry(|| unsafe {
libc::pwrite(fd, buf as *libc::c_void, amt as libc::size_t,
offset as libc::off_t)
} as c_int)
} as c_int))
}
}
#[cfg(windows)]
@ -240,7 +240,7 @@ impl rtio::RtioFileStream for FileDesc {
}
#[cfg(unix)]
fn os_fsync(fd: c_int) -> IoResult<()> {
super::mkerr_libc(unsafe { libc::fsync(fd) })
super::mkerr_libc(retry(|| unsafe { libc::fsync(fd) }))
}
}
#[cfg(windows)]
@ -255,9 +255,13 @@ impl rtio::RtioFileStream for FileDesc {
unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) }
}
#[cfg(target_os = "linux")]
fn os_datasync(fd: c_int) -> c_int { unsafe { libc::fdatasync(fd) } }
fn os_datasync(fd: c_int) -> c_int {
retry(|| unsafe { libc::fdatasync(fd) })
}
#[cfg(not(target_os = "macos"), not(target_os = "linux"))]
fn os_datasync(fd: c_int) -> c_int { unsafe { libc::fsync(fd) } }
fn os_datasync(fd: c_int) -> c_int {
retry(|| unsafe { libc::fsync(fd) })
}
}
#[cfg(windows)]
@ -278,9 +282,9 @@ impl rtio::RtioFileStream for FileDesc {
}
#[cfg(unix)]
fn truncate(&mut self, offset: i64) -> Result<(), IoError> {
super::mkerr_libc(unsafe {
super::mkerr_libc(retry(|| unsafe {
libc::ftruncate(self.fd, offset as libc::off_t)
})
}))
}
}
@ -311,9 +315,17 @@ impl rtio::RtioTTY for FileDesc {
impl Drop for FileDesc {
fn drop(&mut self) {
// closing stdio file handles makes no sense, so never do it
// closing stdio file handles makes no sense, so never do it. Also, note
// that errors are ignored when closing a file descriptor. The reason
// for this is that if an error occurs we don't actually know if the
// file descriptor was closed or not, and if we retried (for something
// like EINTR), we might close another valid file descriptor (opened
// after we closed ours.
if self.close_on_drop && self.fd > libc::STDERR_FILENO {
unsafe { libc::close(self.fd); }
let n = unsafe { libc::close(self.fd) };
if n != 0 {
warn!("error {} when closing file descriptor {}", n, self.fd);
}
}
}
}
@ -336,7 +348,7 @@ impl CFile {
}
pub fn flush(&mut self) -> Result<(), IoError> {
super::mkerr_libc(unsafe { libc::fflush(self.file) })
super::mkerr_libc(retry(|| unsafe { libc::fflush(self.file) }))
}
}
@ -444,13 +456,13 @@ pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess)
#[cfg(windows)]
fn os_open(path: &CString, flags: c_int, mode: c_int) -> c_int {
as_utf16_p(path.as_str().unwrap(), |path| {
unsafe { libc::wopen(path, flags, mode) }
retry(|| unsafe { libc::wopen(path, flags, mode) })
})
}
#[cfg(unix)]
fn os_open(path: &CString, flags: c_int, mode: c_int) -> c_int {
unsafe { libc::open(path.with_ref(|p| p), flags, mode) }
retry(|| unsafe { libc::open(path.with_ref(|p| p), flags, mode) })
}
}
@ -469,9 +481,9 @@ pub fn mkdir(p: &CString, mode: io::FilePermission) -> IoResult<()> {
#[cfg(unix)]
fn os_mkdir(p: &CString, mode: c_int) -> IoResult<()> {
super::mkerr_libc(unsafe {
super::mkerr_libc(retry(|| unsafe {
libc::mkdir(p.with_ref(|p| p), mode as libc::mode_t)
})
}))
}
}
@ -582,7 +594,7 @@ pub fn unlink(p: &CString) -> IoResult<()> {
#[cfg(unix)]
fn os_unlink(p: &CString) -> IoResult<()> {
super::mkerr_libc(unsafe { libc::unlink(p.with_ref(|p| p)) })
super::mkerr_libc(retry(|| unsafe { libc::unlink(p.with_ref(|p| p)) }))
}
}
@ -602,9 +614,9 @@ pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
#[cfg(unix)]
fn os_rename(old: &CString, new: &CString) -> IoResult<()> {
super::mkerr_libc(unsafe {
super::mkerr_libc(retry(|| unsafe {
libc::rename(old.with_ref(|p| p), new.with_ref(|p| p))
})
}))
}
}
@ -614,13 +626,15 @@ pub fn chmod(p: &CString, mode: io::FilePermission) -> IoResult<()> {
#[cfg(windows)]
fn os_chmod(p: &CString, mode: c_int) -> c_int {
unsafe {
as_utf16_p(p.as_str().unwrap(), |p| libc::wchmod(p, mode))
as_utf16_p(p.as_str().unwrap(), |p| retry(|| {
libc::wchmod(p, mode)
}))
}
}
#[cfg(unix)]
fn os_chmod(p: &CString, mode: c_int) -> c_int {
unsafe { libc::chmod(p.with_ref(|p| p), mode as libc::mode_t) }
retry(||unsafe { libc::chmod(p.with_ref(|p| p), mode as libc::mode_t) })
}
}
@ -630,13 +644,15 @@ pub fn rmdir(p: &CString) -> IoResult<()> {
#[cfg(windows)]
fn os_rmdir(p: &CString) -> c_int {
unsafe {
as_utf16_p(p.as_str().unwrap(), |p| libc::wrmdir(p))
as_utf16_p(p.as_str().unwrap(), |p| retry(|| {
libc::wrmdir(p)
}))
}
}
#[cfg(unix)]
fn os_rmdir(p: &CString) -> c_int {
unsafe { libc::rmdir(p.with_ref(|p| p)) }
retry(|| unsafe { libc::rmdir(p.with_ref(|p| p)) })
}
}
@ -649,10 +665,10 @@ pub fn chown(p: &CString, uid: int, gid: int) -> IoResult<()> {
#[cfg(unix)]
fn os_chown(p: &CString, uid: int, gid: int) -> c_int {
unsafe {
retry(|| unsafe {
libc::chown(p.with_ref(|p| p), uid as libc::uid_t,
gid as libc::gid_t)
}
})
}
}
@ -697,10 +713,10 @@ pub fn readlink(p: &CString) -> IoResult<Path> {
len = 1024; // XXX: read PATH_MAX from C ffi?
}
let mut buf = vec::with_capacity::<u8>(len as uint);
match unsafe {
match retry(|| unsafe {
libc::readlink(p, buf.as_ptr() as *mut libc::c_char,
len as libc::size_t)
} {
len as libc::size_t) as libc::c_int
}) {
-1 => Err(super::last_error()),
n => {
assert!(n > 0);
@ -725,9 +741,9 @@ pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
#[cfg(unix)]
fn os_symlink(src: &CString, dst: &CString) -> IoResult<()> {
super::mkerr_libc(unsafe {
super::mkerr_libc(retry(|| unsafe {
libc::symlink(src.with_ref(|p| p), dst.with_ref(|p| p))
})
}))
}
}
@ -745,9 +761,9 @@ pub fn link(src: &CString, dst: &CString) -> IoResult<()> {
#[cfg(unix)]
fn os_link(src: &CString, dst: &CString) -> IoResult<()> {
super::mkerr_libc(unsafe {
super::mkerr_libc(retry(|| unsafe {
libc::link(src.with_ref(|p| p), dst.with_ref(|p| p))
})
}))
}
}
@ -842,7 +858,7 @@ pub fn stat(p: &CString) -> IoResult<io::FileStat> {
fn os_stat(p: &CString) -> IoResult<io::FileStat> {
let mut stat: libc::stat = unsafe { intrinsics::uninit() };
as_utf16_p(p.as_str().unwrap(), |up| {
match unsafe { libc::wstat(up, &mut stat) } {
match retry(|| unsafe { libc::wstat(up, &mut stat) }) {
0 => Ok(mkstat(&stat, p)),
_ => Err(super::last_error()),
}
@ -852,7 +868,7 @@ pub fn stat(p: &CString) -> IoResult<io::FileStat> {
#[cfg(unix)]
fn os_stat(p: &CString) -> IoResult<io::FileStat> {
let mut stat: libc::stat = unsafe { intrinsics::uninit() };
match unsafe { libc::stat(p.with_ref(|p| p), &mut stat) } {
match retry(|| unsafe { libc::stat(p.with_ref(|p| p), &mut stat) }) {
0 => Ok(mkstat(&stat, p)),
_ => Err(super::last_error()),
}
@ -871,7 +887,7 @@ pub fn lstat(p: &CString) -> IoResult<io::FileStat> {
#[cfg(unix)]
fn os_lstat(p: &CString) -> IoResult<io::FileStat> {
let mut stat: libc::stat = unsafe { intrinsics::uninit() };
match unsafe { libc::lstat(p.with_ref(|p| p), &mut stat) } {
match retry(|| unsafe { libc::lstat(p.with_ref(|p| p), &mut stat) }) {
0 => Ok(mkstat(&stat, p)),
_ => Err(super::last_error()),
}
@ -888,7 +904,9 @@ pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> {
modtime: (mtime / 1000) as libc::time64_t,
};
unsafe {
as_utf16_p(p.as_str().unwrap(), |p| libc::wutime(p, &buf))
as_utf16_p(p.as_str().unwrap(), |p| retry(|| {
libc::wutime(p, &buf)
}))
}
}
@ -898,7 +916,7 @@ pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> {
actime: (atime / 1000) as libc::time_t,
modtime: (mtime / 1000) as libc::time_t,
};
unsafe { libc::utime(p.with_ref(|p| p), &buf) }
retry(|| unsafe { libc::utime(p.with_ref(|p| p), &buf) })
}
}

View File

@ -134,13 +134,24 @@ fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
}
}
#[cfg(windows)]
#[inline]
fn retry(f: || -> libc::c_int) -> libc::c_int {
loop {
match f() {
-1 if os::errno() as int == libc::WSAEINTR as int => {}
n => return n,
}
}
}
#[cfg(unix)]
fn retry(f: || -> libc::c_int) -> IoResult<libc::c_int> {
#[inline]
fn retry(f: || -> libc::c_int) -> libc::c_int {
loop {
match f() {
-1 if os::errno() as int == libc::EINTR as int => {}
-1 => return Err(last_error()),
n => return Ok(n),
n => return n,
}
}
}

View File

@ -16,7 +16,7 @@ use std::mem;
use std::rt::rtio;
use std::unstable::intrinsics;
use super::IoResult;
use super::{IoResult, retry};
use super::file::keep_going;
////////////////////////////////////////////////////////////////////////////////
@ -227,8 +227,10 @@ impl TcpStream {
let (addr, len) = addr_to_sockaddr(addr);
let addrp = &addr as *libc::sockaddr_storage;
let ret = TcpStream { fd: fd };
match libc::connect(fd, addrp as *libc::sockaddr,
len as libc::socklen_t) {
match retry(|| {
libc::connect(fd, addrp as *libc::sockaddr,
len as libc::socklen_t)
}) {
-1 => Err(super::last_error()),
_ => Ok(ret),
}
@ -394,9 +396,11 @@ impl TcpAcceptor {
let storagep = &mut storage as *mut libc::sockaddr_storage;
let size = mem::size_of::<libc::sockaddr_storage>();
let mut size = size as libc::socklen_t;
match libc::accept(self.fd(),
storagep as *mut libc::sockaddr,
&mut size as *mut libc::socklen_t) {
match retry(|| {
libc::accept(self.fd(),
storagep as *mut libc::sockaddr,
&mut size as *mut libc::socklen_t) as libc::c_int
}) as sock_t {
-1 => Err(super::last_error()),
fd => Ok(TcpStream { fd: fd })
}
@ -493,12 +497,14 @@ impl rtio::RtioUdpSocket for UdpSocket {
let storagep = &mut storage as *mut libc::sockaddr_storage;
let mut addrlen: libc::socklen_t =
mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
let ret = libc::recvfrom(self.fd,
buf.as_ptr() as *mut libc::c_void,
buf.len() as msglen_t,
0,
storagep as *mut libc::sockaddr,
&mut addrlen);
let ret = retry(|| {
libc::recvfrom(self.fd,
buf.as_ptr() as *mut libc::c_void,
buf.len() as msglen_t,
0,
storagep as *mut libc::sockaddr,
&mut addrlen) as libc::c_int
});
if ret < 0 { return Err(super::last_error()) }
sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| {
Ok((ret as uint, addr))
@ -509,12 +515,14 @@ impl rtio::RtioUdpSocket for UdpSocket {
let (dst, len) = addr_to_sockaddr(dst);
let dstp = &dst as *libc::sockaddr_storage;
unsafe {
let ret = libc::sendto(self.fd,
buf.as_ptr() as *libc::c_void,
buf.len() as msglen_t,
0,
dstp as *libc::sockaddr,
len as libc::socklen_t);
let ret = retry(|| {
libc::sendto(self.fd,
buf.as_ptr() as *libc::c_void,
buf.len() as msglen_t,
0,
dstp as *libc::sockaddr,
len as libc::socklen_t) as libc::c_int
});
match ret {
-1 => Err(super::last_error()),
n if n as uint != buf.len() => {

View File

@ -16,11 +16,12 @@ use std::ptr;
use std::rt::rtio;
use p = std::io::process;
#[cfg(windows)] use std::cast;
use super::IoResult;
use super::file;
#[cfg(windows)] use std::cast;
#[cfg(not(windows))] use super::retry;
/**
* A value representing a child process.
*
@ -445,17 +446,17 @@ fn spawn_process_os(prog: &str, args: &[~str],
if in_fd == -1 {
libc::close(libc::STDIN_FILENO);
} else if dup2(in_fd, 0) == -1 {
} else if retry(|| dup2(in_fd, 0)) == -1 {
fail!("failure in dup2(in_fd, 0): {}", os::last_os_error());
}
if out_fd == -1 {
libc::close(libc::STDOUT_FILENO);
} else if dup2(out_fd, 1) == -1 {
} else if retry(|| dup2(out_fd, 1)) == -1 {
fail!("failure in dup2(out_fd, 1): {}", os::last_os_error());
}
if err_fd == -1 {
libc::close(libc::STDERR_FILENO);
} else if dup2(err_fd, 2) == -1 {
} else if retry(|| dup2(err_fd, 2)) == -1 {
fail!("failure in dup3(err_fd, 2): {}", os::last_os_error());
}
// close all other fds
@ -664,9 +665,9 @@ fn waitpid(pid: pid_t) -> p::ProcessExit {
}
let mut status = 0 as c_int;
match super::retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) {
Err(e) => fail!("unknown waitpid error: {:?}", e),
Ok(_ret) => {
match retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) {
-1 => fail!("unknown waitpid error: {:?}", super::last_error()),
_ => {
if imp::WIFEXITED(status) {
p::ExitStatus(imp::WEXITSTATUS(status) as int)
} else {