)
pub fn dumb_println(args: &fmt::Arguments) {
- use std::io::native::stdio::stderr;
- use std::io::Writer;
-
- let mut out = stderr();
- fmt::writeln(&mut out as &mut Writer, args);
+ use std::io::native::file::FileDesc;
+ use std::io;
+ use std::libc;
+ let mut out = FileDesc::new(libc::STDERR_FILENO, false);
+ fmt::writeln(&mut out as &mut io::Writer, args);
}
/// Buffered I/O wrappers
pub mod buffered;
-/// Thread-blocking implementations
-pub mod native {
- /// Posix file I/O
- pub mod file;
- /// Process spawning and child management
- pub mod process;
- /// Posix stdio
- pub mod stdio;
-
- /// Sockets
- /// # XXX - implement this
- pub mod net {
- pub mod tcp { }
- pub mod udp { }
- #[cfg(unix)]
- pub mod unix { }
- }
-}
+pub mod native;
/// Signal handling
pub mod signal;
#[allow(non_camel_case_types)];
+use io::IoError;
+use io;
use libc;
+use ops::Drop;
+use option::{Some, None, Option};
use os;
-use prelude::*;
-use super::super::*;
-
-#[cfg(windows)]
-fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
- match errno {
- libc::EOF => (EndOfFile, "end of file"),
- _ => (OtherIoError, "unknown error"),
- }
-}
-
-#[cfg(not(windows))]
-fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
- // XXX: this should probably be a bit more descriptive...
- match errno {
- libc::EOF => (EndOfFile, "end of file"),
-
- // These two constants can have the same value on some systems, but
- // different values on others, so we can't use a match clause
- x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
- (ResourceUnavailable, "resource temporarily unavailable"),
-
- _ => (OtherIoError, "unknown error"),
- }
-}
-
-fn raise_error() {
- let (kind, desc) = get_err(os::errno() as i32);
- io_error::cond.raise(IoError {
- kind: kind,
- desc: desc,
- detail: Some(os::last_os_error())
- });
-}
+use ptr::RawPtr;
+use result::{Result, Ok, Err};
+use rt::rtio;
+use vec::ImmutableVector;
fn keep_going(data: &[u8], f: &fn(*u8, uint) -> i64) -> i64 {
#[cfg(windows)] static eintr: int = 0; // doesn't matter
pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
FileDesc { fd: fd, close_on_drop: close_on_drop }
}
-}
-impl Reader for FileDesc {
- fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+ fn inner_read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
#[cfg(windows)] type rlen = libc::c_uint;
#[cfg(not(windows))] type rlen = libc::size_t;
let ret = do keep_going(buf) |buf, len| {
}
};
if ret == 0 {
- None
+ Err(io::standard_error(io::EndOfFile))
} else if ret < 0 {
- raise_error();
- None
+ Err(super::last_error())
} else {
- Some(ret as uint)
+ Ok(ret as uint)
}
}
-
- fn eof(&mut self) -> bool { false }
-}
-
-impl Writer for FileDesc {
- fn write(&mut self, buf: &[u8]) {
+ fn inner_write(&mut self, buf: &[u8]) -> Result<(), IoError> {
#[cfg(windows)] type wlen = libc::c_uint;
#[cfg(not(windows))] type wlen = libc::size_t;
let ret = do keep_going(buf) |buf, len| {
}
};
if ret < 0 {
- raise_error();
+ Err(super::last_error())
+ } else {
+ Ok(())
}
}
}
+impl io::Reader for FileDesc {
+ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+ match self.inner_read(buf) { Ok(n) => Some(n), Err(*) => None }
+ }
+ fn eof(&mut self) -> bool { false }
+}
+
+impl io::Writer for FileDesc {
+ fn write(&mut self, buf: &[u8]) {
+ self.inner_write(buf);
+ }
+}
+
+impl rtio::RtioFileStream for FileDesc {
+ fn read(&mut self, buf: &mut [u8]) -> Result<int, IoError> {
+ self.inner_read(buf).map(|i| i as int)
+ }
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+ self.inner_write(buf)
+ }
+ fn pread(&mut self, _buf: &mut [u8], _offset: u64) -> Result<int, IoError> {
+ Err(super::unimpl())
+ }
+ fn pwrite(&mut self, _buf: &[u8], _offset: u64) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+ fn seek(&mut self, _pos: i64, _whence: io::SeekStyle) -> Result<u64, IoError> {
+ Err(super::unimpl())
+ }
+ fn tell(&self) -> Result<u64, IoError> {
+ Err(super::unimpl())
+ }
+ fn fsync(&mut self) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+ fn datasync(&mut self) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+ fn truncate(&mut self, _offset: i64) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+}
+
+impl rtio::RtioPipe for FileDesc {
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
+ self.inner_read(buf)
+ }
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+ self.inner_write(buf)
+ }
+}
+
+impl rtio::RtioTTY for FileDesc {
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
+ self.inner_read(buf)
+ }
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+ self.inner_write(buf)
+ }
+ fn set_raw(&mut self, _raw: bool) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+ fn get_winsize(&mut self) -> Result<(int, int), IoError> {
+ Err(super::unimpl())
+ }
+}
+
impl Drop for FileDesc {
fn drop(&mut self) {
- if self.close_on_drop {
+ // closing stdio file handles makes no sense, so never do it
+ if self.close_on_drop && self.fd > libc::STDERR_FILENO {
unsafe { libc::close(self.fd); }
}
}
pub fn new(file: *libc::FILE) -> CFile { CFile { file: file } }
}
-impl Reader for CFile {
- fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+impl rtio::RtioFileStream for CFile {
+ fn read(&mut self, buf: &mut [u8]) -> Result<int, IoError> {
let ret = do keep_going(buf) |buf, len| {
unsafe {
libc::fread(buf as *mut libc::c_void, 1, len as libc::size_t,
}
};
if ret == 0 {
- None
+ Err(io::standard_error(io::EndOfFile))
} else if ret < 0 {
- raise_error();
- None
+ Err(super::last_error())
} else {
- Some(ret as uint)
+ Ok(ret as int)
}
}
- fn eof(&mut self) -> bool {
- unsafe { libc::feof(self.file) != 0 }
- }
-}
-
-impl Writer for CFile {
- fn write(&mut self, buf: &[u8]) {
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
let ret = do keep_going(buf) |buf, len| {
unsafe {
libc::fwrite(buf as *libc::c_void, 1, len as libc::size_t,
}
};
if ret < 0 {
- raise_error();
+ Err(super::last_error())
+ } else {
+ Ok(())
}
}
- fn flush(&mut self) {
- if unsafe { libc::fflush(self.file) } < 0 {
- raise_error();
+ fn pread(&mut self, _buf: &mut [u8], _offset: u64) -> Result<int, IoError> {
+ Err(super::unimpl())
+ }
+ fn pwrite(&mut self, _buf: &[u8], _offset: u64) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+ fn seek(&mut self, pos: i64, style: io::SeekStyle) -> Result<u64, IoError> {
+ let whence = match style {
+ io::SeekSet => libc::SEEK_SET,
+ io::SeekEnd => libc::SEEK_END,
+ io::SeekCur => libc::SEEK_CUR,
+ };
+ let n = unsafe { libc::fseek(self.file, pos as libc::c_long, whence) };
+ if n < 0 {
+ Err(super::last_error())
+ } else {
+ Ok(n as u64)
}
}
-}
-
-impl Seek for CFile {
- fn tell(&self) -> u64 {
+ fn tell(&self) -> Result<u64, IoError> {
let ret = unsafe { libc::ftell(self.file) };
if ret < 0 {
- raise_error();
+ Err(super::last_error())
+ } else {
+ Ok(ret as u64)
}
- return ret as u64;
}
-
- fn seek(&mut self, pos: i64, style: SeekStyle) {
- let whence = match style {
- SeekSet => libc::SEEK_SET,
- SeekEnd => libc::SEEK_END,
- SeekCur => libc::SEEK_CUR,
- };
- if unsafe { libc::fseek(self.file, pos as libc::c_long, whence) } < 0 {
- raise_error();
- }
+ fn fsync(&mut self) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+ fn datasync(&mut self) -> Result<(), IoError> {
+ Err(super::unimpl())
+ }
+ fn truncate(&mut self, _offset: i64) -> Result<(), IoError> {
+ Err(super::unimpl())
}
}
mod tests {
use libc;
use os;
- use prelude::*;
- use io::{io_error, SeekSet};
- use super::*;
+ use io::{io_error, SeekSet, Writer, Reader};
+ use result::Ok;
+ use super::{CFile, FileDesc};
#[ignore(cfg(target_os = "freebsd"))] // hmm, maybe pipes have a tiny buffer
fn test_file_desc() {
let mut reader = FileDesc::new(input, true);
let mut writer = FileDesc::new(out, true);
- writer.write(bytes!("test"));
+ writer.inner_write(bytes!("test"));
let mut buf = [0u8, ..4];
- match reader.read(buf) {
- Some(4) => {
+ match reader.inner_read(buf) {
+ Ok(4) => {
assert_eq!(buf[0], 't' as u8);
assert_eq!(buf[1], 'e' as u8);
assert_eq!(buf[2], 's' as u8);
r => fail!("invalid read: {:?}", r)
}
- let mut raised = false;
- do io_error::cond.trap(|_| { raised = true; }).inside {
- writer.read(buf);
- }
- assert!(raised);
-
- raised = false;
- do io_error::cond.trap(|_| { raised = true; }).inside {
- reader.write(buf);
- }
- assert!(raised);
+ assert!(writer.inner_read(buf).is_err());
+ assert!(reader.inner_write(buf).is_err());
}
}
let mut buf = [0u8, ..4];
file.seek(0, SeekSet);
match file.read(buf) {
- Some(4) => {
+ Ok(4) => {
assert_eq!(buf[0], 't' as u8);
assert_eq!(buf[1], 'e' as u8);
assert_eq!(buf[2], 's' as u8);
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Native thread-blocking I/O implementation
+//!
+//! This module contains the implementation of native thread-blocking
+//! implementations of I/O on all platforms. This module is not intended to be
+//! used directly, but rather the rust runtime will fall back to using it if
+//! necessary.
+//!
+//! Rust code normally runs inside of green tasks with a local scheduler using
+//! asynchronous I/O to cooperate among tasks. This model is not always
+//! available, however, and that's where these native implementations come into
+//! play. The only dependencies of these modules are the normal system libraries
+//! that you would find on the respective platform.
+
+use c_str::CString;
+use comm::SharedChan;
+use libc::c_int;
+use libc;
+use option::{Option, None, Some};
+use os;
+use path::Path;
+use result::{Result, Ok, Err};
+use rt::rtio;
+use rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket, RtioUnixListener,
+ RtioPipe, RtioFileStream, RtioProcess, RtioSignal, RtioTTY,
+ CloseBehavior, RtioTimer};
+use io;
+use io::IoError;
+use io::net::ip::SocketAddr;
+use io::process::ProcessConfig;
+use io::signal::Signum;
+use ai = io::net::addrinfo;
+
+// Local re-exports
+pub use self::file::FileDesc;
+pub use self::process::Process;
+
+// Native I/O implementations
+pub mod file;
+pub mod process;
+
+type IoResult<T> = Result<T, IoError>;
+
+fn unimpl() -> IoError {
+ IoError {
+ kind: io::IoUnavailable,
+ desc: "unimplemented I/O interface",
+ detail: None,
+ }
+}
+
+fn last_error() -> IoError {
+ #[cfg(windows)]
+ fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
+ match errno {
+ libc::EOF => (io::EndOfFile, "end of file"),
+ _ => (io::OtherIoError, "unknown error"),
+ }
+ }
+
+ #[cfg(not(windows))]
+ fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
+ // XXX: this should probably be a bit more descriptive...
+ match errno {
+ libc::EOF => (io::EndOfFile, "end of file"),
+
+ // These two constants can have the same value on some systems, but
+ // different values on others, so we can't use a match clause
+ x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+ (io::ResourceUnavailable, "resource temporarily unavailable"),
+
+ _ => (io::OtherIoError, "unknown error"),
+ }
+ }
+
+ let (kind, desc) = get_err(os::errno() as i32);
+ IoError {
+ kind: kind,
+ desc: desc,
+ detail: Some(os::last_os_error())
+ }
+}
+
+/// Implementation of rt::rtio's IoFactory trait to generate handles to the
+/// native I/O functionality.
+pub struct IoFactory;
+
+impl rtio::IoFactory for IoFactory {
+ // networking
+ fn tcp_connect(&mut self, _addr: SocketAddr) -> IoResult<~RtioTcpStream> {
+ Err(unimpl())
+ }
+ fn tcp_bind(&mut self, _addr: SocketAddr) -> IoResult<~RtioTcpListener> {
+ Err(unimpl())
+ }
+ fn udp_bind(&mut self, _addr: SocketAddr) -> IoResult<~RtioUdpSocket> {
+ Err(unimpl())
+ }
+ fn unix_bind(&mut self, _path: &CString) -> IoResult<~RtioUnixListener> {
+ Err(unimpl())
+ }
+ fn unix_connect(&mut self, _path: &CString) -> IoResult<~RtioPipe> {
+ Err(unimpl())
+ }
+ fn get_host_addresses(&mut self, _host: Option<&str>, _servname: Option<&str>,
+ _hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
+ Err(unimpl())
+ }
+
+ // filesystem operations
+ fn fs_from_raw_fd(&mut self, fd: c_int,
+ close: CloseBehavior) -> ~RtioFileStream {
+ let close = match close {
+ rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
+ rtio::DontClose => false
+ };
+ ~file::FileDesc::new(fd, close) as ~RtioFileStream
+ }
+ fn fs_open(&mut self, _path: &CString, _fm: io::FileMode, _fa: io::FileAccess)
+ -> IoResult<~RtioFileStream> {
+ Err(unimpl())
+ }
+ fn fs_unlink(&mut self, _path: &CString) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_stat(&mut self, _path: &CString) -> IoResult<io::FileStat> {
+ Err(unimpl())
+ }
+ fn fs_mkdir(&mut self, _path: &CString,
+ _mode: io::FilePermission) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_chmod(&mut self, _path: &CString,
+ _mode: io::FilePermission) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_rmdir(&mut self, _path: &CString) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_rename(&mut self, _path: &CString, _to: &CString) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_readdir(&mut self, _path: &CString, _flags: c_int) -> IoResult<~[Path]> {
+ Err(unimpl())
+ }
+ fn fs_lstat(&mut self, _path: &CString) -> IoResult<io::FileStat> {
+ Err(unimpl())
+ }
+ fn fs_chown(&mut self, _path: &CString, _uid: int, _gid: int) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_readlink(&mut self, _path: &CString) -> IoResult<Path> {
+ Err(unimpl())
+ }
+ fn fs_symlink(&mut self, _src: &CString, _dst: &CString) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_link(&mut self, _src: &CString, _dst: &CString) -> IoResult<()> {
+ Err(unimpl())
+ }
+ fn fs_utime(&mut self, _src: &CString, _atime: u64,
+ _mtime: u64) -> IoResult<()> {
+ Err(unimpl())
+ }
+
+ // misc
+ fn timer_init(&mut self) -> IoResult<~RtioTimer> {
+ Err(unimpl())
+ }
+ fn spawn(&mut self, config: ProcessConfig)
+ -> IoResult<(~RtioProcess, ~[Option<~RtioPipe>])> {
+ process::Process::spawn(config).map(|(p, io)| {
+ (~p as ~RtioProcess,
+ io.move_iter().map(|p| p.map(|p| ~p as ~RtioPipe)).collect())
+ })
+ }
+ fn pipe_open(&mut self, _fd: c_int) -> IoResult<~RtioPipe> {
+ Err(unimpl())
+ }
+ fn tty_open(&mut self, fd: c_int, _readable: bool) -> IoResult<~RtioTTY> {
+ if unsafe { libc::isatty(fd) } != 0 {
+ Ok(~file::FileDesc::new(fd, true) as ~RtioTTY)
+ } else {
+ Err(unimpl())
+ }
+ }
+ fn signal(&mut self, _signal: Signum, _channel: SharedChan<Signum>)
+ -> IoResult<~RtioSignal> {
+ Err(unimpl())
+ }
+}
// except according to those terms.
use cast;
+use io;
use libc::{pid_t, c_void, c_int};
use libc;
use os;
use prelude::*;
use ptr;
-use io;
+use rt::rtio;
use super::file;
+use p = io::process;
+
/**
* A value representing a child process.
*
/// pid being re-used until the handle is closed.
priv handle: *(),
- /// Currently known stdin of the child, if any
- priv input: Option<file::FileDesc>,
- /// Currently known stdout of the child, if any
- priv output: Option<file::FileDesc>,
- /// Currently known stderr of the child, if any
- priv error: Option<file::FileDesc>,
-
/// None until finish() is called.
priv exit_code: Option<int>,
}
/// these are `None`, then this module will bind the input/output to an
/// os pipe instead. This process takes ownership of these file
/// descriptors, closing them upon destruction of the process.
- pub fn new(prog: &str, args: &[~str], env: Option<~[(~str, ~str)]>,
- cwd: Option<&Path>,
- stdin: Option<file::fd_t>,
- stdout: Option<file::fd_t>,
- stderr: Option<file::fd_t>) -> Process {
- let (in_pipe, in_fd) = match stdin {
- None => {
- let pipe = os::pipe();
- (Some(pipe), pipe.input)
- },
- Some(fd) => (None, fd)
- };
- let (out_pipe, out_fd) = match stdout {
- None => {
- let pipe = os::pipe();
- (Some(pipe), pipe.out)
- },
- Some(fd) => (None, fd)
- };
- let (err_pipe, err_fd) = match stderr {
- None => {
- let pipe = os::pipe();
- (Some(pipe), pipe.out)
- },
- Some(fd) => (None, fd)
- };
+ pub fn spawn(config: p::ProcessConfig)
+ -> Result<(Process, ~[Option<file::FileDesc>]), io::IoError>
+ {
+ // right now we only handle stdin/stdout/stderr.
+ if config.io.len() > 3 {
+ return Err(super::unimpl());
+ }
+
+ fn get_io(io: &[p::StdioContainer],
+ ret: &mut ~[Option<file::FileDesc>],
+ idx: uint) -> (Option<os::Pipe>, c_int) {
+ if idx >= io.len() { return (None, -1); }
+ ret.push(None);
+ match io[idx] {
+ p::Ignored => (None, -1),
+ p::InheritFd(fd) => (None, fd),
+ p::CreatePipe(readable, _writable) => {
+ let pipe = os::pipe();
+ let (theirs, ours) = if readable {
+ (pipe.input, pipe.out)
+ } else {
+ (pipe.out, pipe.input)
+ };
+ ret[idx] = Some(file::FileDesc::new(ours, true));
+ (Some(pipe), theirs)
+ }
+ }
+ }
+
+ let mut ret_io = ~[];
+ let (in_pipe, in_fd) = get_io(config.io, &mut ret_io, 0);
+ let (out_pipe, out_fd) = get_io(config.io, &mut ret_io, 1);
+ let (err_pipe, err_fd) = get_io(config.io, &mut ret_io, 2);
- let res = spawn_process_os(prog, args, env, cwd,
- in_fd, out_fd, err_fd);
+ let env = config.env.map(|a| a.to_owned());
+ let cwd = config.cwd.map(|a| Path::new(a));
+ let res = spawn_process_os(config.program, config.args, env,
+ cwd.as_ref(), in_fd, out_fd, err_fd);
unsafe {
for pipe in in_pipe.iter() { libc::close(pipe.input); }
for pipe in err_pipe.iter() { libc::close(pipe.out); }
}
- Process {
- pid: res.pid,
- handle: res.handle,
- input: in_pipe.map(|pipe| file::FileDesc::new(pipe.out, true)),
- output: out_pipe.map(|pipe| file::FileDesc::new(pipe.input, true)),
- error: err_pipe.map(|pipe| file::FileDesc::new(pipe.input, true)),
- exit_code: None,
- }
- }
-
- /// Returns the unique id of the process
- pub fn id(&self) -> pid_t { self.pid }
-
- /**
- * Returns an io::Writer that can be used to write to this Process's stdin.
- *
- * Fails if there is no stdinavailable (it's already been removed by
- * take_input)
- */
- pub fn input<'a>(&'a mut self) -> &'a mut io::Writer {
- match self.input {
- Some(ref mut fd) => fd as &mut io::Writer,
- None => fail!("This process has no stdin")
- }
- }
-
- /**
- * Returns an io::Reader that can be used to read from this Process's
- * stdout.
- *
- * Fails if there is no stdin available (it's already been removed by
- * take_output)
- */
- pub fn output<'a>(&'a mut self) -> &'a mut io::Reader {
- match self.input {
- Some(ref mut fd) => fd as &mut io::Reader,
- None => fail!("This process has no stdout")
- }
- }
-
- /**
- * Returns an io::Reader that can be used to read from this Process's
- * stderr.
- *
- * Fails if there is no stdin available (it's already been removed by
- * take_error)
- */
- pub fn error<'a>(&'a mut self) -> &'a mut io::Reader {
- match self.error {
- Some(ref mut fd) => fd as &mut io::Reader,
- None => fail!("This process has no stderr")
- }
- }
-
- /**
- * Takes the stdin of this process, transferring ownership to the caller.
- * Note that when the return value is destroyed, the handle will be closed
- * for the child process.
- */
- pub fn take_input(&mut self) -> Option<~io::Writer> {
- self.input.take().map(|fd| ~fd as ~io::Writer)
- }
-
- /**
- * Takes the stdout of this process, transferring ownership to the caller.
- * Note that when the return value is destroyed, the handle will be closed
- * for the child process.
- */
- pub fn take_output(&mut self) -> Option<~io::Reader> {
- self.output.take().map(|fd| ~fd as ~io::Reader)
+ Ok((Process { pid: res.pid, handle: res.handle, exit_code: None }, ret_io))
}
+}
- /**
- * Takes the stderr of this process, transferring ownership to the caller.
- * Note that when the return value is destroyed, the handle will be closed
- * for the child process.
- */
- pub fn take_error(&mut self) -> Option<~io::Reader> {
- self.error.take().map(|fd| ~fd as ~io::Reader)
- }
+impl rtio::RtioProcess for Process {
+ fn id(&self) -> pid_t { self.pid }
- pub fn wait(&mut self) -> int {
- for &code in self.exit_code.iter() {
- return code;
- }
- let code = waitpid(self.pid);
- self.exit_code = Some(code);
- return code;
+ fn wait(&mut self) -> p::ProcessExit {
+ let code = match self.exit_code {
+ Some(code) => code,
+ None => {
+ let code = waitpid(self.pid);
+ self.exit_code = Some(code);
+ code
+ }
+ };
+ return p::ExitStatus(code); // XXX: this is wrong
}
- pub fn signal(&mut self, signum: int) -> Result<(), io::IoError> {
+ fn kill(&mut self, signum: int) -> Result<(), io::IoError> {
// if the process has finished, and therefore had waitpid called,
// and we kill it, then on unix we might ending up killing a
// newer process that happens to have the same (re-used) id
#[cfg(windows)]
unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> {
match signal {
- io::process::PleaseExitSignal |
- io::process::MustDieSignal => {
+ io::process::PleaseExitSignal | io::process::MustDieSignal => {
libc::funcs::extra::kernel32::TerminateProcess(
cast::transmute(pid), 1);
Ok(())
impl Drop for Process {
fn drop(&mut self) {
- // close all these handles
- self.take_input();
- self.take_output();
- self.take_error();
- self.wait();
free_handle(self.handle);
}
}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use libc;
-use option::Option;
-use io::{Reader, Writer};
-use super::file;
-
-/// Creates a new handle to the stdin of this process
-pub fn stdin() -> StdIn { StdIn::new() }
-/// Creates a new handle to the stdout of this process
-pub fn stdout() -> StdOut { StdOut::new(libc::STDOUT_FILENO) }
-/// Creates a new handle to the stderr of this process
-pub fn stderr() -> StdOut { StdOut::new(libc::STDERR_FILENO) }
-
-pub fn print(s: &str) {
- stdout().write(s.as_bytes())
-}
-
-pub fn println(s: &str) {
- let mut out = stdout();
- out.write(s.as_bytes());
- out.write(['\n' as u8]);
-}
-
-pub struct StdIn {
- priv fd: file::FileDesc
-}
-
-impl StdIn {
- /// Duplicates the stdin file descriptor, returning an io::Reader
- pub fn new() -> StdIn {
- StdIn { fd: file::FileDesc::new(libc::STDIN_FILENO, false) }
- }
-}
-
-impl Reader for StdIn {
- fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.fd.read(buf) }
- fn eof(&mut self) -> bool { self.fd.eof() }
-}
-
-pub struct StdOut {
- priv fd: file::FileDesc
-}
-
-impl StdOut {
- /// Duplicates the specified file descriptor, returning an io::Writer
- pub fn new(fd: file::fd_t) -> StdOut {
- StdOut { fd: file::FileDesc::new(fd, false) }
- }
-}
-
-impl Writer for StdOut {
- fn write(&mut self, buf: &[u8]) { self.fd.write(buf) }
- fn flush(&mut self) { self.fd.flush() }
-}
use rt::task::Task;
unsafe {
- // Logging may require scheduling operations, so we can't remove the
- // task from TLS right now, hence the unsafe borrow. Sad.
- let task: *mut Task = Local::unsafe_borrow();
+ let task: Option<*mut Task> = Local::try_unsafe_borrow();
+ match task {
+ Some(task) => {
+ match (*task).stdout_handle {
+ Some(ref mut handle) => f(*handle),
+ None => {
+ let handle = ~LineBufferedWriter::new(stdout());
+ let mut handle = handle as ~Writer;
+ f(handle);
+ (*task).stdout_handle = Some(handle);
+ }
+ }
+ }
- match (*task).stdout_handle {
- Some(ref mut handle) => f(*handle),
None => {
- let handle = stdout();
- let mut handle = ~LineBufferedWriter::new(handle) as ~Writer;
- f(handle);
- (*task).stdout_handle = Some(handle);
+ let mut io = stdout();
+ f(&mut io as &mut Writer);
}
}
}
use rt::rtio::{EventLoop, IoFactory, RemoteCallback, PausibleIdleCallback,
Callback};
use unstable::sync::Exclusive;
+use io::native;
use util;
/// This is the only exported function from this module.
idle: Option<*mut BasicPausible>, // only one is allowed
remotes: ~[(uint, ~Callback)],
next_remote: uint,
- messages: Exclusive<~[Message]>
+ messages: Exclusive<~[Message]>,
+ io: ~IoFactory,
}
enum Message { RunRemote(uint), RemoveRemote(uint) }
next_remote: 0,
remotes: ~[],
messages: Exclusive::new(~[]),
+ io: ~native::IoFactory as ~IoFactory,
}
}
~BasicRemote::new(self.messages.clone(), id) as ~RemoteCallback
}
- /// This has no bindings for local I/O
- fn io<'a>(&'a mut self, _: &fn(&'a mut IoFactory)) {}
+ fn io<'a>(&'a mut self, f: &fn(&'a mut IoFactory)) {
+ f(self.io)
+ }
}
struct BasicRemote {
pub fn with_local_io<T>(f: &fn(&mut IoFactory) -> Option<T>) -> Option<T> {
use rt::sched::Scheduler;
use rt::local::Local;
- use io::{io_error, standard_error, IoUnavailable};
+ use io::native;
unsafe {
- let sched: *mut Scheduler = Local::unsafe_borrow();
- let mut io = None;
- (*sched).event_loop.io(|i| io = Some(i));
- match io {
- Some(io) => f(io),
- None => {
- io_error::cond.raise(standard_error(IoUnavailable));
- None
+ // First, attempt to use the local scheduler's I/O services
+ let sched: Option<*mut Scheduler> = Local::try_unsafe_borrow();
+ match sched {
+ Some(sched) => {
+ let mut io = None;
+ (*sched).event_loop.io(|i| io = Some(i));
+ match io {
+ Some(io) => return f(io),
+ None => {}
+ }
}
+ None => {}
}
}
+
+ // If we don't have a scheduler or the scheduler doesn't have I/O services,
+ // then fall back to the native I/O services.
+ let mut io = native::IoFactory;
+ f(&mut io as &mut IoFactory)
}
pub trait IoFactory {
}
pub fn dumb_println(args: &fmt::Arguments) {
- use io::native::stdio::stderr;
- use io::{Writer, io_error, ResourceUnavailable};
- use rt::task::Task;
- use rt::local::Local;
-
- let mut out = stderr();
- if Local::exists(None::<Task>) {
- let mut again = true;
- do io_error::cond.trap(|e| {
- again = e.kind == ResourceUnavailable;
- }).inside {
- while again {
- again = false;
- fmt::writeln(&mut out as &mut Writer, args);
- }
- }
- } else {
- fmt::writeln(&mut out as &mut Writer, args);
- }
+ use io::native::file::FileDesc;
+ use io;
+ use libc;
+ let mut out = FileDesc::new(libc::STDERR_FILENO, false);
+ fmt::writeln(&mut out as &mut io::Writer, args);
}
pub fn abort(msg: &str) -> ! {
// given a FASTA file on stdin, process sequence THREE
fn main() {
use std::io::Reader;
- use std::io::native::stdio;
+ use std::io::stdio;
use std::io::mem::MemReader;
use std::io::buffered::BufferedReader;
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast
+
+#[no_uv];
+
+#[start]
+fn main(_: int, _: **u8) -> int {
+ println!("hello");
+ 0
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast
+
+#[no_uv];
+
+fn main() {
+ println!("hello");
+}