Remove unsafe libc layer

This commit is contained in:
Jeremy Soller 2016-10-28 14:17:34 -06:00
parent 8b09e01fef
commit a5de9bb591
10 changed files with 207 additions and 651 deletions

View file

@ -348,6 +348,16 @@ impl File {
inner: self.inner.duplicate()?
})
}
/// Get the path that this file points to.
///
/// This function is only implemented on Redox, but could be
/// implemented on other operating systems using readlink
#[cfg(redox)]
#[stable(feature = "rust1", since = "1.14.0")]
pub fn path(&self) -> io::Result<PathBuf> {
self.inner.path()
}
}
impl AsInner<fs_imp::File> for File {

View file

@ -13,13 +13,12 @@
#![stable(feature = "rust1", since = "1.0.0")]
use fs;
use os::raw;
use sys;
use sys_common::{AsInner, FromInner, IntoInner};
/// Raw file descriptors.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = raw::c_int;
pub type RawFd = usize;
/// A trait to extract the raw unix file descriptor from an underlying
/// object.

View file

@ -11,37 +11,32 @@
#![unstable(reason = "not public", issue = "0", feature = "fd")]
use io::{self, Read};
use libc::{self, c_int, c_void};
use libc;
use mem;
use sys::cvt;
use sys_common::AsInner;
use sys_common::io::read_to_end_uninitialized;
pub struct FileDesc {
fd: c_int,
fd: usize,
}
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
pub fn new(fd: usize) -> FileDesc {
FileDesc { fd: fd }
}
pub fn raw(&self) -> c_int { self.fd }
pub fn raw(&self) -> usize { self.fd }
/// Extracts the actual filedescriptor without closing it.
pub fn into_raw(self) -> c_int {
pub fn into_raw(self) -> usize {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::read(self.fd,
buf.as_mut_ptr() as *mut c_void,
buf.len())
})?;
Ok(ret as usize)
cvt(libc::read(self.fd, buf))
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
@ -50,12 +45,7 @@ impl FileDesc {
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(self.fd,
buf.as_ptr() as *const c_void,
buf.len())
})?;
Ok(ret as usize)
cvt(libc::write(self.fd, buf))
}
pub fn set_cloexec(&self) -> io::Result<()> {
@ -86,7 +76,7 @@ impl FileDesc {
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
let new_fd = cvt(unsafe { libc::dup(self.fd) })?;
let new_fd = cvt(libc::dup(self.fd, &[]))?;
Ok(FileDesc::new(new_fd))
}
}
@ -101,8 +91,8 @@ impl<'a> Read for &'a FileDesc {
}
}
impl AsInner<c_int> for FileDesc {
fn as_inner(&self) -> &c_int { &self.fd }
impl AsInner<usize> for FileDesc {
fn as_inner(&self) -> &usize { &self.fd }
}
impl Drop for FileDesc {
@ -112,6 +102,6 @@ impl Drop for FileDesc {
// 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.
let _ = unsafe { libc::close(self.fd) };
let _ = libc::close(self.fd);
}
}

View file

@ -10,26 +10,24 @@
use os::unix::prelude::*;
use ffi::{CString, CStr, OsString, OsStr};
use ffi::{OsString, OsStr};
use fmt;
use io::{self, Error, ErrorKind, SeekFrom};
use libc::{self, c_int, mode_t};
use mem;
use path::{Path, PathBuf};
use sync::Arc;
use sys::fd::FileDesc;
use sys::time::SystemTime;
use sys::{cvt, cvt_r};
use sys::cvt;
use sys_common::{AsInner, FromInner};
use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
ftruncate as ftruncate64, lseek as lseek64, open as open64};
use libc::{stat, fstat, fsync, ftruncate, lseek, open};
pub struct File(FileDesc);
#[derive(Clone)]
pub struct FileAttr {
stat: stat64,
stat: stat,
}
pub struct ReadDir {
@ -104,8 +102,8 @@ impl FileAttr {
}
}
impl AsInner<stat64> for FileAttr {
fn as_inner(&self) -> &stat64 { &self.stat }
impl AsInner<stat> for FileAttr {
fn as_inner(&self) -> &stat { &self.stat }
}
impl FilePermissions {
@ -254,60 +252,32 @@ impl OpenOptions {
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = cstr(path)?;
File::open_c(&path, opts)
}
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
let flags = libc::O_CLOEXEC as i32 |
opts.get_access_mode()? |
opts.get_creation_mode()? |
(opts.custom_flags as usize & !libc::O_ACCMODE) as i32;
let fd = cvt_r(|| unsafe {
open64(path.as_ptr(), flags, opts.mode as mode_t)
})?;
let fd = FileDesc::new(fd);
Ok(File(fd))
let flags = libc::O_CLOEXEC |
opts.get_access_mode()? as usize |
opts.get_creation_mode()? as usize |
(opts.custom_flags as usize & !libc::O_ACCMODE);
let fd = cvt(open(path.to_str().unwrap(), flags | opts.mode as usize))?;
Ok(File(FileDesc::new(fd)))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
fstat64(self.0.raw(), &mut stat)
})?;
let mut stat: stat = stat::default();
cvt(fstat(self.0.raw(), &mut stat))?;
Ok(FileAttr { stat: stat })
}
pub fn fsync(&self) -> io::Result<()> {
cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?;
cvt(fsync(self.0.raw()))?;
Ok(())
}
pub fn datasync(&self) -> io::Result<()> {
cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
return Ok(());
#[cfg(any(target_os = "macos", target_os = "ios"))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC)
}
#[cfg(target_os = "linux")]
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) }
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "linux")))]
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) }
self.fsync()
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
#[cfg(target_os = "android")]
return ::sys::android::ftruncate64(self.0.raw(), size);
#[cfg(not(target_os = "android"))]
return cvt_r(|| unsafe {
ftruncate64(self.0.raw(), size as off64_t)
}).map(|_| ());
cvt(ftruncate(self.0.raw(), size as usize))?;
Ok(())
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
@ -332,7 +302,7 @@ impl File {
SeekFrom::End(off) => (libc::SEEK_END, off),
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
};
let n = cvt(unsafe { lseek64(self.0.raw(), pos as usize, whence) } as isize)?;
let n = cvt(lseek(self.0.raw(), pos as isize, whence))?;
Ok(n as u64)
}
@ -341,9 +311,8 @@ impl File {
}
pub fn dup(&self, buf: &[u8]) -> io::Result<File> {
libc::dup_extra(*self.fd().as_inner() as usize, buf)
.map(|fd| File(FileDesc::new(fd as i32)))
.map_err(|err| Error::from_raw_os_error(err.errno))
let fd = cvt(libc::dup(*self.fd().as_inner() as usize, buf))?;
Ok(File(FileDesc::new(fd)))
}
pub fn path(&self) -> io::Result<PathBuf> {
@ -365,8 +334,7 @@ impl DirBuilder {
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
let p = cstr(p)?;
cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?;
cvt(libc::mkdir(p.to_str().unwrap(), self.mode))?;
Ok(())
}
@ -375,96 +343,39 @@ impl DirBuilder {
}
}
fn cstr(path: &Path) -> io::Result<CString> {
Ok(CString::new(path.as_os_str().as_bytes())?)
}
impl FromInner<c_int> for File {
fn from_inner(fd: c_int) -> File {
impl FromInner<usize> for File {
fn from_inner(fd: usize) -> File {
File(FileDesc::new(fd))
}
}
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(target_os = "linux")]
fn get_path(fd: c_int) -> Option<PathBuf> {
let mut p = PathBuf::from("/proc/self/fd");
p.push(&fd.to_string());
readlink(&p).ok()
}
#[cfg(target_os = "macos")]
fn get_path(fd: c_int) -> Option<PathBuf> {
// FIXME: The use of PATH_MAX is generally not encouraged, but it
// is inevitable in this case because OS X defines `fcntl` with
// `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
// alternatives. If a better method is invented, it should be used
// instead.
let mut buf = vec![0;libc::PATH_MAX as usize];
let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
if n == -1 {
return None;
}
let l = buf.iter().position(|&c| c == 0).unwrap();
buf.truncate(l as usize);
buf.shrink_to_fit();
Some(PathBuf::from(OsString::from_vec(buf)))
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_path(_fd: c_int) -> Option<PathBuf> {
// FIXME(#24570): implement this for other Unix platforms
None
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn get_mode(fd: c_int) -> Option<(bool, bool)> {
let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
if mode == -1 {
return None;
}
match mode & libc::O_ACCMODE {
libc::O_RDONLY => Some((true, false)),
libc::O_RDWR => Some((true, true)),
libc::O_WRONLY => Some((false, true)),
_ => None
}
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
// FIXME(#24570): implement this for other Unix platforms
None
}
let fd = self.0.raw();
let mut b = f.debug_struct("File");
b.field("fd", &fd);
if let Some(path) = get_path(fd) {
b.field("fd", &self.0.raw());
if let Ok(path) = self.path() {
b.field("path", &path);
}
/*
if let Some((read, write)) = get_mode(fd) {
b.field("read", &read).field("write", &write);
}
*/
b.finish()
}
}
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
let root = Arc::new(p.to_path_buf());
let p = cstr(p)?;
unsafe {
let fd = FileDesc::new(cvt(libc::open(p.as_ptr(), 0, 0))?);
let mut data = Vec::new();
fd.read_to_end(&mut data)?;
Ok(ReadDir { data: data, i: 0, root: root })
}
let options = OpenOptions::new();
let fd = File::open(p, &options)?;
let mut data = Vec::new();
fd.read_to_end(&mut data)?;
Ok(ReadDir { data: data, i: 0, root: root })
}
pub fn unlink(p: &Path) -> io::Result<()> {
let p = cstr(p)?;
cvt(unsafe { libc::unlink(p.as_ptr()) })?;
cvt(libc::unlink(p.to_str().unwrap()))?;
Ok(())
}
@ -477,8 +388,7 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
}
pub fn rmdir(p: &Path) -> io::Result<()> {
let p = cstr(p)?;
cvt(unsafe { libc::rmdir(p.as_ptr()) })?;
cvt(libc::rmdir(p.to_str().unwrap()))?;
Ok(())
}
@ -503,8 +413,8 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
rmdir(path)
}
pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
unimplemented!();
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
canonicalize(p)
}
pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
@ -516,25 +426,21 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
}
pub fn stat(p: &Path) -> io::Result<FileAttr> {
let p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
stat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
})?;
let mut stat: stat = stat::default();
let options = OpenOptions::new();
let file = File::open(p, &options)?;
cvt(fstat(file.0.raw(), &mut stat))?;
Ok(FileAttr { stat: stat })
}
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
let p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
lstat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
})?;
Ok(FileAttr { stat: stat })
stat(p)
}
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
unimplemented!();
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
let options = OpenOptions::new();
let file = File::open(p, &options)?;
file.path()
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {

View file

@ -41,9 +41,7 @@ pub fn init() {
use intrinsics;
let msg = "fatal runtime error: out of memory\n";
unsafe {
libc::write(libc::STDERR_FILENO,
msg.as_ptr() as *const libc::c_void,
msg.len());
let _ = libc::write(libc::STDERR_FILENO, msg.as_bytes());
intrinsics::abort();
}
}
@ -75,37 +73,6 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
}
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
if t.is_minus_one() {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}
pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
where T: IsMinusOne,
F: FnMut() -> T
{
loop {
match cvt(f()) {
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
other => return other,
}
}
pub fn cvt(result: Result<usize, libc::Error>) -> io::Result<usize> {
result.map_err(|err| io::Error::from_raw_os_error(err.errno as i32))
}

View file

@ -35,109 +35,28 @@ use vec;
const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();
extern {
#[cfg(not(target_os = "dragonfly"))]
#[cfg_attr(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"),
link_name = "__errno_location")]
#[cfg_attr(any(target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
#[cfg_attr(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd"),
link_name = "__error")]
#[cfg_attr(target_os = "haiku", link_name = "_errnop")]
fn errno_location() -> *mut c_int;
}
/// Returns the platform-specific value of errno
#[cfg(not(target_os = "dragonfly"))]
pub fn errno() -> i32 {
unsafe {
(*errno_location()) as i32
}
}
/// Sets the platform-specific value of errno
#[cfg(target_os = "solaris")] // only needed for readdir so far
pub fn set_errno(e: i32) {
unsafe {
*errno_location() = e as c_int
}
}
#[cfg(target_os = "dragonfly")]
pub fn errno() -> i32 {
extern {
#[thread_local]
static errno: c_int;
}
errno as i32
0
}
/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
extern {
#[cfg_attr(any(target_os = "linux", target_env = "newlib"),
link_name = "__xpg_strerror_r")]
fn strerror_r(errnum: c_int, buf: *mut c_char,
buflen: libc::size_t) -> c_int;
}
let mut buf = [0 as c_char; TMPBUF_SZ];
let p = buf.as_mut_ptr();
unsafe {
if strerror_r(errno as c_int, p, buf.len()) < 0 {
panic!("strerror_r failure");
}
let p = p as *const _;
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
if let Some(string) = libc::STR_ERROR.get(errno as usize) {
string.to_string()
} else {
"unknown error".to_string()
}
}
pub fn getcwd() -> io::Result<PathBuf> {
let mut buf = Vec::with_capacity(512);
loop {
unsafe {
let ptr = buf.as_mut_ptr() as *mut libc::c_char;
if !libc::getcwd(ptr, buf.capacity()).is_null() {
let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
buf.set_len(len);
buf.shrink_to_fit();
return Ok(PathBuf::from(OsString::from_vec(buf)));
} else {
let error = io::Error::last_os_error();
if error.raw_os_error() != Some(libc::ERANGE) {
return Err(error);
}
}
// Trigger the internal buffer resizing logic of `Vec` by requiring
// more space than the current capacity.
let cap = buf.capacity();
buf.set_len(cap);
buf.reserve(1);
}
}
let mut buf = [0; 4096];
let count = cvt(libc::getcwd(&mut buf))?;
Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
}
pub fn chdir(p: &path::Path) -> io::Result<()> {
let p: &OsStr = p.as_ref();
let p = CString::new(p.as_bytes())?;
unsafe {
match libc::chdir(p.as_ptr()) == (0 as c_int) {
true => Ok(()),
false => Err(io::Error::last_os_error()),
}
}
cvt(libc::chdir(p.to_str().unwrap())).and(Ok(()))
}
pub struct SplitPaths<'a> {
@ -242,5 +161,6 @@ pub fn home_dir() -> Option<PathBuf> {
}
pub fn exit(code: i32) -> ! {
unsafe { libc::exit(code as c_int) }
let _ = libc::exit(code as usize);
unreachable!();
}

