libnative/io: generic retry() for Unix 64 bit read/write().

Win32/WinSock APIs never call WSASetLastError() with WSAEINTR
unless a programmer specifically cancels the ongoing blocking call by
a deprecated WinSock1 API WSACancelBlockingCall().
So the errno check was simply removed and retry() became an id function
on Windows.
Note: Windows' equivalent of SIGINT is always handled in a separate thread:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682541%28v=vs.85%29.aspx
"CTRL+C and CTRL+BREAK Signals"

Also, incidentally rename a type parameter and clean up some module imports.
This commit is contained in:
NODA, Kai 2014-09-05 15:05:22 +08:00
parent 67b97ab6d2
commit 52e99cbcaa
3 changed files with 22 additions and 34 deletions

View File

@ -11,12 +11,10 @@
//! Blocking posix-based file I/O //! Blocking posix-based file I/O
use alloc::arc::Arc; use alloc::arc::Arc;
use libc::{c_int, c_void}; use libc::{mod, c_int, c_void};
use libc;
use std::c_str::CString; use std::c_str::CString;
use std::mem; use std::mem;
use std::rt::rtio; use std::rt::rtio::{mod, IoResult};
use std::rt::rtio::IoResult;
use io::{retry, keep_going}; use io::{retry, keep_going};
use io::util; use io::util;
@ -55,7 +53,7 @@ impl FileDesc {
let ret = retry(|| unsafe { let ret = retry(|| unsafe {
libc::read(self.fd(), libc::read(self.fd(),
buf.as_mut_ptr() as *mut libc::c_void, buf.as_mut_ptr() as *mut libc::c_void,
buf.len() as libc::size_t) as libc::c_int buf.len() as libc::size_t)
}); });
if ret == 0 { if ret == 0 {
Err(util::eof()) Err(util::eof())
@ -93,7 +91,7 @@ impl rtio::RtioFileStream for FileDesc {
match retry(|| unsafe { match retry(|| unsafe {
libc::pread(self.fd(), buf.as_ptr() as *mut _, libc::pread(self.fd(), buf.as_ptr() as *mut _,
buf.len() as libc::size_t, buf.len() as libc::size_t,
offset as libc::off_t) as libc::c_int offset as libc::off_t)
}) { }) {
-1 => Err(super::last_error()), -1 => Err(super::last_error()),
n => Ok(n as int) n => Ok(n as int)
@ -103,7 +101,7 @@ impl rtio::RtioFileStream for FileDesc {
super::mkerr_libc(retry(|| unsafe { super::mkerr_libc(retry(|| unsafe {
libc::pwrite(self.fd(), buf.as_ptr() as *const _, libc::pwrite(self.fd(), buf.as_ptr() as *const _,
buf.len() as libc::size_t, offset as libc::off_t) buf.len() as libc::size_t, offset as libc::off_t)
} as c_int)) }))
} }
fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult<u64> { fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult<u64> {
let whence = match whence { let whence = match whence {

View File

@ -23,12 +23,11 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use libc::c_int; use libc::{mod, c_int};
use libc;
use std::c_str::CString; use std::c_str::CString;
use std::os; use std::os;
use std::rt::rtio; use std::rt::rtio::{mod, IoResult, IoError};
use std::rt::rtio::{IoResult, IoError}; use std::num;
// Local re-exports // Local re-exports
pub use self::file::FileDesc; pub use self::file::FileDesc;
@ -97,8 +96,8 @@ fn last_error() -> IoError {
} }
// unix has nonzero values as errors // unix has nonzero values as errors
fn mkerr_libc(ret: libc::c_int) -> IoResult<()> { fn mkerr_libc <Int: num::Zero>(ret: Int) -> IoResult<()> {
if ret != 0 { if !ret.is_zero() {
Err(last_error()) Err(last_error())
} else { } else {
Ok(()) Ok(())
@ -117,39 +116,33 @@ fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
#[cfg(windows)] #[cfg(windows)]
#[inline] #[inline]
fn retry(f: || -> libc::c_int) -> libc::c_int { fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020
loop {
match f() {
-1 if os::errno() as int == libc::WSAEINTR as int => {}
n => return n,
}
}
}
#[cfg(unix)] #[cfg(unix)]
#[inline] #[inline]
fn retry(f: || -> libc::c_int) -> libc::c_int { fn retry<I: PartialEq + num::One + Neg<I>> (f: || -> I) -> I {
let minus_one = -num::one::<I>();
loop { loop {
match f() { let n = f();
-1 if os::errno() as int == libc::EINTR as int => {} if n == minus_one && os::errno() == libc::EINTR as int { }
n => return n, else { return n }
}
} }
} }
fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 { fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
let origamt = data.len(); let origamt = data.len();
let mut data = data.as_ptr(); let mut data = data.as_ptr();
let mut amt = origamt; let mut amt = origamt;
while amt > 0 { while amt > 0 {
let ret = retry(|| f(data, amt) as libc::c_int); let ret = retry(|| f(data, amt));
if ret == 0 { if ret == 0 {
break break
} else if ret != -1 { } else if ret != -1 {
amt -= ret as uint; amt -= ret as uint;
data = unsafe { data.offset(ret as int) }; data = unsafe { data.offset(ret as int) };
} else { } else {
return ret as i64; return ret;
} }
} }
return (origamt - amt) as i64; return (origamt - amt) as i64;

View File

@ -13,8 +13,7 @@ use libc;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::rt::mutex; use std::rt::mutex;
use std::rt::rtio; use std::rt::rtio::{mod, IoResult, IoError};
use std::rt::rtio::{IoResult, IoError};
use std::sync::atomic; use std::sync::atomic;
use super::{retry, keep_going}; use super::{retry, keep_going};
@ -988,9 +987,7 @@ pub fn write<T>(fd: sock_t,
write(false, inner, len) write(false, inner, len)
}); });
} else { } else {
ret = retry(|| { ret = retry(|| { write(false, buf.as_ptr(), buf.len()) });
write(false, buf.as_ptr(), buf.len()) as libc::c_int
}) as i64;
if ret > 0 { written = ret as uint; } if ret > 0 { written = ret as uint; }
} }
} }
@ -1017,7 +1014,7 @@ pub fn write<T>(fd: sock_t,
let _guard = lock(); let _guard = lock();
let ptr = buf.slice_from(written).as_ptr(); let ptr = buf.slice_from(written).as_ptr();
let len = buf.len() - written; let len = buf.len() - written;
match retry(|| write(deadline.is_some(), ptr, len) as libc::c_int) { match retry(|| write(deadline.is_some(), ptr, len)) {
-1 if util::wouldblock() => {} -1 if util::wouldblock() => {}
-1 => return Err(os::last_error()), -1 => return Err(os::last_error()),
n => { written += n as uint; } n => { written += n as uint; }