diff --git a/mk/crates.mk b/mk/crates.mk index 97bf7db5332ce..433490f6f5dbf 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -51,7 +51,7 @@ TARGET_CRATES := libc std green rustuv native flate arena glob term semver \ uuid serialize sync getopts collections num test time rand \ - url log regex graphviz core rlibc alloc debug + url log regex graphviz core rlibc alloc debug rustrt HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc @@ -60,7 +60,9 @@ DEPS_core := DEPS_rlibc := DEPS_alloc := core libc native:jemalloc DEPS_debug := std -DEPS_std := core rand libc alloc collections native:rustrt native:backtrace +DEPS_rustrt := alloc core libc collections native:rustrt_native +DEPS_std := core libc rand alloc collections rustrt \ + native:rust_builtin native:backtrace DEPS_graphviz := std DEPS_green := std native:context_switch DEPS_rustuv := std native:uv native:uv_support diff --git a/mk/rt.mk b/mk/rt.mk index 625e1a8d0c7a7..a75cb8aa4deb2 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -35,8 +35,8 @@ # that's per-target so you're allowed to conditionally add files based on the # target. ################################################################################ -NATIVE_LIBS := rustrt hoedown uv_support morestack miniz context_switch \ - rust_test_helpers +NATIVE_LIBS := rust_builtin hoedown uv_support morestack miniz context_switch \ + rustrt_native rust_test_helpers # $(1) is the target triple define NATIVE_LIBRARIES @@ -52,8 +52,9 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \ hoedown/src/version.c NATIVE_DEPS_uv_support_$(1) := rust_uv.c NATIVE_DEPS_miniz_$(1) = miniz.c -NATIVE_DEPS_rustrt_$(1) := rust_builtin.c \ - rust_android_dummy.c \ +NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \ + rust_android_dummy.c +NATIVE_DEPS_rustrt_native_$(1) := \ rust_try.ll \ arch/$$(HOST_$(1))/record_sp.S NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 511983da4f7f2..ca7ed6f4ba05b 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -96,6 +96,21 @@ pub mod owned; pub mod arc; pub mod rc; +// FIXME(#14344): When linking liballoc with libstd, this library will be linked +// as an rlib (it only exists as an rlib). It turns out that an +// optimized standard library doesn't actually use *any* symbols +// from this library. Everything is inlined and optimized away. +// This means that linkers will actually omit the object for this +// file, even though it may be needed in the future. +// +// To get around this for now, we define a dummy symbol which +// will never get inlined so the stdlib can call it. The stdlib's +// reference to this symbol will cause this library's object file +// to get linked in to libstd successfully (the linker won't +// optimize it out). +#[doc(hidden)] +pub fn fixme_14344_be_sure_to_link_to_collections() {} + #[cfg(not(test))] #[doc(hidden)] mod std { diff --git a/src/liballoc/util.rs b/src/liballoc/util.rs index 64d620358903e..7e35af79eab1c 100644 --- a/src/liballoc/util.rs +++ b/src/liballoc/util.rs @@ -28,20 +28,3 @@ fn align_to(size: uint, align: uint) -> uint { assert!(align != 0); (size + align - 1) & !(align - 1) } - -// FIXME(#14344): When linking liballoc with libstd, this library will be linked -// as an rlib (it only exists as an rlib). It turns out that an -// optimized standard library doesn't actually use *any* symbols -// from this library. Everything is inlined and optimized away. -// This means that linkers will actually omit the object for this -// file, even though it may be needed in the future. -// -// To get around this for now, we define a dummy symbol which -// will never get inlined so the stdlib can call it. The stdlib's -// reference to this symbol will cause this library's object file -// to get linked in to libstd successfully (the linker won't -// optimize it out). -#[deprecated] -#[doc(hidden)] -pub fn make_stdlib_link_work() {} - diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index a65c06107ce34..c46ea84a765ce 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -72,6 +72,10 @@ fn expect(a: core::option::Option, b: &str) -> T { } } +// FIXME(#14344) this shouldn't be necessary +#[doc(hidden)] +pub fn fixme_14344_be_sure_to_link_to_collections() {} + #[cfg(not(test))] mod std { pub use core::fmt; // necessary for fail!() diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index e631b8b77cf9c..4798218e3ff25 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -862,7 +862,7 @@ mod tests { use std::prelude::*; use std::rand::{Rng, task_rng}; use std::rc::Rc; - use std::unstable; + use std::rt; use slice::*; use vec::Vec; @@ -1104,9 +1104,9 @@ mod tests { #[test] fn test_swap_remove_noncopyable() { // Tests that we don't accidentally run destructors twice. - let mut v = vec![unstable::sync::Exclusive::new(()), - unstable::sync::Exclusive::new(()), - unstable::sync::Exclusive::new(())]; + let mut v = vec![rt::exclusive::Exclusive::new(()), + rt::exclusive::Exclusive::new(()), + rt::exclusive::Exclusive::new(())]; let mut _e = v.swap_remove(0); assert_eq!(v.len(), 2); _e = v.swap_remove(1); diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 94901aff001c0..7942a1569ed2f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -98,6 +98,20 @@ macro_rules! try( ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) }) ) +/// Writing a formatted string into a writer +#[macro_export] +macro_rules! write( + ($dst:expr, $($arg:tt)*) => (format_args_method!($dst, write_fmt, $($arg)*)) +) + +/// Writing a formatted string plus a newline into a writer +#[macro_export] +macro_rules! writeln( + ($dst:expr, $fmt:expr $($arg:tt)*) => ( + write!($dst, concat!($fmt, "\n") $($arg)*) + ) +) + #[cfg(test)] macro_rules! vec( ($($e:expr),*) => ({ let mut _v = ::std::vec::Vec::new(); diff --git a/src/libgreen/basic.rs b/src/libgreen/basic.rs index 1ebebbe555e8b..7f033a1bc6163 100644 --- a/src/libgreen/basic.rs +++ b/src/libgreen/basic.rs @@ -20,7 +20,7 @@ use std::sync::atomics; use std::mem; use std::rt::rtio::{EventLoop, IoFactory, RemoteCallback}; use std::rt::rtio::{PausableIdleCallback, Callback}; -use std::unstable::sync::Exclusive; +use std::rt::exclusive::Exclusive; /// This is the only exported function from this module. pub fn event_loop() -> Box { @@ -31,7 +31,7 @@ struct BasicLoop { work: Vec, // pending work remotes: Vec<(uint, Box)>, next_remote: uint, - messages: Exclusive>, + messages: Arc>>, idle: Option>, idle_active: Option>, } @@ -46,7 +46,7 @@ impl BasicLoop { idle_active: None, next_remote: 0, remotes: vec![], - messages: Exclusive::new(vec![]), + messages: Arc::new(Exclusive::new(Vec::new())), } } @@ -61,19 +61,10 @@ impl BasicLoop { fn remote_work(&mut self) { let messages = unsafe { - self.messages.with(|messages| { - if messages.len() > 0 { - Some(mem::replace(messages, vec![])) - } else { - None - } - }) - }; - let messages = match messages { - Some(m) => m, None => return + mem::replace(&mut *self.messages.lock(), Vec::new()) }; - for message in messages.iter() { - self.message(*message); + for message in messages.move_iter() { + self.message(message); } } @@ -125,13 +116,13 @@ impl EventLoop for BasicLoop { } unsafe { + let mut messages = self.messages.lock(); // We block here if we have no messages to process and we may // receive a message at a later date - self.messages.hold_and_wait(|messages| { - self.remotes.len() > 0 && - messages.len() == 0 && - self.work.len() == 0 - }) + if self.remotes.len() > 0 && messages.len() == 0 && + self.work.len() == 0 { + messages.wait() + } } } } @@ -165,33 +156,29 @@ impl EventLoop for BasicLoop { } struct BasicRemote { - queue: Exclusive>, + queue: Arc>>, id: uint, } impl BasicRemote { - fn new(queue: Exclusive>, id: uint) -> BasicRemote { + fn new(queue: Arc>>, id: uint) -> BasicRemote { BasicRemote { queue: queue, id: id } } } impl RemoteCallback for BasicRemote { fn fire(&mut self) { - unsafe { - self.queue.hold_and_signal(|queue| { - queue.push(RunRemote(self.id)); - }) - } + let mut queue = unsafe { self.queue.lock() }; + queue.push(RunRemote(self.id)); + queue.signal(); } } impl Drop for BasicRemote { fn drop(&mut self) { - unsafe { - self.queue.hold_and_signal(|queue| { - queue.push(RemoveRemote(self.id)); - }) - } + let mut queue = unsafe { self.queue.lock() }; + queue.push(RemoveRemote(self.id)); + queue.signal(); } } @@ -216,7 +203,7 @@ impl Drop for BasicPausable { #[cfg(test)] mod test { - use std::task::TaskOpts; + use std::rt::task::TaskOpts; use basic; use PoolConfig; diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs index c75d69480ce0d..333ac80907f6a 100644 --- a/src/libgreen/lib.rs +++ b/src/libgreen/lib.rs @@ -160,7 +160,7 @@ //! # Using a scheduler pool //! //! ```rust -//! use std::task::TaskOpts; +//! use std::rt::task::TaskOpts; //! use green::{SchedPool, PoolConfig}; //! use green::sched::{PinnedTask, TaskFromFriend}; //! @@ -221,10 +221,10 @@ use std::mem::replace; use std::os; use std::rt::rtio; use std::rt::thread::Thread; +use std::rt::task::TaskOpts; use std::rt; use std::sync::atomics::{SeqCst, AtomicUint, INIT_ATOMIC_UINT}; use std::sync::deque; -use std::task::TaskOpts; use sched::{Shutdown, Scheduler, SchedHandle, TaskFromFriend, NewNeighbor}; use sleeper_list::SleeperList; @@ -319,7 +319,7 @@ pub fn run(event_loop_factory: fn() -> Box, let mut pool = SchedPool::new(cfg); let (tx, rx) = channel(); let mut opts = TaskOpts::new(); - opts.notify_chan = Some(tx); + opts.on_exit = Some(proc(r) tx.send(r)); opts.name = Some("
".into_maybe_owned()); pool.spawn(opts, main); diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index e410d2719b147..f55dc92eac610 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -10,11 +10,11 @@ use std::mem; use std::rt::local::Local; +use std::rt::mutex::NativeMutex; use std::rt::rtio::{RemoteCallback, PausableIdleCallback, Callback, EventLoop}; use std::rt::task::BlockedTask; use std::rt::task::Task; use std::sync::deque; -use std::unstable::mutex::NativeMutex; use std::raw; use std::rand::{XorShiftRng, Rng, Rand}; @@ -1022,7 +1022,7 @@ fn new_sched_rng() -> XorShiftRng { mod test { use rustuv; - use std::task::TaskOpts; + use std::rt::task::TaskOpts; use std::rt::task::Task; use std::rt::local::Local; @@ -1475,7 +1475,7 @@ mod test { #[test] fn test_spawn_sched_blocking() { - use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; // Testing that a task in one scheduler can block in foreign code diff --git a/src/libgreen/simple.rs b/src/libgreen/simple.rs index 49aef15f93b61..7b738ed9c7c15 100644 --- a/src/libgreen/simple.rs +++ b/src/libgreen/simple.rs @@ -15,10 +15,9 @@ use std::any::Any; use std::mem; use std::rt::Runtime; use std::rt::local::Local; +use std::rt::mutex::NativeMutex; use std::rt::rtio; -use std::rt::task::{Task, BlockedTask}; -use std::task::TaskOpts; -use std::unstable::mutex::NativeMutex; +use std::rt::task::{Task, BlockedTask, TaskOpts}; struct SimpleTask { lock: NativeMutex, diff --git a/src/libgreen/stack.rs b/src/libgreen/stack.rs index f42d636cafbdd..2e385f75e1d3e 100644 --- a/src/libgreen/stack.rs +++ b/src/libgreen/stack.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rt::env::max_cached_stacks; +use std::sync::atomics; use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable, - MapNonStandardFlags, MapVirtual}; + MapNonStandardFlags, MapVirtual, getenv}; use libc; /// A task's stack. The name "Stack" is a vestige of segmented stacks. @@ -151,6 +151,22 @@ impl StackPool { } } +fn max_cached_stacks() -> uint { + static mut AMT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; + match unsafe { AMT.load(atomics::SeqCst) } { + 0 => {} + n => return n - 1, + } + let amt = getenv("RUST_MAX_CACHED_STACKS").and_then(|s| from_str(s.as_slice())); + // This default corresponds to 20M of cache per scheduler (at the + // default size). + let amt = amt.unwrap_or(10); + // 0 is our sentinel value, so ensure that we'll never see 0 after + // initialization has run + unsafe { AMT.store(amt + 1, atomics::SeqCst); } + return amt; +} + extern { fn rust_valgrind_stack_register(start: *libc::uintptr_t, end: *libc::uintptr_t) -> libc::c_uint; diff --git a/src/libgreen/task.rs b/src/libgreen/task.rs index f50f65af6f9eb..91ebad3b3f8ab 100644 --- a/src/libgreen/task.rs +++ b/src/libgreen/task.rs @@ -22,13 +22,12 @@ use std::any::Any; use std::mem; use std::raw; use std::rt::Runtime; -use std::rt::env; use std::rt::local::Local; +use std::rt::mutex::NativeMutex; use std::rt::rtio; use std::rt::stack; -use std::rt::task::{Task, BlockedTask, SendMessage}; -use std::task::TaskOpts; -use std::unstable::mutex::NativeMutex; +use std::rt::task::{Task, BlockedTask, TaskOpts}; +use std::rt; use context::Context; use coroutine::Coroutine; @@ -142,7 +141,7 @@ impl GreenTask { let mut ops = GreenTask::new_typed(None, TypeGreen(Some(home))); // Allocate a stack for us to run on - let stack_size = stack_size.unwrap_or_else(|| env::min_stack()); + let stack_size = stack_size.unwrap_or_else(|| rt::min_stack()); let mut stack = stack_pool.take_stack(stack_size); let context = Context::new(bootstrap_green_task, ops.as_uint(), start, &mut stack); @@ -176,23 +175,13 @@ impl GreenTask { pub fn configure(pool: &mut StackPool, opts: TaskOpts, f: proc():Send) -> Box { - let TaskOpts { - notify_chan, name, stack_size, - stderr, stdout, - } = opts; + let TaskOpts { name, stack_size, on_exit } = opts; let mut green = GreenTask::new(pool, stack_size, f); { let task = green.task.get_mut_ref(); task.name = name; - task.stderr = stderr; - task.stdout = stdout; - match notify_chan { - Some(chan) => { - task.death.on_exit = Some(SendMessage(chan)); - } - None => {} - } + task.death.on_exit = on_exit; } return green; } @@ -490,7 +479,7 @@ mod tests { use std::rt::local::Local; use std::rt::task::Task; use std::task; - use std::task::TaskOpts; + use std::rt::task::TaskOpts; use super::super::{PoolConfig, SchedPool}; use super::GreenTask; @@ -529,7 +518,7 @@ mod tests { opts.name = Some("test".into_maybe_owned()); opts.stack_size = Some(20 * 4096); let (tx, rx) = channel(); - opts.notify_chan = Some(tx); + opts.on_exit = Some(proc(r) tx.send(r)); spawn_opts(opts, proc() {}); assert!(rx.recv().is_ok()); } @@ -538,7 +527,7 @@ mod tests { fn smoke_opts_fail() { let mut opts = TaskOpts::new(); let (tx, rx) = channel(); - opts.notify_chan = Some(tx); + opts.on_exit = Some(proc(r) tx.send(r)); spawn_opts(opts, proc() { fail!() }); assert!(rx.recv().is_err()); } diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 5b7f58fcb815c..b833b2a65158d 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -172,6 +172,7 @@ pub use funcs::bsd43::{shutdown}; #[cfg(unix)] pub use consts::os::posix88::{ENOTCONN, ECONNABORTED, EADDRNOTAVAIL, EINTR}; #[cfg(unix)] pub use consts::os::posix88::{EADDRINUSE, ENOENT, EISDIR, EAGAIN, EWOULDBLOCK}; #[cfg(unix)] pub use consts::os::posix88::{ECANCELED, SIGINT, EINPROGRESS}; +#[cfg(unix)] pub use consts::os::posix88::{ENOSYS, ENOTTY, ETIMEDOUT}; #[cfg(unix)] pub use consts::os::posix88::{SIGTERM, SIGKILL, SIGPIPE, PROT_NONE}; #[cfg(unix)] pub use consts::os::posix01::{SIG_IGN}; #[cfg(unix)] pub use consts::os::bsd44::{AF_UNIX}; @@ -195,7 +196,7 @@ pub use funcs::bsd43::{shutdown}; #[cfg(windows)] pub use consts::os::c95::{WSAECONNREFUSED, WSAECONNRESET, WSAEACCES}; #[cfg(windows)] pub use consts::os::c95::{WSAEWOULDBLOCK, WSAENOTCONN, WSAECONNABORTED}; #[cfg(windows)] pub use consts::os::c95::{WSAEADDRNOTAVAIL, WSAEADDRINUSE, WSAEINTR}; -#[cfg(windows)] pub use consts::os::c95::{WSAEINPROGRESS}; +#[cfg(windows)] pub use consts::os::c95::{WSAEINPROGRESS, WSAEINVAL}; #[cfg(windows)] pub use consts::os::extra::{ERROR_INSUFFICIENT_BUFFER}; #[cfg(windows)] pub use consts::os::extra::{O_BINARY, O_NOINHERIT, PAGE_NOACCESS}; #[cfg(windows)] pub use consts::os::extra::{PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE}; @@ -205,6 +206,9 @@ pub use funcs::bsd43::{shutdown}; #[cfg(windows)] pub use consts::os::extra::{ERROR_ALREADY_EXISTS, ERROR_NO_DATA}; #[cfg(windows)] pub use consts::os::extra::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_NAME}; #[cfg(windows)] pub use consts::os::extra::{ERROR_BROKEN_PIPE, ERROR_INVALID_FUNCTION}; +#[cfg(windows)] pub use consts::os::extra::{ERROR_CALL_NOT_IMPLEMENTED}; +#[cfg(windows)] pub use consts::os::extra::{ERROR_NOTHING_TO_TERMINATE}; +#[cfg(windows)] pub use consts::os::extra::{ERROR_INVALID_HANDLE}; #[cfg(windows)] pub use consts::os::extra::{TRUE, FALSE, INFINITE}; #[cfg(windows)] pub use consts::os::extra::{PROCESS_TERMINATE, PROCESS_QUERY_INFORMATION}; #[cfg(windows)] pub use consts::os::extra::{STILL_ACTIVE, DETACHED_PROCESS}; @@ -1758,6 +1762,7 @@ pub mod consts { pub static ERROR_NO_DATA: c_int = 232; pub static ERROR_INVALID_ADDRESS : c_int = 487; pub static ERROR_PIPE_CONNECTED: c_int = 535; + pub static ERROR_NOTHING_TO_TERMINATE: c_int = 758; pub static ERROR_OPERATION_ABORTED: c_int = 995; pub static ERROR_IO_PENDING: c_int = 997; pub static ERROR_FILE_INVALID : c_int = 1006; diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs index 6bc41a9c4c5b2..255c3f4bd213d 100644 --- a/src/libnative/io/addrinfo.rs +++ b/src/libnative/io/addrinfo.rs @@ -8,21 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ai = std::io::net::addrinfo; use libc::{c_char, c_int}; use libc; use std::c_str::CString; -use std::io::IoError; use std::mem; use std::ptr::{null, mut_null}; +use std::rt::rtio; +use std::rt::rtio::IoError; -use super::net::sockaddr_to_addr; +use super::net; pub struct GetAddrInfoRequest; impl GetAddrInfoRequest { pub fn run(host: Option<&str>, servname: Option<&str>, - hint: Option) -> Result, IoError> { + hint: Option) + -> Result, IoError> + { assert!(host.is_some() || servname.is_some()); let c_host = host.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str()); @@ -61,16 +63,16 @@ impl GetAddrInfoRequest { let mut rp = res; while rp.is_not_null() { unsafe { - let addr = match sockaddr_to_addr(mem::transmute((*rp).ai_addr), - (*rp).ai_addrlen as uint) { + let addr = match net::sockaddr_to_addr(mem::transmute((*rp).ai_addr), + (*rp).ai_addrlen as uint) { Ok(a) => a, Err(e) => return Err(e) }; - addrs.push(ai::Info { + addrs.push(rtio::AddrinfoInfo { address: addr, family: (*rp).ai_family as uint, - socktype: None, - protocol: None, + socktype: 0, + protocol: 0, flags: (*rp).ai_flags as uint }); @@ -90,27 +92,22 @@ extern "system" { fn freeaddrinfo(res: *mut libc::addrinfo); #[cfg(not(windows))] fn gai_strerror(errcode: c_int) -> *c_char; - #[cfg(windows)] - fn WSAGetLastError() -> c_int; } #[cfg(windows)] fn get_error(_: c_int) -> IoError { - unsafe { - IoError::from_errno(WSAGetLastError() as uint, true) - } + net::last_error() } #[cfg(not(windows))] fn get_error(s: c_int) -> IoError { - use std::io; let err_str = unsafe { CString::new(gai_strerror(s), false).as_str().unwrap().to_string() }; IoError { - kind: io::OtherIoError, - desc: "unable to resolve host", + code: s as uint, + extra: 0, detail: Some(err_str), } } diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index b10284a3b6c3f..fda9b7b1932b0 100644 --- a/src/libnative/io/file_unix.rs +++ b/src/libnative/io/file_unix.rs @@ -14,12 +14,12 @@ use alloc::arc::Arc; use libc::{c_int, c_void}; use libc; use std::c_str::CString; -use std::io::IoError; -use std::io; use std::mem; use std::rt::rtio; +use std::rt::rtio::IoResult; -use io::{IoResult, retry, keep_going}; +use io::{retry, keep_going}; +use io::util; pub type fd_t = libc::c_int; @@ -51,21 +51,21 @@ impl FileDesc { // FIXME(#10465) these functions should not be public, but anything in // native::io wanting to use them is forced to have all the // rtio traits in scope - pub fn inner_read(&mut self, buf: &mut [u8]) -> Result { + pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult { let ret = retry(|| unsafe { libc::read(self.fd(), buf.as_mut_ptr() as *mut libc::c_void, buf.len() as libc::size_t) as libc::c_int }); if ret == 0 { - Err(io::standard_error(io::EndOfFile)) + Err(util::eof()) } else if ret < 0 { Err(super::last_error()) } else { Ok(ret as uint) } } - pub fn inner_write(&mut self, buf: &[u8]) -> Result<(), IoError> { + pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> { let ret = keep_going(buf, |buf, len| { unsafe { libc::write(self.fd(), buf as *libc::c_void, @@ -82,26 +82,14 @@ impl FileDesc { pub fn fd(&self) -> fd_t { self.inner.fd } } -impl io::Reader for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::IoResult { - self.inner_read(buf) - } -} - -impl io::Writer for FileDesc { - fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { - self.inner_write(buf) - } -} - impl rtio::RtioFileStream for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner_read(buf).map(|i| i as int) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner_write(buf) } - fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result { + fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { match retry(|| unsafe { libc::pread(self.fd(), buf.as_ptr() as *libc::c_void, buf.len() as libc::size_t, @@ -111,17 +99,17 @@ impl rtio::RtioFileStream for FileDesc { n => Ok(n as int) } } - fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> { + fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> { super::mkerr_libc(retry(|| unsafe { libc::pwrite(self.fd(), buf.as_ptr() as *libc::c_void, buf.len() as libc::size_t, offset as libc::off_t) } as c_int)) } - fn seek(&mut self, pos: i64, whence: io::SeekStyle) -> Result { + fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult { let whence = match whence { - io::SeekSet => libc::SEEK_SET, - io::SeekEnd => libc::SEEK_END, - io::SeekCur => libc::SEEK_CUR, + rtio::SeekSet => libc::SEEK_SET, + rtio::SeekEnd => libc::SEEK_END, + rtio::SeekCur => libc::SEEK_CUR, }; let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) }; if n < 0 { @@ -130,7 +118,7 @@ impl rtio::RtioFileStream for FileDesc { Ok(n as u64) } } - fn tell(&self) -> Result { + fn tell(&self) -> IoResult { let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) }; if n < 0 { Err(super::last_error()) @@ -138,10 +126,10 @@ impl rtio::RtioFileStream for FileDesc { Ok(n as u64) } } - fn fsync(&mut self) -> Result<(), IoError> { + fn fsync(&mut self) -> IoResult<()> { super::mkerr_libc(retry(|| unsafe { libc::fsync(self.fd()) })) } - fn datasync(&mut self) -> Result<(), IoError> { + fn datasync(&mut self) -> IoResult<()> { return super::mkerr_libc(os_datasync(self.fd())); #[cfg(target_os = "macos")] @@ -157,13 +145,13 @@ impl rtio::RtioFileStream for FileDesc { retry(|| unsafe { libc::fsync(fd) }) } } - fn truncate(&mut self, offset: i64) -> Result<(), IoError> { + fn truncate(&mut self, offset: i64) -> IoResult<()> { super::mkerr_libc(retry(|| unsafe { libc::ftruncate(self.fd(), offset as libc::off_t) })) } - fn fstat(&mut self) -> IoResult { + fn fstat(&mut self) -> IoResult { let mut stat: libc::stat = unsafe { mem::zeroed() }; match retry(|| unsafe { libc::fstat(self.fd(), &mut stat) }) { 0 => Ok(mkstat(&stat)), @@ -173,10 +161,10 @@ impl rtio::RtioFileStream for FileDesc { } impl rtio::RtioPipe for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner_read(buf) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner_write(buf) } fn clone(&self) -> Box { @@ -187,11 +175,11 @@ impl rtio::RtioPipe for FileDesc { // impact on the std::io primitives, this is never called via // std::io::PipeStream. If the functionality is exposed in the future, then // these methods will need to be implemented. - fn close_read(&mut self) -> Result<(), IoError> { - Err(io::standard_error(io::InvalidInput)) + fn close_read(&mut self) -> IoResult<()> { + Err(super::unimpl()) } - fn close_write(&mut self) -> Result<(), IoError> { - Err(io::standard_error(io::InvalidInput)) + fn close_write(&mut self) -> IoResult<()> { + Err(super::unimpl()) } fn set_timeout(&mut self, _t: Option) {} fn set_read_timeout(&mut self, _t: Option) {} @@ -199,16 +187,16 @@ impl rtio::RtioPipe for FileDesc { } impl rtio::RtioTTY for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner_read(buf) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner_write(buf) } - fn set_raw(&mut self, _raw: bool) -> Result<(), IoError> { + fn set_raw(&mut self, _raw: bool) -> IoResult<()> { Err(super::unimpl()) } - fn get_winsize(&mut self) -> Result<(int, int), IoError> { + fn get_winsize(&mut self) -> IoResult<(int, int)> { Err(super::unimpl()) } fn isatty(&self) -> bool { false } @@ -249,13 +237,13 @@ impl CFile { } } - pub fn flush(&mut self) -> Result<(), IoError> { + pub fn flush(&mut self) -> IoResult<()> { super::mkerr_libc(retry(|| unsafe { libc::fflush(self.file) })) } } impl rtio::RtioFileStream for CFile { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { let ret = keep_going(buf, |buf, len| { unsafe { libc::fread(buf as *mut libc::c_void, 1, len as libc::size_t, @@ -263,7 +251,7 @@ impl rtio::RtioFileStream for CFile { } }); if ret == 0 { - Err(io::standard_error(io::EndOfFile)) + Err(util::eof()) } else if ret < 0 { Err(super::last_error()) } else { @@ -271,7 +259,7 @@ impl rtio::RtioFileStream for CFile { } } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { let ret = keep_going(buf, |buf, len| { unsafe { libc::fwrite(buf as *libc::c_void, 1, len as libc::size_t, @@ -285,17 +273,17 @@ impl rtio::RtioFileStream for CFile { } } - fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result { + fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { self.flush().and_then(|()| self.fd.pread(buf, offset)) } - fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> { + fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> { self.flush().and_then(|()| self.fd.pwrite(buf, offset)) } - fn seek(&mut self, pos: i64, style: io::SeekStyle) -> Result { + fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult { let whence = match style { - io::SeekSet => libc::SEEK_SET, - io::SeekEnd => libc::SEEK_END, - io::SeekCur => libc::SEEK_CUR, + rtio::SeekSet => libc::SEEK_SET, + rtio::SeekEnd => libc::SEEK_END, + rtio::SeekCur => libc::SEEK_CUR, }; let n = unsafe { libc::fseek(self.file, pos as libc::c_long, whence) }; if n < 0 { @@ -304,7 +292,7 @@ impl rtio::RtioFileStream for CFile { Ok(n as u64) } } - fn tell(&self) -> Result { + fn tell(&self) -> IoResult { let ret = unsafe { libc::ftell(self.file) }; if ret < 0 { Err(super::last_error()) @@ -312,17 +300,17 @@ impl rtio::RtioFileStream for CFile { Ok(ret as u64) } } - fn fsync(&mut self) -> Result<(), IoError> { + fn fsync(&mut self) -> IoResult<()> { self.flush().and_then(|()| self.fd.fsync()) } - fn datasync(&mut self) -> Result<(), IoError> { + fn datasync(&mut self) -> IoResult<()> { self.flush().and_then(|()| self.fd.fsync()) } - fn truncate(&mut self, offset: i64) -> Result<(), IoError> { + fn truncate(&mut self, offset: i64) -> IoResult<()> { self.flush().and_then(|()| self.fd.truncate(offset)) } - fn fstat(&mut self) -> IoResult { + fn fstat(&mut self) -> IoResult { self.flush().and_then(|()| self.fd.fstat()) } } @@ -333,20 +321,21 @@ impl Drop for CFile { } } -pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess) - -> IoResult { +pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess) + -> IoResult +{ let flags = match fm { - io::Open => 0, - io::Append => libc::O_APPEND, - io::Truncate => libc::O_TRUNC, + rtio::Open => 0, + rtio::Append => libc::O_APPEND, + rtio::Truncate => libc::O_TRUNC, }; // Opening with a write permission must silently create the file. let (flags, mode) = match fa { - io::Read => (flags | libc::O_RDONLY, 0), - io::Write => (flags | libc::O_WRONLY | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), - io::ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), + rtio::Read => (flags | libc::O_RDONLY, 0), + rtio::Write => (flags | libc::O_WRONLY | libc::O_CREAT, + libc::S_IRUSR | libc::S_IWUSR), + rtio::ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT, + libc::S_IRUSR | libc::S_IWUSR), }; match retry(|| unsafe { libc::open(path.with_ref(|p| p), flags, mode) }) { @@ -355,23 +344,23 @@ pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess) } } -pub fn mkdir(p: &CString, mode: io::FilePermission) -> IoResult<()> { +pub fn mkdir(p: &CString, mode: uint) -> IoResult<()> { super::mkerr_libc(retry(|| unsafe { - libc::mkdir(p.with_ref(|p| p), mode.bits() as libc::mode_t) + libc::mkdir(p.with_ref(|p| p), mode as libc::mode_t) })) } -pub fn readdir(p: &CString) -> IoResult> { +pub fn readdir(p: &CString) -> IoResult> { use libc::{dirent_t}; use libc::{opendir, readdir_r, closedir}; - fn prune(root: &CString, dirs: Vec) -> Vec { + fn prune(root: &CString, dirs: Vec) -> Vec { let root = unsafe { CString::new(root.with_ref(|p| p), false) }; let root = Path::new(root); dirs.move_iter().filter(|path| { path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..") - }).map(|path| root.join(path)).collect() + }).map(|path| root.join(path).to_c_str()).collect() } extern { @@ -412,9 +401,9 @@ pub fn rename(old: &CString, new: &CString) -> IoResult<()> { })) } -pub fn chmod(p: &CString, mode: io::FilePermission) -> IoResult<()> { +pub fn chmod(p: &CString, mode: uint) -> IoResult<()> { super::mkerr_libc(retry(|| unsafe { - libc::chmod(p.with_ref(|p| p), mode.bits() as libc::mode_t) + libc::chmod(p.with_ref(|p| p), mode as libc::mode_t) })) } @@ -431,7 +420,7 @@ pub fn chown(p: &CString, uid: int, gid: int) -> IoResult<()> { })) } -pub fn readlink(p: &CString) -> IoResult { +pub fn readlink(p: &CString) -> IoResult { let p = p.with_ref(|p| p); let mut len = unsafe { libc::pathconf(p, libc::_PC_NAME_MAX) }; if len == -1 { @@ -446,7 +435,7 @@ pub fn readlink(p: &CString) -> IoResult { n => { assert!(n > 0); unsafe { buf.set_len(n as uint); } - Ok(Path::new(buf)) + Ok(buf.as_slice().to_c_str()) } } } @@ -463,19 +452,10 @@ pub fn link(src: &CString, dst: &CString) -> IoResult<()> { })) } -fn mkstat(stat: &libc::stat) -> io::FileStat { +fn mkstat(stat: &libc::stat) -> rtio::FileStat { // FileStat times are in milliseconds fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } - let kind = match (stat.st_mode as c_int) & libc::S_IFMT { - libc::S_IFREG => io::TypeFile, - libc::S_IFDIR => io::TypeDirectory, - libc::S_IFIFO => io::TypeNamedPipe, - libc::S_IFBLK => io::TypeBlockSpecial, - libc::S_IFLNK => io::TypeSymlink, - _ => io::TypeUnknown, - }; - #[cfg(not(target_os = "linux"), not(target_os = "android"))] fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 } #[cfg(target_os = "linux")] #[cfg(target_os = "android")] @@ -486,29 +466,27 @@ fn mkstat(stat: &libc::stat) -> io::FileStat { #[cfg(target_os = "linux")] #[cfg(target_os = "android")] fn gen(_stat: &libc::stat) -> u64 { 0 } - io::FileStat { + rtio::FileStat { size: stat.st_size as u64, - kind: kind, - perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32), + kind: stat.st_mode as u64, + perm: stat.st_mode as u64, created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64), modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64), accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64), - unstable: io::UnstableFileStat { - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize: stat.st_blksize as u64, - blocks: stat.st_blocks as u64, - flags: flags(stat), - gen: gen(stat), - } + device: stat.st_dev as u64, + inode: stat.st_ino as u64, + rdev: stat.st_rdev as u64, + nlink: stat.st_nlink as u64, + uid: stat.st_uid as u64, + gid: stat.st_gid as u64, + blksize: stat.st_blksize as u64, + blocks: stat.st_blocks as u64, + flags: flags(stat), + gen: gen(stat), } } -pub fn stat(p: &CString) -> IoResult { +pub fn stat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::zeroed() }; match retry(|| unsafe { libc::stat(p.with_ref(|p| p), &mut stat) }) { 0 => Ok(mkstat(&stat)), @@ -516,7 +494,7 @@ pub fn stat(p: &CString) -> IoResult { } } -pub fn lstat(p: &CString) -> IoResult { +pub fn lstat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::zeroed() }; match retry(|| unsafe { libc::lstat(p.with_ref(|p| p), &mut stat) }) { 0 => Ok(mkstat(&stat)), @@ -537,10 +515,9 @@ pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> { #[cfg(test)] mod tests { use super::{CFile, FileDesc}; - use std::io; use libc; use std::os; - use std::rt::rtio::RtioFileStream; + use std::rt::rtio::{RtioFileStream, SeekSet}; #[ignore(cfg(target_os = "freebsd"))] // hmm, maybe pipes have a tiny buffer #[test] @@ -551,7 +528,7 @@ mod tests { let mut reader = FileDesc::new(input, true); let mut writer = FileDesc::new(out, true); - writer.inner_write(bytes!("test")).unwrap(); + writer.inner_write(bytes!("test")).ok().unwrap(); let mut buf = [0u8, ..4]; match reader.inner_read(buf) { Ok(4) => { @@ -574,9 +551,9 @@ mod tests { assert!(!f.is_null()); let mut file = CFile::new(f); - file.write(bytes!("test")).unwrap(); + file.write(bytes!("test")).ok().unwrap(); let mut buf = [0u8, ..4]; - let _ = file.seek(0, io::SeekSet).unwrap(); + let _ = file.seek(0, SeekSet).ok().unwrap(); match file.read(buf) { Ok(4) => { assert_eq!(buf[0], 't' as u8); diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index 4f1f3b3ca26f7..2a5b78e55067c 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -14,17 +14,14 @@ use alloc::arc::Arc; use libc::{c_int, c_void}; use libc; use std::c_str::CString; -use std::io::IoError; -use std::io; use std::mem; use std::os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; use std::ptr; use std::rt::rtio; +use std::rt::rtio::IoResult; use std::str; use std::vec; -use io::IoResult; - pub type fd_t = libc::c_int; struct Inner { @@ -52,7 +49,7 @@ impl FileDesc { }) } } - pub fn inner_read(&mut self, buf: &mut [u8]) -> Result { + pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult { let mut read = 0; let ret = unsafe { libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID, @@ -65,7 +62,7 @@ impl FileDesc { Err(super::last_error()) } } - pub fn inner_write(&mut self, buf: &[u8]) -> Result<(), IoError> { + pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> { let mut cur = buf.as_ptr(); let mut remaining = buf.len(); while remaining > 0 { @@ -93,11 +90,11 @@ impl FileDesc { // A version of seek that takes &self so that tell can call it // - the private seek should of course take &mut self. - fn seek_common(&self, pos: i64, style: io::SeekStyle) -> Result { + fn seek_common(&self, pos: i64, style: rtio::SeekStyle) -> IoResult { let whence = match style { - io::SeekSet => libc::FILE_BEGIN, - io::SeekEnd => libc::FILE_END, - io::SeekCur => libc::FILE_CURRENT, + rtio::SeekSet => libc::FILE_BEGIN, + rtio::SeekEnd => libc::FILE_END, + rtio::SeekCur => libc::FILE_CURRENT, }; unsafe { let mut newpos = 0; @@ -111,27 +108,15 @@ impl FileDesc { } -impl io::Reader for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::IoResult { - self.inner_read(buf) - } -} - -impl io::Writer for FileDesc { - fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { - self.inner_write(buf) - } -} - impl rtio::RtioFileStream for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner_read(buf).map(|i| i as int) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner_write(buf) } - fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result { + fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { let mut read = 0; let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() }; overlap.Offset = offset as libc::DWORD; @@ -147,7 +132,7 @@ impl rtio::RtioFileStream for FileDesc { Err(super::last_error()) } } - fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> Result<(), IoError> { + fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> IoResult<()> { let mut cur = buf.as_ptr(); let mut remaining = buf.len(); let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() }; @@ -171,36 +156,36 @@ impl rtio::RtioFileStream for FileDesc { Ok(()) } - fn seek(&mut self, pos: i64, style: io::SeekStyle) -> Result { + fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult { self.seek_common(pos, style) } - fn tell(&self) -> Result { - self.seek_common(0, io::SeekCur) + fn tell(&self) -> IoResult { + self.seek_common(0, rtio::SeekCur) } - fn fsync(&mut self) -> Result<(), IoError> { + fn fsync(&mut self) -> IoResult<()> { super::mkerr_winbool(unsafe { libc::FlushFileBuffers(self.handle()) }) } - fn datasync(&mut self) -> Result<(), IoError> { return self.fsync(); } + fn datasync(&mut self) -> IoResult<()> { return self.fsync(); } - fn truncate(&mut self, offset: i64) -> Result<(), IoError> { + fn truncate(&mut self, offset: i64) -> IoResult<()> { let orig_pos = try!(self.tell()); - let _ = try!(self.seek(offset, io::SeekSet)); + let _ = try!(self.seek(offset, rtio::SeekSet)); let ret = unsafe { match libc::SetEndOfFile(self.handle()) { 0 => Err(super::last_error()), _ => Ok(()) } }; - let _ = self.seek(orig_pos as i64, io::SeekSet); + let _ = self.seek(orig_pos as i64, rtio::SeekSet); return ret; } - fn fstat(&mut self) -> IoResult { + fn fstat(&mut self) -> IoResult { let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::fstat(self.fd(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -210,10 +195,10 @@ impl rtio::RtioFileStream for FileDesc { } impl rtio::RtioPipe for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner_read(buf) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner_write(buf) } fn clone(&self) -> Box { @@ -225,10 +210,10 @@ impl rtio::RtioPipe for FileDesc { // std::io::PipeStream. If the functionality is exposed in the future, then // these methods will need to be implemented. fn close_read(&mut self) -> IoResult<()> { - Err(io::standard_error(io::InvalidInput)) + Err(super::unimpl()) } fn close_write(&mut self) -> IoResult<()> { - Err(io::standard_error(io::InvalidInput)) + Err(super::unimpl()) } fn set_timeout(&mut self, _t: Option) {} fn set_read_timeout(&mut self, _t: Option) {} @@ -236,16 +221,16 @@ impl rtio::RtioPipe for FileDesc { } impl rtio::RtioTTY for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner_read(buf) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner_write(buf) } - fn set_raw(&mut self, _raw: bool) -> Result<(), IoError> { + fn set_raw(&mut self, _raw: bool) -> IoResult<()> { Err(super::unimpl()) } - fn get_winsize(&mut self) -> Result<(int, int), IoError> { + fn get_winsize(&mut self) -> IoResult<(int, int)> { Err(super::unimpl()) } fn isatty(&self) -> bool { false } @@ -268,24 +253,24 @@ impl Drop for Inner { } } -pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess) +pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess) -> IoResult { // Flags passed to open_osfhandle let flags = match fm { - io::Open => 0, - io::Append => libc::O_APPEND, - io::Truncate => libc::O_TRUNC, + rtio::Open => 0, + rtio::Append => libc::O_APPEND, + rtio::Truncate => libc::O_TRUNC, }; let flags = match fa { - io::Read => flags | libc::O_RDONLY, - io::Write => flags | libc::O_WRONLY | libc::O_CREAT, - io::ReadWrite => flags | libc::O_RDWR | libc::O_CREAT, + rtio::Read => flags | libc::O_RDONLY, + rtio::Write => flags | libc::O_WRONLY | libc::O_CREAT, + rtio::ReadWrite => flags | libc::O_RDWR | libc::O_CREAT, }; let mut dwDesiredAccess = match fa { - io::Read => libc::FILE_GENERIC_READ, - io::Write => libc::FILE_GENERIC_WRITE, - io::ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE + rtio::Read => libc::FILE_GENERIC_READ, + rtio::Write => libc::FILE_GENERIC_WRITE, + rtio::ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE }; // libuv has a good comment about this, but the basic idea is what we try to @@ -295,15 +280,15 @@ pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess) libc::FILE_SHARE_DELETE; let dwCreationDisposition = match (fm, fa) { - (io::Truncate, io::Read) => libc::TRUNCATE_EXISTING, - (io::Truncate, _) => libc::CREATE_ALWAYS, - (io::Open, io::Read) => libc::OPEN_EXISTING, - (io::Open, _) => libc::OPEN_ALWAYS, - (io::Append, io::Read) => { + (rtio::Truncate, rtio::Read) => libc::TRUNCATE_EXISTING, + (rtio::Truncate, _) => libc::CREATE_ALWAYS, + (rtio::Open, rtio::Read) => libc::OPEN_EXISTING, + (rtio::Open, _) => libc::OPEN_ALWAYS, + (rtio::Append, rtio::Read) => { dwDesiredAccess |= libc::FILE_APPEND_DATA; libc::OPEN_EXISTING } - (io::Append, _) => { + (rtio::Append, _) => { dwDesiredAccess &= !libc::FILE_WRITE_DATA; dwDesiredAccess |= libc::FILE_APPEND_DATA; libc::OPEN_ALWAYS @@ -338,7 +323,7 @@ pub fn open(path: &CString, fm: io::FileMode, fa: io::FileAccess) } } -pub fn mkdir(p: &CString, _mode: io::FilePermission) -> IoResult<()> { +pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> { super::mkerr_winbool(unsafe { // FIXME: turn mode into something useful? #2623 as_utf16_p(p.as_str().unwrap(), |buf| { @@ -347,16 +332,16 @@ pub fn mkdir(p: &CString, _mode: io::FilePermission) -> IoResult<()> { }) } -pub fn readdir(p: &CString) -> IoResult> { +pub fn readdir(p: &CString) -> IoResult> { use std::rt::libc_heap::malloc_raw; - fn prune(root: &CString, dirs: Vec) -> Vec { + fn prune(root: &CString, dirs: Vec) -> Vec { let root = unsafe { CString::new(root.with_ref(|p| p), false) }; let root = Path::new(root); dirs.move_iter().filter(|path| { path.as_vec() != bytes!(".") && path.as_vec() != bytes!("..") - }).map(|path| root.join(path)).collect() + }).map(|path| root.join(path).to_c_str()).collect() } extern { @@ -413,9 +398,9 @@ pub fn rename(old: &CString, new: &CString) -> IoResult<()> { }) } -pub fn chmod(p: &CString, mode: io::FilePermission) -> IoResult<()> { +pub fn chmod(p: &CString, mode: uint) -> IoResult<()> { super::mkerr_libc(as_utf16_p(p.as_str().unwrap(), |p| unsafe { - libc::wchmod(p, mode.bits() as libc::c_int) + libc::wchmod(p, mode as libc::c_int) })) } @@ -430,7 +415,7 @@ pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> { Ok(()) } -pub fn readlink(p: &CString) -> IoResult { +pub fn readlink(p: &CString) -> IoResult { // FIXME: I have a feeling that this reads intermediate symlinks as well. use io::c::compat::kernel32::GetFinalPathNameByHandleW; let handle = unsafe { @@ -457,9 +442,9 @@ pub fn readlink(p: &CString) -> IoResult { }); let ret = match ret { Some(ref s) if s.as_slice().starts_with(r"\\?\") => { - Ok(Path::new(s.as_slice().slice_from(4))) + Ok(Path::new(s.as_slice().slice_from(4)).to_c_str()) } - Some(s) => Ok(Path::new(s)), + Some(s) => Ok(Path::new(s).to_c_str()), None => Err(super::last_error()), }; assert!(unsafe { libc::CloseHandle(handle) } != 0); @@ -483,39 +468,28 @@ pub fn link(src: &CString, dst: &CString) -> IoResult<()> { })) } -fn mkstat(stat: &libc::stat) -> io::FileStat { - let kind = match (stat.st_mode as c_int) & libc::S_IFMT { - libc::S_IFREG => io::TypeFile, - libc::S_IFDIR => io::TypeDirectory, - libc::S_IFIFO => io::TypeNamedPipe, - libc::S_IFBLK => io::TypeBlockSpecial, - libc::S_IFLNK => io::TypeSymlink, - _ => io::TypeUnknown, - }; - - io::FileStat { +fn mkstat(stat: &libc::stat) -> rtio::FileStat { + rtio::FileStat { size: stat.st_size as u64, - kind: kind, - perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32), + kind: stat.st_mode as u64, + perm: stat.st_mode as u64, created: stat.st_ctime as u64, modified: stat.st_mtime as u64, accessed: stat.st_atime as u64, - unstable: io::UnstableFileStat { - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize: 0, - blocks: 0, - flags: 0, - gen: 0, - } + device: stat.st_dev as u64, + inode: stat.st_ino as u64, + rdev: stat.st_rdev as u64, + nlink: stat.st_nlink as u64, + uid: stat.st_uid as u64, + gid: stat.st_gid as u64, + blksize: 0, + blocks: 0, + flags: 0, + gen: 0, } } -pub fn stat(p: &CString) -> IoResult { +pub fn stat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::zeroed() }; as_utf16_p(p.as_str().unwrap(), |up| { match unsafe { libc::wstat(up, &mut stat) } { @@ -525,7 +499,7 @@ pub fn stat(p: &CString) -> IoResult { }) } -pub fn lstat(_p: &CString) -> IoResult { +pub fn lstat(_p: &CString) -> IoResult { // FIXME: implementation is missing Err(super::unimpl()) } diff --git a/src/libnative/io/helper_thread.rs b/src/libnative/io/helper_thread.rs index 2260d74e16177..443c82c6a547c 100644 --- a/src/libnative/io/helper_thread.rs +++ b/src/libnative/io/helper_thread.rs @@ -24,9 +24,9 @@ use std::mem; use std::rt::bookkeeping; +use std::rt::mutex::StaticNativeMutex; use std::rt; use std::ty::Unsafe; -use std::unstable::mutex::StaticNativeMutex; use task; @@ -57,7 +57,7 @@ pub struct Helper { macro_rules! helper_init( (static mut $name:ident: Helper<$m:ty>) => ( static mut $name: Helper<$m> = Helper { - lock: ::std::unstable::mutex::NATIVE_MUTEX_INIT, + lock: ::std::rt::mutex::NATIVE_MUTEX_INIT, chan: ::std::ty::Unsafe { value: 0 as *mut Sender<$m>, marker1: ::std::kinds::marker::InvariantType, @@ -163,7 +163,7 @@ mod imp { } pub fn signal(fd: libc::c_int) { - FileDesc::new(fd, false).inner_write([0]).unwrap(); + FileDesc::new(fd, false).inner_write([0]).ok().unwrap(); } pub fn close(fd: libc::c_int) { diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 240b87fda084d..3b0dbe2d0dce9 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -26,16 +26,9 @@ use libc::c_int; use libc; use std::c_str::CString; -use std::io; -use std::io::IoError; -use std::io::net::ip::SocketAddr; -use std::io::signal::Signum; use std::os; use std::rt::rtio; -use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket}; -use std::rt::rtio::{RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess}; -use std::rt::rtio::{RtioSignal, RtioTTY, CloseBehavior, RtioTimer, ProcessConfig}; -use ai = std::io::net::addrinfo; +use std::rt::rtio::{IoResult, IoError}; // Local re-exports pub use self::file::FileDesc; @@ -78,18 +71,23 @@ pub mod pipe; #[cfg(unix)] #[path = "c_unix.rs"] mod c; #[cfg(windows)] #[path = "c_win32.rs"] mod c; -pub type IoResult = Result; - fn unimpl() -> IoError { + #[cfg(unix)] use ERROR = libc::ENOSYS; + #[cfg(windows)] use ERROR = libc::ERROR_CALL_NOT_IMPLEMENTED; IoError { - kind: io::IoUnavailable, - desc: "unimplemented I/O interface", + code: ERROR as uint, + extra: 0, detail: None, } } fn last_error() -> IoError { - IoError::last_error() + let errno = os::errno() as uint; + IoError { + code: os::errno() as uint, + extra: 0, + detail: Some(os::error_string(errno)), + } } // unix has nonzero values as errors @@ -166,64 +164,70 @@ impl IoFactory { impl rtio::IoFactory for IoFactory { // networking - fn tcp_connect(&mut self, addr: SocketAddr, - timeout: Option) -> IoResult> { + fn tcp_connect(&mut self, addr: rtio::SocketAddr, + timeout: Option) + -> IoResult> + { net::TcpStream::connect(addr, timeout).map(|s| { - box s as Box + box s as Box }) } - fn tcp_bind(&mut self, addr: SocketAddr) - -> IoResult> { + fn tcp_bind(&mut self, addr: rtio::SocketAddr) + -> IoResult> { net::TcpListener::bind(addr).map(|s| { - box s as Box + box s as Box }) } - fn udp_bind(&mut self, addr: SocketAddr) - -> IoResult> { - net::UdpSocket::bind(addr).map(|u| box u as Box) + fn udp_bind(&mut self, addr: rtio::SocketAddr) + -> IoResult> { + net::UdpSocket::bind(addr).map(|u| { + box u as Box + }) } fn unix_bind(&mut self, path: &CString) - -> IoResult> { + -> IoResult> { pipe::UnixListener::bind(path).map(|s| { - box s as Box + box s as Box }) } fn unix_connect(&mut self, path: &CString, - timeout: Option) -> IoResult> { + timeout: Option) -> IoResult> { pipe::UnixStream::connect(path, timeout).map(|s| { - box s as Box + box s as Box }) } fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, - hint: Option) -> IoResult> { + hint: Option) + -> IoResult> + { addrinfo::GetAddrInfoRequest::run(host, servname, hint) } // filesystem operations - fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) - -> Box { + fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior) + -> Box { let close = match close { rtio::CloseSynchronously | rtio::CloseAsynchronously => true, rtio::DontClose => false }; - box file::FileDesc::new(fd, close) as Box + box file::FileDesc::new(fd, close) as Box } - fn fs_open(&mut self, path: &CString, fm: io::FileMode, fa: io::FileAccess) - -> IoResult> { - file::open(path, fm, fa).map(|fd| box fd as Box) + fn fs_open(&mut self, path: &CString, fm: rtio::FileMode, + fa: rtio::FileAccess) + -> IoResult> + { + file::open(path, fm, fa).map(|fd| box fd as Box) } fn fs_unlink(&mut self, path: &CString) -> IoResult<()> { file::unlink(path) } - fn fs_stat(&mut self, path: &CString) -> IoResult { + fn fs_stat(&mut self, path: &CString) -> IoResult { file::stat(path) } - fn fs_mkdir(&mut self, path: &CString, - mode: io::FilePermission) -> IoResult<()> { + fn fs_mkdir(&mut self, path: &CString, mode: uint) -> IoResult<()> { file::mkdir(path, mode) } - fn fs_chmod(&mut self, path: &CString, - mode: io::FilePermission) -> IoResult<()> { + fn fs_chmod(&mut self, path: &CString, mode: uint) -> IoResult<()> { file::chmod(path, mode) } fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> { @@ -232,16 +236,16 @@ impl rtio::IoFactory for IoFactory { fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> { file::rename(path, to) } - fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult> { + fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult> { file::readdir(path) } - fn fs_lstat(&mut self, path: &CString) -> IoResult { + fn fs_lstat(&mut self, path: &CString) -> IoResult { file::lstat(path) } fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> { file::chown(path, uid, gid) } - fn fs_readlink(&mut self, path: &CString) -> IoResult { + fn fs_readlink(&mut self, path: &CString) -> IoResult { file::readlink(path) } fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> { @@ -256,39 +260,41 @@ impl rtio::IoFactory for IoFactory { } // misc - fn timer_init(&mut self) -> IoResult> { - timer::Timer::new().map(|t| box t as Box) + fn timer_init(&mut self) -> IoResult> { + timer::Timer::new().map(|t| box t as Box) } - fn spawn(&mut self, cfg: ProcessConfig) - -> IoResult<(Box, - Vec>>)> { + fn spawn(&mut self, cfg: rtio::ProcessConfig) + -> IoResult<(Box, + Vec>>)> { process::Process::spawn(cfg).map(|(p, io)| { - (box p as Box, + (box p as Box, io.move_iter().map(|p| p.map(|p| { - box p as Box + box p as Box })).collect()) }) } fn kill(&mut self, pid: libc::pid_t, signum: int) -> IoResult<()> { process::Process::kill(pid, signum) } - fn pipe_open(&mut self, fd: c_int) -> IoResult> { - Ok(box file::FileDesc::new(fd, true) as Box) + fn pipe_open(&mut self, fd: c_int) -> IoResult> { + Ok(box file::FileDesc::new(fd, true) as Box) } fn tty_open(&mut self, fd: c_int, _readable: bool) - -> IoResult> { + -> IoResult> { + #[cfg(unix)] use ERROR = libc::ENOTTY; + #[cfg(windows)] use ERROR = libc::ERROR_INVALID_HANDLE; if unsafe { libc::isatty(fd) } != 0 { - Ok(box file::FileDesc::new(fd, true) as Box) + Ok(box file::FileDesc::new(fd, true) as Box) } else { Err(IoError { - kind: io::MismatchedFileTypeForOperation, - desc: "file descriptor is not a TTY", + code: ERROR as uint, + extra: 0, detail: None, }) } } - fn signal(&mut self, _signal: Signum, _channel: Sender) - -> IoResult> { + fn signal(&mut self, _signal: int, _cb: Box) + -> IoResult> { Err(unimpl()) } } diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index 26307feae91f0..24956e514ec83 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -10,13 +10,12 @@ use alloc::arc::Arc; use libc; -use std::io::net::ip; -use std::io; use std::mem; +use std::rt::mutex; use std::rt::rtio; -use std::unstable::mutex; +use std::rt::rtio::{IoResult, IoError}; -use super::{IoResult, retry, keep_going}; +use super::{retry, keep_going}; use super::c; use super::util; @@ -39,9 +38,9 @@ enum InAddr { In6Addr(libc::in6_addr), } -fn ip_to_inaddr(ip: ip::IpAddr) -> InAddr { +fn ip_to_inaddr(ip: rtio::IpAddr) -> InAddr { match ip { - ip::Ipv4Addr(a, b, c, d) => { + rtio::Ipv4Addr(a, b, c, d) => { let ip = (a as u32 << 24) | (b as u32 << 16) | (c as u32 << 8) | @@ -50,7 +49,7 @@ fn ip_to_inaddr(ip: ip::IpAddr) -> InAddr { s_addr: mem::from_be32(ip) }) } - ip::Ipv6Addr(a, b, c, d, e, f, g, h) => { + rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => { In6Addr(libc::in6_addr { s6_addr: [ htons(a), @@ -67,7 +66,7 @@ fn ip_to_inaddr(ip: ip::IpAddr) -> InAddr { } } -fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { +fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) { unsafe { let storage: libc::sockaddr_storage = mem::zeroed(); let len = match ip_to_inaddr(addr.ip) { @@ -90,11 +89,11 @@ fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { } } -fn socket(addr: ip::SocketAddr, ty: libc::c_int) -> IoResult { +fn socket(addr: rtio::SocketAddr, ty: libc::c_int) -> IoResult { unsafe { let fam = match addr.ip { - ip::Ipv4Addr(..) => libc::AF_INET, - ip::Ipv6Addr(..) => libc::AF_INET6, + rtio::Ipv4Addr(..) => libc::AF_INET, + rtio::Ipv6Addr(..) => libc::AF_INET6, }; match libc::socket(fam, ty, 0) { -1 => Err(super::last_error()), @@ -136,12 +135,18 @@ pub fn getsockopt(fd: sock_t, opt: libc::c_int, } #[cfg(windows)] -fn last_error() -> io::IoError { - io::IoError::from_errno(unsafe { c::WSAGetLastError() } as uint, true) +pub fn last_error() -> IoError { + use std::os; + let code = unsafe { c::WSAGetLastError() as uint }; + IoError { + code: code, + extra: 0, + detail: Some(os::error_string(code)), + } } #[cfg(not(windows))] -fn last_error() -> io::IoError { +fn last_error() -> IoError { super::last_error() } @@ -151,7 +156,7 @@ fn last_error() -> io::IoError { fn sockname(fd: sock_t, f: unsafe extern "system" fn(sock_t, *mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int) - -> IoResult + -> IoResult { let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of::() as libc::socklen_t; @@ -168,7 +173,7 @@ fn sockname(fd: sock_t, } pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, - len: uint) -> IoResult { + len: uint) -> IoResult { match storage.ss_family as libc::c_int { libc::AF_INET => { assert!(len as uint >= mem::size_of::()); @@ -180,8 +185,8 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; let d = (ip >> 0) as u8; - Ok(ip::SocketAddr { - ip: ip::Ipv4Addr(a, b, c, d), + Ok(rtio::SocketAddr { + ip: rtio::Ipv4Addr(a, b, c, d), port: ntohs(storage.sin_port), }) } @@ -198,13 +203,19 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let f = ntohs(storage.sin6_addr.s6_addr[5]); let g = ntohs(storage.sin6_addr.s6_addr[6]); let h = ntohs(storage.sin6_addr.s6_addr[7]); - Ok(ip::SocketAddr { - ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h), + Ok(rtio::SocketAddr { + ip: rtio::Ipv6Addr(a, b, c, d, e, f, g, h), port: ntohs(storage.sin6_port), }) } _ => { - Err(io::standard_error(io::OtherIoError)) + #[cfg(unix)] use ERROR = libc::EINVAL; + #[cfg(windows)] use ERROR = libc::WSAEINVAL; + Err(IoError { + code: ERROR as uint, + extra: 0, + detail: None, + }) } } } @@ -216,7 +227,7 @@ pub fn init() {} pub fn init() { unsafe { - use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut INITIALIZED: bool = false; static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; @@ -258,7 +269,7 @@ impl Inner { } impl TcpStream { - pub fn connect(addr: ip::SocketAddr, + pub fn connect(addr: rtio::SocketAddr, timeout: Option) -> IoResult { let fd = try!(socket(addr, libc::SOCK_STREAM)); let ret = TcpStream::new(Inner::new(fd)); @@ -366,7 +377,7 @@ impl rtio::RtioTcpStream for TcpStream { Err(e) => Err(e) } } - fn peer_name(&mut self) -> IoResult { + fn peer_name(&mut self) -> IoResult { sockname(self.fd(), libc::getpeername) } fn control_congestion(&mut self) -> IoResult<()> { @@ -411,7 +422,7 @@ impl rtio::RtioTcpStream for TcpStream { } impl rtio::RtioSocket for TcpStream { - fn socket_name(&mut self) -> IoResult { + fn socket_name(&mut self) -> IoResult { sockname(self.fd(), libc::getsockname) } } @@ -436,7 +447,7 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(addr: ip::SocketAddr) -> IoResult { + pub fn bind(addr: rtio::SocketAddr) -> IoResult { let fd = try!(socket(addr, libc::SOCK_STREAM)); let ret = TcpListener { inner: Inner::new(fd) }; @@ -477,7 +488,7 @@ impl rtio::RtioTcpListener for TcpListener { } impl rtio::RtioSocket for TcpListener { - fn socket_name(&mut self) -> IoResult { + fn socket_name(&mut self) -> IoResult { sockname(self.fd(), libc::getsockname) } } @@ -512,7 +523,7 @@ impl TcpAcceptor { } impl rtio::RtioSocket for TcpAcceptor { - fn socket_name(&mut self) -> IoResult { + fn socket_name(&mut self) -> IoResult { sockname(self.fd(), libc::getsockname) } } @@ -540,7 +551,7 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(addr: ip::SocketAddr) -> IoResult { + pub fn bind(addr: rtio::SocketAddr) -> IoResult { let fd = try!(socket(addr, libc::SOCK_DGRAM)); let ret = UdpSocket { inner: Arc::new(Inner::new(fd)), @@ -570,7 +581,7 @@ impl UdpSocket { on as libc::c_int) } - pub fn set_membership(&mut self, addr: ip::IpAddr, + pub fn set_membership(&mut self, addr: rtio::IpAddr, opt: libc::c_int) -> IoResult<()> { match ip_to_inaddr(addr) { InAddr(addr) => { @@ -606,7 +617,7 @@ impl UdpSocket { } impl rtio::RtioSocket for UdpSocket { - fn socket_name(&mut self) -> IoResult { + fn socket_name(&mut self) -> IoResult { sockname(self.fd(), libc::getsockname) } } @@ -615,7 +626,7 @@ impl rtio::RtioSocket for UdpSocket { #[cfg(unix)] type msglen_t = libc::size_t; impl rtio::RtioUdpSocket for UdpSocket { - fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, ip::SocketAddr)> { + fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, rtio::SocketAddr)> { let fd = self.fd(); let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; let storagep = &mut storage as *mut _ as *mut libc::sockaddr; @@ -638,7 +649,7 @@ impl rtio::RtioUdpSocket for UdpSocket { }) } - fn sendto(&mut self, buf: &[u8], dst: ip::SocketAddr) -> IoResult<()> { + fn sendto(&mut self, buf: &[u8], dst: rtio::SocketAddr) -> IoResult<()> { let (dst, dstlen) = addr_to_sockaddr(dst); let dstp = &dst as *_ as *libc::sockaddr; let dstlen = dstlen as libc::socklen_t; @@ -657,32 +668,28 @@ impl rtio::RtioUdpSocket for UdpSocket { let n = try!(write(fd, self.write_deadline, buf, false, dolock, dowrite)); if n != buf.len() { - Err(io::IoError { - kind: io::ShortWrite(n), - desc: "couldn't send entire packet at once", - detail: None, - }) + Err(util::short_write(n, "couldn't send entire packet at once")) } else { Ok(()) } } - fn join_multicast(&mut self, multi: ip::IpAddr) -> IoResult<()> { + fn join_multicast(&mut self, multi: rtio::IpAddr) -> IoResult<()> { match multi { - ip::Ipv4Addr(..) => { + rtio::Ipv4Addr(..) => { self.set_membership(multi, libc::IP_ADD_MEMBERSHIP) } - ip::Ipv6Addr(..) => { + rtio::Ipv6Addr(..) => { self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP) } } } - fn leave_multicast(&mut self, multi: ip::IpAddr) -> IoResult<()> { + fn leave_multicast(&mut self, multi: rtio::IpAddr) -> IoResult<()> { match multi { - ip::Ipv4Addr(..) => { + rtio::Ipv4Addr(..) => { self.set_membership(multi, libc::IP_DROP_MEMBERSHIP) } - ip::Ipv6Addr(..) => { + rtio::Ipv6Addr(..) => { self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP) } } @@ -821,7 +828,7 @@ pub fn read(fd: sock_t, } match ret { - 0 => Err(io::standard_error(io::EndOfFile)), + 0 => Err(util::eof()), n if n < 0 => Err(last_error()), n => Ok(n as uint) } @@ -858,13 +865,9 @@ pub fn write(fd: sock_t, // As with read(), first wait for the socket to be ready for // the I/O operation. match util::await(fd, deadline, util::Writable) { - Err(ref e) if e.kind == io::TimedOut && written > 0 => { + Err(ref e) if e.code == libc::EOF as uint && written > 0 => { assert!(deadline.is_some()); - return Err(io::IoError { - kind: io::ShortWrite(written), - desc: "short write", - detail: None, - }) + return Err(util::short_write(written, "short write")) } Err(e) => return Err(e), Ok(()) => {} diff --git a/src/libnative/io/pipe_unix.rs b/src/libnative/io/pipe_unix.rs index a53a58b6cec43..7a1134fbe5956 100644 --- a/src/libnative/io/pipe_unix.rs +++ b/src/libnative/io/pipe_unix.rs @@ -11,13 +11,12 @@ use alloc::arc::Arc; use libc; use std::c_str::CString; -use std::intrinsics; -use std::io; use std::mem; +use std::rt::mutex; use std::rt::rtio; -use std::unstable::mutex; +use std::rt::rtio::{IoResult, IoError}; -use super::{IoResult, retry}; +use super::retry; use super::net; use super::util; use super::c; @@ -34,15 +33,17 @@ fn addr_to_sockaddr_un(addr: &CString) -> IoResult<(libc::sockaddr_storage, uint // the sun_path length is limited to SUN_LEN (with null) assert!(mem::size_of::() >= mem::size_of::()); - let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() }; + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; let s: &mut libc::sockaddr_un = unsafe { mem::transmute(&mut storage) }; let len = addr.len(); if len > s.sun_path.len() - 1 { - return Err(io::IoError { - kind: io::InvalidInput, - desc: "path must be smaller than SUN_LEN", - detail: None, + #[cfg(unix)] use ERROR = libc::EINVAL; + #[cfg(windows)] use ERROR = libc::WSAEINVAL; + return Err(IoError { + code: ERROR as uint, + extra: 0, + detail: Some("path must be smaller than SUN_LEN".to_str()), }) } s.sun_family = libc::AF_UNIX as libc::sa_family_t; @@ -244,7 +245,7 @@ impl UnixAcceptor { if self.deadline != 0 { try!(util::await(self.fd(), Some(self.deadline), util::Readable)); } - let mut storage: libc::sockaddr_storage = unsafe { intrinsics::init() }; + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; let storagep = &mut storage as *mut libc::sockaddr_storage; let size = mem::size_of::(); let mut size = size as libc::socklen_t; diff --git a/src/libnative/io/pipe_win32.rs b/src/libnative/io/pipe_win32.rs index cd4cbf2c90f32..a5694436b9720 100644 --- a/src/libnative/io/pipe_win32.rs +++ b/src/libnative/io/pipe_win32.rs @@ -87,16 +87,15 @@ use alloc::arc::Arc; use libc; use std::c_str::CString; -use std::io; use std::mem; use std::os::win32::as_utf16_p; use std::os; use std::ptr; use std::rt::rtio; +use std::rt::rtio::{IoResult, IoError}; use std::sync::atomics; -use std::unstable::mutex; +use std::rt::mutex; -use super::IoResult; use super::c; use super::util; @@ -190,6 +189,14 @@ pub fn await(handle: libc::HANDLE, deadline: u64, } } +fn epipe() -> IoError { + IoError { + code: libc::ERROR_BROKEN_PIPE as uint, + extra: 0, + detail: None, + } +} + //////////////////////////////////////////////////////////////////////////////// // Unix Streams //////////////////////////////////////////////////////////////////////////////// @@ -355,7 +362,7 @@ impl rtio::RtioPipe for UnixStream { // See comments in close_read() about why this lock is necessary. let guard = unsafe { self.inner.lock.lock() }; if self.read_closed() { - return Err(io::standard_error(io::EndOfFile)) + return Err(util::eof()) } // Issue a nonblocking requests, succeeding quickly if it happened to @@ -403,10 +410,10 @@ impl rtio::RtioPipe for UnixStream { // If the reading half is now closed, then we're done. If we woke up // because the writing half was closed, keep trying. if !succeeded { - return Err(io::standard_error(io::TimedOut)) + return Err(util::timeout("read timed out")) } if self.read_closed() { - return Err(io::standard_error(io::EndOfFile)) + return Err(util::eof()) } } } @@ -431,7 +438,7 @@ impl rtio::RtioPipe for UnixStream { // See comments in close_read() about why this lock is necessary. let guard = unsafe { self.inner.lock.lock() }; if self.write_closed() { - return Err(io::standard_error(io::BrokenPipe)) + return Err(epipe()) } let ret = unsafe { libc::WriteFile(self.handle(), @@ -445,7 +452,11 @@ impl rtio::RtioPipe for UnixStream { if ret == 0 { if err != libc::ERROR_IO_PENDING as uint { - return Err(io::IoError::from_errno(err, true)); + return Err(IoError { + code: err as uint, + extra: 0, + detail: Some(os::error_string(err as uint)), + }) } // Process a timeout if one is pending let succeeded = await(self.handle(), self.write_deadline, @@ -466,17 +477,17 @@ impl rtio::RtioPipe for UnixStream { if !succeeded { let amt = offset + bytes_written as uint; return if amt > 0 { - Err(io::IoError { - kind: io::ShortWrite(amt), - desc: "short write during write", - detail: None, + Err(IoError { + code: libc::ERROR_OPERATION_ABORTED as uint, + extra: amt, + detail: Some("short write during write".to_str()), }) } else { Err(util::timeout("write timed out")) } } if self.write_closed() { - return Err(io::standard_error(io::BrokenPipe)) + return Err(epipe()) } continue // retry } diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index 4b75e1b73599d..2c2b7cec1dec4 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -10,16 +10,13 @@ use libc::{pid_t, c_void, c_int}; use libc; -use std::io; use std::mem; use std::os; use std::ptr; use std::rt::rtio; -use std::rt::rtio::ProcessConfig; +use std::rt::rtio::{ProcessConfig, IoResult, IoError}; use std::c_str::CString; -use p = std::io::process; -use super::IoResult; use super::file; use super::util; @@ -48,7 +45,7 @@ pub struct Process { handle: *(), /// None until finish() is called. - exit_code: Option, + exit_code: Option, /// Manually delivered signal exit_signal: Option, @@ -59,7 +56,7 @@ pub struct Process { #[cfg(unix)] enum Req { - NewChild(libc::pid_t, Sender, u64), + NewChild(libc::pid_t, Sender, u64), } impl Process { @@ -67,20 +64,21 @@ impl Process { /// by the OS. Operations on this process will be blocking instead of using /// the runtime for sleeping just this current task. pub fn spawn(cfg: ProcessConfig) - -> Result<(Process, Vec>), io::IoError> + -> IoResult<(Process, Vec>)> { // right now we only handle stdin/stdout/stderr. if cfg.extra_io.len() > 0 { return Err(super::unimpl()); } - fn get_io(io: p::StdioContainer, ret: &mut Vec>) + fn get_io(io: rtio::StdioContainer, + ret: &mut Vec>) -> (Option, c_int) { match io { - p::Ignored => { ret.push(None); (None, -1) } - p::InheritFd(fd) => { ret.push(None); (None, fd) } - p::CreatePipe(readable, _writable) => { + rtio::Ignored => { ret.push(None); (None, -1) } + rtio::InheritFd(fd) => { ret.push(None); (None, fd) } + rtio::CreatePipe(readable, _writable) => { let pipe = os::pipe(); let (theirs, ours) = if readable { (pipe.input, pipe.out) @@ -133,7 +131,7 @@ impl rtio::RtioProcess for Process { self.deadline = timeout.map(|i| i + ::io::timer::now()).unwrap_or(0); } - fn wait(&mut self) -> IoResult { + fn wait(&mut self) -> IoResult { match self.exit_code { Some(code) => Ok(code), None => { @@ -143,7 +141,7 @@ impl rtio::RtioProcess for Process { // consider it as having died via a signal. let code = match self.exit_signal { None => code, - Some(signal) if cfg!(windows) => p::ExitSignal(signal), + Some(signal) if cfg!(windows) => rtio::ExitSignal(signal), Some(..) => code, }; self.exit_code = Some(code); @@ -152,7 +150,10 @@ impl rtio::RtioProcess for Process { } } - fn kill(&mut self, signum: int) -> Result<(), io::IoError> { + fn kill(&mut self, signum: int) -> IoResult<()> { + #[cfg(unix)] use ERROR = libc::EINVAL; + #[cfg(windows)] use ERROR = libc::ERROR_NOTHING_TO_TERMINATE; + // On linux (and possibly other unices), a process that has exited will // continue to accept signals because it is "defunct". The delivery of // signals will only fail once the child has been reaped. For this @@ -169,10 +170,10 @@ impl rtio::RtioProcess for Process { // and we kill it, then on unix we might ending up killing a // newer process that happens to have the same (re-used) id match self.exit_code { - Some(..) => return Err(io::IoError { - kind: io::OtherIoError, - desc: "can't kill an exited process", - detail: None, + Some(..) => return Err(IoError { + code: ERROR as uint, + extra: 0, + detail: Some("can't kill an exited process".to_str()), }), None => {} } @@ -194,7 +195,7 @@ impl Drop for Process { } #[cfg(windows)] -unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> { +unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> { let handle = libc::OpenProcess(libc::PROCESS_TERMINATE | libc::PROCESS_QUERY_INFORMATION, libc::FALSE, pid as libc::DWORD); @@ -209,23 +210,23 @@ unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> { if ret == 0 { Err(super::last_error()) } else if status != libc::STILL_ACTIVE { - Err(io::IoError { - kind: io::OtherIoError, - desc: "process no longer alive", + Err(IoError { + code: libc::ERROR_NOTHING_TO_TERMINATE as uint, + extra: 0, detail: None, }) } else { Ok(()) } } - io::process::PleaseExitSignal | io::process::MustDieSignal => { + 15 | 9 => { // sigterm or sigkill let ret = libc::TerminateProcess(handle, 1); super::mkerr_winbool(ret) } - _ => Err(io::IoError { - kind: io::OtherIoError, - desc: "unsupported signal on windows", - detail: None, + _ => Err(IoError { + code: libc::ERROR_CALL_NOT_IMPLEMENTED as uint, + extra: 0, + detail: Some("unsupported signal on windows".to_string()), }) }; let _ = libc::CloseHandle(handle); @@ -233,7 +234,7 @@ unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> { } #[cfg(not(windows))] -unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> { +unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> { let r = libc::funcs::posix88::signal::kill(pid, signal as c_int); super::mkerr_libc(r) } @@ -265,10 +266,10 @@ fn spawn_process_os(cfg: ProcessConfig, use std::mem; if cfg.gid.is_some() || cfg.uid.is_some() { - return Err(io::IoError { - kind: io::OtherIoError, - desc: "unsupported gid/uid requested on windows", - detail: None, + return Err(IoError { + code: libc::ERROR_CALL_NOT_IMPLEMENTED as uint, + extra: 0, + detail: Some("unsupported gid/uid requested on windows".to_str()), }) } @@ -521,12 +522,13 @@ fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_i (bytes[1] << 16) as i32 | (bytes[2] << 8) as i32 | (bytes[3] << 0) as i32; - Err(io::IoError::from_errno(errno as uint, false)) + Err(IoError { + code: errno as uint, + detail: None, + extra: 0, + }) } - Err(e) => { - assert!(e.kind == io::BrokenPipe || - e.kind == io::EndOfFile, - "unexpected error: {}", e); + Err(..) => { Ok(SpawnProcessResult { pid: pid, handle: ptr::null() @@ -757,7 +759,7 @@ fn free_handle(_handle: *()) { } #[cfg(unix)] -fn translate_status(status: c_int) -> p::ProcessExit { +fn translate_status(status: c_int) -> rtio::ProcessExit { #![allow(non_snake_case_functions)] #[cfg(target_os = "linux")] #[cfg(target_os = "android")] @@ -776,9 +778,9 @@ fn translate_status(status: c_int) -> p::ProcessExit { } if imp::WIFEXITED(status) { - p::ExitStatus(imp::WEXITSTATUS(status) as int) + rtio::ExitStatus(imp::WEXITSTATUS(status) as int) } else { - p::ExitSignal(imp::WTERMSIG(status) as int) + rtio::ExitSignal(imp::WTERMSIG(status) as int) } } @@ -793,7 +795,7 @@ fn translate_status(status: c_int) -> p::ProcessExit { * with the same id. */ #[cfg(windows)] -fn waitpid(pid: pid_t, deadline: u64) -> IoResult { +fn waitpid(pid: pid_t, deadline: u64) -> IoResult { use libc::types::os::arch::extra::DWORD; use libc::consts::os::extra::{ SYNCHRONIZE, @@ -828,7 +830,7 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult { } if status != STILL_ACTIVE { assert!(CloseHandle(process) != 0); - return Ok(p::ExitStatus(status as int)); + return Ok(rtio::ExitStatus(status as int)); } let interval = if deadline == 0 { INFINITE @@ -853,7 +855,7 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult { } #[cfg(unix)] -fn waitpid(pid: pid_t, deadline: u64) -> IoResult { +fn waitpid(pid: pid_t, deadline: u64) -> IoResult { use std::cmp; use std::comm; @@ -862,7 +864,7 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult { let mut status = 0 as c_int; if deadline == 0 { return match retry(|| unsafe { c::waitpid(pid, &mut status, 0) }) { - -1 => fail!("unknown waitpid error: {}", super::last_error()), + -1 => fail!("unknown waitpid error: {}", super::last_error().code), _ => Ok(translate_status(status)), } } @@ -928,8 +930,8 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult { unsafe { let mut pipes = [0, ..2]; assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0); - util::set_nonblocking(pipes[0], true).unwrap(); - util::set_nonblocking(pipes[1], true).unwrap(); + util::set_nonblocking(pipes[0], true).ok().unwrap(); + util::set_nonblocking(pipes[1], true).ok().unwrap(); WRITE_FD = pipes[1]; let mut old: c::sigaction = mem::zeroed(); @@ -945,10 +947,10 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult { fn waitpid_helper(input: libc::c_int, messages: Receiver, (read_fd, old): (libc::c_int, c::sigaction)) { - util::set_nonblocking(input, true).unwrap(); + util::set_nonblocking(input, true).ok().unwrap(); let mut set: c::fd_set = unsafe { mem::zeroed() }; let mut tv: libc::timeval; - let mut active = Vec::<(libc::pid_t, Sender, u64)>::new(); + let mut active = Vec::<(libc::pid_t, Sender, u64)>::new(); let max = cmp::max(input, read_fd) + 1; 'outer: loop { @@ -1094,22 +1096,23 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult { } } -fn waitpid_nowait(pid: pid_t) -> Option { +fn waitpid_nowait(pid: pid_t) -> Option { return waitpid_os(pid); // This code path isn't necessary on windows #[cfg(windows)] - fn waitpid_os(_pid: pid_t) -> Option { None } + fn waitpid_os(_pid: pid_t) -> Option { None } #[cfg(unix)] - fn waitpid_os(pid: pid_t) -> Option { + fn waitpid_os(pid: pid_t) -> Option { let mut status = 0 as c_int; match retry(|| unsafe { c::waitpid(pid, &mut status, c::WNOHANG) }) { n if n == pid => Some(translate_status(status)), 0 => None, - n => fail!("unknown waitpid error `{}`: {}", n, super::last_error()), + n => fail!("unknown waitpid error `{}`: {}", n, + super::last_error().code), } } } diff --git a/src/libnative/io/timer_unix.rs b/src/libnative/io/timer_unix.rs index 8aa8b12b26d27..11f9c4b3d8cb8 100644 --- a/src/libnative/io/timer_unix.rs +++ b/src/libnative/io/timer_unix.rs @@ -51,10 +51,10 @@ use std::mem; use std::os; use std::ptr; use std::rt::rtio; +use std::rt::rtio::IoResult; use std::sync::atomics; use std::comm; -use io::IoResult; use io::c; use io::file::FileDesc; use io::helper_thread::Helper; @@ -67,7 +67,7 @@ pub struct Timer { } struct Inner { - tx: Option>, + cb: Option>, interval: u64, repeat: bool, target: u64, @@ -119,13 +119,13 @@ fn helper(input: libc::c_int, messages: Receiver, _: ()) { let mut timer = match active.shift() { Some(timer) => timer, None => return }; - let tx = timer.tx.take_unwrap(); - if tx.send_opt(()).is_ok() && timer.repeat { - timer.tx = Some(tx); + let mut cb = timer.cb.take_unwrap(); + cb.call(); + if timer.repeat { + timer.cb = Some(cb); timer.target += timer.interval; insert(timer, active); } else { - drop(tx); dead.push((timer.id, timer)); } } @@ -190,7 +190,7 @@ fn helper(input: libc::c_int, messages: Receiver, _: ()) { // drain the file descriptor let mut buf = [0]; - assert_eq!(fd.inner_read(buf).unwrap(), 1); + assert_eq!(fd.inner_read(buf).ok().unwrap(), 1); } -1 if os::errno() == libc::EINTR as int => {} @@ -209,7 +209,7 @@ impl Timer { Ok(Timer { id: id, inner: Some(box Inner { - tx: None, + cb: None, interval: 0, target: 0, repeat: false, @@ -245,38 +245,34 @@ impl Timer { impl rtio::RtioTimer for Timer { fn sleep(&mut self, msecs: u64) { let mut inner = self.inner(); - inner.tx = None; // cancel any previous request + inner.cb = None; // cancel any previous request self.inner = Some(inner); Timer::sleep(msecs); } - fn oneshot(&mut self, msecs: u64) -> Receiver<()> { + fn oneshot(&mut self, msecs: u64, cb: Box) { let now = now(); let mut inner = self.inner(); - let (tx, rx) = channel(); inner.repeat = false; - inner.tx = Some(tx); + inner.cb = Some(cb); inner.interval = msecs; inner.target = now + msecs; unsafe { HELPER.send(NewTimer(inner)); } - return rx; } - fn period(&mut self, msecs: u64) -> Receiver<()> { + fn period(&mut self, msecs: u64, cb: Box) { let now = now(); let mut inner = self.inner(); - let (tx, rx) = channel(); inner.repeat = true; - inner.tx = Some(tx); + inner.cb = Some(cb); inner.interval = msecs; inner.target = now + msecs; unsafe { HELPER.send(NewTimer(inner)); } - return rx; } } diff --git a/src/libnative/io/timer_win32.rs b/src/libnative/io/timer_win32.rs index e7130de05c26d..d175060dd9860 100644 --- a/src/libnative/io/timer_win32.rs +++ b/src/libnative/io/timer_win32.rs @@ -23,10 +23,10 @@ use libc; use std::ptr; use std::rt::rtio; +use std::rt::rtio::{IoResult, Callback}; use std::comm; use io::helper_thread::Helper; -use io::IoResult; helper_init!(static mut HELPER: Helper) @@ -36,7 +36,7 @@ pub struct Timer { } pub enum Req { - NewTimer(libc::HANDLE, Sender<()>, bool), + NewTimer(libc::HANDLE, Box, bool), RemoveTimer(libc::HANDLE, Sender<()>), } @@ -79,8 +79,8 @@ fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { } } else { let remove = { - match chans.get(idx as uint - 1) { - &(ref c, oneshot) => c.send_opt(()).is_err() || oneshot + match chans.get_mut(idx as uint - 1) { + &(ref mut c, oneshot) => { c.call(); oneshot } } }; if remove { @@ -148,9 +148,8 @@ impl rtio::RtioTimer for Timer { let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) }; } - fn oneshot(&mut self, msecs: u64) -> Receiver<()> { + fn oneshot(&mut self, msecs: u64, cb: Box) { self.remove(); - let (tx, rx) = channel(); // see above for the calculation let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; @@ -159,14 +158,12 @@ impl rtio::RtioTimer for Timer { ptr::mut_null(), 0) }, 1); - unsafe { HELPER.send(NewTimer(self.obj, tx, true)) } + unsafe { HELPER.send(NewTimer(self.obj, cb, true)) } self.on_worker = true; - return rx; } - fn period(&mut self, msecs: u64) -> Receiver<()> { + fn period(&mut self, msecs: u64, cb: Box) { self.remove(); - let (tx, rx) = channel(); // see above for the calculation let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; @@ -175,10 +172,8 @@ impl rtio::RtioTimer for Timer { ptr::null(), ptr::mut_null(), 0) }, 1); - unsafe { HELPER.send(NewTimer(self.obj, tx, false)) } + unsafe { HELPER.send(NewTimer(self.obj, cb, false)) } self.on_worker = true; - - return rx; } } diff --git a/src/libnative/io/util.rs b/src/libnative/io/util.rs index fe7a58a5e6868..a3c5349fa4582 100644 --- a/src/libnative/io/util.rs +++ b/src/libnative/io/util.rs @@ -9,11 +9,10 @@ // except according to those terms. use libc; -use std::io::IoResult; -use std::io; use std::mem; use std::os; use std::ptr; +use std::rt::rtio::{IoResult, IoError}; use super::c; use super::net; @@ -25,10 +24,30 @@ pub enum SocketStatus { Writable, } -pub fn timeout(desc: &'static str) -> io::IoError { - io::IoError { - kind: io::TimedOut, - desc: desc, +pub fn timeout(desc: &'static str) -> IoError { + #[cfg(unix)] use ERROR = libc::ETIMEDOUT; + #[cfg(windows)] use ERROR = libc::ERROR_OPERATION_ABORTED; + IoError { + code: ERROR as uint, + extra: 0, + detail: Some(desc.to_str()), + } +} + +pub fn short_write(n: uint, desc: &'static str) -> IoError { + #[cfg(unix)] use ERROR = libc::EAGAIN; + #[cfg(windows)] use ERROR = libc::ERROR_OPERATION_ABORTED; + IoError { + code: ERROR as uint, + extra: n, + detail: Some(desc.to_str()), + } +} + +pub fn eof() -> IoError { + IoError { + code: libc::EOF as uint, + extra: 0, detail: None, } } @@ -100,7 +119,11 @@ pub fn connect_timeout(fd: net::sock_t, if err == 0 { Ok(()) } else { - Err(io::IoError::from_errno(err as uint, true)) + Err(IoError { + code: err as uint, + extra: 0, + detail: Some(os::error_string(err as uint)), + }) } } } diff --git a/src/libnative/task.rs b/src/libnative/task.rs index 4183dec19d02d..f16c41d4e28f7 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -17,15 +17,13 @@ use std::any::Any; use std::mem; use std::rt::bookkeeping; -use std::rt::env; use std::rt::local::Local; +use std::rt::mutex::NativeMutex; use std::rt::rtio; use std::rt::stack; -use std::rt::task::{Task, BlockedTask, SendMessage}; +use std::rt::task::{Task, BlockedTask, TaskOpts}; use std::rt::thread::Thread; use std::rt; -use std::task::TaskOpts; -use std::unstable::mutex::NativeMutex; use io; use task; @@ -51,27 +49,19 @@ fn ops() -> Box { /// Spawns a function with the default configuration pub fn spawn(f: proc():Send) { - spawn_opts(TaskOpts::new(), f) + spawn_opts(TaskOpts { name: None, stack_size: None, on_exit: None }, f) } /// Spawns a new task given the configuration options and a procedure to run /// inside the task. pub fn spawn_opts(opts: TaskOpts, f: proc():Send) { - let TaskOpts { - notify_chan, name, stack_size, - stderr, stdout, - } = opts; + let TaskOpts { name, stack_size, on_exit } = opts; let mut task = box Task::new(); task.name = name; - task.stderr = stderr; - task.stdout = stdout; - match notify_chan { - Some(chan) => { task.death.on_exit = Some(SendMessage(chan)); } - None => {} - } + task.death.on_exit = on_exit; - let stack = stack_size.unwrap_or(env::min_stack()); + let stack = stack_size.unwrap_or(rt::min_stack()); let task = task; let ops = ops(); @@ -267,9 +257,8 @@ impl rt::Runtime for Ops { #[cfg(test)] mod tests { use std::rt::local::Local; - use std::rt::task::Task; + use std::rt::task::{Task, TaskOpts}; use std::task; - use std::task::TaskOpts; use super::{spawn, spawn_opts, Ops}; #[test] @@ -297,7 +286,7 @@ mod tests { opts.name = Some("test".into_maybe_owned()); opts.stack_size = Some(20 * 4096); let (tx, rx) = channel(); - opts.notify_chan = Some(tx); + opts.on_exit = Some(proc(r) tx.send(r)); spawn_opts(opts, proc() {}); assert!(rx.recv().is_ok()); } @@ -306,7 +295,7 @@ mod tests { fn smoke_opts_fail() { let mut opts = TaskOpts::new(); let (tx, rx) = channel(); - opts.notify_chan = Some(tx); + opts.on_exit = Some(proc(r) tx.send(r)); spawn_opts(opts, proc() { fail!() }); assert!(rx.recv().is_err()); } diff --git a/src/libstd/rt/args.rs b/src/librustrt/args.rs similarity index 85% rename from src/libstd/rt/args.rs rename to src/librustrt/args.rs index e016c9da418e1..0789bf7f906f6 100644 --- a/src/libstd/rt/args.rs +++ b/src/librustrt/args.rs @@ -18,10 +18,9 @@ //! discover the command line arguments. //! //! FIXME #7756: Would be nice for this to not exist. -//! FIXME #7756: This has a lot of C glue for lack of globals. -use option::Option; -use vec::Vec; +use core::prelude::*; +use collections::vec::Vec; /// One-time global initialization. pub unsafe fn init(argc: int, argv: **u8) { imp::init(argc, argv) } @@ -44,14 +43,14 @@ pub fn clone() -> Option>> { imp::clone() } #[cfg(target_os = "android")] #[cfg(target_os = "freebsd")] mod imp { - use clone::Clone; - use iter::Iterator; - use option::{Option, Some, None}; - use owned::Box; - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - use mem; - use vec::Vec; - use ptr::RawPtr; + use core::prelude::*; + + use alloc::owned::Box; + use collections::vec::Vec; + use core::mem; + use core::slice; + + use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut global_args_ptr: uint = 0; static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT; @@ -100,24 +99,23 @@ mod imp { unsafe { mem::transmute(&global_args_ptr) } } - // Copied from `os`. unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> Vec> { - use c_str::CString; - use ptr::RawPtr; - use libc; - use vec::Vec; - Vec::from_fn(argc as uint, |i| { - let cs = CString::new(*(argv as **libc::c_char).offset(i as int), false); - Vec::from_slice(cs.as_bytes_no_nul()) + let base = *argv.offset(i as int); + let mut len = 0; + while *base.offset(len) != 0 { len += 1; } + slice::raw::buf_as_slice(base, len as uint, |slice| { + Vec::from_slice(slice) + }) }) } #[cfg(test)] mod tests { - use prelude::*; + use std::prelude::*; + use std::finally::Finally; + use super::*; - use finally::Finally; #[test] fn smoke_test() { @@ -149,8 +147,8 @@ mod imp { #[cfg(target_os = "macos")] #[cfg(target_os = "win32")] mod imp { - use option::Option; - use vec::Vec; + use core::prelude::*; + use collections::vec::Vec; pub unsafe fn init(_argc: int, _argv: **u8) { } diff --git a/src/librustrt/at_exit_imp.rs b/src/librustrt/at_exit_imp.rs new file mode 100644 index 0000000000000..d38d06950bf8b --- /dev/null +++ b/src/librustrt/at_exit_imp.rs @@ -0,0 +1,63 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation of running at_exit routines +//! +//! Documentation can be found on the `rt::at_exit` function. + +use core::prelude::*; + +use alloc::owned::Box; +use collections::vec::Vec; +use core::atomics; +use core::mem; + +use exclusive::Exclusive; + +type Queue = Exclusive>; + +static mut QUEUE: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; +static mut RUNNING: atomics::AtomicBool = atomics::INIT_ATOMIC_BOOL; + +pub fn init() { + let state: Box = box Exclusive::new(Vec::new()); + unsafe { + rtassert!(!RUNNING.load(atomics::SeqCst)); + rtassert!(QUEUE.swap(mem::transmute(state), atomics::SeqCst) == 0); + } +} + +pub fn push(f: proc():Send) { + unsafe { + // Note that the check against 0 for the queue pointer is not atomic at + // all with respect to `run`, meaning that this could theoretically be a + // use-after-free. There's not much we can do to protect against that, + // however. Let's just assume a well-behaved runtime and go from there! + rtassert!(!RUNNING.load(atomics::SeqCst)); + let queue = QUEUE.load(atomics::SeqCst); + rtassert!(queue != 0); + (*(queue as *Queue)).lock().push(f); + } +} + +pub fn run() { + let cur = unsafe { + rtassert!(!RUNNING.load(atomics::SeqCst)); + let queue = QUEUE.swap(0, atomics::SeqCst); + rtassert!(queue != 0); + + let queue: Box = mem::transmute(queue); + mem::replace(&mut *queue.lock(), Vec::new()) + }; + + for to_run in cur.move_iter() { + to_run(); + } +} diff --git a/src/libstd/rt/bookkeeping.rs b/src/librustrt/bookkeeping.rs similarity index 91% rename from src/libstd/rt/bookkeeping.rs rename to src/librustrt/bookkeeping.rs index 9e772d8ad2385..fd290491eaf1e 100644 --- a/src/libstd/rt/bookkeeping.rs +++ b/src/librustrt/bookkeeping.rs @@ -18,11 +18,9 @@ //! each respective runtime to make sure that they call increment() and //! decrement() manually. -#![experimental] // this is a massive code smell -#![doc(hidden)] +use core::atomics; -use sync::atomics; -use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; +use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; diff --git a/src/libstd/c_str.rs b/src/librustrt/c_str.rs similarity index 97% rename from src/libstd/c_str.rs rename to src/librustrt/c_str.rs index 4e39518deb48c..4234c085148cb 100644 --- a/src/libstd/c_str.rs +++ b/src/librustrt/c_str.rs @@ -65,24 +65,17 @@ fn main() { */ -use clone::Clone; -use cmp::PartialEq; -use container::Container; -use iter::{Iterator, range}; -use kinds::marker; +use core::prelude::*; + +use alloc::libc_heap::malloc_raw; +use collections::string::String; +use core::kinds::marker; +use core::mem; +use core::ptr; +use core::raw::Slice; +use core::slice; +use core::str; use libc; -use mem; -use ops::Drop; -use option::{Option, Some, None}; -use ptr::RawPtr; -use ptr; -use raw::Slice; -use rt::libc_heap::malloc_raw; -use slice::{ImmutableVector, MutableVector}; -use slice; -use str::StrSlice; -use str; -use string::String; /// The representation of a C String. /// @@ -245,9 +238,15 @@ impl Container for CString { #[inline] fn len(&self) -> uint { if self.buf.is_null() { fail!("CString is null!"); } + let mut cur = self.buf; + let mut len = 0; unsafe { - ptr::position(self.buf, |c| *c == 0) + while *cur != 0 { + len += 1; + cur = cur.offset(1); + } } + return len; } } @@ -454,11 +453,12 @@ pub unsafe fn from_c_multistring(buf: *libc::c_char, #[cfg(test)] mod tests { - use prelude::*; - use super::*; + use std::prelude::*; + use std::ptr; + use std::task; use libc; - use ptr; - use str::StrSlice; + + use super::*; #[test] fn test_str_multistring_parsing() { @@ -574,7 +574,6 @@ mod tests { #[test] fn test_to_c_str_fail() { - use task; assert!(task::try(proc() { "he\x00llo".to_c_str() }).is_err()); } @@ -700,10 +699,9 @@ mod tests { #[cfg(test)] mod bench { - extern crate test; - use self::test::Bencher; + use test::Bencher; use libc; - use prelude::*; + use std::prelude::*; #[inline] fn check(s: &str, c_str: *libc::c_char) { diff --git a/src/librustrt/exclusive.rs b/src/librustrt/exclusive.rs new file mode 100644 index 0000000000000..62313965768a6 --- /dev/null +++ b/src/librustrt/exclusive.rs @@ -0,0 +1,115 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::prelude::*; + +use core::ty::Unsafe; +use mutex; + +/// An OS mutex over some data. +/// +/// This is not a safe primitive to use, it is unaware of the libgreen +/// scheduler, as well as being easily susceptible to misuse due to the usage of +/// the inner NativeMutex. +/// +/// > **Note**: This type is not recommended for general use. The mutex provided +/// > as part of `libsync` should almost always be favored. +pub struct Exclusive { + lock: mutex::NativeMutex, + data: Unsafe, +} + +/// An RAII guard returned via `lock` +pub struct ExclusiveGuard<'a, T> { + // FIXME #12808: strange name to try to avoid interfering with + // field accesses of the contained type via Deref + _data: &'a mut T, + _guard: mutex::LockGuard<'a>, +} + +impl Exclusive { + /// Creates a new `Exclusive` which will protect the data provided. + pub fn new(user_data: T) -> Exclusive { + Exclusive { + lock: unsafe { mutex::NativeMutex::new() }, + data: Unsafe::new(user_data), + } + } + + /// Acquires this lock, returning a guard which the data is accessed through + /// and from which that lock will be unlocked. + /// + /// This method is unsafe due to many of the same reasons that the + /// NativeMutex itself is unsafe. + pub unsafe fn lock<'a>(&'a self) -> ExclusiveGuard<'a, T> { + let guard = self.lock.lock(); + let data = &mut *self.data.get(); + + ExclusiveGuard { + _data: data, + _guard: guard, + } + } +} + +impl<'a, T: Send> ExclusiveGuard<'a, T> { + // The unsafety here should be ok because our loan guarantees that the lock + // itself is not moving + pub fn signal(&self) { + unsafe { self._guard.signal() } + } + pub fn wait(&self) { + unsafe { self._guard.wait() } + } +} + +impl<'a, T: Send> Deref for ExclusiveGuard<'a, T> { + fn deref<'a>(&'a self) -> &'a T { &*self._data } +} +impl<'a, T: Send> DerefMut for ExclusiveGuard<'a, T> { + fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self._data } +} + +#[cfg(test)] +mod tests { + use std::prelude::*; + use alloc::arc::Arc; + use super::Exclusive; + use std::task; + + #[test] + fn exclusive_new_arc() { + unsafe { + let mut futures = Vec::new(); + + let num_tasks = 10; + let count = 10; + + let total = Arc::new(Exclusive::new(box 0)); + + for _ in range(0u, num_tasks) { + let total = total.clone(); + let (tx, rx) = channel(); + futures.push(rx); + + task::spawn(proc() { + for _ in range(0u, count) { + **total.lock() += 1; + } + tx.send(()); + }); + }; + + for f in futures.mut_iter() { f.recv() } + + assert_eq!(**total.lock(), num_tasks * count); + } + } +} diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs new file mode 100644 index 0000000000000..3158687c6ab93 --- /dev/null +++ b/src/librustrt/lib.rs @@ -0,0 +1,164 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_id = "rustrt#0.11.0-pre"] +#![license = "MIT/ASL2"] +#![crate_type = "rlib"] +#![crate_type = "dylib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/")] +#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)] +#![no_std] +#![experimental] + +#[phase(syntax, link)] +extern crate core; +extern crate alloc; +extern crate libc; +extern crate collections; + +#[cfg(test)] extern crate realrustrt = "rustrt"; +#[cfg(test)] extern crate test; +#[cfg(test)] extern crate native; +#[cfg(test)] #[phase(syntax, link)] extern crate std; + +pub use self::util::{Stdio, Stdout, Stderr}; +pub use self::unwind::{begin_unwind, begin_unwind_fmt}; + +use core::prelude::*; + +use alloc::owned::Box; +use core::any::Any; + +use task::{Task, BlockedTask, TaskOpts}; + +mod macros; + +mod at_exit_imp; +mod local_ptr; +mod thread_local_storage; +mod util; +mod libunwind; + +pub mod args; +pub mod bookkeeping; +pub mod exclusive; +pub mod local; +pub mod local_data; +pub mod local_heap; +pub mod mutex; +pub mod rtio; +pub mod stack; +pub mod task; +pub mod unwind; +pub mod c_str; + +/// The interface to the current runtime. +/// +/// This trait is used as the abstraction between 1:1 and M:N scheduling. The +/// two independent crates, libnative and libgreen, both have objects which +/// implement this trait. The goal of this trait is to encompass all the +/// fundamental differences in functionality between the 1:1 and M:N runtime +/// modes. +pub trait Runtime { + // Necessary scheduling functions, used for channels and blocking I/O + // (sometimes). + fn yield_now(~self, cur_task: Box); + fn maybe_yield(~self, cur_task: Box); + fn deschedule(~self, times: uint, cur_task: Box, + f: |BlockedTask| -> Result<(), BlockedTask>); + fn reawaken(~self, to_wake: Box); + + // Miscellaneous calls which are very different depending on what context + // you're in. + fn spawn_sibling(~self, + cur_task: Box, + opts: TaskOpts, + f: proc():Send); + fn local_io<'a>(&'a mut self) -> Option>; + /// The (low, high) edges of the current stack. + fn stack_bounds(&self) -> (uint, uint); // (lo, hi) + fn can_block(&self) -> bool; + + // FIXME: This is a serious code smell and this should not exist at all. + fn wrap(~self) -> Box; +} + +/// The default error code of the rust runtime if the main task fails instead +/// of exiting cleanly. +pub static DEFAULT_ERROR_CODE: int = 101; + +/// One-time runtime initialization. +/// +/// Initializes global state, including frobbing +/// the crate's logging flags, registering GC +/// metadata, and storing the process arguments. +pub fn init(argc: int, argv: **u8) { + // FIXME: Derefing these pointers is not safe. + // Need to propagate the unsafety to `start`. + unsafe { + args::init(argc, argv); + local_ptr::init(); + at_exit_imp::init(); + } + + // FIXME(#14344) this shouldn't be necessary + collections::fixme_14344_be_sure_to_link_to_collections(); + alloc::fixme_14344_be_sure_to_link_to_collections(); + libc::issue_14344_workaround(); +} + +/// Enqueues a procedure to run when the runtime is cleaned up +/// +/// The procedure passed to this function will be executed as part of the +/// runtime cleanup phase. For normal rust programs, this means that it will run +/// after all other tasks have exited. +/// +/// The procedure is *not* executed with a local `Task` available to it, so +/// primitives like logging, I/O, channels, spawning, etc, are *not* available. +/// This is meant for "bare bones" usage to clean up runtime details, this is +/// not meant as a general-purpose "let's clean everything up" function. +/// +/// It is forbidden for procedures to register more `at_exit` handlers when they +/// are running, and doing so will lead to a process abort. +pub fn at_exit(f: proc():Send) { + at_exit_imp::push(f); +} + +/// One-time runtime cleanup. +/// +/// This function is unsafe because it performs no checks to ensure that the +/// runtime has completely ceased running. It is the responsibility of the +/// caller to ensure that the runtime is entirely shut down and nothing will be +/// poking around at the internal components. +/// +/// Invoking cleanup while portions of the runtime are still in use may cause +/// undefined behavior. +pub unsafe fn cleanup() { + bookkeeping::wait_for_other_tasks(); + at_exit_imp::run(); + args::cleanup(); + local_ptr::cleanup(); +} + +// FIXME: these probably shouldn't be public... +#[doc(hidden)] +pub mod shouldnt_be_public { + #[cfg(not(test))] + pub use super::local_ptr::native::maybe_tls_key; + #[cfg(not(windows), not(target_os = "android"))] + pub use super::local_ptr::compiled::RT_TLS_PTR; +} + +#[cfg(not(test))] +mod std { + pub use core::{fmt, option, cmp}; +} diff --git a/src/libstd/rt/libunwind.rs b/src/librustrt/libunwind.rs similarity index 52% rename from src/libstd/rt/libunwind.rs rename to src/librustrt/libunwind.rs index 00301e71b0d8b..846ec248805e9 100644 --- a/src/libstd/rt/libunwind.rs +++ b/src/librustrt/libunwind.rs @@ -79,10 +79,6 @@ pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *_Unwind_Exception); -pub type _Unwind_Trace_Fn = - extern "C" fn(ctx: *_Unwind_Context, - arg: *libc::c_void) -> _Unwind_Reason_Code; - #[cfg(target_os = "linux")] #[cfg(target_os = "freebsd")] #[cfg(target_os = "win32")] @@ -97,67 +93,4 @@ extern "C" { pub fn _Unwind_RaiseException(exception: *_Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_DeleteException(exception: *_Unwind_Exception); - pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, - trace_argument: *libc::c_void) - -> _Unwind_Reason_Code; - - #[cfg(not(target_os = "android"), - not(target_os = "linux", target_arch = "arm"))] - pub fn _Unwind_GetIP(ctx: *_Unwind_Context) -> libc::uintptr_t; - #[cfg(not(target_os = "android"), - not(target_os = "linux", target_arch = "arm"))] - pub fn _Unwind_FindEnclosingFunction(pc: *libc::c_void) -> *libc::c_void; -} - -// On android, the function _Unwind_GetIP is a macro, and this is the expansion -// of the macro. This is all copy/pasted directly from the header file with the -// definition of _Unwind_GetIP. -#[cfg(target_os = "android")] -#[cfg(target_os = "linux", target_arch = "arm")] -pub unsafe fn _Unwind_GetIP(ctx: *_Unwind_Context) -> libc::uintptr_t { - #[repr(C)] - enum _Unwind_VRS_Result { - _UVRSR_OK = 0, - _UVRSR_NOT_IMPLEMENTED = 1, - _UVRSR_FAILED = 2, - } - #[repr(C)] - enum _Unwind_VRS_RegClass { - _UVRSC_CORE = 0, - _UVRSC_VFP = 1, - _UVRSC_FPA = 2, - _UVRSC_WMMXD = 3, - _UVRSC_WMMXC = 4, - } - #[repr(C)] - enum _Unwind_VRS_DataRepresentation { - _UVRSD_UINT32 = 0, - _UVRSD_VFPX = 1, - _UVRSD_FPAX = 2, - _UVRSD_UINT64 = 3, - _UVRSD_FLOAT = 4, - _UVRSD_DOUBLE = 5, - } - - type _Unwind_Word = libc::c_uint; - extern { - fn _Unwind_VRS_Get(ctx: *_Unwind_Context, - klass: _Unwind_VRS_RegClass, - word: _Unwind_Word, - repr: _Unwind_VRS_DataRepresentation, - data: *mut libc::c_void) -> _Unwind_VRS_Result; - } - - let mut val: _Unwind_Word = 0; - let ptr = &mut val as *mut _Unwind_Word; - let _ = _Unwind_VRS_Get(ctx, _UVRSC_CORE, 15, _UVRSD_UINT32, - ptr as *mut libc::c_void); - (val & !1) as libc::uintptr_t -} - -// This function also doesn't exist on android or arm/linux, so make it a no-op -#[cfg(target_os = "android")] -#[cfg(target_os = "linux", target_arch = "arm")] -pub unsafe fn _Unwind_FindEnclosingFunction(pc: *libc::c_void) -> *libc::c_void { - pc } diff --git a/src/libstd/rt/local.rs b/src/librustrt/local.rs similarity index 95% rename from src/libstd/rt/local.rs rename to src/librustrt/local.rs index 9f0ed8044800c..7fe9dbc6d4ff5 100644 --- a/src/libstd/rt/local.rs +++ b/src/librustrt/local.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::Option; -use owned::Box; -use rt::task::Task; -use rt::local_ptr; +use core::prelude::*; + +use alloc::owned::Box; +use local_ptr; +use task::Task; /// Encapsulates some task-local data. pub trait Local { @@ -52,11 +53,10 @@ impl Local> for Task { #[cfg(test)] mod test { - use option::{None, Option}; - use rt::thread::Thread; + use std::prelude::*; + use std::rt::thread::Thread; use super::*; - use owned::Box; - use rt::task::Task; + use task::Task; #[test] fn thread_local_task_smoke_test() { diff --git a/src/libstd/local_data.rs b/src/librustrt/local_data.rs similarity index 96% rename from src/libstd/local_data.rs rename to src/librustrt/local_data.rs index 930d1df02f126..6b468bd0827c6 100644 --- a/src/libstd/local_data.rs +++ b/src/librustrt/local_data.rs @@ -38,18 +38,16 @@ assert_eq!(*key_vector.get().unwrap(), ~[4]); // Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation // magic. -use iter::{Iterator}; -use kinds::Send; -use kinds::marker; -use mem::replace; -use mem; -use ops::{Drop, Deref}; -use option::{None, Option, Some}; -use owned::Box; -use raw; -use rt::task::{Task, LocalStorage}; -use slice::{ImmutableVector, MutableVector}; -use vec::Vec; +use core::prelude::*; + +use alloc::owned::Box; +use collections::vec::Vec; +use core::kinds::marker; +use core::mem; +use core::raw; + +use local::Local; +use task::{Task, LocalStorage}; /** * Indexes a task-local data slot. This pointer is used for comparison to @@ -97,8 +95,6 @@ type TLSValue = Box; // Gets the map from the runtime. Lazily initialises if not done so already. unsafe fn get_local_map() -> Option<&mut Map> { - use rt::local::Local; - if !Local::exists(None::) { return None } let task: *mut Task = Local::unsafe_borrow(); @@ -111,10 +107,10 @@ unsafe fn get_local_map() -> Option<&mut Map> { // If this is the first time we've accessed TLS, perform similar // actions to the oldsched way of doing things. &LocalStorage(ref mut slot) => { - *slot = Some(vec!()); + *slot = Some(Vec::new()); match *slot { Some(ref mut map_ptr) => { return Some(map_ptr) } - None => unreachable!(), + None => fail!("unreachable code"), } } } @@ -192,7 +188,7 @@ impl KeyValue { match pos { Some(i) => { - replace(map.get_mut(i), newval).map(|(_, data, _)| { + mem::replace(map.get_mut(i), newval).map(|(_, data, _)| { // Move `data` into transmute to get out the memory that it // owns, we must free it manually later. let t: raw::TraitObject = unsafe { mem::transmute(data) }; @@ -277,10 +273,9 @@ impl Drop for Ref { #[cfg(test)] mod tests { - use prelude::*; + use std::prelude::*; use super::*; - use owned::Box; - use task; + use std::task; #[test] fn test_tls_multitask() { diff --git a/src/libstd/rt/local_heap.rs b/src/librustrt/local_heap.rs similarity index 75% rename from src/libstd/rt/local_heap.rs rename to src/librustrt/local_heap.rs index 240d137adc6e3..52fe5c35a268f 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/librustrt/local_heap.rs @@ -10,55 +10,45 @@ //! The local, garbage collected heap +use core::prelude::*; + +use alloc::libc_heap; use alloc::util; -use iter::Iterator; use libc::{c_void, free}; -use mem; -use ops::Drop; -use option::{Option, None, Some}; -use ptr::RawPtr; -use ptr; -use raw; -use rt::libc_heap; -use rt::local::Local; -use rt::task::Task; -use slice::{ImmutableVector, Vector}; -use vec::Vec; - -// This has no meaning with out rtdebug also turned on. -#[cfg(rtdebug)] -static TRACK_ALLOCATIONS: int = 0; -#[cfg(rtdebug)] -static MAGIC: u32 = 0xbadc0ffe; + +use core::mem; +use core::ptr; +use core::raw; +use local::Local; +use task::Task; + +static RC_IMMORTAL : uint = 0x77777777; pub type Box = raw::Box<()>; pub struct MemoryRegion { - allocations: Vec<*AllocHeader>, live_allocations: uint, } pub struct LocalHeap { memory_region: MemoryRegion, - live_allocs: *mut raw::Box<()>, } impl LocalHeap { - #[inline] pub fn new() -> LocalHeap { - let region = MemoryRegion { - allocations: Vec::new(), - live_allocations: 0, - }; LocalHeap { - memory_region: region, + memory_region: MemoryRegion { live_allocations: 0 }, live_allocs: ptr::mut_null(), } } #[inline] - pub fn alloc(&mut self, drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut Box { + #[allow(deprecated)] + pub fn alloc(&mut self, + drop_glue: fn(*mut u8), + size: uint, + align: uint) -> *mut Box { let total_size = util::get_box_size(size, align); let alloc = self.memory_region.malloc(total_size); { @@ -119,6 +109,63 @@ impl LocalHeap { self.memory_region.free(alloc); } + + pub unsafe fn annihilate(&mut self) { + let mut n_total_boxes = 0u; + + // Pass 1: Make all boxes immortal. + // + // In this pass, nothing gets freed, so it does not matter whether + // we read the next field before or after the callback. + self.each_live_alloc(true, |_, alloc| { + n_total_boxes += 1; + (*alloc).ref_count = RC_IMMORTAL; + }); + + // Pass 2: Drop all boxes. + // + // In this pass, unique-managed boxes may get freed, but not + // managed boxes, so we must read the `next` field *after* the + // callback, as the original value may have been freed. + self.each_live_alloc(false, |_, alloc| { + let drop_glue = (*alloc).drop_glue; + let data = &mut (*alloc).data as *mut (); + drop_glue(data as *mut u8); + }); + + // Pass 3: Free all boxes. + // + // In this pass, managed boxes may get freed (but not + // unique-managed boxes, though I think that none of those are + // left), so we must read the `next` field before, since it will + // not be valid after. + self.each_live_alloc(true, |me, alloc| { + me.free(alloc); + }); + + if debug_mem() { + // We do logging here w/o allocation. + rterrln!("total boxes annihilated: {}", n_total_boxes); + } + } + + unsafe fn each_live_alloc(&mut self, read_next_before: bool, + f: |&mut LocalHeap, alloc: *mut raw::Box<()>|) { + //! Walks the internal list of allocations + + let mut alloc = self.live_allocs; + while alloc != ptr::mut_null() { + let next_before = (*alloc).next; + + f(self, alloc); + + if read_next_before { + alloc = next_before; + } else { + alloc = (*alloc).next; + } + } + } } impl Drop for LocalHeap { @@ -127,43 +174,11 @@ impl Drop for LocalHeap { } } -#[cfg(rtdebug)] -struct AllocHeader { - magic: u32, - index: i32, - size: u32, -} -#[cfg(not(rtdebug))] struct AllocHeader; impl AllocHeader { - #[cfg(rtdebug)] - fn init(&mut self, size: u32) { - if TRACK_ALLOCATIONS > 0 { - self.magic = MAGIC; - self.index = -1; - self.size = size; - } - } - #[cfg(not(rtdebug))] fn init(&mut self, _size: u32) {} - - #[cfg(rtdebug)] - fn assert_sane(&self) { - if TRACK_ALLOCATIONS > 0 { - rtassert!(self.magic == MAGIC); - } - } - #[cfg(not(rtdebug))] fn assert_sane(&self) {} - - #[cfg(rtdebug)] - fn update_size(&mut self, size: u32) { - if TRACK_ALLOCATIONS > 0 { - self.size = size; - } - } - #[cfg(not(rtdebug))] fn update_size(&mut self, _size: u32) {} fn as_box(&mut self) -> *mut Box { @@ -183,6 +198,17 @@ impl AllocHeader { } } +#[cfg(unix)] +fn debug_mem() -> bool { + // FIXME: Need to port the environment struct to newsched + false +} + +#[cfg(windows)] +fn debug_mem() -> bool { + false +} + impl MemoryRegion { #[inline] fn malloc(&mut self, size: uint) -> *mut Box { @@ -230,39 +256,10 @@ impl MemoryRegion { } } - #[cfg(rtdebug)] - fn claim(&mut self, alloc: &mut AllocHeader) { - alloc.assert_sane(); - if TRACK_ALLOCATIONS > 1 { - alloc.index = self.allocations.len() as i32; - self.allocations.push(&*alloc as *AllocHeader); - } - } - #[cfg(not(rtdebug))] #[inline] fn claim(&mut self, _alloc: &mut AllocHeader) {} - - #[cfg(rtdebug)] - fn release(&mut self, alloc: &AllocHeader) { - alloc.assert_sane(); - if TRACK_ALLOCATIONS > 1 { - rtassert!(self.allocations.as_slice()[alloc.index] == alloc as *AllocHeader); - self.allocations.as_mut_slice()[alloc.index] = ptr::null(); - } - } - #[cfg(not(rtdebug))] #[inline] fn release(&mut self, _alloc: &AllocHeader) {} - - #[cfg(rtdebug)] - fn update(&mut self, alloc: &mut AllocHeader, orig: *AllocHeader) { - alloc.assert_sane(); - if TRACK_ALLOCATIONS > 1 { - rtassert!(self.allocations.as_slice()[alloc.index] == orig); - self.allocations.as_mut_slice()[alloc.index] = &*alloc as *AllocHeader; - } - } - #[cfg(not(rtdebug))] #[inline] fn update(&mut self, _alloc: &mut AllocHeader, _orig: *AllocHeader) {} } @@ -272,11 +269,9 @@ impl Drop for MemoryRegion { if self.live_allocations != 0 { rtabort!("leaked managed memory ({} objects)", self.live_allocations); } - rtassert!(self.allocations.as_slice().iter().all(|s| s.is_null())); } } - #[cfg(not(test))] #[lang="malloc"] #[inline] @@ -318,10 +313,6 @@ pub unsafe fn local_free(ptr: *u8) { } } -pub fn live_allocs() -> *mut Box { - Local::borrow(None::).heap.live_allocs -} - #[cfg(test)] mod bench { extern crate test; diff --git a/src/libstd/rt/local_ptr.rs b/src/librustrt/local_ptr.rs similarity index 96% rename from src/libstd/rt/local_ptr.rs rename to src/librustrt/local_ptr.rs index 1197a4ccbe670..91e3409892ea5 100644 --- a/src/libstd/rt/local_ptr.rs +++ b/src/librustrt/local_ptr.rs @@ -17,10 +17,10 @@ #![allow(dead_code)] -use mem; -use ops::{Drop, Deref, DerefMut}; -use owned::Box; -use ptr::RawPtr; +use core::prelude::*; + +use core::mem; +use alloc::owned::Box; #[cfg(windows)] // mingw-w32 doesn't like thread_local things #[cfg(target_os = "android")] // see #10686 @@ -83,13 +83,13 @@ pub unsafe fn borrow() -> Borrowed { /// it wherever possible. #[cfg(not(windows), not(target_os = "android"))] pub mod compiled { - use mem; - use option::{Option, Some, None}; - use owned::Box; - use ptr::RawPtr; + use core::prelude::*; + + use alloc::owned::Box; + use core::mem; #[cfg(test)] - pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR; + pub use realrustrt::shouldnt_be_public::RT_TLS_PTR; #[cfg(not(test))] #[thread_local] @@ -234,12 +234,12 @@ pub mod compiled { /// implementation uses the `thread_local_storage` module to provide a /// thread-local value. pub mod native { - use mem; - use option::{Option, Some, None}; - use owned::Box; - use ptr::RawPtr; - use ptr; - use tls = rt::thread_local_storage; + use core::prelude::*; + + use alloc::owned::Box; + use core::mem; + use core::ptr; + use tls = thread_local_storage; static mut RT_TLS_KEY: tls::Key = -1; @@ -396,9 +396,9 @@ pub mod native { #[inline] #[cfg(test)] pub fn maybe_tls_key() -> Option { - use realstd; + use realrustrt; unsafe { - mem::transmute(realstd::rt::shouldnt_be_public::maybe_tls_key()) + mem::transmute(realrustrt::shouldnt_be_public::maybe_tls_key()) } } } diff --git a/src/libstd/rt/macros.rs b/src/librustrt/macros.rs similarity index 82% rename from src/libstd/rt/macros.rs rename to src/librustrt/macros.rs index aef41de925ffa..d4e92736a9d4d 100644 --- a/src/libstd/rt/macros.rs +++ b/src/librustrt/macros.rs @@ -16,8 +16,8 @@ #![macro_escape] macro_rules! rterrln ( - ($($arg:tt)*) => ( { - format_args!(::rt::util::dumb_println, $($arg)*) + ($fmt:expr $($arg:tt)*) => ( { + format_args!(::util::dumb_print, concat!($fmt, "\n") $($arg)*) } ) ) @@ -32,7 +32,7 @@ macro_rules! rtdebug ( macro_rules! rtassert ( ( $arg:expr ) => ( { - if ::rt::util::ENFORCE_SANITY { + if ::util::ENFORCE_SANITY { if !$arg { rtabort!(" assertion failed: {}", stringify!($arg)); } @@ -42,8 +42,5 @@ macro_rules! rtassert ( macro_rules! rtabort ( - ($($arg:tt)*) => ( { - use str::Str; - ::rt::util::abort(format!($($arg)*).as_slice()); - } ) + ($($arg:tt)*) => (format_args!(::util::abort, $($arg)*)) ) diff --git a/src/libstd/unstable/mutex.rs b/src/librustrt/mutex.rs similarity index 97% rename from src/libstd/unstable/mutex.rs rename to src/librustrt/mutex.rs index 4e51e71477757..fccbe4a15e948 100644 --- a/src/libstd/unstable/mutex.rs +++ b/src/librustrt/mutex.rs @@ -33,7 +33,7 @@ //! # Example //! //! ```rust -//! use std::unstable::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT}; +//! use std::rt::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT}; //! //! // Use a statically initialized mutex //! static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; @@ -58,8 +58,7 @@ #![allow(non_camel_case_types)] -use option::{Option, None, Some}; -use ops::Drop; +use core::prelude::*; /// A native mutex suitable for storing in statics (that is, it has /// the `destroy` method rather than a destructor). @@ -109,7 +108,7 @@ impl StaticNativeMutex { /// # Example /// /// ```rust - /// use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + /// use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; /// static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT; /// unsafe { /// let _guard = LOCK.lock(); @@ -183,7 +182,7 @@ impl NativeMutex { /// /// # Example /// ```rust - /// use std::unstable::mutex::NativeMutex; + /// use std::rt::mutex::NativeMutex; /// unsafe { /// let mut lock = NativeMutex::new(); /// @@ -264,8 +263,8 @@ mod imp { use libc; use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, pthread_mutex_t, pthread_cond_t}; - use ty::Unsafe; - use kinds::marker; + use core::ty::Unsafe; + use core::kinds::marker; type pthread_mutexattr_t = libc::c_void; type pthread_condattr_t = libc::c_void; @@ -432,11 +431,11 @@ mod imp { #[cfg(windows)] mod imp { - use rt::libc_heap::malloc_raw; + use alloc::libc_heap::malloc_raw; + use core::atomics; + use core::ptr; use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR}; use libc; - use ptr; - use sync::atomics; type LPCRITICAL_SECTION = *mut c_void; static SPIN_COUNT: DWORD = 4000; @@ -563,11 +562,11 @@ mod imp { #[cfg(test)] mod test { - use prelude::*; + use std::prelude::*; - use mem::drop; + use std::mem::drop; use super::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - use rt::thread::Thread; + use std::rt::thread::Thread; #[test] fn smoke_lock() { diff --git a/src/libstd/rt/rtio.rs b/src/librustrt/rtio.rs similarity index 82% rename from src/libstd/rt/rtio.rs rename to src/librustrt/rtio.rs index 06db465f7eeed..00f761bae2152 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/librustrt/rtio.rs @@ -10,33 +10,18 @@ //! The EventLoop and internal synchronous I/O interface. -use c_str::CString; -use comm::{Sender, Receiver}; -use kinds::Send; +use core::prelude::*; +use alloc::owned::Box; +use collections::string::String; +use collections::vec::Vec; +use core::fmt; +use core::mem; use libc::c_int; use libc; -use mem; -use ops::Drop; -use option::{Option, Some, None}; -use owned::Box; -use path::Path; -use result::Err; -use rt::local::Local; -use rt::task::Task; -use vec::Vec; - -use ai = io::net::addrinfo; -use io; -use io::IoResult; -use io::net::ip::{IpAddr, SocketAddr}; -use io::process::{StdioContainer, ProcessExit}; -use io::signal::Signum; -use io::{FileMode, FileAccess, FileStat, FilePermission}; -use io::{SeekStyle}; -pub trait Callback { - fn call(&mut self); -} +use c_str::CString; +use local::Local; +use task::Task; pub trait EventLoop { fn run(&mut self); @@ -51,6 +36,10 @@ pub trait EventLoop { fn has_active_io(&self) -> bool; } +pub trait Callback { + fn call(&mut self); +} + pub trait RemoteCallback { /// Trigger the remote callback. Note that the number of times the /// callback is run is not guaranteed. All that is guaranteed is @@ -61,18 +50,6 @@ pub trait RemoteCallback { fn fire(&mut self); } -/// Data needed to make a successful open(2) call -/// Using unix flag conventions for now, which happens to also be what's supported -/// libuv (it does translation to windows under the hood). -pub struct FileOpenConfig { - /// Path to file to be opened - pub path: Path, - /// Flags for file access mode (as per open(2)) - pub flags: int, - /// File creation mode, ignored unless O_CREAT is passed as part of flags - pub mode: int -} - /// Description of what to do when a file handle is closed pub enum CloseBehavior { /// Do not close this handle when the object is destroyed @@ -185,9 +162,15 @@ impl<'a> LocalIo<'a> { pub fn maybe_raise(f: |io: &mut IoFactory| -> IoResult) -> IoResult { + #[cfg(unix)] use ERROR = libc::EINVAL; + #[cfg(windows)] use ERROR = libc::ERROR_CALL_NOT_IMPLEMENTED; match LocalIo::borrow() { - None => Err(io::standard_error(io::IoUnavailable)), Some(mut io) => f(io.get()), + None => Err(IoError { + code: ERROR as uint, + extra: 0, + detail: None, + }), } } @@ -198,11 +181,8 @@ impl<'a> LocalIo<'a> { /// Returns the underlying I/O factory as a trait reference. #[inline] pub fn get<'a>(&'a mut self) -> &'a mut IoFactory { - // FIXME(pcwalton): I think this is actually sound? Could borrow check - // allow this safely? - unsafe { - mem::transmute_copy(&self.factory) - } + let f: &'a mut IoFactory = self.factory; + f } } @@ -219,7 +199,8 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString, timeout: Option) -> IoResult>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, - hint: Option) -> IoResult>; + hint: Option) + -> IoResult>; // filesystem operations fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) @@ -228,18 +209,16 @@ pub trait IoFactory { -> IoResult>; fn fs_unlink(&mut self, path: &CString) -> IoResult<()>; fn fs_stat(&mut self, path: &CString) -> IoResult; - fn fs_mkdir(&mut self, path: &CString, - mode: FilePermission) -> IoResult<()>; - fn fs_chmod(&mut self, path: &CString, - mode: FilePermission) -> IoResult<()>; + fn fs_mkdir(&mut self, path: &CString, mode: uint) -> IoResult<()>; + fn fs_chmod(&mut self, path: &CString, mode: uint) -> IoResult<()>; fn fs_rmdir(&mut self, path: &CString) -> IoResult<()>; fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()>; fn fs_readdir(&mut self, path: &CString, flags: c_int) -> - IoResult>; + IoResult>; fn fs_lstat(&mut self, path: &CString) -> IoResult; fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()>; - fn fs_readlink(&mut self, path: &CString) -> IoResult; + fn fs_readlink(&mut self, path: &CString) -> IoResult; fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()>; fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()>; fn fs_utime(&mut self, src: &CString, atime: u64, mtime: u64) -> @@ -254,7 +233,7 @@ pub trait IoFactory { fn pipe_open(&mut self, fd: c_int) -> IoResult>; fn tty_open(&mut self, fd: c_int, readable: bool) -> IoResult>; - fn signal(&mut self, signal: Signum, channel: Sender) + fn signal(&mut self, signal: int, cb: Box) -> IoResult>; } @@ -313,8 +292,8 @@ pub trait RtioUdpSocket : RtioSocket { pub trait RtioTimer { fn sleep(&mut self, msecs: u64); - fn oneshot(&mut self, msecs: u64) -> Receiver<()>; - fn period(&mut self, msecs: u64) -> Receiver<()>; + fn oneshot(&mut self, msecs: u64, cb: Box); + fn period(&mut self, msecs: u64, cb: Box); } pub trait RtioFileStream { @@ -372,3 +351,99 @@ pub trait PausableIdleCallback { } pub trait RtioSignal {} + +pub struct IoError { + pub code: uint, + pub extra: uint, + pub detail: Option, +} + +pub type IoResult = Result; + +#[deriving(PartialEq, Eq)] +pub enum IpAddr { + Ipv4Addr(u8, u8, u8, u8), + Ipv6Addr(u16, u16, u16, u16, u16, u16, u16, u16), +} + +impl fmt::Show for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Ipv4Addr(a, b, c, d) => write!(fmt, "{}.{}.{}.{}", a, b, c, d), + Ipv6Addr(a, b, c, d, e, f, g, h) => { + write!(fmt, + "{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}:{:04x}", + a, b, c, d, e, f, g, h) + } + } + } +} + +#[deriving(PartialEq, Eq)] +pub struct SocketAddr { + pub ip: IpAddr, + pub port: u16, +} + +pub enum StdioContainer { + Ignored, + InheritFd(i32), + CreatePipe(bool, bool), +} + +pub enum ProcessExit { + ExitStatus(int), + ExitSignal(int), +} + +pub enum FileMode { + Open, + Append, + Truncate, +} + +pub enum FileAccess { + Read, + Write, + ReadWrite, +} + +pub struct FileStat { + pub size: u64, + pub kind: u64, + pub perm: u64, + pub created: u64, + pub modified: u64, + pub accessed: u64, + pub device: u64, + pub inode: u64, + pub rdev: u64, + pub nlink: u64, + pub uid: u64, + pub gid: u64, + pub blksize: u64, + pub blocks: u64, + pub flags: u64, + pub gen: u64, +} + +pub enum SeekStyle { + SeekSet, + SeekEnd, + SeekCur, +} + +pub struct AddrinfoHint { + pub family: uint, + pub socktype: uint, + pub protocol: uint, + pub flags: uint, +} + +pub struct AddrinfoInfo { + pub address: SocketAddr, + pub family: uint, + pub socktype: uint, + pub protocol: uint, + pub flags: uint, +} diff --git a/src/libstd/rt/stack.rs b/src/librustrt/stack.rs similarity index 98% rename from src/libstd/rt/stack.rs rename to src/librustrt/stack.rs index dc6ab494d643e..148d93adc8485 100644 --- a/src/libstd/rt/stack.rs +++ b/src/librustrt/stack.rs @@ -33,12 +33,11 @@ pub static RED_ZONE: uint = 20 * 1024; #[cfg(not(test))] // in testing, use the original libstd's version #[lang = "stack_exhausted"] extern fn stack_exhausted() { - use option::{Option, None, Some}; - use owned::Box; - use rt::local::Local; - use rt::task::Task; - use str::Str; - use intrinsics; + use core::prelude::*; + use alloc::owned::Box; + use local::Local; + use task::Task; + use core::intrinsics; unsafe { // We're calling this function because the stack just ran out. We need diff --git a/src/libstd/rt/task.rs b/src/librustrt/task.rs similarity index 83% rename from src/libstd/rt/task.rs rename to src/librustrt/task.rs index 7f492a00b80db..0640b2b9c77ae 100644 --- a/src/libstd/rt/task.rs +++ b/src/librustrt/task.rs @@ -13,30 +13,24 @@ //! local storage, and logging. Even a 'freestanding' Rust would likely want //! to implement this. +use core::prelude::*; + use alloc::arc::Arc; +use alloc::owned::{AnyOwnExt, Box}; +use core::any::Any; +use core::atomics::{AtomicUint, SeqCst}; +use core::finally::Finally; +use core::iter::Take; +use core::mem; +use core::raw; -use cleanup; -use clone::Clone; -use comm::Sender; -use io::Writer; -use iter::{Iterator, Take}; -use kinds::Send; use local_data; -use mem; -use ops::Drop; -use option::{Option, Some, None}; -use owned::{AnyOwnExt, Box}; -use prelude::drop; -use result::{Result, Ok, Err}; -use rt::Runtime; -use rt::local::Local; -use rt::local_heap::LocalHeap; -use rt::rtio::LocalIo; -use rt::unwind::Unwinder; -use str::SendStr; -use sync::atomics::{AtomicUint, SeqCst}; -use task::{TaskResult, TaskOpts}; -use finally::Finally; +use Runtime; +use local::Local; +use local_heap::LocalHeap; +use rtio::LocalIo; +use unwind::Unwinder; +use collections::str::SendStr; /// The Task struct represents all state associated with a rust /// task. There are at this point two primary "subtypes" of task, @@ -52,12 +46,26 @@ pub struct Task { pub destroyed: bool, pub name: Option, - pub stdout: Option>, - pub stderr: Option>, - imp: Option>, } +pub struct TaskOpts { + /// Invoke this procedure with the result of the task when it finishes. + pub on_exit: Option, + /// A name for the task-to-be, for identification in failure messages + pub name: Option, + /// The size of the stack for the spawned task + pub stack_size: Option, +} + +/// Indicates the manner in which a task exited. +/// +/// A task that completes without failing is considered to exit successfully. +/// +/// If you wish for this result's delivery to block until all +/// children tasks complete, recommend using a result future. +pub type Result = ::core::result::Result<(), Box>; + pub struct GarbageCollector; pub struct LocalStorage(pub Option); @@ -69,17 +77,9 @@ pub enum BlockedTask { Shared(Arc), } -pub enum DeathAction { - /// Action to be done with the exit code. If set, also makes the task wait - /// until all its watched children exit before collecting the status. - Execute(proc(TaskResult):Send), - /// A channel to send the result of the task on when the task exits - SendMessage(Sender), -} - /// Per-task state related to task death, killing, failure, etc. pub struct Death { - pub on_exit: Option, + pub on_exit: Option, } pub struct BlockedTasks { @@ -96,8 +96,6 @@ impl Task { death: Death::new(), destroyed: false, name: None, - stdout: None, - stderr: None, imp: None, } } @@ -126,20 +124,6 @@ impl Task { // Run the task main function, then do some cleanup. f.finally(|| { - #[allow(unused_must_use)] - fn close_outputs() { - let mut task = Local::borrow(None::); - let stderr = task.stderr.take(); - let stdout = task.stdout.take(); - drop(task); - match stdout { Some(mut w) => { w.flush(); }, None => {} } - match stderr { Some(mut w) => { w.flush(); }, None => {} } - } - - // First, flush/destroy the user stdout/logger because these - // destructors can run arbitrary code. - close_outputs(); - // First, destroy task-local storage. This may run user dtors. // // FIXME #8302: Dear diary. I'm so tired and confused. @@ -159,23 +143,19 @@ impl Task { // TLS, or possibly some destructors for those objects being // annihilated invoke TLS. Sadly these two operations seemed to // be intertwined, and miraculously work for now... - let mut task = Local::borrow(None::); - let storage_map = { + drop({ + let mut task = Local::borrow(None::); let &LocalStorage(ref mut optmap) = &mut task.storage; optmap.take() - }; - drop(task); - drop(storage_map); + }); // Destroy remaining boxes. Also may run user dtors. - unsafe { cleanup::annihilate(); } - - // Finally, just in case user dtors printed/logged during TLS - // cleanup and annihilation, re-destroy stdout and the logger. - // Note that these will have been initialized with a - // runtime-provided type which we have control over what the - // destructor does. - close_outputs(); + let mut heap = { + let mut task = Local::borrow(None::); + mem::replace(&mut task.heap, LocalHeap::new()) + }; + unsafe { heap.annihilate() } + drop(heap); }) }; @@ -222,13 +202,16 @@ impl Task { // crops up. unsafe { let imp = self.imp.take_unwrap(); - let &(vtable, _): &(uint, uint) = mem::transmute(&imp); + let vtable = mem::transmute::<_, &raw::TraitObject>(&imp).vtable; match imp.wrap().move::() { Ok(t) => Some(t), Err(t) => { - let (_, obj): (uint, uint) = mem::transmute(t); + let data = mem::transmute::<_, raw::TraitObject>(t).data; let obj: Box = - mem::transmute((vtable, obj)); + mem::transmute(raw::TraitObject { + vtable: vtable, + data: data, + }); self.put_runtime(obj); None } @@ -247,7 +230,7 @@ impl Task { /// recommended to use this function directly, but rather communication /// primitives in `std::comm` should be used. pub fn deschedule(mut ~self, amt: uint, - f: |BlockedTask| -> Result<(), BlockedTask>) { + f: |BlockedTask| -> ::core::result::Result<(), BlockedTask>) { let ops = self.imp.take_unwrap(); ops.deschedule(amt, self, f) } @@ -303,6 +286,12 @@ impl Drop for Task { } } +impl TaskOpts { + pub fn new() -> TaskOpts { + TaskOpts { on_exit: None, name: None, stack_size: None } + } +} + impl Iterator for BlockedTasks { fn next(&mut self) -> Option { Some(Shared(self.inner.clone())) @@ -389,10 +378,9 @@ impl Death { } /// Collect failure exit codes from children and propagate them to a parent. - pub fn collect_failure(&mut self, result: TaskResult) { + pub fn collect_failure(&mut self, result: Result) { match self.on_exit.take() { - Some(Execute(f)) => f(result), - Some(SendMessage(ch)) => { let _ = ch.send_opt(result); } + Some(f) => f(result), None => {} } } @@ -407,8 +395,8 @@ impl Drop for Death { #[cfg(test)] mod test { use super::*; - use prelude::*; - use task; + use std::prelude::*; + use std::task; #[test] fn local_heap() { @@ -440,16 +428,11 @@ mod test { #[test] fn rng() { - use rand::{StdRng, Rng}; + use std::rand::{StdRng, Rng}; let mut r = StdRng::new().ok().unwrap(); let _ = r.next_u32(); } - #[test] - fn logging() { - info!("here i am. logging in a newsched task"); - } - #[test] fn comm_stream() { let (tx, rx) = channel(); @@ -466,8 +449,7 @@ mod test { #[test] fn heap_cycles() { - use cell::RefCell; - use option::{Option, Some, None}; + use std::cell::RefCell; struct List { next: Option<@RefCell>, @@ -485,7 +467,7 @@ mod test { #[test] #[should_fail] fn test_begin_unwind() { - use rt::unwind::begin_unwind; + use std::rt::unwind::begin_unwind; begin_unwind("cause", file!(), line!()) } diff --git a/src/libstd/rt/thread_local_storage.rs b/src/librustrt/thread_local_storage.rs similarity index 72% rename from src/libstd/rt/thread_local_storage.rs rename to src/librustrt/thread_local_storage.rs index a3ebcbafff8d3..2cdeb21fb83dd 100644 --- a/src/libstd/rt/thread_local_storage.rs +++ b/src/librustrt/thread_local_storage.rs @@ -10,26 +10,21 @@ #![allow(dead_code)] -#[cfg(test)] -use owned::Box; -#[cfg(unix)] -use libc::c_int; -#[cfg(unix)] -use ptr::null; -#[cfg(windows)] -use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL}; +#[cfg(unix)] use libc::c_int; +#[cfg(unix)] use core::ptr::null; +#[cfg(windows)] use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL}; #[cfg(unix)] pub type Key = pthread_key_t; #[cfg(unix)] pub unsafe fn create(key: &mut Key) { - assert_eq!(0, pthread_key_create(key, null())); + assert!(pthread_key_create(key, null()) == 0); } #[cfg(unix)] pub unsafe fn set(key: Key, value: *mut u8) { - assert_eq!(0, pthread_setspecific(key, value)); + assert!(pthread_setspecific(key, value) == 0); } #[cfg(unix)] @@ -39,7 +34,7 @@ pub unsafe fn get(key: Key) -> *mut u8 { #[cfg(unix)] pub unsafe fn destroy(key: Key) { - assert_eq!(0, pthread_key_delete(key)); + assert!(pthread_key_delete(key) == 0); } #[cfg(target_os="macos")] @@ -94,19 +89,25 @@ extern "system" { fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; } -#[test] -fn tls_smoke_test() { - use mem::transmute; - unsafe { - let mut key = 0; - let value = box 20; - create(&mut key); - set(key, transmute(value)); - let value: Box = transmute(get(key)); - assert_eq!(value, box 20); - let value = box 30; - set(key, transmute(value)); - let value: Box = transmute(get(key)); - assert_eq!(value, box 30); +#[cfg(test)] +mod test { + use std::prelude::*; + use super::*; + + #[test] + fn tls_smoke_test() { + use std::mem::transmute; + unsafe { + let mut key = 0; + let value = box 20; + create(&mut key); + set(key, transmute(value)); + let value: Box = transmute(get(key)); + assert_eq!(value, box 20); + let value = box 30; + set(key, transmute(value)); + let value: Box = transmute(get(key)); + assert_eq!(value, box 30); + } } } diff --git a/src/libstd/rt/unwind.rs b/src/librustrt/unwind.rs similarity index 59% rename from src/libstd/rt/unwind.rs rename to src/librustrt/unwind.rs index af73e6167afce..2fd9f4ef1f18c 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/librustrt/unwind.rs @@ -8,73 +8,74 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Stack unwinding - -// Implementation of Rust stack unwinding -// -// For background on exception handling and stack unwinding please see -// "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and -// documents linked from it. -// These are also good reads: -// http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/ -// http://monoinfinito.wordpress.com/series/exception-handling-in-c/ -// http://www.airs.com/blog/index.php?s=exception+frames -// -// ~~~ A brief summary ~~~ -// Exception handling happens in two phases: a search phase and a cleanup phase. -// -// In both phases the unwinder walks stack frames from top to bottom using -// information from the stack frame unwind sections of the current process's -// modules ("module" here refers to an OS module, i.e. an executable or a -// dynamic library). -// -// For each stack frame, it invokes the associated "personality routine", whose -// address is also stored in the unwind info section. -// -// In the search phase, the job of a personality routine is to examine exception -// object being thrown, and to decide whether it should be caught at that stack -// frame. Once the handler frame has been identified, cleanup phase begins. -// -// In the cleanup phase, personality routines invoke cleanup code associated -// with their stack frames (i.e. destructors). Once stack has been unwound down -// to the handler frame level, unwinding stops and the last personality routine -// transfers control to its' catch block. -// -// ~~~ Frame unwind info registration ~~~ -// Each module has its' own frame unwind info section (usually ".eh_frame"), and -// unwinder needs to know about all of them in order for unwinding to be able to -// cross module boundaries. -// -// On some platforms, like Linux, this is achieved by dynamically enumerating -// currently loaded modules via the dl_iterate_phdr() API and finding all -// .eh_frame sections. -// -// Others, like Windows, require modules to actively register their unwind info -// sections by calling __register_frame_info() API at startup. In the latter -// case it is essential that there is only one copy of the unwinder runtime in -// the process. This is usually achieved by linking to the dynamic version of -// the unwind runtime. -// -// Currently Rust uses unwind runtime provided by libgcc. - -use any::{Any, AnyRefExt}; -use fmt; -use intrinsics; -use kinds::Send; -use mem; -use option::{Some, None, Option}; -use owned::Box; -use prelude::drop; -use ptr::RawPtr; -use result::{Err, Ok, Result}; -use rt::backtrace; -use rt::local::Local; -use rt::task::Task; -use str::Str; -use string::String; -use task::TaskResult; - -use uw = rt::libunwind; +//! Implementation of Rust stack unwinding +//! +//! For background on exception handling and stack unwinding please see +//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and +//! documents linked from it. +//! These are also good reads: +//! http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/ +//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/ +//! http://www.airs.com/blog/index.php?s=exception+frames +//! +//! ## A brief summary +//! +//! Exception handling happens in two phases: a search phase and a cleanup phase. +//! +//! In both phases the unwinder walks stack frames from top to bottom using +//! information from the stack frame unwind sections of the current process's +//! modules ("module" here refers to an OS module, i.e. an executable or a +//! dynamic library). +//! +//! For each stack frame, it invokes the associated "personality routine", whose +//! address is also stored in the unwind info section. +//! +//! In the search phase, the job of a personality routine is to examine exception +//! object being thrown, and to decide whether it should be caught at that stack +//! frame. Once the handler frame has been identified, cleanup phase begins. +//! +//! In the cleanup phase, personality routines invoke cleanup code associated +//! with their stack frames (i.e. destructors). Once stack has been unwound down +//! to the handler frame level, unwinding stops and the last personality routine +//! transfers control to its' catch block. +//! +//! ## Frame unwind info registration +//! +//! Each module has its' own frame unwind info section (usually ".eh_frame"), and +//! unwinder needs to know about all of them in order for unwinding to be able to +//! cross module boundaries. +//! +//! On some platforms, like Linux, this is achieved by dynamically enumerating +//! currently loaded modules via the dl_iterate_phdr() API and finding all +//! .eh_frame sections. +//! +//! Others, like Windows, require modules to actively register their unwind info +//! sections by calling __register_frame_info() API at startup. In the latter +//! case it is essential that there is only one copy of the unwinder runtime in +//! the process. This is usually achieved by linking to the dynamic version of +//! the unwind runtime. +//! +//! Currently Rust uses unwind runtime provided by libgcc. + +use core::prelude::*; + +use alloc::owned::Box; +use collections::string::String; +use collections::vec::Vec; +use core::any::Any; +use core::atomics; +use core::cmp; +use core::fmt; +use core::intrinsics; +use core::mem; +use core::raw::Closure; +use libc::c_void; + +use local::Local; +use task::{Task, Result}; +use exclusive::Exclusive; + +use uw = libunwind; pub struct Unwinder { unwinding: bool, @@ -86,6 +87,24 @@ struct Exception { cause: Option>, } +pub type Callback = fn(msg: &Any:Send, file: &'static str, line: uint); +type Queue = Exclusive>; + +// Variables used for invoking callbacks when a task starts to unwind. +// +// For more information, see below. +static MAX_CALLBACKS: uint = 16; +static mut CALLBACKS: [atomics::AtomicUint, ..MAX_CALLBACKS] = + [atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT, + atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT, + atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT, + atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT, + atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT, + atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT, + atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT, + atomics::INIT_ATOMIC_UINT, atomics::INIT_ATOMIC_UINT]; +static mut CALLBACK_CNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; + impl Unwinder { pub fn new() -> Unwinder { Unwinder { @@ -102,7 +121,7 @@ impl Unwinder { self.cause = unsafe { try(f) }.err(); } - pub fn result(&mut self) -> TaskResult { + pub fn result(&mut self) -> Result { if self.unwinding { Err(self.cause.take().unwrap()) } else { @@ -131,10 +150,7 @@ impl Unwinder { /// guaranteed that a rust task is in place when invoking this function. /// Unwinding twice can lead to resource leaks where some destructors are not /// run. -pub unsafe fn try(f: ||) -> Result<(), Box> { - use raw::Closure; - use libc::{c_void}; - +pub unsafe fn try(f: ||) -> ::core::result::Result<(), Box> { let closure: Closure = mem::transmute(f); let ep = rust_try(try_fn, closure.code as *c_void, closure.env as *c_void); @@ -158,6 +174,7 @@ pub unsafe fn try(f: ||) -> Result<(), Box> { } } + #[link(name = "rustrt_native", kind = "static")] extern { // Rust's try-catch // When f(...) returns normally, the return value is null. @@ -227,7 +244,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { #[doc(hidden)] #[allow(visible_private_types)] pub mod eabi { - use uw = rt::libunwind; + use uw = libunwind; use libc::c_int; extern "C" { @@ -280,7 +297,7 @@ pub mod eabi { #[cfg(target_arch = "arm", not(test))] #[allow(visible_private_types)] pub mod eabi { - use uw = rt::libunwind; + use uw = libunwind; use libc::c_int; extern "C" { @@ -338,11 +355,26 @@ pub extern fn rust_begin_unwind(msg: &fmt::Arguments, #[inline(never)] #[cold] pub fn begin_unwind_fmt(msg: &fmt::Arguments, file: &'static str, line: uint) -> ! { + use core::fmt::FormatWriter; + // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // failure + OOM properly anyway (see comment in begin_unwind // below). - begin_unwind_inner(box fmt::format(msg), file, line) + + struct VecWriter<'a> { v: &'a mut Vec } + + impl<'a> fmt::FormatWriter for VecWriter<'a> { + fn write(&mut self, buf: &[u8]) -> fmt::Result { + self.v.push_all(buf); + Ok(()) + } + } + + let mut v = Vec::new(); + let _ = write!(&mut VecWriter { v: &mut v }, "{}", msg); + + begin_unwind_inner(box String::from_utf8(v).unwrap(), file, line) } /// This is the entry point of unwinding for fail!() and assert!(). @@ -373,122 +405,78 @@ pub fn begin_unwind(msg: M, file: &'static str, line: uint) -> ! fn begin_unwind_inner(msg: Box, file: &'static str, line: uint) -> ! { - // First up, print the message that we're failing - print_failure(msg, file, line); - - let opt_task: Option> = Local::try_take(); - match opt_task { - Some(mut task) => { - // Now that we've printed why we're failing, do a check - // to make sure that we're not double failing. - // - // If a task fails while it's already unwinding then we - // have limited options. Currently our preference is to - // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the task cleanly. - if task.unwinder.unwinding { - rterrln!("task failed during unwinding. aborting."); - - // Don't print the backtrace twice (it would have already been - // printed if logging was enabled). - if !backtrace::log_enabled() { - let mut err = ::rt::util::Stderr; - let _err = backtrace::write(&mut err); - } - unsafe { intrinsics::abort() } + // First, invoke call the user-defined callbacks triggered on task failure. + // + // By the time that we see a callback has been registered (by reading + // MAX_CALLBACKS), the actuall callback itself may have not been stored yet, + // so we just chalk it up to a race condition and move on to the next + // callback. Additionally, CALLBACK_CNT may briefly be higher than + // MAX_CALLBACKS, so we're sure to clamp it as necessary. + let callbacks = unsafe { + let amt = CALLBACK_CNT.load(atomics::SeqCst); + CALLBACKS.slice_to(cmp::min(amt, MAX_CALLBACKS)) + }; + for cb in callbacks.iter() { + match cb.load(atomics::SeqCst) { + 0 => {} + n => { + let f: Callback = unsafe { mem::transmute(n) }; + f(msg, file, line); } - - // Finally, we've printed our failure and figured out we're not in a - // double failure, so flag that we've started to unwind and then - // actually unwind. Be sure that the task is in TLS so destructors - // can do fun things like I/O. - task.unwinder.unwinding = true; - Local::put(task); } - None => {} + }; + + // Now that we've run all the necessary unwind callbacks, we actually + // perform the unwinding. If we don't have a task, then it's time to die + // (hopefully someone printed something about this). + let mut task: Box = match Local::try_take() { + Some(task) => task, + None => rust_fail(msg), + }; + + if task.unwinder.unwinding { + // If a task fails while it's already unwinding then we + // have limited options. Currently our preference is to + // just abort. In the future we may consider resuming + // unwinding or otherwise exiting the task cleanly. + rterrln!("task failed during unwinding. aborting."); + unsafe { intrinsics::abort() } } - rust_fail(msg) + task.unwinder.unwinding = true; + + // Put the task back in TLS because the unwinding process may run code which + // requires the task. We need a handle to its unwinder, however, so after + // this we unsafely extract it and continue along. + Local::put(task); + rust_fail(msg); } -/// Given a failure message and the location that it occurred, prints the -/// message to the local task's appropriate stream. +/// Register a callback to be invoked when a task unwinds. /// -/// This function currently handles three cases: +/// This is an unsafe and experimental API which allows for an arbitrary +/// callback to be invoked when a task fails. This callback is invoked on both +/// the initial unwinding and a double unwinding if one occurs. Additionally, +/// the local `Task` will be in place for the duration of the callback, and +/// the callback must ensure that it remains in place once the callback returns. /// -/// - There is no local task available. In this case the error is printed to -/// stderr. -/// - There is a local task available, but it does not have a stderr handle. -/// In this case the message is also printed to stderr. -/// - There is a local task available, and it has a stderr handle. The -/// message is printed to the handle given in this case. -fn print_failure(msg: &Any:Send, file: &str, line: uint) { - let msg = match msg.as_ref::<&'static str>() { - Some(s) => *s, - None => match msg.as_ref::() { - Some(s) => s.as_slice(), - None => "Box", +/// Only a limited number of callbacks can be registered, and this function +/// returns whether the callback was successfully registered or not. It is not +/// currently possible to unregister a callback once it has been registered. +#[experimental] +pub unsafe fn register(f: Callback) -> bool { + match CALLBACK_CNT.fetch_add(1, atomics::SeqCst) { + // The invocation code has knowledge of this window where the count has + // been incremented, but the callback has not been stored. We're + // guaranteed that the slot we're storing into is 0. + n if n < MAX_CALLBACKS => { + let prev = CALLBACKS[n].swap(mem::transmute(f), atomics::SeqCst); + rtassert!(prev == 0); + true } - }; - - // It is assumed that all reasonable rust code will have a local task at - // all times. This means that this `try_take` will succeed almost all of - // the time. There are border cases, however, when the runtime has - // *almost* set up the local task, but hasn't quite gotten there yet. In - // order to get some better diagnostics, we print on failure and - // immediately abort the whole process if there is no local task - // available. - let mut task: Box = match Local::try_take() { - Some(t) => t, - None => { - rterrln!("failed at '{}', {}:{}", msg, file, line); - if backtrace::log_enabled() { - let mut err = ::rt::util::Stderr; - let _err = backtrace::write(&mut err); - } else { - rterrln!("run with `RUST_BACKTRACE=1` to see a backtrace"); - } - return - } - }; - - // See comments in io::stdio::with_task_stdout as to why we have to be - // careful when using an arbitrary I/O handle from the task. We - // essentially need to dance to make sure when a task is in TLS when - // running user code. - let name = task.name.take(); - { - let n = name.as_ref().map(|n| n.as_slice()).unwrap_or(""); - - match task.stderr.take() { - Some(mut stderr) => { - Local::put(task); - // FIXME: what to do when the task printing fails? - let _err = write!(stderr, - "task '{}' failed at '{}', {}:{}\n", - n, msg, file, line); - if backtrace::log_enabled() { - let _err = backtrace::write(stderr); - } - task = Local::take(); - - match mem::replace(&mut task.stderr, Some(stderr)) { - Some(prev) => { - Local::put(task); - drop(prev); - task = Local::take(); - } - None => {} - } - } - None => { - rterrln!("task '{}' failed at '{}', {}:{}", n, msg, file, line); - if backtrace::log_enabled() { - let mut err = ::rt::util::Stderr; - let _err = backtrace::write(&mut err); - } - } + // If we accidentally bumped the count too high, pull it back. + _ => { + CALLBACK_CNT.store(MAX_CALLBACKS, atomics::SeqCst); + false } } - task.name = name; - Local::put(task); } diff --git a/src/librustrt/util.rs b/src/librustrt/util.rs new file mode 100644 index 0000000000000..c08652cc08c79 --- /dev/null +++ b/src/librustrt/util.rs @@ -0,0 +1,129 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::prelude::*; + +use core::cmp; +use core::fmt; +use core::intrinsics; +use core::slice; +use core::str; +use libc; + +// Indicates whether we should perform expensive sanity checks, including rtassert! +// +// FIXME: Once the runtime matures remove the `true` below to turn off rtassert, +// etc. +pub static ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || + cfg!(rtassert); + +pub struct Stdio(libc::c_int); + +pub static Stdout: Stdio = Stdio(libc::STDOUT_FILENO); +pub static Stderr: Stdio = Stdio(libc::STDERR_FILENO); + +impl fmt::FormatWriter for Stdio { + fn write(&mut self, data: &[u8]) -> fmt::Result { + #[cfg(unix)] + type WriteLen = libc::size_t; + #[cfg(windows)] + type WriteLen = libc::c_uint; + unsafe { + let Stdio(fd) = *self; + libc::write(fd, + data.as_ptr() as *libc::c_void, + data.len() as WriteLen); + } + Ok(()) // yes, we're lying + } +} + +pub fn dumb_print(args: &fmt::Arguments) { + use core::fmt::FormatWriter; + let mut w = Stderr; + let _ = w.write_fmt(args); +} + +pub fn abort(args: &fmt::Arguments) -> ! { + use core::fmt::FormatWriter; + + struct BufWriter<'a> { + buf: &'a mut [u8], + pos: uint, + } + impl<'a> FormatWriter for BufWriter<'a> { + fn write(&mut self, bytes: &[u8]) -> fmt::Result { + let left = self.buf.mut_slice_from(self.pos); + let to_write = bytes.slice_to(cmp::min(bytes.len(), left.len())); + slice::bytes::copy_memory(left, to_write); + self.pos += to_write.len(); + Ok(()) + } + } + + // Convert the arguments into a stack-allocated string + let mut msg = [0u8, ..512]; + let mut w = BufWriter { buf: msg, pos: 0 }; + let _ = write!(&mut w, "{}", args); + let msg = str::from_utf8(w.buf.slice_to(w.pos)).unwrap_or("aborted"); + let msg = if msg.is_empty() {"aborted"} else {msg}; + + // Give some context to the message + let hash = msg.bytes().fold(0, |accum, val| accum + (val as uint) ); + let quote = match hash % 10 { + 0 => " +It was from the artists and poets that the pertinent answers came, and I +know that panic would have broken loose had they been able to compare notes. +As it was, lacking their original letters, I half suspected the compiler of +having asked leading questions, or of having edited the correspondence in +corroboration of what he had latently resolved to see.", + 1 => " +There are not many persons who know what wonders are opened to them in the +stories and visions of their youth; for when as children we listen and dream, +we think but half-formed thoughts, and when as men we try to remember, we are +dulled and prosaic with the poison of life. But some of us awake in the night +with strange phantasms of enchanted hills and gardens, of fountains that sing +in the sun, of golden cliffs overhanging murmuring seas, of plains that stretch +down to sleeping cities of bronze and stone, and of shadowy companies of heroes +that ride caparisoned white horses along the edges of thick forests; and then +we know that we have looked back through the ivory gates into that world of +wonder which was ours before we were wise and unhappy.", + 2 => " +Instead of the poems I had hoped for, there came only a shuddering blackness +and ineffable loneliness; and I saw at last a fearful truth which no one had +ever dared to breathe before — the unwhisperable secret of secrets — The fact +that this city of stone and stridor is not a sentient perpetuation of Old New +York as London is of Old London and Paris of Old Paris, but that it is in fact +quite dead, its sprawling body imperfectly embalmed and infested with queer +animate things which have nothing to do with it as it was in life.", + 3 => " +The ocean ate the last of the land and poured into the smoking gulf, thereby +giving up all it had ever conquered. From the new-flooded lands it flowed +again, uncovering death and decay; and from its ancient and immemorial bed it +trickled loathsomely, uncovering nighted secrets of the years when Time was +young and the gods unborn. Above the waves rose weedy remembered spires. The +moon laid pale lilies of light on dead London, and Paris stood up from its damp +grave to be sanctified with star-dust. Then rose spires and monoliths that were +weedy but not remembered; terrible spires and monoliths of lands that men never +knew were lands...", + 4 => " +There was a night when winds from unknown spaces whirled us irresistibly into +limitless vacuum beyond all thought and entity. Perceptions of the most +maddeningly untransmissible sort thronged upon us; perceptions of infinity +which at the time convulsed us with joy, yet which are now partly lost to my +memory and partly incapable of presentation to others.", + _ => "You've met with a terrible fate, haven't you?" + }; + rterrln!("{}", ""); + rterrln!("{}", quote); + rterrln!("{}", ""); + rterrln!("fatal runtime error: {}", msg); + unsafe { intrinsics::abort(); } +} diff --git a/src/librustuv/addrinfo.rs b/src/librustuv/addrinfo.rs index 1e18f2ea9ec25..daca3005f12ff 100644 --- a/src/librustuv/addrinfo.rs +++ b/src/librustuv/addrinfo.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ai = std::io::net::addrinfo; use libc::c_int; use libc; use std::mem; use std::ptr::null; use std::rt::task::BlockedTask; +use std::rt::rtio; use net; use super::{Loop, UvError, Request, wait_until_woken_after, wakeup}; @@ -33,7 +33,9 @@ pub struct GetAddrInfoRequest; impl GetAddrInfoRequest { pub fn run(loop_: &Loop, node: Option<&str>, service: Option<&str>, - hints: Option) -> Result, UvError> { + hints: Option) + -> Result, UvError> + { assert!(node.is_some() || service.is_some()); let (_c_node, c_node_ptr) = match node { Some(n) => { @@ -54,20 +56,11 @@ impl GetAddrInfoRequest { }; let hint = hints.map(|hint| { - let mut flags = 0; - each_ai_flag(|cval, aival| { - if hint.flags & (aival as uint) != 0 { - flags |= cval as i32; - } - }); - let socktype = 0; - let protocol = 0; - libc::addrinfo { - ai_flags: flags, + ai_flags: 0, ai_family: hint.family as c_int, - ai_socktype: socktype, - ai_protocol: protocol, + ai_socktype: 0, + ai_protocol: 0, ai_addrlen: 0, ai_canonname: null(), ai_addr: null(), @@ -119,22 +112,8 @@ impl Drop for Addrinfo { } } -fn each_ai_flag(_f: |c_int, ai::Flag|) { - /* FIXME: do we really want to support these? - unsafe { - f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig); - f(uvll::rust_AI_ALL(), ai::All); - f(uvll::rust_AI_CANONNAME(), ai::CanonName); - f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost); - f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ); - f(uvll::rust_AI_PASSIVE(), ai::Passive); - f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped); - } - */ -} - // Traverse the addrinfo linked list, producing a vector of Rust socket addresses -pub fn accum_addrinfo(addr: &Addrinfo) -> Vec { +pub fn accum_addrinfo(addr: &Addrinfo) -> Vec { unsafe { let mut addr = addr.handle; @@ -143,35 +122,12 @@ pub fn accum_addrinfo(addr: &Addrinfo) -> Vec { let rustaddr = net::sockaddr_to_addr(mem::transmute((*addr).ai_addr), (*addr).ai_addrlen as uint); - let mut flags = 0; - each_ai_flag(|cval, aival| { - if (*addr).ai_flags & cval != 0 { - flags |= aival as uint; - } - }); - - /* FIXME: do we really want to support these - let protocol = match (*addr).ai_protocol { - p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP), - p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP), - _ => None, - }; - let socktype = match (*addr).ai_socktype { - p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream), - p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram), - p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw), - _ => None, - }; - */ - let protocol = None; - let socktype = None; - - addrs.push(ai::Info { + addrs.push(rtio::AddrinfoInfo { address: rustaddr, family: (*addr).ai_family as uint, - socktype: socktype, - protocol: protocol, - flags: flags, + socktype: 0, + protocol: 0, + flags: 0, }); if (*addr).ai_next.is_not_null() { addr = (*addr).ai_next; diff --git a/src/librustuv/async.rs b/src/librustuv/async.rs index 7a16baaa9f2a6..5167ce5aff2d9 100644 --- a/src/librustuv/async.rs +++ b/src/librustuv/async.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use alloc::arc::Arc; use std::mem; +use std::rt::exclusive::Exclusive; use std::rt::rtio::{Callback, RemoteCallback}; -use std::unstable::sync::Exclusive; use uvll; use super::{Loop, UvHandle}; @@ -22,12 +23,12 @@ pub struct AsyncWatcher { // A flag to tell the callback to exit, set from the dtor. This is // almost never contested - only in rare races with the dtor. - exit_flag: Exclusive + exit_flag: Arc>, } struct Payload { callback: Box, - exit_flag: Exclusive, + exit_flag: Arc>, } impl AsyncWatcher { @@ -36,7 +37,7 @@ impl AsyncWatcher { assert_eq!(unsafe { uvll::uv_async_init(loop_.handle, handle, async_cb) }, 0); - let flag = Exclusive::new(false); + let flag = Arc::new(Exclusive::new(false)); let payload = box Payload { callback: cb, exit_flag: flag.clone() }; unsafe { let payload: *u8 = mem::transmute(payload); @@ -80,9 +81,7 @@ extern fn async_cb(handle: *uvll::uv_async_t) { // could be called in the other thread, missing the final // callback while still destroying the handle. - let should_exit = unsafe { - payload.exit_flag.with_imm(|&should_exit| should_exit) - }; + let should_exit = unsafe { *payload.exit_flag.lock() }; payload.callback.call(); @@ -108,16 +107,13 @@ impl RemoteCallback for AsyncWatcher { impl Drop for AsyncWatcher { fn drop(&mut self) { - unsafe { - self.exit_flag.with(|should_exit| { - // NB: These two things need to happen atomically. Otherwise - // the event handler could wake up due to a *previous* - // signal and see the exit flag, destroying the handle - // before the final send. - *should_exit = true; - uvll::uv_async_send(self.handle) - }) - } + let mut should_exit = unsafe { self.exit_flag.lock() }; + // NB: These two things need to happen atomically. Otherwise + // the event handler could wake up due to a *previous* + // signal and see the exit flag, destroying the handle + // before the final send. + *should_exit = true; + unsafe { uvll::uv_async_send(self.handle) } } } diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 7143f420b08a1..4b1343045de37 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -12,9 +12,9 @@ use libc::{c_int, c_char, c_void, ssize_t}; use libc; use std::c_str::CString; use std::c_str; -use std::io::{FileStat, IoError}; -use std::io; use std::mem; +use std::os; +use std::rt::rtio::{IoResult, IoError}; use std::rt::rtio; use std::rt::task::BlockedTask; @@ -56,21 +56,23 @@ impl FsRequest { }) } - pub fn lstat(loop_: &Loop, path: &CString) -> Result { + pub fn lstat(loop_: &Loop, path: &CString) + -> Result + { execute(|req, cb| unsafe { uvll::uv_fs_lstat(loop_.handle, req, path.with_ref(|p| p), cb) }).map(|req| req.mkstat()) } - pub fn stat(loop_: &Loop, path: &CString) -> Result { + pub fn stat(loop_: &Loop, path: &CString) -> Result { execute(|req, cb| unsafe { uvll::uv_fs_stat(loop_.handle, req, path.with_ref(|p| p), cb) }).map(|req| req.mkstat()) } - pub fn fstat(loop_: &Loop, fd: c_int) -> Result { + pub fn fstat(loop_: &Loop, fd: c_int) -> Result { execute(|req, cb| unsafe { uvll::uv_fs_fstat(loop_.handle, req, fd, cb) }).map(|req| req.mkstat()) @@ -157,7 +159,7 @@ impl FsRequest { } pub fn readdir(loop_: &Loop, path: &CString, flags: c_int) - -> Result, UvError> + -> Result, UvError> { execute(|req, cb| unsafe { uvll::uv_fs_readdir(loop_.handle, @@ -170,20 +172,22 @@ impl FsRequest { Some(req.get_result() as uint), |rel| { let p = rel.as_bytes(); - paths.push(parent.join(p.slice_to(rel.len()))); + paths.push(parent.join(p.slice_to(rel.len())).to_c_str()); }); paths }) } - pub fn readlink(loop_: &Loop, path: &CString) -> Result { + pub fn readlink(loop_: &Loop, path: &CString) -> Result { execute(|req, cb| unsafe { uvll::uv_fs_readlink(loop_.handle, req, path.with_ref(|p| p), cb) }).map(|req| { - Path::new(unsafe { - CString::new(req.get_ptr() as *libc::c_char, false) - }) + // Be sure to clone the cstring so we get an independently owned + // allocation to work with and return. + unsafe { + CString::new(req.get_ptr() as *libc::c_char, false).clone() + } }) } @@ -267,40 +271,30 @@ impl FsRequest { unsafe { uvll::get_ptr_from_fs_req(self.req) } } - pub fn mkstat(&self) -> FileStat { + pub fn mkstat(&self) -> rtio::FileStat { let stat = self.get_stat(); fn to_msec(stat: uvll::uv_timespec_t) -> u64 { // Be sure to cast to u64 first to prevent overflowing if the tv_sec // field is a 32-bit integer. (stat.tv_sec as u64) * 1000 + (stat.tv_nsec as u64) / 1000000 } - let kind = match (stat.st_mode as c_int) & libc::S_IFMT { - libc::S_IFREG => io::TypeFile, - libc::S_IFDIR => io::TypeDirectory, - libc::S_IFIFO => io::TypeNamedPipe, - libc::S_IFBLK => io::TypeBlockSpecial, - libc::S_IFLNK => io::TypeSymlink, - _ => io::TypeUnknown, - }; - FileStat { + rtio::FileStat { size: stat.st_size as u64, - kind: kind, - perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32), + kind: stat.st_mode as u64, + perm: stat.st_mode as u64, created: to_msec(stat.st_birthtim), modified: to_msec(stat.st_mtim), accessed: to_msec(stat.st_atim), - unstable: io::UnstableFileStat { - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize: stat.st_blksize as u64, - blocks: stat.st_blocks as u64, - flags: stat.st_flags as u64, - gen: stat.st_gen as u64, - } + device: stat.st_dev as u64, + inode: stat.st_ino as u64, + rdev: stat.st_rdev as u64, + nlink: stat.st_nlink as u64, + uid: stat.st_uid as u64, + gid: stat.st_gid as u64, + blksize: stat.st_blksize as u64, + blocks: stat.st_blocks as u64, + flags: stat.st_flags as u64, + gen: stat.st_gen as u64, } } } @@ -367,29 +361,26 @@ impl FileWatcher { } } - fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result { + fn base_read(&mut self, buf: &mut [u8], offset: i64) -> IoResult { let _m = self.fire_homing_missile(); let r = FsRequest::read(&self.loop_, self.fd, buf, offset); r.map_err(uv_error_to_io_error) } - fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { + fn base_write(&mut self, buf: &[u8], offset: i64) -> IoResult<()> { let _m = self.fire_homing_missile(); let r = FsRequest::write(&self.loop_, self.fd, buf, offset); r.map_err(uv_error_to_io_error) } - fn seek_common(&self, pos: i64, whence: c_int) -> - Result{ - unsafe { - match libc::lseek(self.fd, pos as libc::off_t, whence) { - -1 => { - Err(IoError { - kind: io::OtherIoError, - desc: "Failed to lseek.", - detail: None - }) - }, - n => Ok(n as u64) - } + fn seek_common(&self, pos: i64, whence: c_int) -> IoResult{ + match unsafe { libc::lseek(self.fd, pos as libc::off_t, whence) } { + -1 => { + Err(IoError { + code: os::errno() as uint, + extra: 0, + detail: None, + }) + }, + n => Ok(n as u64) } } } @@ -423,47 +414,47 @@ impl Drop for FileWatcher { } impl rtio::RtioFileStream for FileWatcher { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { self.base_read(buf, -1) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.base_write(buf, -1) } - fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result { + fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { self.base_read(buf, offset as i64) } - fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> { + fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> { self.base_write(buf, offset as i64) } - fn seek(&mut self, pos: i64, whence: io::SeekStyle) -> Result { + fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult { use libc::{SEEK_SET, SEEK_CUR, SEEK_END}; let whence = match whence { - io::SeekSet => SEEK_SET, - io::SeekCur => SEEK_CUR, - io::SeekEnd => SEEK_END + rtio::SeekSet => SEEK_SET, + rtio::SeekCur => SEEK_CUR, + rtio::SeekEnd => SEEK_END }; self.seek_common(pos, whence) } - fn tell(&self) -> Result { + fn tell(&self) -> IoResult { use libc::SEEK_CUR; self.seek_common(0, SEEK_CUR) } - fn fsync(&mut self) -> Result<(), IoError> { + fn fsync(&mut self) -> IoResult<()> { let _m = self.fire_homing_missile(); FsRequest::fsync(&self.loop_, self.fd).map_err(uv_error_to_io_error) } - fn datasync(&mut self) -> Result<(), IoError> { + fn datasync(&mut self) -> IoResult<()> { let _m = self.fire_homing_missile(); FsRequest::datasync(&self.loop_, self.fd).map_err(uv_error_to_io_error) } - fn truncate(&mut self, offset: i64) -> Result<(), IoError> { + fn truncate(&mut self, offset: i64) -> IoResult<()> { let _m = self.fire_homing_missile(); let r = FsRequest::truncate(&self.loop_, self.fd, offset); r.map_err(uv_error_to_io_error) } - fn fstat(&mut self) -> Result { + fn fstat(&mut self) -> IoResult { let _m = self.fire_homing_missile(); FsRequest::fstat(&self.loop_, self.fd).map_err(uv_error_to_io_error) } @@ -473,7 +464,6 @@ impl rtio::RtioFileStream for FileWatcher { mod test { use libc::c_int; use libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR}; - use std::io; use std::str; use super::FsRequest; use super::super::Loop; @@ -560,10 +550,6 @@ mod test { let result = FsRequest::mkdir(l(), path, mode); assert!(result.is_ok()); - let result = FsRequest::stat(l(), path); - assert!(result.is_ok()); - assert!(result.unwrap().kind == io::TypeDirectory); - let result = FsRequest::rmdir(l(), path); assert!(result.is_ok()); diff --git a/src/librustuv/homing.rs b/src/librustuv/homing.rs index 4f565de6791d4..644ac4e45f656 100644 --- a/src/librustuv/homing.rs +++ b/src/librustuv/homing.rs @@ -153,8 +153,7 @@ mod test { use green::sched; use green::{SchedPool, PoolConfig}; use std::rt::rtio::RtioUdpSocket; - use std::io::test::next_test_ip4; - use std::task::TaskOpts; + use std::rt::task::TaskOpts; use net::UdpWatcher; use super::super::local_loop; @@ -172,7 +171,7 @@ mod test { }); pool.spawn(TaskOpts::new(), proc() { - let listener = UdpWatcher::bind(local_loop(), next_test_ip4()); + let listener = UdpWatcher::bind(local_loop(), ::next_test_ip4()); tx.send(listener.unwrap()); }); @@ -193,18 +192,18 @@ mod test { }); pool.spawn(TaskOpts::new(), proc() { - let addr1 = next_test_ip4(); - let addr2 = next_test_ip4(); + let addr1 = ::next_test_ip4(); + let addr2 = ::next_test_ip4(); let listener = UdpWatcher::bind(local_loop(), addr2); tx.send((listener.unwrap(), addr1)); let mut listener = UdpWatcher::bind(local_loop(), addr1).unwrap(); - listener.sendto([1, 2, 3, 4], addr2).unwrap(); + listener.sendto([1, 2, 3, 4], addr2).ok().unwrap(); }); let task = pool.task(TaskOpts::new(), proc() { let (mut watcher, addr) = rx.recv(); let mut buf = [0, ..10]; - assert_eq!(watcher.recvfrom(buf).unwrap(), (4, addr)); + assert!(watcher.recvfrom(buf).ok().unwrap() == (4, addr)); }); pool.spawn_sched().send(sched::TaskFromFriend(task)); diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index 20893b9e84c88..e2122aea0365e 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -51,16 +51,14 @@ extern crate alloc; use libc::{c_int, c_void}; use std::fmt; -use std::io::IoError; -use std::io; use std::mem; use std::ptr::null; use std::ptr; use std::rt::local::Local; use std::rt::rtio; +use std::rt::rtio::{IoResult, IoError}; use std::rt::task::{BlockedTask, Task}; use std::str::raw::from_c_str; -use std::str; use std::task; pub use self::async::AsyncWatcher; @@ -391,40 +389,40 @@ fn error_smoke_test() { assert_eq!(err.to_str(), "EOF: end of file".to_string()); } +#[cfg(unix)] pub fn uv_error_to_io_error(uverr: UvError) -> IoError { - unsafe { - // Importing error constants - - // uv error descriptions are static - let UvError(errcode) = uverr; - let c_desc = uvll::uv_strerror(errcode); - let desc = str::raw::c_str_to_static_slice(c_desc); - - let kind = match errcode { - uvll::UNKNOWN => io::OtherIoError, - uvll::OK => io::OtherIoError, - uvll::EOF => io::EndOfFile, - uvll::EACCES => io::PermissionDenied, - uvll::ECONNREFUSED => io::ConnectionRefused, - uvll::ECONNRESET => io::ConnectionReset, - uvll::ENOTCONN => io::NotConnected, - uvll::ENOENT => io::FileNotFound, - uvll::EPIPE => io::BrokenPipe, - uvll::ECONNABORTED => io::ConnectionAborted, - uvll::EADDRNOTAVAIL => io::ConnectionRefused, - uvll::ECANCELED => io::TimedOut, + let UvError(errcode) = uverr; + IoError { + code: if errcode == uvll::EOF {libc::EOF as uint} else {-errcode as uint}, + extra: 0, + detail: Some(uverr.desc()), + } +} + +#[cfg(windows)] +pub fn uv_error_to_io_error(uverr: UvError) -> IoError { + let UvError(errcode) = uverr; + IoError { + code: match errcode { + uvll::EOF => libc::EOF, + uvll::EACCES => libc::ERROR_ACCESS_DENIED, + uvll::ECONNREFUSED => libc::WSAECONNREFUSED, + uvll::ECONNRESET => libc::WSAECONNRESET, + uvll::ENOTCONN => libc::WSAENOTCONN, + uvll::ENOENT => libc::ERROR_FILE_NOT_FOUND, + uvll::EPIPE => libc::ERROR_NO_DATA, + uvll::ECONNABORTED => libc::WSAECONNABORTED, + uvll::EADDRNOTAVAIL => libc::WSAEADDRNOTAVAIL, + uvll::ECANCELED => libc::ERROR_OPERATION_ABORTED, + uvll::EADDRINUSE => libc::WSAEADDRINUSE, err => { uvdebug!("uverr.code {}", err as int); // FIXME: Need to map remaining uv error types - io::OtherIoError + -1 } - }; - - IoError { - kind: kind, - desc: desc, - detail: None - } + } as uint, + extra: 0, + detail: Some(uverr.desc()), } } @@ -437,7 +435,7 @@ pub fn status_to_maybe_uv_error(status: c_int) -> Option { } } -pub fn status_to_io_result(status: c_int) -> Result<(), IoError> { +pub fn status_to_io_result(status: c_int) -> IoResult<()> { if status >= 0 {Ok(())} else {Err(uv_error_to_io_error(UvError(status)))} } @@ -471,6 +469,33 @@ fn local_loop() -> &'static mut uvio::UvIoFactory { } } +#[cfg(test)] +fn next_test_ip4() -> std::rt::rtio::SocketAddr { + use std::io; + use std::rt::rtio; + + let io::net::ip::SocketAddr { ip, port } = io::test::next_test_ip4(); + let ip = match ip { + io::net::ip::Ipv4Addr(a, b, c, d) => rtio::Ipv4Addr(a, b, c, d), + _ => unreachable!(), + }; + rtio::SocketAddr { ip: ip, port: port } +} + +#[cfg(test)] +fn next_test_ip6() -> std::rt::rtio::SocketAddr { + use std::io; + use std::rt::rtio; + + let io::net::ip::SocketAddr { ip, port } = io::test::next_test_ip6(); + let ip = match ip { + io::net::ip::Ipv6Addr(a, b, c, d, e, f, g, h) => + rtio::Ipv6Addr(a, b, c, d, e, f, g, h), + _ => unreachable!(), + }; + rtio::SocketAddr { ip: ip, port: port } +} + #[cfg(test)] mod test { use std::mem::transmute; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 2f35e48b8476b..e7bdc25a1fd91 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -10,12 +10,10 @@ use libc::{size_t, ssize_t, c_int, c_void, c_uint}; use libc; -use std::io; -use std::io::IoError; -use std::io::net::ip; use std::mem; use std::ptr; use std::rt::rtio; +use std::rt::rtio::IoError; use std::rt::task::BlockedTask; use homing::{HomingIO, HomeHandle}; @@ -36,7 +34,7 @@ pub fn htons(u: u16) -> u16 { mem::to_be16(u) } pub fn ntohs(u: u16) -> u16 { mem::from_be16(u) } pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, - len: uint) -> ip::SocketAddr { + len: uint) -> rtio::SocketAddr { match storage.ss_family as c_int { libc::AF_INET => { assert!(len as uint >= mem::size_of::()); @@ -48,8 +46,8 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let b = (ip >> 16) as u8; let c = (ip >> 8) as u8; let d = (ip >> 0) as u8; - ip::SocketAddr { - ip: ip::Ipv4Addr(a, b, c, d), + rtio::SocketAddr { + ip: rtio::Ipv4Addr(a, b, c, d), port: ntohs(storage.sin_port), } } @@ -66,8 +64,8 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, let f = ntohs(storage.sin6_addr.s6_addr[5]); let g = ntohs(storage.sin6_addr.s6_addr[6]); let h = ntohs(storage.sin6_addr.s6_addr[7]); - ip::SocketAddr { - ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h), + rtio::SocketAddr { + ip: rtio::Ipv6Addr(a, b, c, d, e, f, g, h), port: ntohs(storage.sin6_port), } } @@ -77,11 +75,11 @@ pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, } } -fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { +fn addr_to_sockaddr(addr: rtio::SocketAddr) -> (libc::sockaddr_storage, uint) { unsafe { let mut storage: libc::sockaddr_storage = mem::zeroed(); let len = match addr.ip { - ip::Ipv4Addr(a, b, c, d) => { + rtio::Ipv4Addr(a, b, c, d) => { let ip = (a as u32 << 24) | (b as u32 << 16) | (c as u32 << 8) | @@ -95,7 +93,7 @@ fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) { }; mem::size_of::() } - ip::Ipv6Addr(a, b, c, d, e, f, g, h) => { + rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => { let storage: &mut libc::sockaddr_in6 = mem::transmute(&mut storage); storage.sin6_family = libc::AF_INET6 as libc::sa_family_t; @@ -126,7 +124,7 @@ enum SocketNameKind { } fn socket_name(sk: SocketNameKind, - handle: *c_void) -> Result { + handle: *c_void) -> Result { let getsockname = match sk { TcpPeer => uvll::uv_tcp_getpeername, Tcp => uvll::uv_tcp_getsockname, @@ -201,7 +199,7 @@ impl TcpWatcher { } pub fn connect(io: &mut UvIoFactory, - address: ip::SocketAddr, + address: rtio::SocketAddr, timeout: Option) -> Result { let tcp = TcpWatcher::new(io); let cx = ConnectCtx { status: -1, task: None, timer: None }; @@ -218,7 +216,7 @@ impl HomingIO for TcpWatcher { } impl rtio::RtioSocket for TcpWatcher { - fn socket_name(&mut self) -> Result { + fn socket_name(&mut self) -> Result { let _m = self.fire_homing_missile(); socket_name(Tcp, self.handle) } @@ -231,7 +229,7 @@ impl rtio::RtioTcpStream for TcpWatcher { // see comments in close_read about this check if guard.access.is_closed() { - return Err(io::standard_error(io::EndOfFile)) + return Err(uv_error_to_io_error(UvError(uvll::EOF))) } self.stream.read(buf).map_err(uv_error_to_io_error) @@ -243,7 +241,7 @@ impl rtio::RtioTcpStream for TcpWatcher { self.stream.write(buf, guard.can_timeout).map_err(uv_error_to_io_error) } - fn peer_name(&mut self) -> Result { + fn peer_name(&mut self) -> Result { let _m = self.fire_homing_missile(); socket_name(TcpPeer, self.handle) } @@ -350,7 +348,7 @@ impl Drop for TcpWatcher { // TCP listeners (unbound servers) impl TcpListener { - pub fn bind(io: &mut UvIoFactory, address: ip::SocketAddr) + pub fn bind(io: &mut UvIoFactory, address: rtio::SocketAddr) -> Result, UvError> { let handle = unsafe { uvll::malloc_handle(uvll::UV_TCP) }; assert_eq!(unsafe { @@ -385,7 +383,7 @@ impl UvHandle for TcpListener { } impl rtio::RtioSocket for TcpListener { - fn socket_name(&mut self) -> Result { + fn socket_name(&mut self) -> Result { let _m = self.fire_homing_missile(); socket_name(Tcp, self.handle) } @@ -439,7 +437,7 @@ impl HomingIO for TcpAcceptor { } impl rtio::RtioSocket for TcpAcceptor { - fn socket_name(&mut self) -> Result { + fn socket_name(&mut self) -> Result { let _m = self.fire_homing_missile(); socket_name(Tcp, self.listener.handle) } @@ -492,7 +490,7 @@ pub struct UdpWatcher { struct UdpRecvCtx { task: Option, buf: Option, - result: Option<(ssize_t, Option)>, + result: Option<(ssize_t, Option)>, } struct UdpSendCtx { @@ -502,7 +500,7 @@ struct UdpSendCtx { } impl UdpWatcher { - pub fn bind(io: &mut UvIoFactory, address: ip::SocketAddr) + pub fn bind(io: &mut UvIoFactory, address: rtio::SocketAddr) -> Result { let udp = UdpWatcher { handle: unsafe { uvll::malloc_handle(uvll::UV_UDP) }, @@ -536,7 +534,7 @@ impl HomingIO for UdpWatcher { } impl rtio::RtioSocket for UdpWatcher { - fn socket_name(&mut self) -> Result { + fn socket_name(&mut self) -> Result { let _m = self.fire_homing_missile(); socket_name(Udp, self.handle) } @@ -544,7 +542,7 @@ impl rtio::RtioSocket for UdpWatcher { impl rtio::RtioUdpSocket for UdpWatcher { fn recvfrom(&mut self, buf: &mut [u8]) - -> Result<(uint, ip::SocketAddr), IoError> + -> Result<(uint, rtio::SocketAddr), IoError> { let loop_ = self.uv_loop(); let m = self.fire_homing_missile(); @@ -609,7 +607,7 @@ impl rtio::RtioUdpSocket for UdpWatcher { } } - fn sendto(&mut self, buf: &[u8], dst: ip::SocketAddr) -> Result<(), IoError> { + fn sendto(&mut self, buf: &[u8], dst: rtio::SocketAddr) -> Result<(), IoError> { let m = self.fire_homing_missile(); let loop_ = self.uv_loop(); let guard = try!(self.write_access.grant(m)); @@ -675,7 +673,7 @@ impl rtio::RtioUdpSocket for UdpWatcher { } } - fn join_multicast(&mut self, multi: ip::IpAddr) -> Result<(), IoError> { + fn join_multicast(&mut self, multi: rtio::IpAddr) -> Result<(), IoError> { let _m = self.fire_homing_missile(); status_to_io_result(unsafe { multi.to_str().with_c_str(|m_addr| { @@ -686,7 +684,7 @@ impl rtio::RtioUdpSocket for UdpWatcher { }) } - fn leave_multicast(&mut self, multi: ip::IpAddr) -> Result<(), IoError> { + fn leave_multicast(&mut self, multi: rtio::IpAddr) -> Result<(), IoError> { let _m = self.fire_homing_missile(); status_to_io_result(unsafe { multi.to_str().with_c_str(|m_addr| { @@ -843,14 +841,13 @@ pub fn shutdown(handle: *uvll::uv_stream_t, loop_: &Loop) -> Result<(), IoError> mod test { use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioTcpAcceptor, RtioUdpSocket}; - use std::io::test::{next_test_ip4, next_test_ip6}; use super::{UdpWatcher, TcpWatcher, TcpListener}; use super::super::local_loop; #[test] fn connect_close_ip4() { - match TcpWatcher::connect(local_loop(), next_test_ip4(), None) { + match TcpWatcher::connect(local_loop(), ::next_test_ip4(), None) { Ok(..) => fail!(), Err(e) => assert_eq!(e.name(), "ECONNREFUSED".to_string()), } @@ -858,7 +855,7 @@ mod test { #[test] fn connect_close_ip6() { - match TcpWatcher::connect(local_loop(), next_test_ip6(), None) { + match TcpWatcher::connect(local_loop(), ::next_test_ip6(), None) { Ok(..) => fail!(), Err(e) => assert_eq!(e.name(), "ECONNREFUSED".to_string()), } @@ -866,7 +863,7 @@ mod test { #[test] fn udp_bind_close_ip4() { - match UdpWatcher::bind(local_loop(), next_test_ip4()) { + match UdpWatcher::bind(local_loop(), ::next_test_ip4()) { Ok(..) => {} Err(..) => fail!() } @@ -874,7 +871,7 @@ mod test { #[test] fn udp_bind_close_ip6() { - match UdpWatcher::bind(local_loop(), next_test_ip6()) { + match UdpWatcher::bind(local_loop(), ::next_test_ip6()) { Ok(..) => {} Err(..) => fail!() } @@ -883,7 +880,7 @@ mod test { #[test] fn listen_ip4() { let (tx, rx) = channel(); - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); spawn(proc() { let w = match TcpListener::bind(local_loop(), addr) { @@ -919,7 +916,7 @@ mod test { #[test] fn listen_ip6() { let (tx, rx) = channel(); - let addr = next_test_ip6(); + let addr = ::next_test_ip6(); spawn(proc() { let w = match TcpListener::bind(local_loop(), addr) { @@ -955,8 +952,8 @@ mod test { #[test] fn udp_recv_ip4() { let (tx, rx) = channel(); - let client = next_test_ip4(); - let server = next_test_ip4(); + let client = ::next_test_ip4(); + let server = ::next_test_ip4(); spawn(proc() { match UdpWatcher::bind(local_loop(), server) { @@ -964,7 +961,7 @@ mod test { tx.send(()); let mut buf = [0u8, ..10]; match w.recvfrom(buf) { - Ok((10, addr)) => assert_eq!(addr, client), + Ok((10, addr)) => assert!(addr == client), e => fail!("{:?}", e), } for i in range(0, 10u8) { @@ -987,8 +984,8 @@ mod test { #[test] fn udp_recv_ip6() { let (tx, rx) = channel(); - let client = next_test_ip6(); - let server = next_test_ip6(); + let client = ::next_test_ip6(); + let server = ::next_test_ip6(); spawn(proc() { match UdpWatcher::bind(local_loop(), server) { @@ -996,7 +993,7 @@ mod test { tx.send(()); let mut buf = [0u8, ..10]; match w.recvfrom(buf) { - Ok((10, addr)) => assert_eq!(addr, client), + Ok((10, addr)) => assert!(addr == client), e => fail!("{:?}", e), } for i in range(0, 10u8) { @@ -1018,15 +1015,15 @@ mod test { #[test] fn test_read_read_read() { - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); static MAX: uint = 5000; let (tx, rx) = channel(); spawn(proc() { let listener = TcpListener::bind(local_loop(), addr).unwrap(); - let mut acceptor = listener.listen().unwrap(); + let mut acceptor = listener.listen().ok().unwrap(); tx.send(()); - let mut stream = acceptor.accept().unwrap(); + let mut stream = acceptor.accept().ok().unwrap(); let buf = [1, .. 2048]; let mut total_bytes_written = 0; while total_bytes_written < MAX { @@ -1041,7 +1038,7 @@ mod test { let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; while total_bytes_read < MAX { - let nread = stream.read(buf).unwrap(); + let nread = stream.read(buf).ok().unwrap(); total_bytes_read += nread; for i in range(0u, nread) { assert_eq!(buf[i], 1); @@ -1053,8 +1050,8 @@ mod test { #[test] #[ignore(cfg(windows))] // FIXME(#10102) server never sees second packet fn test_udp_twice() { - let server_addr = next_test_ip4(); - let client_addr = next_test_ip4(); + let server_addr = ::next_test_ip4(); + let client_addr = ::next_test_ip4(); let (tx, rx) = channel(); spawn(proc() { @@ -1068,22 +1065,22 @@ mod test { tx.send(()); let mut buf1 = [0]; let mut buf2 = [0]; - let (nread1, src1) = server.recvfrom(buf1).unwrap(); - let (nread2, src2) = server.recvfrom(buf2).unwrap(); + let (nread1, src1) = server.recvfrom(buf1).ok().unwrap(); + let (nread2, src2) = server.recvfrom(buf2).ok().unwrap(); assert_eq!(nread1, 1); assert_eq!(nread2, 1); - assert_eq!(src1, client_addr); - assert_eq!(src2, client_addr); + assert!(src1 == client_addr); + assert!(src2 == client_addr); assert_eq!(buf1[0], 1); assert_eq!(buf2[0], 2); } #[test] fn test_udp_many_read() { - let server_out_addr = next_test_ip4(); - let server_in_addr = next_test_ip4(); - let client_out_addr = next_test_ip4(); - let client_in_addr = next_test_ip4(); + let server_out_addr = ::next_test_ip4(); + let server_in_addr = ::next_test_ip4(); + let client_out_addr = ::next_test_ip4(); + let client_in_addr = ::next_test_ip4(); static MAX: uint = 500_000; let (tx1, rx1) = channel::<()>(); @@ -1106,9 +1103,9 @@ mod test { // check if the client has received enough let res = server_in.recvfrom(buf); assert!(res.is_ok()); - let (nread, src) = res.unwrap(); + let (nread, src) = res.ok().unwrap(); assert_eq!(nread, 1); - assert_eq!(src, client_out_addr); + assert!(src == client_out_addr); } assert!(total_bytes_sent >= MAX); }); @@ -1127,8 +1124,8 @@ mod test { // wait for data let res = client_in.recvfrom(buf); assert!(res.is_ok()); - let (nread, src) = res.unwrap(); - assert_eq!(src, server_out_addr); + let (nread, src) = res.ok().unwrap(); + assert!(src == server_out_addr); total_bytes_recv += nread; for i in range(0u, nread) { assert_eq!(buf[i], 1); @@ -1140,25 +1137,25 @@ mod test { #[test] fn test_read_and_block() { - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); let (tx, rx) = channel::>(); spawn(proc() { let rx = rx.recv(); let mut stream = TcpWatcher::connect(local_loop(), addr, None).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]).ok().unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]).ok().unwrap(); rx.recv(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]).ok().unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]).ok().unwrap(); rx.recv(); }); let listener = TcpListener::bind(local_loop(), addr).unwrap(); - let mut acceptor = listener.listen().unwrap(); + let mut acceptor = listener.listen().ok().unwrap(); let (tx2, rx2) = channel(); tx.send(rx2); - let mut stream = acceptor.accept().unwrap(); + let mut stream = acceptor.accept().ok().unwrap(); let mut buf = [0, .. 2048]; let expected = 32; @@ -1166,7 +1163,7 @@ mod test { let mut reads = 0; while current < expected { - let nread = stream.read(buf).unwrap(); + let nread = stream.read(buf).ok().unwrap(); for i in range(0u, nread) { let val = buf[i] as uint; assert_eq!(val, current % 8); @@ -1183,14 +1180,14 @@ mod test { #[test] fn test_simple_tcp_server_and_client_on_diff_threads() { - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); spawn(proc() { let listener = TcpListener::bind(local_loop(), addr).unwrap(); - let mut acceptor = listener.listen().unwrap(); - let mut stream = acceptor.accept().unwrap(); + let mut acceptor = listener.listen().ok().unwrap(); + let mut stream = acceptor.accept().ok().unwrap(); let mut buf = [0, .. 2048]; - let nread = stream.read(buf).unwrap(); + let nread = stream.read(buf).ok().unwrap(); assert_eq!(nread, 8); for i in range(0u, nread) { assert_eq!(buf[i], i as u8); @@ -1201,27 +1198,27 @@ mod test { while stream.is_err() { stream = TcpWatcher::connect(local_loop(), addr, None); } - stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); + stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]).ok().unwrap(); } #[should_fail] #[test] fn tcp_listener_fail_cleanup() { - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); let w = TcpListener::bind(local_loop(), addr).unwrap(); - let _w = w.listen().unwrap(); + let _w = w.listen().ok().unwrap(); fail!(); } #[should_fail] #[test] fn tcp_stream_fail_cleanup() { let (tx, rx) = channel(); - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); spawn(proc() { let w = TcpListener::bind(local_loop(), addr).unwrap(); - let mut w = w.listen().unwrap(); + let mut w = w.listen().ok().unwrap(); tx.send(()); - drop(w.accept().unwrap()); + drop(w.accept().ok().unwrap()); }); rx.recv(); let _w = TcpWatcher::connect(local_loop(), addr, None).unwrap(); @@ -1230,14 +1227,14 @@ mod test { #[should_fail] #[test] fn udp_listener_fail_cleanup() { - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); let _w = UdpWatcher::bind(local_loop(), addr).unwrap(); fail!(); } #[should_fail] #[test] fn udp_fail_other_task() { - let addr = next_test_ip4(); + let addr = ::next_test_ip4(); let (tx, rx) = channel(); // force the handle to be created on a different scheduler, failure in diff --git a/src/librustuv/pipe.rs b/src/librustuv/pipe.rs index cf3d4f672e618..e5c134b6b9268 100644 --- a/src/librustuv/pipe.rs +++ b/src/librustuv/pipe.rs @@ -10,10 +10,9 @@ use libc; use std::c_str::CString; -use std::io::IoError; -use std::io; use std::mem; -use std::rt::rtio::{RtioPipe, RtioUnixListener, RtioUnixAcceptor}; +use std::rt::rtio; +use std::rt::rtio::IoResult; use std::rt::task::BlockedTask; use homing::{HomingIO, HomeHandle}; @@ -39,8 +38,8 @@ pub struct PipeWatcher { pub struct PipeListener { home: HomeHandle, pipe: *uvll::uv_pipe_t, - outgoing: Sender, IoError>>, - incoming: Receiver, IoError>>, + outgoing: Sender>>, + incoming: Receiver>>, } pub struct PipeAcceptor { @@ -111,26 +110,26 @@ impl PipeWatcher { } } -impl RtioPipe for PipeWatcher { - fn read(&mut self, buf: &mut [u8]) -> Result { +impl rtio::RtioPipe for PipeWatcher { + fn read(&mut self, buf: &mut [u8]) -> IoResult { let m = self.fire_homing_missile(); let guard = try!(self.read_access.grant(m)); // see comments in close_read about this check if guard.access.is_closed() { - return Err(io::standard_error(io::EndOfFile)) + return Err(uv_error_to_io_error(UvError(uvll::EOF))) } self.stream.read(buf).map_err(uv_error_to_io_error) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { let m = self.fire_homing_missile(); let guard = try!(self.write_access.grant(m)); self.stream.write(buf, guard.can_timeout).map_err(uv_error_to_io_error) } - fn clone(&self) -> Box { + fn clone(&self) -> Box { box PipeWatcher { stream: StreamWatcher::new(self.stream.handle), defused: false, @@ -138,10 +137,10 @@ impl RtioPipe for PipeWatcher { refcount: self.refcount.clone(), read_access: self.read_access.clone(), write_access: self.write_access.clone(), - } as Box + } as Box } - fn close_read(&mut self) -> Result<(), IoError> { + fn close_read(&mut self) -> IoResult<()> { // The current uv_shutdown method only shuts the writing half of the // connection, and no method is provided to shut down the reading half // of the connection. With a lack of method, we emulate shutting down @@ -168,7 +167,7 @@ impl RtioPipe for PipeWatcher { Ok(()) } - fn close_write(&mut self) -> Result<(), IoError> { + fn close_write(&mut self) -> IoResult<()> { let _m = self.fire_homing_missile(); net::shutdown(self.stream.handle, &self.uv_loop()) } @@ -248,8 +247,8 @@ impl PipeListener { } } -impl RtioUnixListener for PipeListener { - fn listen(~self) -> Result, IoError> { +impl rtio::RtioUnixListener for PipeListener { + fn listen(~self) -> IoResult> { // create the acceptor object from ourselves let mut acceptor = box PipeAcceptor { listener: self, @@ -259,7 +258,7 @@ impl RtioUnixListener for PipeListener { let _m = acceptor.fire_homing_missile(); // FIXME: the 128 backlog should be configurable match unsafe { uvll::uv_listen(acceptor.listener.pipe, 128, listen_cb) } { - 0 => Ok(acceptor as Box), + 0 => Ok(acceptor as Box), n => Err(uv_error_to_io_error(UvError(n))), } } @@ -284,7 +283,7 @@ extern fn listen_cb(server: *uvll::uv_stream_t, status: libc::c_int) { }); let client = PipeWatcher::new_home(&loop_, pipe.home().clone(), false); assert_eq!(unsafe { uvll::uv_accept(server, client.handle()) }, 0); - Ok(box client as Box) + Ok(box client as Box) } n => Err(uv_error_to_io_error(UvError(n))) }; @@ -300,8 +299,8 @@ impl Drop for PipeListener { // PipeAcceptor implementation and traits -impl RtioUnixAcceptor for PipeAcceptor { - fn accept(&mut self) -> Result, IoError> { +impl rtio::RtioUnixAcceptor for PipeAcceptor { + fn accept(&mut self) -> IoResult> { self.timeout.accept(&self.listener.incoming) } @@ -366,11 +365,11 @@ mod tests { spawn(proc() { let p = PipeListener::bind(local_loop(), &path2.to_c_str()).unwrap(); - let mut p = p.listen().unwrap(); + let mut p = p.listen().ok().unwrap(); tx.send(()); - let mut client = p.accept().unwrap(); + let mut client = p.accept().ok().unwrap(); let mut buf = [0]; - assert!(client.read(buf).unwrap() == 1); + assert!(client.read(buf).ok().unwrap() == 1); assert_eq!(buf[0], 1); assert!(client.write([2]).is_ok()); }); @@ -378,7 +377,7 @@ mod tests { let mut c = PipeWatcher::connect(local_loop(), &path.to_c_str(), None).unwrap(); assert!(c.write([1]).is_ok()); let mut buf = [0]; - assert!(c.read(buf).unwrap() == 1); + assert!(c.read(buf).ok().unwrap() == 1); assert_eq!(buf[0], 2); } @@ -390,9 +389,9 @@ mod tests { spawn(proc() { let p = PipeListener::bind(local_loop(), &path2.to_c_str()).unwrap(); - let mut p = p.listen().unwrap(); + let mut p = p.listen().ok().unwrap(); tx.send(()); - drop(p.accept().unwrap()); + drop(p.accept().ok().unwrap()); }); rx.recv(); let _c = PipeWatcher::connect(local_loop(), &path.to_c_str(), None).unwrap(); diff --git a/src/librustuv/process.rs b/src/librustuv/process.rs index f6fcf3e48162f..aa87582da26d8 100644 --- a/src/librustuv/process.rs +++ b/src/librustuv/process.rs @@ -10,11 +10,10 @@ use libc::c_int; use libc; -use std::io::IoError; -use std::io::process; use std::ptr; use std::c_str::CString; -use std::rt::rtio::{ProcessConfig, RtioProcess}; +use std::rt::rtio; +use std::rt::rtio::IoResult; use std::rt::task::BlockedTask; use homing::{HomingIO, HomeHandle}; @@ -33,7 +32,7 @@ pub struct Process { to_wake: Option, /// Collected from the exit_cb - exit_status: Option, + exit_status: Option, /// Lazily initialized timeout timer timer: Option>, @@ -51,7 +50,7 @@ impl Process { /// /// Returns either the corresponding process object or an error which /// occurred. - pub fn spawn(io_loop: &mut UvIoFactory, cfg: ProcessConfig) + pub fn spawn(io_loop: &mut UvIoFactory, cfg: rtio::ProcessConfig) -> Result<(Box, Vec>), UvError> { let mut io = vec![cfg.stdin, cfg.stdout, cfg.stderr]; for slot in cfg.extra_io.iter() { @@ -137,8 +136,8 @@ extern fn on_exit(handle: *uvll::uv_process_t, assert!(p.exit_status.is_none()); p.exit_status = Some(match term_signal { - 0 => process::ExitStatus(exit_status as int), - n => process::ExitSignal(n as int), + 0 => rtio::ExitStatus(exit_status as int), + n => rtio::ExitSignal(n as int), }); if p.to_wake.is_none() { return } @@ -146,19 +145,19 @@ extern fn on_exit(handle: *uvll::uv_process_t, } unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, - io: &process::StdioContainer, + io: &rtio::StdioContainer, io_loop: &mut UvIoFactory) -> Option { match *io { - process::Ignored => { + rtio::Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); None } - process::InheritFd(fd) => { + rtio::InheritFd(fd) => { uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD); uvll::set_stdio_container_fd(dst, fd); None } - process::CreatePipe(readable, writable) => { + rtio::CreatePipe(readable, writable) => { let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int; if readable { flags |= uvll::STDIO_READABLE_PIPE as libc::c_int; @@ -231,12 +230,12 @@ impl UvHandle for Process { fn uv_handle(&self) -> *uvll::uv_process_t { self.handle } } -impl RtioProcess for Process { +impl rtio::RtioProcess for Process { fn id(&self) -> libc::pid_t { unsafe { uvll::process_pid(self.handle) as libc::pid_t } } - fn kill(&mut self, signal: int) -> Result<(), IoError> { + fn kill(&mut self, signal: int) -> IoResult<()> { let _m = self.fire_homing_missile(); match unsafe { uvll::uv_process_kill(self.handle, signal as libc::c_int) @@ -246,7 +245,7 @@ impl RtioProcess for Process { } } - fn wait(&mut self) -> Result { + fn wait(&mut self) -> IoResult { // Make sure (on the home scheduler) that we have an exit status listed let _m = self.fire_homing_missile(); match self.exit_status { diff --git a/src/librustuv/queue.rs b/src/librustuv/queue.rs index 98ae865cb1da3..a3694bfe9c2be 100644 --- a/src/librustuv/queue.rs +++ b/src/librustuv/queue.rs @@ -23,8 +23,8 @@ use alloc::arc::Arc; use libc::c_void; use std::mem; +use std::rt::mutex::NativeMutex; use std::rt::task::BlockedTask; -use std::unstable::mutex::NativeMutex; use mpsc = std::sync::mpsc_queue; use async::AsyncWatcher; diff --git a/src/librustuv/signal.rs b/src/librustuv/signal.rs index b2e1c7520128b..fd0b6acb8ae74 100644 --- a/src/librustuv/signal.rs +++ b/src/librustuv/signal.rs @@ -9,8 +9,7 @@ // except according to those terms. use libc::c_int; -use std::io::signal::Signum; -use std::rt::rtio::RtioSignal; +use std::rt::rtio::{RtioSignal, Callback}; use homing::{HomingIO, HomeHandle}; use super::{UvError, UvHandle}; @@ -21,18 +20,16 @@ pub struct SignalWatcher { handle: *uvll::uv_signal_t, home: HomeHandle, - channel: Sender, - signal: Signum, + cb: Box, } impl SignalWatcher { - pub fn new(io: &mut UvIoFactory, signum: Signum, channel: Sender) + pub fn new(io: &mut UvIoFactory, signum: int, cb: Box) -> Result, UvError> { let s = box SignalWatcher { handle: UvHandle::alloc(None::, uvll::UV_SIGNAL), home: io.make_handle(), - channel: channel, - signal: signum, + cb: cb, }; assert_eq!(unsafe { uvll::uv_signal_init(io.uv_loop(), s.handle) @@ -48,10 +45,9 @@ impl SignalWatcher { } } -extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) { +extern fn signal_cb(handle: *uvll::uv_signal_t, _signum: c_int) { let s: &mut SignalWatcher = unsafe { UvHandle::from_uv_handle(&handle) }; - assert_eq!(signum as int, s.signal as int); - let _ = s.channel.send_opt(s.signal); + let _ = s.cb.call(); } impl HomingIO for SignalWatcher { @@ -70,25 +66,3 @@ impl Drop for SignalWatcher { self.close(); } } - -#[cfg(test)] -mod test { - use super::super::local_loop; - use std::io::signal; - use super::SignalWatcher; - - #[test] - fn closing_channel_during_drop_doesnt_kill_everything() { - // see issue #10375, relates to timers as well. - let (tx, rx) = channel(); - let _signal = SignalWatcher::new(local_loop(), signal::Interrupt, - tx); - - spawn(proc() { - let _ = rx.recv_opt(); - }); - - // when we drop the SignalWatcher we're going to destroy the channel, - // which must wake up the task on the other end - } -} diff --git a/src/librustuv/timeout.rs b/src/librustuv/timeout.rs index 15add60b59c48..1c191d476edb9 100644 --- a/src/librustuv/timeout.rs +++ b/src/librustuv/timeout.rs @@ -9,9 +9,9 @@ // except according to those terms. use libc::c_int; -use std::io::IoResult; use std::mem; use std::rt::task::BlockedTask; +use std::rt::rtio::IoResult; use access; use homing::{HomeHandle, HomingMissile, HomingIO}; diff --git a/src/librustuv/timer.rs b/src/librustuv/timer.rs index 525539f8b36f9..b940774323a2a 100644 --- a/src/librustuv/timer.rs +++ b/src/librustuv/timer.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::mem; -use std::rt::rtio::RtioTimer; +use std::rt::rtio::{RtioTimer, Callback}; use std::rt::task::BlockedTask; use homing::{HomeHandle, HomingIO}; @@ -27,8 +27,8 @@ pub struct TimerWatcher { pub enum NextAction { WakeTask, - SendOnce(Sender<()>), - SendMany(Sender<()>, uint), + CallOnce(Box), + CallMany(Box, uint), } impl TimerWatcher { @@ -103,9 +103,7 @@ impl RtioTimer for TimerWatcher { self.stop(); } - fn oneshot(&mut self, msecs: u64) -> Receiver<()> { - let (tx, rx) = channel(); - + fn oneshot(&mut self, msecs: u64, cb: Box) { // similarly to the destructor, we must drop the previous action outside // of the homing missile let _prev_action = { @@ -113,15 +111,11 @@ impl RtioTimer for TimerWatcher { self.id += 1; self.stop(); self.start(timer_cb, msecs, 0); - mem::replace(&mut self.action, Some(SendOnce(tx))) + mem::replace(&mut self.action, Some(CallOnce(cb))) }; - - return rx; } - fn period(&mut self, msecs: u64) -> Receiver<()> { - let (tx, rx) = channel(); - + fn period(&mut self, msecs: u64, cb: Box) { // similarly to the destructor, we must drop the previous action outside // of the homing missile let _prev_action = { @@ -129,10 +123,8 @@ impl RtioTimer for TimerWatcher { self.id += 1; self.stop(); self.start(timer_cb, msecs, msecs); - mem::replace(&mut self.action, Some(SendMany(tx, self.id))) + mem::replace(&mut self.action, Some(CallMany(cb, self.id))) }; - - return rx; } } @@ -145,9 +137,9 @@ extern fn timer_cb(handle: *uvll::uv_timer_t) { let task = timer.blocker.take_unwrap(); let _ = task.wake().map(|t| t.reawaken()); } - SendOnce(chan) => { let _ = chan.send_opt(()); } - SendMany(chan, id) => { - let _ = chan.send_opt(()); + CallOnce(mut cb) => { cb.call() } + CallMany(mut cb, id) => { + cb.call(); // Note that the above operation could have performed some form of // scheduling. This means that the timer may have decided to insert @@ -158,7 +150,7 @@ extern fn timer_cb(handle: *uvll::uv_timer_t) { // for you. We're guaranteed to all be running on the same thread, // so there's no need for any synchronization here. if timer.id == id { - timer.action = Some(SendMany(chan, id)); + timer.action = Some(CallMany(cb, id)); } } } @@ -179,145 +171,3 @@ impl Drop for TimerWatcher { }; } } - -#[cfg(test)] -mod test { - use std::rt::rtio::RtioTimer; - use super::super::local_loop; - use super::TimerWatcher; - - #[test] - fn oneshot() { - let mut timer = TimerWatcher::new(local_loop()); - let port = timer.oneshot(1); - port.recv(); - let port = timer.oneshot(1); - port.recv(); - } - - #[test] - fn override() { - let mut timer = TimerWatcher::new(local_loop()); - let oport = timer.oneshot(1); - let pport = timer.period(1); - timer.sleep(1); - assert_eq!(oport.recv_opt(), Err(())); - assert_eq!(pport.recv_opt(), Err(())); - timer.oneshot(1).recv(); - } - - #[test] - fn period() { - let mut timer = TimerWatcher::new(local_loop()); - let port = timer.period(1); - port.recv(); - port.recv(); - let port2 = timer.period(1); - port2.recv(); - port2.recv(); - } - - #[test] - fn sleep() { - let mut timer = TimerWatcher::new(local_loop()); - timer.sleep(1); - timer.sleep(1); - } - - #[test] #[should_fail] - fn oneshot_fail() { - let mut timer = TimerWatcher::new(local_loop()); - let _port = timer.oneshot(1); - fail!(); - } - - #[test] #[should_fail] - fn period_fail() { - let mut timer = TimerWatcher::new(local_loop()); - let _port = timer.period(1); - fail!(); - } - - #[test] #[should_fail] - fn normal_fail() { - let _timer = TimerWatcher::new(local_loop()); - fail!(); - } - - #[test] - fn closing_channel_during_drop_doesnt_kill_everything() { - // see issue #10375 - let mut timer = TimerWatcher::new(local_loop()); - let timer_port = timer.period(1000); - - spawn(proc() { - let _ = timer_port.recv_opt(); - }); - - // when we drop the TimerWatcher we're going to destroy the channel, - // which must wake up the task on the other end - } - - #[test] - fn reset_doesnt_switch_tasks() { - // similar test to the one above. - let mut timer = TimerWatcher::new(local_loop()); - let timer_port = timer.period(1000); - - spawn(proc() { - let _ = timer_port.recv_opt(); - }); - - drop(timer.oneshot(1)); - } - #[test] - fn reset_doesnt_switch_tasks2() { - // similar test to the one above. - let mut timer = TimerWatcher::new(local_loop()); - let timer_port = timer.period(1000); - - spawn(proc() { - let _ = timer_port.recv_opt(); - }); - - timer.sleep(1); - } - - #[test] - fn sender_goes_away_oneshot() { - let port = { - let mut timer = TimerWatcher::new(local_loop()); - timer.oneshot(1000) - }; - assert_eq!(port.recv_opt(), Err(())); - } - - #[test] - fn sender_goes_away_period() { - let port = { - let mut timer = TimerWatcher::new(local_loop()); - timer.period(1000) - }; - assert_eq!(port.recv_opt(), Err(())); - } - - #[test] - fn receiver_goes_away_oneshot() { - let mut timer1 = TimerWatcher::new(local_loop()); - drop(timer1.oneshot(1)); - let mut timer2 = TimerWatcher::new(local_loop()); - // while sleeping, the prevous timer should fire and not have its - // callback do something terrible. - timer2.sleep(2); - } - - #[test] - fn receiver_goes_away_period() { - let mut timer1 = TimerWatcher::new(local_loop()); - drop(timer1.period(1)); - let mut timer2 = TimerWatcher::new(local_loop()); - // while sleeping, the prevous timer should fire and not have its - // callback do something terrible. - timer2.sleep(2); - } -} diff --git a/src/librustuv/tty.rs b/src/librustuv/tty.rs index f70c3b4c1bd75..828a3d0c63b0a 100644 --- a/src/librustuv/tty.rs +++ b/src/librustuv/tty.rs @@ -9,9 +9,8 @@ // except according to those terms. use libc; -use std::io::IoError; use std::ptr; -use std::rt::rtio::RtioTTY; +use std::rt::rtio::{RtioTTY, IoResult}; use homing::{HomingIO, HomeHandle}; use stream::StreamWatcher; @@ -80,17 +79,17 @@ impl TtyWatcher { } impl RtioTTY for TtyWatcher { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { let _m = self.fire_homing_missile(); self.stream.read(buf).map_err(uv_error_to_io_error) } - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { let _m = self.fire_homing_missile(); self.stream.write(buf, false).map_err(uv_error_to_io_error) } - fn set_raw(&mut self, raw: bool) -> Result<(), IoError> { + fn set_raw(&mut self, raw: bool) -> IoResult<()> { let raw = raw as libc::c_int; let _m = self.fire_homing_missile(); match unsafe { uvll::uv_tty_set_mode(self.tty, raw) } { @@ -100,7 +99,7 @@ impl RtioTTY for TtyWatcher { } #[allow(unused_mut)] - fn get_winsize(&mut self) -> Result<(int, int), IoError> { + fn get_winsize(&mut self) -> IoResult<(int, int)> { let mut width: libc::c_int = 0; let mut height: libc::c_int = 0; let widthptr: *libc::c_int = &width; diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index 71589e00fc008..cf2a2d73d4d9f 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -11,21 +11,13 @@ //! The implementation of `rtio` for libuv use std::c_str::CString; -use std::io::IoError; -use std::io::net::ip::SocketAddr; -use std::io::signal::Signum; -use std::io::{FileMode, FileAccess, Open, Append, Truncate, Read, Write, - ReadWrite, FileStat}; -use std::io; use std::mem; use libc::c_int; use libc::{O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, S_IRUSR, S_IWUSR}; use libc; -use std::path::Path; use std::rt::rtio; -use std::rt::rtio::{ProcessConfig, IoFactory, EventLoop}; -use ai = std::io::net::addrinfo; +use std::rt::rtio::{ProcessConfig, IoFactory, EventLoop, IoResult}; #[cfg(test)] use std::rt::thread::Thread; @@ -148,36 +140,38 @@ impl IoFactory for UvIoFactory { // Connect to an address and return a new stream // NB: This blocks the task waiting on the connection. // It would probably be better to return a future - fn tcp_connect(&mut self, addr: SocketAddr, timeout: Option) - -> Result, IoError> { + fn tcp_connect(&mut self, addr: rtio::SocketAddr, timeout: Option) + -> IoResult> { match TcpWatcher::connect(self, addr, timeout) { Ok(t) => Ok(box t as Box), Err(e) => Err(uv_error_to_io_error(e)), } } - fn tcp_bind(&mut self, addr: SocketAddr) - -> Result, IoError> { + fn tcp_bind(&mut self, addr: rtio::SocketAddr) + -> IoResult> { match TcpListener::bind(self, addr) { Ok(t) => Ok(t as Box), Err(e) => Err(uv_error_to_io_error(e)), } } - fn udp_bind(&mut self, addr: SocketAddr) - -> Result, IoError> { + fn udp_bind(&mut self, addr: rtio::SocketAddr) + -> IoResult> { match UdpWatcher::bind(self, addr) { Ok(u) => Ok(box u as Box), Err(e) => Err(uv_error_to_io_error(e)), } } - fn timer_init(&mut self) -> Result, IoError> { + fn timer_init(&mut self) -> IoResult> { Ok(TimerWatcher::new(self) as Box) } fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, - hint: Option) -> Result, IoError> { + hint: Option) + -> IoResult> + { let r = GetAddrInfoRequest::run(&self.loop_, host, servname, hint); r.map_err(uv_error_to_io_error) } @@ -188,20 +182,22 @@ impl IoFactory for UvIoFactory { Box } - fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) - -> Result, IoError> { + fn fs_open(&mut self, path: &CString, fm: rtio::FileMode, + fa: rtio::FileAccess) + -> IoResult> + { let flags = match fm { - io::Open => 0, - io::Append => libc::O_APPEND, - io::Truncate => libc::O_TRUNC, + rtio::Open => 0, + rtio::Append => libc::O_APPEND, + rtio::Truncate => libc::O_TRUNC, }; // Opening with a write permission must silently create the file. let (flags, mode) = match fa { - io::Read => (flags | libc::O_RDONLY, 0), - io::Write => (flags | libc::O_WRONLY | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), - io::ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), + rtio::Read => (flags | libc::O_RDONLY, 0), + rtio::Write => (flags | libc::O_WRONLY | libc::O_CREAT, + libc::S_IRUSR | libc::S_IWUSR), + rtio::ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT, + libc::S_IRUSR | libc::S_IWUSR), }; match FsRequest::open(self, path, flags as int, mode as int) { @@ -210,69 +206,66 @@ impl IoFactory for UvIoFactory { } } - fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError> { + fn fs_unlink(&mut self, path: &CString) -> IoResult<()> { let r = FsRequest::unlink(&self.loop_, path); r.map_err(uv_error_to_io_error) } - fn fs_lstat(&mut self, path: &CString) -> Result { + fn fs_lstat(&mut self, path: &CString) -> IoResult { let r = FsRequest::lstat(&self.loop_, path); r.map_err(uv_error_to_io_error) } - fn fs_stat(&mut self, path: &CString) -> Result { + fn fs_stat(&mut self, path: &CString) -> IoResult { let r = FsRequest::stat(&self.loop_, path); r.map_err(uv_error_to_io_error) } - fn fs_mkdir(&mut self, path: &CString, - perm: io::FilePermission) -> Result<(), IoError> { - let r = FsRequest::mkdir(&self.loop_, path, perm.bits() as c_int); + fn fs_mkdir(&mut self, path: &CString, perm: uint) -> IoResult<()> { + let r = FsRequest::mkdir(&self.loop_, path, perm as c_int); r.map_err(uv_error_to_io_error) } - fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError> { + fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> { let r = FsRequest::rmdir(&self.loop_, path); r.map_err(uv_error_to_io_error) } - fn fs_rename(&mut self, path: &CString, to: &CString) -> Result<(), IoError> { + fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> { let r = FsRequest::rename(&self.loop_, path, to); r.map_err(uv_error_to_io_error) } - fn fs_chmod(&mut self, path: &CString, - perm: io::FilePermission) -> Result<(), IoError> { - let r = FsRequest::chmod(&self.loop_, path, perm.bits() as c_int); + fn fs_chmod(&mut self, path: &CString, perm: uint) -> IoResult<()> { + let r = FsRequest::chmod(&self.loop_, path, perm as c_int); r.map_err(uv_error_to_io_error) } fn fs_readdir(&mut self, path: &CString, flags: c_int) - -> Result, IoError> + -> IoResult> { let r = FsRequest::readdir(&self.loop_, path, flags); r.map_err(uv_error_to_io_error) } - fn fs_link(&mut self, src: &CString, dst: &CString) -> Result<(), IoError> { + fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> { let r = FsRequest::link(&self.loop_, src, dst); r.map_err(uv_error_to_io_error) } - fn fs_symlink(&mut self, src: &CString, dst: &CString) -> Result<(), IoError> { + fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> { let r = FsRequest::symlink(&self.loop_, src, dst); r.map_err(uv_error_to_io_error) } - fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> Result<(), IoError> { + fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> { let r = FsRequest::chown(&self.loop_, path, uid, gid); r.map_err(uv_error_to_io_error) } - fn fs_readlink(&mut self, path: &CString) -> Result { + fn fs_readlink(&mut self, path: &CString) -> IoResult { let r = FsRequest::readlink(&self.loop_, path); r.map_err(uv_error_to_io_error) } fn fs_utime(&mut self, path: &CString, atime: u64, mtime: u64) - -> Result<(), IoError> + -> IoResult<()> { let r = FsRequest::utime(&self.loop_, path, atime, mtime); r.map_err(uv_error_to_io_error) } fn spawn(&mut self, cfg: ProcessConfig) - -> Result<(Box, - Vec>>), - IoError> + -> IoResult<(Box, + Vec>>)> { match Process::spawn(self, cfg) { Ok((p, io)) => { @@ -285,12 +278,12 @@ impl IoFactory for UvIoFactory { } } - fn kill(&mut self, pid: libc::pid_t, signum: int) -> Result<(), IoError> { + fn kill(&mut self, pid: libc::pid_t, signum: int) -> IoResult<()> { Process::kill(pid, signum).map_err(uv_error_to_io_error) } fn unix_bind(&mut self, path: &CString) - -> Result, IoError> { + -> IoResult> { match PipeListener::bind(self, path) { Ok(p) => Ok(p as Box), Err(e) => Err(uv_error_to_io_error(e)), @@ -298,7 +291,7 @@ impl IoFactory for UvIoFactory { } fn unix_connect(&mut self, path: &CString, timeout: Option) - -> Result, IoError> { + -> IoResult> { match PipeWatcher::connect(self, path, timeout) { Ok(p) => Ok(box p as Box), Err(e) => Err(uv_error_to_io_error(e)), @@ -306,7 +299,7 @@ impl IoFactory for UvIoFactory { } fn tty_open(&mut self, fd: c_int, readable: bool) - -> Result, IoError> { + -> IoResult> { match TtyWatcher::new(self, fd, readable) { Ok(tty) => Ok(box tty as Box), Err(e) => Err(uv_error_to_io_error(e)) @@ -314,16 +307,18 @@ impl IoFactory for UvIoFactory { } fn pipe_open(&mut self, fd: c_int) - -> Result, IoError> { + -> IoResult> + { match PipeWatcher::open(self, fd) { Ok(s) => Ok(box s as Box), Err(e) => Err(uv_error_to_io_error(e)) } } - fn signal(&mut self, signum: Signum, channel: Sender) - -> Result, IoError> { - match SignalWatcher::new(self, signum, channel) { + fn signal(&mut self, signum: int, cb: Box) + -> IoResult> + { + match SignalWatcher::new(self, signum, cb) { Ok(s) => Ok(s as Box), Err(e) => Err(uv_error_to_io_error(e)), } diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 91c6814725144..f6c6d6c9068e0 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -38,7 +38,8 @@ use std::rt::libc_heap::malloc_raw; use libc::uintptr_t; pub use self::errors::{EACCES, ECONNREFUSED, ECONNRESET, EPIPE, ECONNABORTED, - ECANCELED, EBADF, ENOTCONN, ENOENT, EADDRNOTAVAIL}; + ECANCELED, EBADF, ENOTCONN, ENOENT, EADDRNOTAVAIL, + EADDRINUSE}; pub static OK: c_int = 0; pub static EOF: c_int = -4095; @@ -61,6 +62,7 @@ pub mod errors { pub static ECANCELED: c_int = -4081; pub static EBADF: c_int = -4083; pub static EADDRNOTAVAIL: c_int = -4090; + pub static EADDRINUSE: c_int = -4091; } #[cfg(not(windows))] pub mod errors { @@ -77,6 +79,7 @@ pub mod errors { pub static ECANCELED : c_int = -libc::ECANCELED; pub static EBADF : c_int = -libc::EBADF; pub static EADDRNOTAVAIL : c_int = -libc::EADDRNOTAVAIL; + pub static EADDRINUSE : c_int = -libc::EADDRINUSE; } pub static PROCESS_SETUID: c_int = 1 << 0; diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs deleted file mode 100644 index 2e51931f15a13..0000000000000 --- a/src/libstd/cleanup.rs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![doc(hidden)] - -use ptr; -use raw; - -static RC_IMMORTAL : uint = 0x77777777; - -/* - * Box annihilation - * - * This runs at task death to free all boxes. - */ - -unsafe fn each_live_alloc(read_next_before: bool, - f: |alloc: *mut raw::Box<()>| -> bool) - -> bool { - //! Walks the internal list of allocations - - use rt::local_heap; - - let mut alloc = local_heap::live_allocs(); - while alloc != ptr::mut_null() { - let next_before = (*alloc).next; - - if !f(alloc) { - return false; - } - - if read_next_before { - alloc = next_before; - } else { - alloc = (*alloc).next; - } - } - return true; -} - -#[cfg(unix)] -fn debug_mem() -> bool { - // FIXME: Need to port the environment struct to newsched - false -} - -#[cfg(windows)] -fn debug_mem() -> bool { - false -} - -/// Destroys all managed memory (i.e. @ boxes) held by the current task. -pub unsafe fn annihilate() { - use rt::local_heap::local_free; - - let mut n_total_boxes = 0u; - - // Pass 1: Make all boxes immortal. - // - // In this pass, nothing gets freed, so it does not matter whether - // we read the next field before or after the callback. - each_live_alloc(true, |alloc| { - n_total_boxes += 1; - (*alloc).ref_count = RC_IMMORTAL; - true - }); - - // Pass 2: Drop all boxes. - // - // In this pass, unique-managed boxes may get freed, but not - // managed boxes, so we must read the `next` field *after* the - // callback, as the original value may have been freed. - each_live_alloc(false, |alloc| { - let drop_glue = (*alloc).drop_glue; - let data = &mut (*alloc).data as *mut (); - drop_glue(data as *mut u8); - true - }); - - // Pass 3: Free all boxes. - // - // In this pass, managed boxes may get freed (but not - // unique-managed boxes, though I think that none of those are - // left), so we must read the `next` field before, since it will - // not be valid after. - each_live_alloc(true, |alloc| { - local_free(alloc as *u8); - true - }); - - if debug_mem() { - // We do logging here w/o allocation. - println!("total boxes annihilated: {}", n_total_boxes); - } -} diff --git a/src/libstd/comm/shared.rs b/src/libstd/comm/shared.rs index 3fde584a46f71..f4eeebeeea06f 100644 --- a/src/libstd/comm/shared.rs +++ b/src/libstd/comm/shared.rs @@ -27,10 +27,10 @@ use option::{Some, None, Option}; use owned::Box; use result::{Ok, Err, Result}; use rt::local::Local; +use rt::mutex::NativeMutex; use rt::task::{Task, BlockedTask}; use rt::thread::Thread; use sync::atomics; -use unstable::mutex::NativeMutex; use mpsc = sync::mpsc_queue; diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs index 819e885526cbf..7fe505573b799 100644 --- a/src/libstd/comm/sync.rs +++ b/src/libstd/comm/sync.rs @@ -43,10 +43,10 @@ use owned::Box; use ptr::RawPtr; use result::{Result, Ok, Err}; use rt::local::Local; +use rt::mutex::{NativeMutex, LockGuard}; use rt::task::{Task, BlockedTask}; use sync::atomics; use ty::Unsafe; -use unstable::mutex::{NativeMutex, LockGuard}; use vec::Vec; pub struct Packet { diff --git a/src/libstd/failure.rs b/src/libstd/failure.rs new file mode 100644 index 0000000000000..903f39c7b06a3 --- /dev/null +++ b/src/libstd/failure.rs @@ -0,0 +1,102 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use alloc::owned::Box; +use any::{Any, AnyRefExt}; +use fmt; +use io::{Writer, IoResult}; +use kinds::Send; +use option::{Some, None}; +use result::Ok; +use rt::backtrace; +use rt::{Stderr, Stdio}; +use rustrt::local::Local; +use rustrt::task::Task; +use str::Str; +use string::String; + +// Defined in this module instead of io::stdio so that the unwinding +local_data_key!(pub local_stderr: Box) + +impl Writer for Stdio { + fn write(&mut self, bytes: &[u8]) -> IoResult<()> { + fn fmt_write(f: &mut F, bytes: &[u8]) { + let _ = f.write(bytes); + } + fmt_write(self, bytes); + Ok(()) + } +} + +pub fn on_fail(obj: &Any:Send, file: &'static str, line: uint) { + let msg = match obj.as_ref::<&'static str>() { + Some(s) => *s, + None => match obj.as_ref::() { + Some(s) => s.as_slice(), + None => "Box", + } + }; + let mut err = Stderr; + + // It is assumed that all reasonable rust code will have a local task at + // all times. This means that this `exists` will return true almost all of + // the time. There are border cases, however, when the runtime has + // *almost* set up the local task, but hasn't quite gotten there yet. In + // order to get some better diagnostics, we print on failure and + // immediately abort the whole process if there is no local task + // available. + if !Local::exists(None::) { + let _ = writeln!(&mut err, "failed at '{}', {}:{}", msg, file, line); + if backtrace::log_enabled() { + let _ = backtrace::write(&mut err); + } else { + let _ = writeln!(&mut err, "run with `RUST_BACKTRACE=1` to \ + see a backtrace"); + } + return + } + + // Peel the name out of local task so we can print it. We've got to be sure + // that the local task is in TLS while we're printing as I/O may occur. + let (name, unwinding) = { + let mut t = Local::borrow(None::); + (t.name.take(), t.unwinder.unwinding()) + }; + { + let n = name.as_ref().map(|n| n.as_slice()).unwrap_or(""); + + match local_stderr.replace(None) { + Some(mut stderr) => { + // FIXME: what to do when the task printing fails? + let _ = writeln!(stderr, + "task '{}' failed at '{}', {}:{}\n", + n, msg, file, line); + if backtrace::log_enabled() { + let _ = backtrace::write(stderr); + } + local_stderr.replace(Some(stderr)); + } + None => { + let _ = writeln!(&mut err, "task '{}' failed at '{}', {}:{}", + n, msg, file, line); + if backtrace::log_enabled() { + let _ = backtrace::write(&mut err); + } + } + } + + // If this is a double failure, make sure that we printed a backtrace + // for this failure. + if unwinding && !backtrace::log_enabled() { + let _ = backtrace::write(&mut err); + } + } + Local::borrow(None::).name = name; +} diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index a77c7107f282f..49e8d37923661 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -52,19 +52,22 @@ fs::unlink(&path); use c_str::ToCStr; use clone::Clone; use container::Container; +use io; use iter::Iterator; use kinds::Send; -use super::{Reader, Writer, Seek}; -use super::{SeekStyle, Read, Write, Open, IoError, Truncate}; -use super::{FileMode, FileAccess, FileStat, IoResult, FilePermission}; -use rt::rtio::{RtioFileStream, IoFactory, LocalIo}; -use io; +use libc; use option::{Some, None, Option}; use owned::Box; -use result::{Ok, Err}; -use path; use path::{Path, GenericPath}; +use path; +use result::{Ok, Err}; +use rt::rtio::{RtioFileStream, IoFactory, LocalIo}; +use rt::rtio; use slice::{OwnedVector, ImmutableVector}; +use super::UnstableFileStat; +use super::{FileMode, FileAccess, FileStat, IoResult, FilePermission}; +use super::{Reader, Writer, Seek, Append, SeekCur, SeekEnd, SeekSet}; +use super::{SeekStyle, Read, Write, ReadWrite, Open, IoError, Truncate}; use vec::Vec; /// Unconstrained file access type that exposes read and write operations @@ -126,6 +129,16 @@ impl File { pub fn open_mode(path: &Path, mode: FileMode, access: FileAccess) -> IoResult { + let mode = match mode { + Open => rtio::Open, + Append => rtio::Append, + Truncate => rtio::Truncate, + }; + let access = match access { + Read => rtio::Read, + Write => rtio::Write, + ReadWrite => rtio::ReadWrite, + }; LocalIo::maybe_raise(|io| { io.fs_open(&path.to_c_str(), mode, access).map(|fd| { File { @@ -134,7 +147,7 @@ impl File { last_nread: -1 } }) - }) + }).map_err(IoError::from_rtio_error) } /// Attempts to open a file in read-only mode. This function is equivalent to @@ -184,7 +197,7 @@ impl File { /// device. This will flush any internal buffers necessary to perform this /// operation. pub fn fsync(&mut self) -> IoResult<()> { - self.fd.fsync() + self.fd.fsync().map_err(IoError::from_rtio_error) } /// This function is similar to `fsync`, except that it may not synchronize @@ -192,7 +205,7 @@ impl File { /// must synchronize content, but don't need the metadata on disk. The goal /// of this method is to reduce disk operations. pub fn datasync(&mut self) -> IoResult<()> { - self.fd.datasync() + self.fd.datasync().map_err(IoError::from_rtio_error) } /// Either truncates or extends the underlying file, updating the size of @@ -204,7 +217,7 @@ impl File { /// will be extended to `size` and have all of the intermediate data filled /// in with 0s. pub fn truncate(&mut self, size: i64) -> IoResult<()> { - self.fd.truncate(size) + self.fd.truncate(size).map_err(IoError::from_rtio_error) } /// Tests whether this stream has reached EOF. @@ -217,7 +230,10 @@ impl File { /// Queries information about the underlying file. pub fn stat(&mut self) -> IoResult { - self.fd.fstat() + match self.fd.fstat() { + Ok(s) => Ok(from_rtio(s)), + Err(e) => Err(IoError::from_rtio_error(e)), + } } } @@ -243,7 +259,9 @@ impl File { /// user lacks permissions to remove the file, or if some other filesystem-level /// error occurs. pub fn unlink(path: &Path) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str())) + LocalIo::maybe_raise(|io| { + io.fs_unlink(&path.to_c_str()) + }).map_err(IoError::from_rtio_error) } /// Given a path, query the file system to get information about a file, @@ -268,9 +286,10 @@ pub fn unlink(path: &Path) -> IoResult<()> { /// to perform a `stat` call on the given path or if there is no entry in the /// filesystem at the provided path. pub fn stat(path: &Path) -> IoResult { - LocalIo::maybe_raise(|io| { - io.fs_stat(&path.to_c_str()) - }) + match LocalIo::maybe_raise(|io| io.fs_stat(&path.to_c_str())) { + Ok(s) => Ok(from_rtio(s)), + Err(e) => Err(IoError::from_rtio_error(e)), + } } /// Perform the same operation as the `stat` function, except that this @@ -282,9 +301,46 @@ pub fn stat(path: &Path) -> IoResult { /// /// See `stat` pub fn lstat(path: &Path) -> IoResult { - LocalIo::maybe_raise(|io| { - io.fs_lstat(&path.to_c_str()) - }) + match LocalIo::maybe_raise(|io| io.fs_lstat(&path.to_c_str())) { + Ok(s) => Ok(from_rtio(s)), + Err(e) => Err(IoError::from_rtio_error(e)), + } +} + +fn from_rtio(s: rtio::FileStat) -> FileStat { + let rtio::FileStat { + size, kind, perm, created, modified, + accessed, device, inode, rdev, + nlink, uid, gid, blksize, blocks, flags, gen + } = s; + + FileStat { + size: size, + kind: match (kind as libc::c_int) & libc::S_IFMT { + libc::S_IFREG => io::TypeFile, + libc::S_IFDIR => io::TypeDirectory, + libc::S_IFIFO => io::TypeNamedPipe, + libc::S_IFBLK => io::TypeBlockSpecial, + libc::S_IFLNK => io::TypeSymlink, + _ => io::TypeUnknown, + }, + perm: FilePermission::from_bits_truncate(perm as u32), + created: created, + modified: modified, + accessed: accessed, + unstable: UnstableFileStat { + device: device, + inode: inode, + rdev: rdev, + nlink: nlink, + uid: uid, + gid: gid, + blksize: blksize, + blocks: blocks, + flags: flags, + gen: gen, + }, + } } /// Rename a file or directory to a new name. @@ -304,7 +360,9 @@ pub fn lstat(path: &Path) -> IoResult { /// permissions to view the contents, or if some other intermittent I/O error /// occurs. pub fn rename(from: &Path, to: &Path) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str())) + LocalIo::maybe_raise(|io| { + io.fs_rename(&from.to_c_str(), &to.to_c_str()) + }).map_err(IoError::from_rtio_error) } /// Copies the contents of one file to another. This function will also @@ -382,25 +440,33 @@ pub fn copy(from: &Path, to: &Path) -> IoResult<()> { /// Some possible error situations are not having the permission to /// change the attributes of a file or the file not existing. pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode)) + LocalIo::maybe_raise(|io| { + io.fs_chmod(&path.to_c_str(), mode.bits() as uint) + }).map_err(IoError::from_rtio_error) } /// Change the user and group owners of a file at the specified path. pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid)) + LocalIo::maybe_raise(|io| { + io.fs_chown(&path.to_c_str(), uid, gid) + }).map_err(IoError::from_rtio_error) } /// Creates a new hard link on the filesystem. The `dst` path will be a /// link pointing to the `src` path. Note that systems often require these /// two paths to both be located on the same filesystem. pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str())) + LocalIo::maybe_raise(|io| { + io.fs_link(&src.to_c_str(), &dst.to_c_str()) + }).map_err(IoError::from_rtio_error) } /// Creates a new symbolic link on the filesystem. The `dst` path will be a /// symlink pointing to the `src` path. pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str())) + LocalIo::maybe_raise(|io| { + io.fs_symlink(&src.to_c_str(), &dst.to_c_str()) + }).map_err(IoError::from_rtio_error) } /// Reads a symlink, returning the file that the symlink points to. @@ -410,7 +476,9 @@ pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { /// This function will return an error on failure. Failure conditions include /// reading a file that does not exist or reading a file which is not a symlink. pub fn readlink(path: &Path) -> IoResult { - LocalIo::maybe_raise(|io| io.fs_readlink(&path.to_c_str())) + LocalIo::maybe_raise(|io| { + Ok(Path::new(try!(io.fs_readlink(&path.to_c_str())))) + }).map_err(IoError::from_rtio_error) } /// Create a new, empty directory at the provided path @@ -431,7 +499,9 @@ pub fn readlink(path: &Path) -> IoResult { /// This call will return an error if the user lacks permissions to make a new /// directory at the provided path, or if the directory already exists. pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode)) + LocalIo::maybe_raise(|io| { + io.fs_mkdir(&path.to_c_str(), mode.bits() as uint) + }).map_err(IoError::from_rtio_error) } /// Remove an existing, empty directory @@ -451,7 +521,9 @@ pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { /// This call will return an error if the user lacks permissions to remove the /// directory at the provided path, or if the directory isn't empty. pub fn rmdir(path: &Path) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str())) + LocalIo::maybe_raise(|io| { + io.fs_rmdir(&path.to_c_str()) + }).map_err(IoError::from_rtio_error) } /// Retrieve a vector containing all entries within a provided directory @@ -487,8 +559,10 @@ pub fn rmdir(path: &Path) -> IoResult<()> { /// file pub fn readdir(path: &Path) -> IoResult> { LocalIo::maybe_raise(|io| { - io.fs_readdir(&path.to_c_str(), 0) - }) + Ok(try!(io.fs_readdir(&path.to_c_str(), 0)).move_iter().map(|a| { + Path::new(a) + }).collect()) + }).map_err(IoError::from_rtio_error) } /// Returns an iterator which will recursively walk the directory structure @@ -612,7 +686,9 @@ pub fn rmdir_recursive(path: &Path) -> IoResult<()> { /// be in milliseconds. // FIXME(#10301) these arguments should not be u64 pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime)) + LocalIo::maybe_raise(|io| { + io.fs_utime(&path.to_c_str(), atime, mtime) + }).map_err(IoError::from_rtio_error) } impl Reader for File { @@ -625,28 +701,35 @@ impl Reader for File { _ => Ok(read as uint) } }, - Err(e) => Err(e), + Err(e) => Err(IoError::from_rtio_error(e)), } } } impl Writer for File { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.fd.write(buf) } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.fd.write(buf).map_err(IoError::from_rtio_error) + } } impl Seek for File { fn tell(&self) -> IoResult { - self.fd.tell() + self.fd.tell().map_err(IoError::from_rtio_error) } fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { + let style = match style { + SeekSet => rtio::SeekSet, + SeekCur => rtio::SeekCur, + SeekEnd => rtio::SeekEnd, + }; match self.fd.seek(pos, style) { Ok(_) => { // successful seek resets EOF indicator self.last_nread = -1; Ok(()) } - Err(e) => Err(e), + Err(e) => Err(IoError::from_rtio_error(e)), } } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 78700d353afd8..c72cc0ded9bc3 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -225,6 +225,7 @@ use option::{Option, Some, None}; use os; use owned::Box; use result::{Ok, Err, Result}; +use rt::rtio; use slice::{Vector, MutableVector, ImmutableVector}; use str::{StrSlice, StrAllocating}; use str; @@ -312,7 +313,8 @@ impl IoError { libc::ERROR_INVALID_NAME => (InvalidInput, "invalid file name"), libc::WSAECONNREFUSED => (ConnectionRefused, "connection refused"), libc::WSAECONNRESET => (ConnectionReset, "connection reset"), - libc::WSAEACCES => (PermissionDenied, "permission denied"), + libc::ERROR_ACCESS_DENIED | libc::WSAEACCES => + (PermissionDenied, "permission denied"), libc::WSAEWOULDBLOCK => { (ResourceUnavailable, "resource temporarily unavailable") } @@ -323,6 +325,14 @@ impl IoError { libc::ERROR_BROKEN_PIPE => (EndOfFile, "the pipe has ended"), libc::ERROR_OPERATION_ABORTED => (TimedOut, "operation timed out"), + libc::WSAEINVAL => (InvalidInput, "invalid argument"), + libc::ERROR_CALL_NOT_IMPLEMENTED => + (IoUnavailable, "function not implemented"), + libc::ERROR_INVALID_HANDLE => + (MismatchedFileTypeForOperation, + "invalid handle provided to function"), + libc::ERROR_NOTHING_TO_TERMINATE => + (InvalidInput, "no process to kill"), // libuv maps this error code to EISDIR. we do too. if it is found // to be incorrect, we can add in some more machinery to only @@ -351,9 +361,17 @@ impl IoError { libc::EADDRINUSE => (ConnectionRefused, "address in use"), libc::ENOENT => (FileNotFound, "no such file or directory"), libc::EISDIR => (InvalidInput, "illegal operation on a directory"), - - // These two constants can have the same value on some systems, but - // different values on others, so we can't use a match clause + libc::ENOSYS => (IoUnavailable, "function not implemented"), + libc::EINVAL => (InvalidInput, "invalid argument"), + libc::ENOTTY => + (MismatchedFileTypeForOperation, + "file descriptor is not a TTY"), + libc::ETIMEDOUT => (TimedOut, "operation timed out"), + libc::ECANCELED => (TimedOut, "operation aborted"), + + // 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"), @@ -382,6 +400,17 @@ impl IoError { pub fn last_error() -> IoError { IoError::from_errno(os::errno() as uint, true) } + + fn from_rtio_error(err: rtio::IoError) -> IoError { + let rtio::IoError { code, extra, detail } = err; + let mut ioerr = IoError::from_errno(code, false); + ioerr.detail = detail; + ioerr.kind = match ioerr.kind { + TimedOut if extra > 0 => ShortWrite(extra), + k => k, + }; + return ioerr; + } } impl fmt::Show for IoError { diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs index 879c66e0769d8..8d5fd2b99fd7b 100644 --- a/src/libstd/io/net/addrinfo.rs +++ b/src/libstd/io/net/addrinfo.rs @@ -20,10 +20,12 @@ getaddrinfo() #![allow(missing_doc)] use iter::Iterator; -use io::IoResult; +use io::{IoResult, IoError}; use io::net::ip::{SocketAddr, IpAddr}; use option::{Option, Some, None}; +use result::{Ok, Err}; use rt::rtio::{IoFactory, LocalIo}; +use rt::rtio; use vec::Vec; /// Hints to the types of sockets that are desired when looking up hosts @@ -89,9 +91,34 @@ pub fn get_host_addresses(host: &str) -> IoResult> { /// /// FIXME: this is not public because the `Hint` structure is not ready for public /// consumption just yet. +#[allow(unused_variable)] fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option) -> IoResult> { - LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint)) + let hint = hint.map(|Hint { family, socktype, protocol, flags }| { + rtio::AddrinfoHint { + family: family, + socktype: 0, // FIXME: this should use the above variable + protocol: 0, // FIXME: this should use the above variable + flags: flags, + } + }); + match LocalIo::maybe_raise(|io| { + io.get_host_addresses(hostname, servname, hint) + }) { + Ok(v) => Ok(v.move_iter().map(|info| { + Info { + address: SocketAddr { + ip: super::from_rtio(info.address.ip), + port: info.address.port, + }, + family: info.family, + socktype: None, // FIXME: this should use the above variable + protocol: None, // FIXME: this should use the above variable + flags: info.flags, + } + }).collect()), + Err(e) => Err(IoError::from_rtio_error(e)), + } } // Ignored on android since we cannot give tcp/ip diff --git a/src/libstd/io/net/mod.rs b/src/libstd/io/net/mod.rs index 1939d6537521f..54af83462eed6 100644 --- a/src/libstd/io/net/mod.rs +++ b/src/libstd/io/net/mod.rs @@ -10,6 +10,9 @@ //! Networking I/O +use rt::rtio; +use self::ip::{Ipv4Addr, Ipv6Addr, IpAddr}; + pub use self::addrinfo::get_host_addresses; pub mod addrinfo; @@ -18,3 +21,21 @@ pub mod udp; pub mod ip; // FIXME(#12093) - this should not be called unix pub mod unix; + +fn to_rtio(ip: IpAddr) -> rtio::IpAddr { + match ip { + Ipv4Addr(a, b, c, d) => rtio::Ipv4Addr(a, b, c, d), + Ipv6Addr(a, b, c, d, e, f, g, h) => { + rtio::Ipv6Addr(a, b, c, d, e, f, g, h) + } + } +} + +fn from_rtio(ip: rtio::IpAddr) -> IpAddr { + match ip { + rtio::Ipv4Addr(a, b, c, d) => Ipv4Addr(a, b, c, d), + rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => { + Ipv6Addr(a, b, c, d, e, f, g, h) + } + } +} diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index ac17bc1de1379..6c773467553d2 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -32,6 +32,7 @@ use option::{None, Some, Option}; use owned::Box; use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener}; use rt::rtio::{RtioTcpAcceptor, RtioTcpStream}; +use rt::rtio; /// A structure which represents a TCP stream between a local socket and a /// remote socket. @@ -67,22 +68,22 @@ impl TcpStream { Some(addr) => vec!(addr), None => try!(get_host_addresses(host)) }; - let mut err = IoError{ + let mut err = IoError { kind: ConnectionFailed, desc: "no addresses found for hostname", detail: None }; - for address in addresses.iter() { - let socket_addr = SocketAddr{ip: *address, port: port}; + for addr in addresses.iter() { + let addr = rtio::SocketAddr{ ip: super::to_rtio(*addr), port: port }; let result = LocalIo::maybe_raise(|io| { - io.tcp_connect(socket_addr, None).map(TcpStream::new) + io.tcp_connect(addr, None).map(TcpStream::new) }); match result { Ok(stream) => { return Ok(stream) } Err(connect_err) => { - err = connect_err + err = IoError::from_rtio_error(connect_err) } } } @@ -101,19 +102,31 @@ impl TcpStream { #[experimental = "the timeout argument may eventually change types"] pub fn connect_timeout(addr: SocketAddr, timeout_ms: u64) -> IoResult { + let SocketAddr { ip, port } = addr; + let addr = rtio::SocketAddr { ip: super::to_rtio(ip), port: port }; LocalIo::maybe_raise(|io| { io.tcp_connect(addr, Some(timeout_ms)).map(TcpStream::new) - }) + }).map_err(IoError::from_rtio_error) } /// Returns the socket address of the remote peer of this TCP connection. pub fn peer_name(&mut self) -> IoResult { - self.obj.peer_name() + match self.obj.peer_name() { + Ok(rtio::SocketAddr { ip, port }) => { + Ok(SocketAddr { ip: super::from_rtio(ip), port: port }) + } + Err(e) => Err(IoError::from_rtio_error(e)), + } } /// Returns the socket address of the local half of this TCP connection. pub fn socket_name(&mut self) -> IoResult { - self.obj.socket_name() + match self.obj.socket_name() { + Ok(rtio::SocketAddr { ip, port }) => { + Ok(SocketAddr { ip: super::from_rtio(ip), port: port }) + } + Err(e) => Err(IoError::from_rtio_error(e)), + } } /// Sets the nodelay flag on this connection to the boolean specified @@ -123,7 +136,7 @@ impl TcpStream { self.obj.nodelay() } else { self.obj.control_congestion() - } + }.map_err(IoError::from_rtio_error) } /// Sets the keepalive timeout to the timeout specified. @@ -136,7 +149,7 @@ impl TcpStream { match delay_in_seconds { Some(i) => self.obj.keepalive(i), None => self.obj.letdie(), - } + }.map_err(IoError::from_rtio_error) } /// Closes the reading half of this connection. @@ -168,7 +181,9 @@ impl TcpStream { /// /// Note that this method affects all cloned handles associated with this /// stream, not just this one handle. - pub fn close_read(&mut self) -> IoResult<()> { self.obj.close_read() } + pub fn close_read(&mut self) -> IoResult<()> { + self.obj.close_read().map_err(IoError::from_rtio_error) + } /// Closes the writing half of this connection. /// @@ -177,7 +192,9 @@ impl TcpStream { /// /// Note that this method affects all cloned handles associated with this /// stream, not just this one handle. - pub fn close_write(&mut self) -> IoResult<()> { self.obj.close_write() } + pub fn close_write(&mut self) -> IoResult<()> { + self.obj.close_write().map_err(IoError::from_rtio_error) + } /// Sets a timeout, in milliseconds, for blocking operations on this stream. /// @@ -261,11 +278,15 @@ impl Clone for TcpStream { } impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { self.obj.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult { + self.obj.read(buf).map_err(IoError::from_rtio_error) + } } impl Writer for TcpStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.obj.write(buf).map_err(IoError::from_rtio_error) + } } /// A structure representing a socket server. This listener is used to create a @@ -319,10 +340,13 @@ impl TcpListener { pub fn bind(addr: &str, port: u16) -> IoResult { match FromStr::from_str(addr) { Some(ip) => { - let socket_addr = SocketAddr{ip: ip, port: port}; + let addr = rtio::SocketAddr{ + ip: super::to_rtio(ip), + port: port, + }; LocalIo::maybe_raise(|io| { - io.tcp_bind(socket_addr).map(|l| TcpListener { obj: l }) - }) + io.tcp_bind(addr).map(|l| TcpListener { obj: l }) + }).map_err(IoError::from_rtio_error) } None => { Err(IoError{ @@ -336,13 +360,21 @@ impl TcpListener { /// Returns the local socket address of this listener. pub fn socket_name(&mut self) -> IoResult { - self.obj.socket_name() + match self.obj.socket_name() { + Ok(rtio::SocketAddr { ip, port }) => { + Ok(SocketAddr { ip: super::from_rtio(ip), port: port }) + } + Err(e) => Err(IoError::from_rtio_error(e)), + } } } impl Listener for TcpListener { fn listen(self) -> IoResult { - self.obj.listen().map(|acceptor| TcpAcceptor { obj: acceptor }) + match self.obj.listen() { + Ok(acceptor) => Ok(TcpAcceptor { obj: acceptor }), + Err(e) => Err(IoError::from_rtio_error(e)), + } } } @@ -403,7 +435,10 @@ impl TcpAcceptor { impl Acceptor for TcpAcceptor { fn accept(&mut self) -> IoResult { - self.obj.accept().map(TcpStream::new) + match self.obj.accept(){ + Ok(s) => Ok(TcpStream::new(s)), + Err(e) => Err(IoError::from_rtio_error(e)), + } } } @@ -947,7 +982,8 @@ mod test { match TcpListener::bind(ip_str.as_slice(), port).listen() { Ok(..) => fail!(), Err(e) => { - assert!(e.kind == ConnectionRefused || e.kind == OtherIoError); + assert!(e.kind == ConnectionRefused || e.kind == OtherIoError, + "unknown error: {} {}", e, e.kind); } } }) diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index 875dd01be823b..538bba3695811 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -17,12 +17,13 @@ use clone::Clone; use io::net::ip::{SocketAddr, IpAddr}; -use io::{Reader, Writer, IoResult}; +use io::{Reader, Writer, IoResult, IoError}; use kinds::Send; use owned::Box; use option::Option; use result::{Ok, Err}; use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, LocalIo}; +use rt::rtio; /// A User Datagram Protocol socket. /// @@ -62,22 +63,32 @@ pub struct UdpSocket { impl UdpSocket { /// Creates a UDP socket from the given socket address. pub fn bind(addr: SocketAddr) -> IoResult { + let SocketAddr { ip, port } = addr; LocalIo::maybe_raise(|io| { + let addr = rtio::SocketAddr { ip: super::to_rtio(ip), port: port }; io.udp_bind(addr).map(|s| UdpSocket { obj: s }) - }) + }).map_err(IoError::from_rtio_error) } /// Receives data from the socket. On success, returns the number of bytes /// read and the address from whence the data came. pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> { - self.obj.recvfrom(buf) + match self.obj.recvfrom(buf) { + Ok((amt, rtio::SocketAddr { ip, port })) => { + Ok((amt, SocketAddr { ip: super::from_rtio(ip), port: port })) + } + Err(e) => Err(IoError::from_rtio_error(e)), + } } /// Sends data on the socket to the given address. Returns nothing on /// success. pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> { - self.obj.sendto(buf, dst) + self.obj.sendto(buf, rtio::SocketAddr { + ip: super::to_rtio(dst.ip), + port: dst.port, + }).map_err(IoError::from_rtio_error) } /// Creates a `UdpStream`, which allows use of the `Reader` and `Writer` @@ -95,19 +106,24 @@ impl UdpSocket { /// Returns the socket address that this socket was created from. pub fn socket_name(&mut self) -> IoResult { - self.obj.socket_name() + match self.obj.socket_name() { + Ok(a) => Ok(SocketAddr { ip: super::from_rtio(a.ip), port: a.port }), + Err(e) => Err(IoError::from_rtio_error(e)) + } } /// Joins a multicast IP address (becomes a member of it) #[experimental] pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> { - self.obj.join_multicast(multi) + let e = self.obj.join_multicast(super::to_rtio(multi)); + e.map_err(IoError::from_rtio_error) } /// Leaves a multicast IP address (drops membership from it) #[experimental] pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> { - self.obj.leave_multicast(multi) + let e = self.obj.leave_multicast(super::to_rtio(multi)); + e.map_err(IoError::from_rtio_error) } /// Set the multicast loop flag to the specified value @@ -119,19 +135,19 @@ impl UdpSocket { self.obj.loop_multicast_locally() } else { self.obj.dont_loop_multicast_locally() - } + }.map_err(IoError::from_rtio_error) } /// Sets the multicast TTL #[experimental] pub fn set_multicast_ttl(&mut self, ttl: int) -> IoResult<()> { - self.obj.multicast_time_to_live(ttl) + self.obj.multicast_time_to_live(ttl).map_err(IoError::from_rtio_error) } /// Sets this socket's TTL #[experimental] pub fn set_ttl(&mut self, ttl: int) -> IoResult<()> { - self.obj.time_to_live(ttl) + self.obj.time_to_live(ttl).map_err(IoError::from_rtio_error) } /// Sets the broadcast flag on or off @@ -141,7 +157,7 @@ impl UdpSocket { self.obj.hear_broadcasts() } else { self.obj.ignore_broadcasts() - } + }.map_err(IoError::from_rtio_error) } /// Sets the read/write timeout for this socket. diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index 1e320fe1aaed4..9715a821e4fcb 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -28,7 +28,7 @@ use prelude::*; use c_str::ToCStr; use clone::Clone; -use io::{Listener, Acceptor, Reader, Writer, IoResult}; +use io::{Listener, Acceptor, Reader, Writer, IoResult, IoError}; use kinds::Send; use owned::Box; use rt::rtio::{IoFactory, LocalIo, RtioUnixListener}; @@ -58,7 +58,7 @@ impl UnixStream { pub fn connect(path: &P) -> IoResult { LocalIo::maybe_raise(|io| { io.unix_connect(&path.to_c_str(), None).map(|p| UnixStream { obj: p }) - }) + }).map_err(IoError::from_rtio_error) } /// Connect to a pipe named by `path`, timing out if the specified number of @@ -72,7 +72,7 @@ impl UnixStream { LocalIo::maybe_raise(|io| { let s = io.unix_connect(&path.to_c_str(), Some(timeout_ms)); s.map(|p| UnixStream { obj: p }) - }) + }).map_err(IoError::from_rtio_error) } @@ -83,7 +83,9 @@ impl UnixStream { /// /// Note that this method affects all cloned handles associated with this /// stream, not just this one handle. - pub fn close_read(&mut self) -> IoResult<()> { self.obj.close_read() } + pub fn close_read(&mut self) -> IoResult<()> { + self.obj.close_read().map_err(IoError::from_rtio_error) + } /// Closes the writing half of this connection. /// @@ -92,7 +94,9 @@ impl UnixStream { /// /// Note that this method affects all cloned handles associated with this /// stream, not just this one handle. - pub fn close_write(&mut self) -> IoResult<()> { self.obj.close_write() } + pub fn close_write(&mut self) -> IoResult<()> { + self.obj.close_write().map_err(IoError::from_rtio_error) + } /// Sets the read/write timeout for this socket. /// @@ -126,11 +130,15 @@ impl Clone for UnixStream { } impl Reader for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { self.obj.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult { + self.obj.read(buf).map_err(IoError::from_rtio_error) + } } impl Writer for UnixStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.obj.write(buf).map_err(IoError::from_rtio_error) + } } /// A value that can listen for incoming named pipe connection requests. @@ -165,13 +173,15 @@ impl UnixListener { pub fn bind(path: &P) -> IoResult { LocalIo::maybe_raise(|io| { io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s }) - }) + }).map_err(IoError::from_rtio_error) } } impl Listener for UnixListener { fn listen(self) -> IoResult { - self.obj.listen().map(|obj| UnixAcceptor { obj: obj }) + self.obj.listen().map(|obj| { + UnixAcceptor { obj: obj } + }).map_err(IoError::from_rtio_error) } } @@ -202,7 +212,9 @@ impl UnixAcceptor { impl Acceptor for UnixAcceptor { fn accept(&mut self) -> IoResult { - self.obj.accept().map(|s| UnixStream { obj: s }) + self.obj.accept().map(|s| { + UnixStream { obj: s } + }).map_err(IoError::from_rtio_error) } } diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs index fbb0d5bc8d8ed..11bb27573c29a 100644 --- a/src/libstd/io/pipe.rs +++ b/src/libstd/io/pipe.rs @@ -16,7 +16,7 @@ #![allow(missing_doc)] use prelude::*; -use io::IoResult; +use io::{IoResult, IoError}; use libc; use owned::Box; use rt::rtio::{RtioPipe, LocalIo}; @@ -51,7 +51,7 @@ impl PipeStream { pub fn open(fd: libc::c_int) -> IoResult { LocalIo::maybe_raise(|io| { io.pipe_open(fd).map(|obj| PipeStream { obj: obj }) - }) + }).map_err(IoError::from_rtio_error) } #[doc(hidden)] @@ -67,11 +67,15 @@ impl Clone for PipeStream { } impl Reader for PipeStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { self.obj.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult { + self.obj.read(buf).map_err(IoError::from_rtio_error) + } } impl Writer for PipeStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.obj.write(buf).map_err(IoError::from_rtio_error) + } } #[cfg(test)] diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 1ed4659356218..059286339a6fa 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -16,12 +16,13 @@ use prelude::*; use str; use fmt; -use io::IoResult; +use io::{IoResult, IoError}; use io; use libc; use mem; use owned::Box; use rt::rtio::{RtioProcess, ProcessConfig, IoFactory, LocalIo}; +use rt::rtio; use c_str::CString; /// Signal a process to exit, without forcibly killing it. Corresponds to @@ -232,16 +233,25 @@ impl Command { /// Executes the command as a child process, which is returned. pub fn spawn(&self) -> IoResult { + fn to_rtio(p: StdioContainer) -> rtio::StdioContainer { + match p { + Ignored => rtio::Ignored, + InheritFd(fd) => rtio::InheritFd(fd), + CreatePipe(a, b) => rtio::CreatePipe(a, b), + } + } + let extra_io: Vec = + self.extra_io.iter().map(|x| to_rtio(*x)).collect(); LocalIo::maybe_raise(|io| { let cfg = ProcessConfig { program: &self.program, args: self.args.as_slice(), env: self.env.as_ref().map(|env| env.as_slice()), cwd: self.cwd.as_ref(), - stdin: self.stdin, - stdout: self.stdout, - stderr: self.stderr, - extra_io: self.extra_io.as_slice(), + stdin: to_rtio(self.stdin), + stdout: to_rtio(self.stdout), + stderr: to_rtio(self.stderr), + extra_io: extra_io.as_slice(), uid: self.uid, gid: self.gid, detach: self.detach, @@ -258,7 +268,7 @@ impl Command { extra_io: io.collect(), } }) - }) + }).map_err(IoError::from_rtio_error) } /// Executes the command as a child process, waiting for it to finish and @@ -393,7 +403,9 @@ impl Process { /// be successfully delivered if the child has exited, but not yet been /// reaped. pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> { - LocalIo::maybe_raise(|io| io.kill(id, signal)) + LocalIo::maybe_raise(|io| { + io.kill(id, signal) + }).map_err(IoError::from_rtio_error) } /// Returns the process id of this child process @@ -415,7 +427,7 @@ impl Process { /// /// If the signal delivery fails, the corresponding error is returned. pub fn signal(&mut self, signal: int) -> IoResult<()> { - self.handle.kill(signal) + self.handle.kill(signal).map_err(IoError::from_rtio_error) } /// Sends a signal to this child requesting that it exits. This is @@ -442,7 +454,11 @@ impl Process { /// `set_timeout` and the timeout expires before the child exits. pub fn wait(&mut self) -> IoResult { drop(self.stdin.take()); - self.handle.wait() + match self.handle.wait() { + Ok(rtio::ExitSignal(s)) => Ok(ExitSignal(s)), + Ok(rtio::ExitStatus(s)) => Ok(ExitStatus(s)), + Err(e) => Err(IoError::from_rtio_error(e)), + } } /// Sets a timeout, in milliseconds, for future calls to wait(). diff --git a/src/libstd/io/signal.rs b/src/libstd/io/signal.rs index 05392baff04c3..598a8667d41e9 100644 --- a/src/libstd/io/signal.rs +++ b/src/libstd/io/signal.rs @@ -28,7 +28,7 @@ use mem::drop; use option::{Some, None}; use owned::Box; use result::{Ok, Err}; -use rt::rtio::{IoFactory, LocalIo, RtioSignal}; +use rt::rtio::{IoFactory, LocalIo, RtioSignal, Callback}; use slice::ImmutableVector; use vec::Vec; @@ -122,17 +122,28 @@ impl Listener { /// If this function fails to register a signal handler, then an error will /// be returned. pub fn register(&mut self, signum: Signum) -> io::IoResult<()> { + struct SignalCallback { + signum: Signum, + tx: Sender, + } + impl Callback for SignalCallback { + fn call(&mut self) { self.tx.send(self.signum) } + } + if self.handles.iter().any(|&(sig, _)| sig == signum) { return Ok(()); // self is already listening to signum, so succeed } match LocalIo::maybe_raise(|io| { - io.signal(signum, self.tx.clone()) + io.signal(signum as int, box SignalCallback { + signum: signum, + tx: self.tx.clone(), + }) }) { Ok(handle) => { self.handles.push((signum, handle)); Ok(()) } - Err(e) => Err(e) + Err(e) => Err(io::IoError::from_rtio_error(e)) } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 6de4c6316d1df..5db09076c98e0 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -27,20 +27,19 @@ out.write(bytes!("Hello, world!")); */ +use failure::local_stderr; use fmt; use io::{Reader, Writer, IoResult, IoError, OtherIoError, standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; -use libc; use kinds::Send; -use mem::replace; +use libc; use option::{Option, Some, None}; use owned::Box; -use prelude::drop; use result::{Ok, Err}; use rt; use rt::local::Local; -use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY}; use rt::task::Task; +use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY}; use str::StrSlice; // And so begins the tale of acquiring a uv handle to a stdio stream on all @@ -82,9 +81,11 @@ fn src(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T { Ok(tty) => f(TTY(tty)), Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))), }) - }).unwrap() + }).map_err(IoError::from_rtio_error).unwrap() } +local_data_key!(local_stdout: Box) + /// Creates a new non-blocking handle to the stdin of the current process. /// /// The returned handled is buffered by default with a `BufferedReader`. If @@ -154,22 +155,6 @@ pub fn stderr_raw() -> StdWriter { src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src }) } -fn reset_helper(w: Box, - f: |&mut Task, Box| -> Option>) - -> Option> { - let mut t = Local::borrow(None::); - // Be sure to flush any pending output from the writer - match f(&mut *t, w) { - Some(mut w) => { - drop(t); - // FIXME: is failing right here? - w.flush().unwrap(); - Some(w) - } - None => None - } -} - /// Resets the task-local stdout handle to the specified writer /// /// This will replace the current task's stdout handle, returning the old @@ -179,7 +164,10 @@ fn reset_helper(w: Box, /// Note that this does not need to be called for all new tasks; the default /// output handle is to the process's stdout stream. pub fn set_stdout(stdout: Box) -> Option> { - reset_helper(stdout, |t, w| replace(&mut t.stdout, Some(w))) + local_stdout.replace(Some(stdout)).and_then(|mut s| { + let _ = s.flush(); + Some(s) + }) } /// Resets the task-local stderr handle to the specified writer @@ -191,7 +179,10 @@ pub fn set_stdout(stdout: Box) -> Option> { /// Note that this does not need to be called for all new tasks; the default /// output handle is to the process's stderr stream. pub fn set_stderr(stderr: Box) -> Option> { - reset_helper(stderr, |t, w| replace(&mut t.stderr, Some(w))) + local_stderr.replace(Some(stderr)).and_then(|mut s| { + let _ = s.flush(); + Some(s) + }) } // Helper to access the local task's stdout handle @@ -204,42 +195,18 @@ pub fn set_stderr(stderr: Box) -> Option> { // // io1 aliases io2 // }) // }) -fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) { - let task: Option> = Local::try_take(); - let result = match task { - Some(mut task) => { - // Printing may run arbitrary code, so ensure that the task is in - // TLS to allow all std services. Note that this means a print while - // printing won't use the task's normal stdout handle, but this is - // necessary to ensure safety (no aliasing). - let mut my_stdout = task.stdout.take(); - Local::put(task); - - if my_stdout.is_none() { - my_stdout = Some(box stdout() as Box); - } - let ret = f(*my_stdout.get_mut_ref()); - - // Note that we need to be careful when putting the stdout handle - // back into the task. If the handle was set to `Some` while - // printing, then we can run aribitrary code when destroying the - // previous handle. This means that the local task needs to be in - // TLS while we do this. - // - // To protect against this, we do a little dance in which we - // temporarily take the task, swap the handles, put the task in TLS, - // and only then drop the previous handle. - let prev = replace(&mut Local::borrow(None::).stdout, my_stdout); - drop(prev); - ret - } - - None => { - let mut io = rt::Stdout; - f(&mut io as &mut Writer) - } +fn with_task_stdout(f: |&mut Writer| -> IoResult<()>) { + let result = if Local::exists(None::) { + let mut my_stdout = local_stdout.replace(None).unwrap_or_else(|| { + box stdout() as Box + }); + let result = f(my_stdout); + local_stdout.replace(Some(my_stdout)); + result + } else { + let mut io = rt::Stdout; + f(&mut io as &mut Writer) }; - match result { Ok(()) => {} Err(e) => fail!("failed printing to stdout: {}", e), @@ -311,7 +278,7 @@ impl Reader for StdReader { tty.read(buf) }, File(ref mut file) => file.read(buf).map(|i| i as uint), - }; + }.map_err(IoError::from_rtio_error); match ret { // When reading a piped stdin, libuv will return 0-length reads when // stdin reaches EOF. For pretty much all other streams it will @@ -342,7 +309,9 @@ impl StdWriter { /// connected to a TTY instance, or if querying the TTY instance fails. pub fn winsize(&mut self) -> IoResult<(int, int)> { match self.inner { - TTY(ref mut tty) => tty.get_winsize(), + TTY(ref mut tty) => { + tty.get_winsize().map_err(IoError::from_rtio_error) + } File(..) => { Err(IoError { kind: OtherIoError, @@ -362,7 +331,9 @@ impl StdWriter { /// connected to a TTY instance, or if querying the TTY instance fails. pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { match self.inner { - TTY(ref mut tty) => tty.set_raw(raw), + TTY(ref mut tty) => { + tty.set_raw(raw).map_err(IoError::from_rtio_error) + } File(..) => { Err(IoError { kind: OtherIoError, @@ -387,7 +358,7 @@ impl Writer for StdWriter { match self.inner { TTY(ref mut tty) => tty.write(buf), File(ref mut file) => file.write(buf), - } + }.map_err(IoError::from_rtio_error) } } @@ -413,12 +384,13 @@ mod tests { }) iotest!(fn capture_stderr() { - use io::{ChanReader, ChanWriter}; + use realstd::comm::channel; + use realstd::io::{Writer, ChanReader, ChanWriter, Reader}; let (tx, rx) = channel(); let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx)); spawn(proc() { - set_stderr(box w); + ::realstd::io::stdio::set_stderr(box w); fail!("my special message"); }); let s = r.read_to_str().unwrap(); diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index d7476dd2de874..78b8e55c65174 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -17,11 +17,11 @@ and create receivers which will receive notifications after a period of time. */ -use comm::Receiver; -use io::IoResult; +use comm::{Receiver, Sender, channel}; +use io::{IoResult, IoError}; use kinds::Send; use owned::Box; -use rt::rtio::{IoFactory, LocalIo, RtioTimer}; +use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback}; /// A synchronous timer object /// @@ -67,6 +67,8 @@ pub struct Timer { obj: Box, } +struct TimerCallback { tx: Sender<()> } + /// Sleep the current task for `msecs` milliseconds. pub fn sleep(msecs: u64) { let timer = Timer::new(); @@ -80,7 +82,9 @@ impl Timer { /// for a number of milliseconds, or to possibly create channels which will /// get notified after an amount of time has passed. pub fn new() -> IoResult { - LocalIo::maybe_raise(|io| io.timer_init().map(|t| Timer { obj: t })) + LocalIo::maybe_raise(|io| { + io.timer_init().map(|t| Timer { obj: t }) + }).map_err(IoError::from_rtio_error) } /// Blocks the current task for `msecs` milliseconds. @@ -99,7 +103,9 @@ impl Timer { /// by this timer, and that the returned receiver will be invalidated once /// the timer is destroyed (when it falls out of scope). pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> { - self.obj.oneshot(msecs) + let (tx, rx) = channel(); + self.obj.oneshot(msecs, box TimerCallback { tx: tx }); + return rx } /// Creates a receiver which will have a continuous stream of notifications @@ -112,7 +118,15 @@ impl Timer { /// by this timer, and that the returned receiver will be invalidated once /// the timer is destroyed (when it falls out of scope). pub fn periodic(&mut self, msecs: u64) -> Receiver<()> { - self.obj.period(msecs) + let (tx, rx) = channel(); + self.obj.period(msecs, box TimerCallback { tx: tx }); + return rx + } +} + +impl Callback for TimerCallback { + fn call(&mut self) { + let _ = self.tx.send_opt(()); } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 109832b7c4795..bac4d26b4e49a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -103,8 +103,8 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/", html_playground_url = "http://play.rust-lang.org/")] -#![feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args, - linkage, default_type_params, phase, concat_idents, quad_precision_float)] +#![feature(macro_rules, globs, managed_boxes, + linkage, default_type_params, phase)] // Don't link to std. We are std. #![no_std] @@ -123,9 +123,10 @@ extern crate alloc; extern crate core; -extern crate libc; -extern crate core_rand = "rand"; extern crate core_collections = "collections"; +extern crate core_rand = "rand"; +extern crate libc; +extern crate rustrt; // Make std testable by not duplicating lang items. See #2912 #[cfg(test)] extern crate realstd = "std"; @@ -168,6 +169,9 @@ pub use core_collections::str; pub use core_collections::string; pub use core_collections::vec; +pub use rustrt::c_str; +pub use rustrt::local_data; + // Run tests with libgreen instead of libnative. // // FIXME: This egregiously hacks around starting the test runner in a different @@ -231,19 +235,16 @@ pub mod collections; pub mod task; pub mod comm; -pub mod local_data; pub mod sync; /* Runtime and platform support */ -pub mod c_str; pub mod c_vec; pub mod os; pub mod io; pub mod path; pub mod fmt; -pub mod cleanup; // Private APIs #[unstable] @@ -253,11 +254,7 @@ pub mod unstable; // but name resolution doesn't work without it being pub. #[unstable] pub mod rt; - -#[doc(hidden)] -pub fn issue_14344_workaround() { // FIXME #14344 force linkage to happen correctly - libc::issue_14344_workaround(); -} +mod failure; // A curious inner-module that's not exported that contains the binding // 'std' so that macro-expanded references to std::error and such diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 381ebc0820064..9a7e061c47282 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -189,7 +189,7 @@ Accessing environment variables is not generally threadsafe. Serialize access through a global lock. */ fn with_env_lock(f: || -> T) -> T { - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT; diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs deleted file mode 100644 index c892a73d93484..0000000000000 --- a/src/libstd/rt/at_exit_imp.rs +++ /dev/null @@ -1,74 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of running at_exit routines -//! -//! Documentation can be found on the `rt::at_exit` function. - -use iter::Iterator; -use kinds::Send; -use mem; -use option::{Some, None}; -use owned::Box; -use ptr::RawPtr; -use slice::OwnedVector; -use unstable::sync::Exclusive; -use vec::Vec; - -type Queue = Exclusive>; - -// You'll note that these variables are *not* atomic, and this is done on -// purpose. This module is designed to have init() called *once* in a -// single-task context, and then run() is called only once in another -// single-task context. As a result of this, only the `push` function is -// thread-safe, and it assumes that the `init` function has run previously. -static mut QUEUE: *mut Queue = 0 as *mut Queue; -static mut RUNNING: bool = false; - -pub fn init() { - unsafe { - rtassert!(!RUNNING); - rtassert!(QUEUE.is_null()); - let state: Box = box Exclusive::new(vec!()); - QUEUE = mem::transmute(state); - } -} - -pub fn push(f: proc():Send) { - unsafe { - rtassert!(!RUNNING); - rtassert!(!QUEUE.is_null()); - let state: &mut Queue = mem::transmute(QUEUE); - let mut f = Some(f); - state.with(|arr| { - arr.push(f.take_unwrap()); - }); - } -} - -pub fn run() { - let vec = unsafe { - rtassert!(!RUNNING); - rtassert!(!QUEUE.is_null()); - RUNNING = true; - let state: Box = mem::transmute(QUEUE); - QUEUE = 0 as *mut Queue; - let mut vec = None; - state.with(|arr| { - vec = Some(mem::replace(arr, vec!())); - }); - vec.take_unwrap() - }; - - - for f in vec.move_iter() { - f(); - } -} diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 94472ee72414c..766901fa04f32 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -242,8 +242,7 @@ mod imp { use mem; use option::{Some, None, Option}; use result::{Ok, Err}; - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - use uw = rt::libunwind; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; struct Context<'a> { idx: int, @@ -484,6 +483,106 @@ mod imp { } w.write(['\n' as u8]) } + + /// Unwind library interface used for backtraces + /// + /// Note that the native libraries come from librustrt, not this module. + #[allow(non_camel_case_types)] + #[allow(non_snake_case_functions)] + mod uw { + use libc; + + #[repr(C)] + pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EABI + } + + pub enum _Unwind_Context {} + + pub type _Unwind_Trace_Fn = + extern fn(ctx: *_Unwind_Context, + arg: *libc::c_void) -> _Unwind_Reason_Code; + + extern { + pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, + trace_argument: *libc::c_void) + -> _Unwind_Reason_Code; + + #[cfg(not(target_os = "android"), + not(target_os = "linux", target_arch = "arm"))] + pub fn _Unwind_GetIP(ctx: *_Unwind_Context) -> libc::uintptr_t; + #[cfg(not(target_os = "android"), + not(target_os = "linux", target_arch = "arm"))] + pub fn _Unwind_FindEnclosingFunction(pc: *libc::c_void) + -> *libc::c_void; + } + + // On android, the function _Unwind_GetIP is a macro, and this is the + // expansion of the macro. This is all copy/pasted directly from the + // header file with the definition of _Unwind_GetIP. + #[cfg(target_os = "android")] + #[cfg(target_os = "linux", target_arch = "arm")] + pub unsafe fn _Unwind_GetIP(ctx: *_Unwind_Context) -> libc::uintptr_t { + #[repr(C)] + enum _Unwind_VRS_Result { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2, + } + #[repr(C)] + enum _Unwind_VRS_RegClass { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_FPA = 2, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4, + } + #[repr(C)] + enum _Unwind_VRS_DataRepresentation { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5, + } + + type _Unwind_Word = libc::c_uint; + extern { + fn _Unwind_VRS_Get(ctx: *_Unwind_Context, + klass: _Unwind_VRS_RegClass, + word: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut libc::c_void) + -> _Unwind_VRS_Result; + } + + let mut val: _Unwind_Word = 0; + let ptr = &mut val as *mut _Unwind_Word; + let _ = _Unwind_VRS_Get(ctx, _UVRSC_CORE, 15, _UVRSD_UINT32, + ptr as *mut libc::c_void); + (val & !1) as libc::uintptr_t + } + + // This function also doesn't exist on android or arm/linux, so make it + // a no-op + #[cfg(target_os = "android")] + #[cfg(target_os = "linux", target_arch = "arm")] + pub unsafe fn _Unwind_FindEnclosingFunction(pc: *libc::c_void) + -> *libc::c_void + { + pc + } + } } /// As always, windows has something very different than unix, we mainly want @@ -504,6 +603,7 @@ mod imp { mod imp { use c_str::CString; use container::Container; + use intrinsics; use io::{IoResult, Writer}; use libc; use mem; @@ -511,11 +611,10 @@ mod imp { use option::{Some, None}; use path::Path; use result::{Ok, Err}; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use slice::ImmutableVector; use str::StrSlice; use unstable::dynamic_lib::DynamicLibrary; - use intrinsics; - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - use slice::ImmutableVector; #[allow(non_snake_case_functions)] extern "system" { diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs deleted file mode 100644 index 7271464d1e92f..0000000000000 --- a/src/libstd/rt/env.rs +++ /dev/null @@ -1,61 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Runtime environment settings - -use from_str::from_str; -use option::{Some, None}; -use os; -use str::Str; - -// Note that these are all accessed without any synchronization. -// They are expected to be initialized once then left alone. - -static mut MIN_STACK: uint = 2 * 1024 * 1024; -/// This default corresponds to 20M of cache per scheduler (at the default size). -static mut MAX_CACHED_STACKS: uint = 10; -static mut DEBUG_BORROW: bool = false; - -pub fn init() { - unsafe { - match os::getenv("RUST_MIN_STACK") { - Some(s) => match from_str(s.as_slice()) { - Some(i) => MIN_STACK = i, - None => () - }, - None => () - } - match os::getenv("RUST_MAX_CACHED_STACKS") { - Some(max) => { - MAX_CACHED_STACKS = - from_str(max.as_slice()).expect("expected positive \ - integer in \ - RUST_MAX_CACHED_STACKS") - } - None => () - } - match os::getenv("RUST_DEBUG_BORROW") { - Some(_) => DEBUG_BORROW = true, - None => () - } - } -} - -pub fn min_stack() -> uint { - unsafe { MIN_STACK } -} - -pub fn max_cached_stacks() -> uint { - unsafe { MAX_CACHED_STACKS } -} - -pub fn debug_borrow() -> bool { - unsafe { DEBUG_BORROW } -} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index d2131ad44fb30..a68a632bc37e0 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -54,159 +54,37 @@ Several modules in `core` are clients of `rt`: // FIXME: this should not be here. #![allow(missing_doc)] -use any::Any; -use kinds::Send; -use option::Option; -use owned::Box; -use result::Result; -use task::TaskOpts; +use failure; +use rustrt; -use self::task::{Task, BlockedTask}; - -// this is somewhat useful when a program wants to spawn a "reasonable" number -// of workers based on the constraints of the system that it's running on. -// Perhaps this shouldn't be a `pub use` though and there should be another -// method... -pub use self::util::default_sched_threads; - -// Export unwinding facilities used by the failure macros -pub use self::unwind::{begin_unwind, begin_unwind_fmt}; - -pub use self::util::{Stdio, Stdout, Stderr}; +// Reexport some of our utilities which are expected by other crates. +pub use self::util::{default_sched_threads, min_stack, running_on_valgrind}; +// Reexport functionality from librustrt and other crates underneath the +// standard library which work together to create the entire runtime. pub use alloc::{heap, libc_heap}; - -// Used by I/O tests -#[experimental] -pub use self::util::running_on_valgrind; - -// FIXME: these probably shouldn't be public... -#[doc(hidden)] -pub mod shouldnt_be_public { - #[cfg(not(test))] - pub use super::local_ptr::native::maybe_tls_key; - #[cfg(not(windows), not(target_os = "android"))] - pub use super::local_ptr::compiled::RT_TLS_PTR; -} - -// Internal macros used by the runtime. -mod macros; - -/// Implementations of language-critical runtime features like @. -pub mod task; - -// The EventLoop and internal synchronous I/O interface. -pub mod rtio; - -// The Local trait for types that are accessible via thread-local -// or task-local storage. -pub mod local; +pub use rustrt::{task, local, mutex, exclusive, stack, args, rtio}; +pub use rustrt::{Stdio, Stdout, Stderr, begin_unwind, begin_unwind_fmt}; +pub use rustrt::{bookkeeping, at_exit, unwind, DEFAULT_ERROR_CODE, Runtime}; // Bindings to system threading libraries. pub mod thread; -// The runtime configuration, read from environment variables. -pub mod env; - -// The local, managed heap -pub mod local_heap; - -// The runtime needs to be able to put a pointer into thread-local storage. -mod local_ptr; - -// Bindings to pthread/windows thread-local storage. -mod thread_local_storage; - -// Stack unwinding -pub mod unwind; - -// The interface to libunwind that rust is using. -mod libunwind; - // Simple backtrace functionality (to print on failure) pub mod backtrace; // Just stuff mod util; -// Global command line argument storage -pub mod args; - -// Support for running procedures when a program has exited. -mod at_exit_imp; - -// Bookkeeping for task counts -pub mod bookkeeping; - -// Stack overflow protection -pub mod stack; - -/// The default error code of the rust runtime if the main task fails instead -/// of exiting cleanly. -pub static DEFAULT_ERROR_CODE: int = 101; - -/// The interface to the current runtime. -/// -/// This trait is used as the abstraction between 1:1 and M:N scheduling. The -/// two independent crates, libnative and libgreen, both have objects which -/// implement this trait. The goal of this trait is to encompass all the -/// fundamental differences in functionality between the 1:1 and M:N runtime -/// modes. -pub trait Runtime { - // Necessary scheduling functions, used for channels and blocking I/O - // (sometimes). - fn yield_now(~self, cur_task: Box); - fn maybe_yield(~self, cur_task: Box); - fn deschedule(~self, times: uint, cur_task: Box, - f: |BlockedTask| -> Result<(), BlockedTask>); - fn reawaken(~self, to_wake: Box); - - // Miscellaneous calls which are very different depending on what context - // you're in. - fn spawn_sibling(~self, - cur_task: Box, - opts: TaskOpts, - f: proc():Send); - fn local_io<'a>(&'a mut self) -> Option>; - /// The (low, high) edges of the current stack. - fn stack_bounds(&self) -> (uint, uint); // (lo, hi) - fn can_block(&self) -> bool; - - // FIXME: This is a serious code smell and this should not exist at all. - fn wrap(~self) -> Box; -} - /// One-time runtime initialization. /// /// Initializes global state, including frobbing /// the crate's logging flags, registering GC /// metadata, and storing the process arguments. +#[allow(experimental)] pub fn init(argc: int, argv: **u8) { - // FIXME: Derefing these pointers is not safe. - // Need to propagate the unsafety to `start`. - unsafe { - args::init(argc, argv); - env::init(); - local_ptr::init(); - at_exit_imp::init(); - } -} - -/// Enqueues a procedure to run when the runtime is cleaned up -/// -/// The procedure passed to this function will be executed as part of the -/// runtime cleanup phase. For normal rust programs, this means that it will run -/// after all other tasks have exited. -/// -/// The procedure is *not* executed with a local `Task` available to it, so -/// primitives like logging, I/O, channels, spawning, etc, are *not* available. -/// This is meant for "bare bones" usage to clean up runtime details, this is -/// not meant as a general-purpose "let's clean everything up" function. -/// -/// It is forbidden for procedures to register more `at_exit` handlers when they -/// are running, and doing so will lead to a process abort. -pub fn at_exit(f: proc():Send) { - at_exit_imp::push(f); + rustrt::init(argc, argv); + unsafe { unwind::register(failure::on_fail); } } /// One-time runtime cleanup. @@ -219,8 +97,5 @@ pub fn at_exit(f: proc():Send) { /// Invoking cleanup while portions of the runtime are still in use may cause /// undefined behavior. pub unsafe fn cleanup() { - bookkeeping::wait_for_other_tasks(); - at_exit_imp::run(); - args::cleanup(); - local_ptr::cleanup(); + rustrt::cleanup(); } diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 103fbdc0bc93d..670d4aa2061f1 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -8,23 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use container::Container; -use fmt; use from_str::FromStr; -use io::IoResult; -use io; -use iter::Iterator; -use libc; +use from_str::from_str; use libc::uintptr_t; +use libc; use option::{Some, None, Option}; use os; -use result::Ok; -use str::{Str, StrSlice}; -use slice::ImmutableVector; - -// Indicates whether we should perform expensive sanity checks, including rtassert! -// FIXME: Once the runtime matures remove the `true` below to turn off rtassert, etc. -pub static ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) || cfg!(rtassert); +use str::Str; +use sync::atomics; /// Get the number of cores available pub fn num_cpus() -> uint { @@ -37,6 +28,17 @@ pub fn num_cpus() -> uint { } } +/// Dynamically inquire about whether we're running under V. +/// You should usually not use this unless your test definitely +/// can't run correctly un-altered. Valgrind is there to help +/// you notice weirdness in normal, un-doctored code paths! +pub fn running_on_valgrind() -> bool { + extern { + fn rust_running_on_valgrind() -> uintptr_t; + } + unsafe { rust_running_on_valgrind() != 0 } +} + /// Valgrind has a fixed-sized array (size around 2000) of segment descriptors /// wired into it; this is a hard limit and requires rebuilding valgrind if you /// want to go beyond it. Normally this is not a problem, but in some tests, we @@ -50,6 +52,20 @@ pub fn limit_thread_creation_due_to_osx_and_valgrind() -> bool { (cfg!(target_os="macos")) && running_on_valgrind() } +pub fn min_stack() -> uint { + static mut MIN: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT; + match unsafe { MIN.load(atomics::SeqCst) } { + 0 => {} + n => return n - 1, + } + let amt = os::getenv("RUST_MIN_STACK").and_then(|s| from_str(s.as_slice())); + let amt = amt.unwrap_or(2 * 1024 * 1024); + // 0 is our sentinel value, so ensure that we'll never see 0 after + // initialization has run + unsafe { MIN.store(amt + 1, atomics::SeqCst); } + return amt; +} + /// Get's the number of scheduler threads requested by the environment /// either `RUST_THREADS` or `num_cpus`. pub fn default_sched_threads() -> uint { @@ -58,7 +74,7 @@ pub fn default_sched_threads() -> uint { let opt_n: Option = FromStr::from_str(nstr.as_slice()); match opt_n { Some(n) if n > 0 => n, - _ => rtabort!("`RUST_THREADS` is `{}`, should be a positive integer", nstr) + _ => fail!("`RUST_THREADS` is `{}`, should be a positive integer", nstr) } } None => { @@ -70,107 +86,3 @@ pub fn default_sched_threads() -> uint { } } } - -pub struct Stdio(libc::c_int); - -pub static Stdout: Stdio = Stdio(libc::STDOUT_FILENO); -pub static Stderr: Stdio = Stdio(libc::STDERR_FILENO); - -impl io::Writer for Stdio { - fn write(&mut self, data: &[u8]) -> IoResult<()> { - #[cfg(unix)] - type WriteLen = libc::size_t; - #[cfg(windows)] - type WriteLen = libc::c_uint; - unsafe { - let Stdio(fd) = *self; - libc::write(fd, - data.as_ptr() as *libc::c_void, - data.len() as WriteLen); - } - Ok(()) // yes, we're lying - } -} - -pub fn dumb_println(args: &fmt::Arguments) { - use io::Writer; - let mut w = Stderr; - let _ = writeln!(&mut w, "{}", args); -} - -pub fn abort(msg: &str) -> ! { - let msg = if !msg.is_empty() { msg } else { "aborted" }; - let hash = msg.chars().fold(0, |accum, val| accum + (val as uint) ); - let quote = match hash % 10 { - 0 => " -It was from the artists and poets that the pertinent answers came, and I -know that panic would have broken loose had they been able to compare notes. -As it was, lacking their original letters, I half suspected the compiler of -having asked leading questions, or of having edited the correspondence in -corroboration of what he had latently resolved to see.", - 1 => " -There are not many persons who know what wonders are opened to them in the -stories and visions of their youth; for when as children we listen and dream, -we think but half-formed thoughts, and when as men we try to remember, we are -dulled and prosaic with the poison of life. But some of us awake in the night -with strange phantasms of enchanted hills and gardens, of fountains that sing -in the sun, of golden cliffs overhanging murmuring seas, of plains that stretch -down to sleeping cities of bronze and stone, and of shadowy companies of heroes -that ride caparisoned white horses along the edges of thick forests; and then -we know that we have looked back through the ivory gates into that world of -wonder which was ours before we were wise and unhappy.", - 2 => " -Instead of the poems I had hoped for, there came only a shuddering blackness -and ineffable loneliness; and I saw at last a fearful truth which no one had -ever dared to breathe before — the unwhisperable secret of secrets — The fact -that this city of stone and stridor is not a sentient perpetuation of Old New -York as London is of Old London and Paris of Old Paris, but that it is in fact -quite dead, its sprawling body imperfectly embalmed and infested with queer -animate things which have nothing to do with it as it was in life.", - 3 => " -The ocean ate the last of the land and poured into the smoking gulf, thereby -giving up all it had ever conquered. From the new-flooded lands it flowed -again, uncovering death and decay; and from its ancient and immemorial bed it -trickled loathsomely, uncovering nighted secrets of the years when Time was -young and the gods unborn. Above the waves rose weedy remembered spires. The -moon laid pale lilies of light on dead London, and Paris stood up from its damp -grave to be sanctified with star-dust. Then rose spires and monoliths that were -weedy but not remembered; terrible spires and monoliths of lands that men never -knew were lands...", - 4 => " -There was a night when winds from unknown spaces whirled us irresistibly into -limitless vacuum beyond all thought and entity. Perceptions of the most -maddeningly untransmissible sort thronged upon us; perceptions of infinity -which at the time convulsed us with joy, yet which are now partly lost to my -memory and partly incapable of presentation to others.", - _ => "You've met with a terrible fate, haven't you?" - }; - ::alloc::util::make_stdlib_link_work(); // see comments in liballoc - rterrln!("{}", ""); - rterrln!("{}", quote); - rterrln!("{}", ""); - rterrln!("fatal runtime error: {}", msg); - - { - let mut err = Stderr; - let _err = ::rt::backtrace::write(&mut err); - } - abort(); - - fn abort() -> ! { - use intrinsics; - unsafe { intrinsics::abort() } - } -} - -/// Dynamically inquire about whether we're running under V. -/// You should usually not use this unless your test definitely -/// can't run correctly un-altered. Valgrind is there to help -/// you notice weirdness in normal, un-doctored code paths! -pub fn running_on_valgrind() -> bool { - unsafe { rust_running_on_valgrind() != 0 } -} - -extern { - fn rust_running_on_valgrind() -> uintptr_t; -} diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index f954bcabe5aa9..c804918ae4b41 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -13,7 +13,7 @@ //! necessary for running libstd. // All platforms need to link to rustrt -#[link(name = "rustrt", kind = "static")] +#[link(name = "rust_builtin", kind = "static")] extern {} // LLVM implements the `frem` instruction as a call to `fmod`, which lives in diff --git a/src/libstd/sync/deque.rs b/src/libstd/sync/deque.rs index ea4c12f440198..39e420685abd9 100644 --- a/src/libstd/sync/deque.rs +++ b/src/libstd/sync/deque.rs @@ -63,7 +63,7 @@ use ptr; use rt::heap::{allocate, deallocate}; use slice::ImmutableVector; use sync::atomics::{AtomicInt, AtomicPtr, SeqCst}; -use unstable::sync::Exclusive; +use rt::exclusive::Exclusive; use vec::Vec; // Once the queue is less than 1/K full, then it will be downsized. Note that @@ -121,7 +121,7 @@ pub enum Stolen { /// will only use this structure when allocating a new buffer or deallocating a /// previous one. pub struct BufferPool { - pool: Exclusive>>>, + pool: Arc>>>>, } /// An internal buffer used by the chase-lev deque. This structure is actually @@ -148,7 +148,7 @@ impl BufferPool { /// Allocates a new buffer pool which in turn can be used to allocate new /// deques. pub fn new() -> BufferPool { - BufferPool { pool: Exclusive::new(vec!()) } + BufferPool { pool: Arc::new(Exclusive::new(vec!())) } } /// Allocates a new work-stealing deque which will send/receiving memory to @@ -162,25 +162,21 @@ impl BufferPool { fn alloc(&self, bits: int) -> Box> { unsafe { - self.pool.with(|pool| { - match pool.iter().position(|x| x.size() >= (1 << bits)) { - Some(i) => pool.remove(i).unwrap(), - None => box Buffer::new(bits) - } - }) + let mut pool = self.pool.lock(); + match pool.iter().position(|x| x.size() >= (1 << bits)) { + Some(i) => pool.remove(i).unwrap(), + None => box Buffer::new(bits) + } } } fn free(&self, buf: Box>) { unsafe { - let mut buf = Some(buf); - self.pool.with(|pool| { - let buf = buf.take_unwrap(); - match pool.iter().position(|v| v.size() > buf.size()) { - Some(i) => pool.insert(i, buf), - None => pool.push(buf), - } - }) + let mut pool = self.pool.lock(); + match pool.iter().position(|v| v.size() > buf.size()) { + Some(i) => pool.insert(i, buf), + None => pool.push(buf), + } } } } diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 3b573b875744b..9ee62ee3d81b6 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -38,12 +38,13 @@ use any::Any; use comm::{Sender, Receiver, channel}; -use io::Writer; +use io::{Writer, stdio}; use kinds::{Send, marker}; use option::{None, Some, Option}; use owned::Box; use result::{Result, Ok, Err}; use rt::local::Local; +use rt::task; use rt::task::Task; use str::{Str, SendStr, IntoMaybeOwned}; @@ -53,18 +54,10 @@ use str::{Str, SendStr, IntoMaybeOwned}; #[cfg(test)] use str::StrAllocating; #[cfg(test)] use string::String; -/// Indicates the manner in which a task exited. -/// -/// A task that completes without failing is considered to exit successfully. -/// -/// If you wish for this result's delivery to block until all -/// children tasks complete, recommend using a result future. -pub type TaskResult = Result<(), Box>; - /// Task configuration options pub struct TaskOpts { /// Enable lifecycle notifications on the given channel - pub notify_chan: Option>, + pub notify_chan: Option>, /// A name for the task-to-be, for identification in failure messages pub name: Option, /// The size of the stack for the spawned task @@ -114,7 +107,7 @@ impl TaskBuilder { /// /// # Failure /// Fails if a future_result was already set for this task. - pub fn future_result(&mut self) -> Receiver { + pub fn future_result(&mut self) -> Receiver { // FIXME (#3725): Once linked failure and notification are // handled in the library, I can imagine implementing this by just // registering an arbitrary number of task::on_exit handlers and @@ -180,7 +173,22 @@ impl TaskBuilder { Some(t) => t, None => fail!("need a local task to spawn a new task"), }; - t.spawn_sibling(self.opts, f); + let TaskOpts { notify_chan, name, stack_size, stdout, stderr } = self.opts; + + let opts = task::TaskOpts { + on_exit: notify_chan.map(|c| proc(r) c.send(r)), + name: name, + stack_size: stack_size, + }; + if stdout.is_some() || stderr.is_some() { + t.spawn_sibling(opts, proc() { + let _ = stdout.map(stdio::set_stdout); + let _ = stderr.map(stdio::set_stderr); + f(); + }); + } else { + t.spawn_sibling(opts, f); + } } /** diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs index 6c406a7c8472e..c05cdc85cc53a 100644 --- a/src/libstd/unstable/dynamic_lib.rs +++ b/src/libstd/unstable/dynamic_lib.rs @@ -224,7 +224,7 @@ pub mod dl { } pub fn check_for_errors_in(f: || -> T) -> Result { - use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT; unsafe { // dlerror isn't thread safe, so we need to lock around this entire diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index d8de6463fabbd..985ef2e142cfd 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -11,7 +11,3 @@ #![doc(hidden)] pub mod dynamic_lib; - -pub mod sync; -pub mod mutex; - diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs deleted file mode 100644 index f0f7e40ce09b8..0000000000000 --- a/src/libstd/unstable/sync.rs +++ /dev/null @@ -1,159 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use alloc::arc::Arc; - -use clone::Clone; -use kinds::Send; -use ty::Unsafe; -use unstable::mutex::NativeMutex; - -struct ExData { - lock: NativeMutex, - failed: bool, - data: T, -} - -/** - * An arc over mutable data that is protected by a lock. For library use only. - * - * # Safety note - * - * This uses a pthread mutex, not one that's aware of the userspace scheduler. - * The user of an Exclusive must be careful not to invoke any functions that may - * reschedule the task while holding the lock, or deadlock may result. If you - * need to block or deschedule while accessing shared state, use extra::sync::RWArc. - */ -pub struct Exclusive { - x: Arc>> -} - -impl Clone for Exclusive { - // Duplicate an Exclusive Arc, as std::arc::clone. - fn clone(&self) -> Exclusive { - Exclusive { x: self.x.clone() } - } -} - -impl Exclusive { - pub fn new(user_data: T) -> Exclusive { - let data = ExData { - lock: unsafe {NativeMutex::new()}, - failed: false, - data: user_data - }; - Exclusive { - x: Arc::new(Unsafe::new(data)) - } - } - - // Exactly like sync::MutexArc.access(). Same reason for being - // unsafe. - // - // Currently, scheduling operations (i.e., descheduling, receiving on a pipe, - // accessing the provided condition variable) are prohibited while inside - // the Exclusive. Supporting that is a work in progress. - #[inline] - pub unsafe fn with(&self, f: |x: &mut T| -> U) -> U { - let rec = self.x.get(); - let _l = (*rec).lock.lock(); - if (*rec).failed { - fail!("Poisoned Exclusive::new - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&mut (*rec).data); - (*rec).failed = false; - result - } - - #[inline] - pub unsafe fn with_imm(&self, f: |x: &T| -> U) -> U { - self.with(|x| f(x)) - } - - #[inline] - pub unsafe fn hold_and_signal(&self, f: |x: &mut T|) { - let rec = self.x.get(); - let guard = (*rec).lock.lock(); - if (*rec).failed { - fail!("Poisoned Exclusive::new - another task failed inside!"); - } - (*rec).failed = true; - f(&mut (*rec).data); - (*rec).failed = false; - guard.signal(); - } - - #[inline] - pub unsafe fn hold_and_wait(&self, f: |x: &T| -> bool) { - let rec = self.x.get(); - let l = (*rec).lock.lock(); - if (*rec).failed { - fail!("Poisoned Exclusive::new - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&(*rec).data); - (*rec).failed = false; - if result { - l.wait(); - } - } -} - -#[cfg(test)] -mod tests { - use option::*; - use prelude::*; - use super::Exclusive; - use task; - - #[test] - fn exclusive_new_arc() { - unsafe { - let mut futures = Vec::new(); - - let num_tasks = 10; - let count = 10; - - let total = Exclusive::new(box 0); - - for _ in range(0u, num_tasks) { - let total = total.clone(); - let (tx, rx) = channel(); - futures.push(rx); - - task::spawn(proc() { - for _ in range(0u, count) { - total.with(|count| **count += 1); - } - tx.send(()); - }); - }; - - for f in futures.mut_iter() { f.recv() } - - total.with(|total| assert!(**total == num_tasks * count)); - } - } - - #[test] #[should_fail] - fn exclusive_new_poison() { - unsafe { - // Tests that if one task fails inside of an Exclusive::new, subsequent - // accesses will also fail. - let x = Exclusive::new(1); - let x2 = x.clone(); - let _ = task::try(proc() { - x2.with(|one| assert_eq!(*one, 2)) - }); - x.with(|one| assert_eq!(*one, 1)); - } - } -} diff --git a/src/libsync/mutex.rs b/src/libsync/mutex.rs index ee7fa525e79f5..bcf5a43fb6b3e 100644 --- a/src/libsync/mutex.rs +++ b/src/libsync/mutex.rs @@ -64,7 +64,7 @@ use std::rt::task::{BlockedTask, Task}; use std::rt::thread::Thread; use std::sync::atomics; use std::ty::Unsafe; -use std::unstable::mutex; +use std::rt::mutex; use q = mpsc_intrusive; diff --git a/src/test/run-pass/match-ref-binding-in-guard-3256.rs b/src/test/run-pass/match-ref-binding-in-guard-3256.rs index de4da6e3b06d7..4fdbdf8f5c7ae 100644 --- a/src/test/run-pass/match-ref-binding-in-guard-3256.rs +++ b/src/test/run-pass/match-ref-binding-in-guard-3256.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::unstable; +use std::rt; pub fn main() { unsafe { - let x = Some(unstable::sync::Exclusive::new(true)); + let x = Some(rt::exclusive::Exclusive::new(true)); match x { - Some(ref z) if z.with(|b| *b) => { - z.with(|b| assert!(*b)); + Some(ref z) if *z.lock() => { + assert!(*z.lock()); }, _ => fail!() } diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index 1fe99336bc9ca..0ef48c9978251 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -28,7 +28,7 @@ fn start(argc: int, argv: **u8) -> int { 4 => assert!(try(|| fail!()).is_err()), 5 => assert!(try(|| spawn(proc() {})).is_err()), 6 => assert!(Command::new("test").spawn().is_err()), - 7 => assert!(foo.get().is_some()), + 7 => assert!(foo.get().is_none()), 8 => assert!(try(|| { foo.replace(Some(3)); }).is_err()), _ => fail!() } @@ -49,6 +49,8 @@ fn main() { pass(Command::new(me).arg(&[4u8]).output().unwrap()); pass(Command::new(me).arg(&[5u8]).output().unwrap()); pass(Command::new(me).arg(&[6u8]).output().unwrap()); + pass(Command::new(me).arg(&[7u8]).output().unwrap()); + pass(Command::new(me).arg(&[8u8]).output().unwrap()); } fn pass(output: ProcessOutput) { diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index 4034c2571cd07..a9a6e25adf38b 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -61,7 +61,7 @@ fn main() { for _ in range(0, 1000) { let tx = tx.clone(); let mut builder = TaskBuilder::new(); - builder.opts.stack_size = Some(32 * 1024); + builder.opts.stack_size = Some(64 * 1024); builder.spawn(proc() { let host = addr.ip.to_str(); let port = addr.port; diff --git a/src/test/run-pass/writealias.rs b/src/test/run-pass/writealias.rs index 8142cafd89e91..f2d29c97f155e 100644 --- a/src/test/run-pass/writealias.rs +++ b/src/test/run-pass/writealias.rs @@ -9,7 +9,7 @@ // except according to those terms. -use std::unstable; +use std::rt; struct Point {x: int, y: int, z: int} @@ -17,10 +17,10 @@ fn f(p: &mut Point) { p.z = 13; } pub fn main() { unsafe { - let x = Some(unstable::sync::Exclusive::new(true)); + let x = Some(rt::exclusive::Exclusive::new(true)); match x { - Some(ref z) if z.with(|b| *b) => { - z.with(|b| assert!(*b)); + Some(ref z) if *z.lock() => { + assert!(*z.lock()); }, _ => fail!() }