View file

@ -9,7 +9,7 @@
// except according to those terms.
use io;
use libc::{self, c_int};
use libc;
use sys::fd::FileDesc;
////////////////////////////////////////////////////////////////////////////////
@ -23,8 +23,8 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
libc::pipe2(&mut fds, libc::O_CLOEXEC).map_err(|err| io::Error::from_raw_os_error(err.errno))?;
let fd0 = FileDesc::new(fds[0] as c_int);
let fd1 = FileDesc::new(fds[1] as c_int);
let fd0 = FileDesc::new(fds[0]);
let fd1 = FileDesc::new(fds[1]);
Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?))
}

View file

@ -12,14 +12,15 @@ use os::unix::prelude::*;
use collections::hash_map::HashMap;
use env;
use ffi::{OsStr, CString, CStr};
use ffi::{OsStr, CString};
use fmt;
use io::{self, Error, ErrorKind};
use libc::{self, pid_t, c_int, gid_t, uid_t};
use path::Path;
use sys::fd::FileDesc;
use sys::fs::{File, OpenOptions};
use sys::pipe::{self, AnonPipe};
use sys::{self, cvt, cvt_r};
use sys::{self, cvt};
////////////////////////////////////////////////////////////////////////////////
// Command
@ -47,7 +48,7 @@ pub struct Command {
args: Vec<String>,
env: HashMap<String, String>,
cwd: Option<CString>,
cwd: Option<String>,
uid: Option<uid_t>,
gid: Option<gid_t>,
saw_nul: bool,
@ -75,7 +76,7 @@ struct ChildPipes {
enum ChildStdio {
Inherit,
Explicit(c_int),
Explicit(usize),
Owned(FileDesc),
}
@ -120,7 +121,7 @@ impl Command {
}
pub fn cwd(&mut self, dir: &OsStr) {
self.cwd = Some(os2c(dir, &mut self.saw_nul));
self.cwd = Some(dir.to_str().unwrap().to_owned());
}
pub fn uid(&mut self, id: uid_t) {
self.uid = Some(id);
@ -157,7 +158,7 @@ impl Command {
let (input, output) = sys::pipe::anon_pipe()?;
let pid = unsafe {
match cvt(libc::fork() as isize)? {
match cvt(libc::clone(0))? {
0 => {
drop(input);
let err = self.do_exec(theirs);
@ -174,7 +175,8 @@ impl Command {
// we want to be sure we *don't* run at_exit destructors as
// we're being torn down regardless
assert!(output.write(&bytes).is_ok());
libc::_exit(1)
let _ = libc::exit(1);
unreachable!();
}
n => n as pid_t,
}
@ -271,29 +273,29 @@ impl Command {
}
if let Some(fd) = stdio.stderr.fd() {
libc::close(libc::STDERR_FILENO);
t!(cvt(libc::dup(fd)));
libc::close(fd);
let _ = libc::close(libc::STDERR_FILENO);
t!(cvt(libc::dup(fd, &[])));
let _ = libc::close(fd);
}
if let Some(fd) = stdio.stdout.fd() {
libc::close(libc::STDOUT_FILENO);
t!(cvt(libc::dup(fd)));
libc::close(fd);
let _ = libc::close(libc::STDOUT_FILENO);
t!(cvt(libc::dup(fd, &[])));
let _ = libc::close(fd);
}
if let Some(fd) = stdio.stdin.fd() {
libc::close(libc::STDIN_FILENO);
t!(cvt(libc::dup(fd)));
libc::close(fd);
let _ = libc::close(libc::STDIN_FILENO);
t!(cvt(libc::dup(fd, &[])));
let _ = libc::close(fd);
}
if let Some(u) = self.gid {
t!(cvt(libc::setgid(u as gid_t)));
if let Some(g) = self.gid {
t!(cvt(libc::setgid(g)));
}
if let Some(u) = self.uid {
t!(cvt(libc::setuid(u as uid_t)));
t!(cvt(libc::setuid(u)));
}
if let Some(ref cwd) = self.cwd {
t!(cvt(libc::chdir(cwd.as_ptr())));
t!(cvt(libc::chdir(cwd)));
}
for callback in self.closures.iter_mut() {
@ -363,7 +365,7 @@ impl Stdio {
// stderr. No matter which we dup first, the second will get
// overwritten prematurely.
Stdio::Fd(ref fd) => {
if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
if fd.raw() <= libc::STDERR_FILENO {
Ok((ChildStdio::Owned(fd.duplicate()?), None))
} else {
Ok((ChildStdio::Explicit(fd.raw()), None))
@ -384,10 +386,7 @@ impl Stdio {
let mut opts = OpenOptions::new();
opts.read(readable);
opts.write(!readable);
let path = unsafe {
CStr::from_ptr("/dev/null\0".as_ptr() as *const _)
};
let fd = File::open_c(&path, &opts)?;
let fd = File::open(&Path::new("null:"), &opts)?;
Ok((ChildStdio::Owned(fd.into_fd()), None))
}
}
@ -395,7 +394,7 @@ impl Stdio {
}
impl ChildStdio {
fn fd(&self) -> Option<c_int> {
fn fd(&self) -> Option<usize> {
match *self {
ChildStdio::Inherit => None,
ChildStdio::Explicit(fd) => Some(fd),
@ -496,7 +495,8 @@ impl Process {
Err(Error::new(ErrorKind::InvalidInput,
"invalid argument: can't kill an exited process"))
} else {
cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
cvt(libc::kill(self.pid, libc::SIGKILL))?;
Ok(())
}
}
@ -505,89 +505,8 @@ impl Process {
return Ok(status)
}
let mut status = 0;
cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
cvt(libc::waitpid(self.pid, &mut status, 0))?;
self.status = Some(ExitStatus(status as i32));
Ok(ExitStatus(status as i32))
}
}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use super::*;
use ffi::OsStr;
use mem;
use ptr;
use libc;
use sys::cvt;
macro_rules! t {
($e:expr) => {
match $e {
Ok(t) => t,
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
}
}
}
#[cfg(not(target_os = "android"))]
extern {
#[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
}
#[cfg(target_os = "android")]
unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
use slice;
let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
let bit = (signum - 1) as usize;
raw[bit / 8] |= 1 << (bit % 8);
return 0;
}
// See #14232 for more information, but it appears that signal delivery to a
// newly spawned process may just be raced in the OSX, so to prevent this
// test from being flaky we ignore it on OSX.
#[test]
#[cfg_attr(target_os = "macos", ignore)]
#[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl.
fn test_process_mask() {
unsafe {
// Test to make sure that a signal mask does not get inherited.
let mut cmd = Command::new(OsStr::new("cat"));
let mut set: libc::sigset_t = mem::uninitialized();
let mut old_set: libc::sigset_t = mem::uninitialized();
t!(cvt(libc::sigemptyset(&mut set)));
t!(cvt(sigaddset(&mut set, libc::SIGINT)));
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
cmd.stdin(Stdio::MakePipe);
cmd.stdout(Stdio::MakePipe);
let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
let stdin_write = pipes.stdin.take().unwrap();
let stdout_read = pipes.stdout.take().unwrap();
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set,
ptr::null_mut())));
t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
// We need to wait until SIGINT is definitely delivered. The
// easiest way is to write something to cat, and try to read it
// back: if SIGINT is unmasked, it'll get delivered when cat is
// next scheduled.
let _ = stdin_write.write(b"Hello");
drop(stdin_write);
// Either EOF or failure (EPIPE) is okay.
let mut buf = [0; 5];
if let Ok(ret) = stdout_read.read(&mut buf) {
assert!(ret == 0);
}
t!(cat.wait());
}
}
}

View file

@ -14,7 +14,6 @@ use ffi::CStr;
use io;
use libc;
use mem;
use sys::os;
use sys_common::thread::start_thread;
use time::Duration;
@ -42,7 +41,7 @@ impl Thread {
}
pub fn set_name(_name: &CStr) {
unimplemented!();
}
pub fn sleep(dur: Duration) {
@ -51,20 +50,18 @@ impl Thread {
// If we're awoken with a signal then the return value will be -1 and
// nanosleep will fill in `ts` with the remaining time.
unsafe {
while secs > 0 || nsecs > 0 {
let mut ts = libc::timespec {
tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
tv_nsec: nsecs,
};
secs -= ts.tv_sec as u64;
if libc::nanosleep(&ts, &mut ts) == -1 {
assert_eq!(os::errno(), libc::EINTR);
secs += ts.tv_sec as u64;
nsecs = ts.tv_nsec;
} else {
nsecs = 0;
}
while secs > 0 || nsecs > 0 {
let req = libc::timespec {
tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
tv_nsec: nsecs,
};
secs -= req.tv_sec as u64;
let mut rem = libc::timespec::default();
if libc::nanosleep(&req, &mut rem).is_err() {
secs += rem.tv_sec as u64;
nsecs = rem.tv_nsec;
} else {
nsecs = 0;
}
}
}

View file

@ -9,11 +9,11 @@
// except according to those terms.
use cmp::Ordering;
use fmt;
use libc;
use sys::cvt;
use time::Duration;
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
const NSEC_PER_SEC: u64 = 1_000_000_000;
#[derive(Copy, Clone)]
@ -103,249 +103,97 @@ impl Ord for Timespec {
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
use fmt;
use libc;
use sync::Once;
use sys::cvt;
use sys_common::mul_div_u64;
use time::Duration;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Instant {
t: Timespec,
}
use super::NSEC_PER_SEC;
use super::Timespec;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SystemTime {
t: Timespec,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Instant {
t: u64
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SystemTime {
t: Timespec,
}
pub const UNIX_EPOCH: SystemTime = SystemTime {
t: Timespec {
t: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
pub const UNIX_EPOCH: SystemTime = SystemTime {
t: Timespec {
t: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
};
},
};
impl Instant {
pub fn now() -> Instant {
Instant { t: unsafe { libc::mach_absolute_time() } }
}
pub fn sub_instant(&self, other: &Instant) -> Duration {
let info = info();
let diff = self.t.checked_sub(other.t)
.expect("second instant is later than self");
let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
}
pub fn add_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t.checked_add(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
}
pub fn sub_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t.checked_sub(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
}
impl Instant {
pub fn now() -> Instant {
Instant { t: now(libc::CLOCK_MONOTONIC) }
}
impl SystemTime {
pub fn now() -> SystemTime {
use ptr;
let mut s = libc::timeval {
tv_sec: 0,
tv_usec: 0,
};
cvt(unsafe {
libc::gettimeofday(&mut s, ptr::null_mut())
}).unwrap();
return SystemTime::from(s)
}
pub fn sub_time(&self, other: &SystemTime)
-> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}
pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.add_duration(other) }
}
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.sub_duration(other) }
}
pub fn sub_instant(&self, other: &Instant) -> Duration {
self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
panic!("other was less than the current instant")
})
}
impl From<libc::timeval> for SystemTime {
fn from(t: libc::timeval) -> SystemTime {
SystemTime::from(libc::timespec {
tv_sec: t.tv_sec,
tv_nsec: (t.tv_usec * 1000) as libc::c_long,
})
}
pub fn add_duration(&self, other: &Duration) -> Instant {
Instant { t: self.t.add_duration(other) }
}
impl From<libc::timespec> for SystemTime {
fn from(t: libc::timespec) -> SystemTime {
SystemTime { t: Timespec { t: t } }
}
}
impl fmt::Debug for SystemTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SystemTime")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
fn dur2intervals(dur: &Duration) -> u64 {
let info = info();
let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| {
nanos.checked_add(dur.subsec_nanos() as u64)
}).expect("overflow converting duration to nanoseconds");
mul_div_u64(nanos, info.denom as u64, info.numer as u64)
}
fn info() -> &'static libc::mach_timebase_info {
static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info {
numer: 0,
denom: 0,
};
static ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
libc::mach_timebase_info(&mut INFO);
});
&INFO
}
pub fn sub_duration(&self, other: &Duration) -> Instant {
Instant { t: self.t.sub_duration(other) }
}
}
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
use fmt;
use libc;
use sys::cvt;
use time::Duration;
use super::Timespec;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Instant {
t: Timespec,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SystemTime {
t: Timespec,
}
pub const UNIX_EPOCH: SystemTime = SystemTime {
t: Timespec {
t: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
},
};
impl Instant {
pub fn now() -> Instant {
Instant { t: now(libc::CLOCK_MONOTONIC) }
}
pub fn sub_instant(&self, other: &Instant) -> Duration {
self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
panic!("other was less than the current instant")
})
}
pub fn add_duration(&self, other: &Duration) -> Instant {
Instant { t: self.t.add_duration(other) }
}
pub fn sub_duration(&self, other: &Duration) -> Instant {
Instant { t: self.t.sub_duration(other) }
}
}
impl fmt::Debug for Instant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Instant")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
impl SystemTime {
pub fn now() -> SystemTime {
SystemTime { t: now(libc::CLOCK_REALTIME) }
}
pub fn sub_time(&self, other: &SystemTime)
-> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}
pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.add_duration(other) }
}
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.sub_duration(other) }
}
}
impl From<libc::timespec> for SystemTime {
fn from(t: libc::timespec) -> SystemTime {
SystemTime { t: Timespec { t: t } }
}
}
impl fmt::Debug for SystemTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SystemTime")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
#[cfg(not(any(target_os = "dragonfly", target_os = "redox")))]
pub type clock_t = libc::c_int;
#[cfg(target_os = "dragonfly")]
pub type clock_t = libc::c_ulong;
#[cfg(target_os = "redox")]
pub type clock_t = usize;
fn now(clock: clock_t) -> Timespec {
let mut t = Timespec {
t: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
}
};
cvt(unsafe {
libc::clock_gettime(clock, &mut t.t)
}).unwrap();
t
impl fmt::Debug for Instant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Instant")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
impl SystemTime {
pub fn now() -> SystemTime {
SystemTime { t: now(libc::CLOCK_REALTIME) }
}
pub fn sub_time(&self, other: &SystemTime)
-> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}
pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.add_duration(other) }
}
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.sub_duration(other) }
}
}
impl From<libc::timespec> for SystemTime {
fn from(t: libc::timespec) -> SystemTime {
SystemTime { t: Timespec { t: t } }
}
}
impl fmt::Debug for SystemTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SystemTime")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
pub type clock_t = usize;
fn now(clock: clock_t) -> Timespec {
let mut t = Timespec {
t: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
}
};
cvt(libc::clock_gettime(clock, &mut t.t)).unwrap();
t
}