auto merge of #14638 : alexcrichton/rust/librustrt, r=brson

As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:

* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task

Notably, this crate avoids the following services:

* Thread creation and destruction. The crate does not require the knowledge of
  an OS threading system, and as a result it seemed best to leave out the
  `rt::thread` module from librustrt. The librustrt module does depend on
  mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
  to be able to generate backtraces. As will be discussed later, this
  functionality continues to live in libstd rather than librustrt.

As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:

* The stdout/stderr handles no longer live directly inside of the `Task`
  structure. This is a consequence of librustrt not knowing about `std::io`.
  These two handles are now stored inside of task-local-data.

  The handles were originally stored inside of the `Task` for perf reasons, and
  TLD is not currently as fast as it could be. For comparison, 100k prints goes
  from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
  perf loss for the successful extraction of a librustrt crate.

* The `rtio` module was forced to duplicate more functionality of `std::io`. As
  the module no longer depends on `std::io`, `rtio` now defines structures such
  as socket addresses, addrinfo fiddly bits, etc. The primary change made was
  that `rtio` now defines its own `IoError` type. This type is distinct from
  `std::io::IoError` in that it does not have an enum for what error occurred,
  but rather a platform-specific error code.

  The native and green libraries will be updated in later commits for this
  change, and the bulk of this effort was put behind updating the two libraries
  for this change (with `rtio`).

* Printing a message on task failure (along with the backtrace) continues to
  live in libstd, not in librustrt. This is a consequence of the above decision
  to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
  The unwinding API now supports registration of global callback functions which
  will be invoked when a task fails, allowing for libstd to register a function
  to print a message and a backtrace.

  The API for registering a callback is experimental and unsafe, as the
  ramifications of running code on unwinding is pretty hairy.

* The `std::unstable::mutex` module has moved to `std::rt::mutex`.

* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
  the type has been rewritten to not internally have an Arc and to have an RAII
  guard structure when locking. Old code should stop using `Exclusive` in favor
  of the primitives in `libsync`, but if necessary, old code should port to
  `Arc<Exclusive<T>>`.

* The local heap has been stripped down to have fewer debugging options. None of
  these were tested, and none of these have been used in a very long time.
This commit is contained in:
bors 2014-06-06 23:06:35 -07:00
commit 6266f64d09
95 changed files with 2639 additions and 2614 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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() {}

View File

@ -72,6 +72,10 @@ fn expect<T>(a: core::option::Option<T>, 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!()

View File

@ -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);

View File

@ -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();

View File

@ -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<EventLoop:Send> {
@ -31,7 +31,7 @@ struct BasicLoop {
work: Vec<proc():Send>, // pending work
remotes: Vec<(uint, Box<Callback:Send>)>,
next_remote: uint,
messages: Exclusive<Vec<Message>>,
messages: Arc<Exclusive<Vec<Message>>>,
idle: Option<Box<Callback:Send>>,
idle_active: Option<Arc<atomics::AtomicBool>>,
}
@ -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
}
})
mem::replace(&mut *self.messages.lock(), Vec::new())
};
let messages = match messages {
Some(m) => m, None => return
};
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<Vec<Message>>,
queue: Arc<Exclusive<Vec<Message>>>,
id: uint,
}
impl BasicRemote {
fn new(queue: Exclusive<Vec<Message>>, id: uint) -> BasicRemote {
fn new(queue: Arc<Exclusive<Vec<Message>>>, 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;

View File

@ -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<rtio::EventLoop:Send>,
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("<main>".into_maybe_owned());
pool.spawn(opts, main);

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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<GreenTask> {
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());
}

View File

@ -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;

View File

@ -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<ai::Hint>) -> Result<Vec<ai::Info>, IoError> {
hint: Option<rtio::AddrinfoHint>)
-> Result<Vec<rtio::AddrinfoInfo>, 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),
}
}

View File

@ -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<uint, IoError> {
pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<uint> {
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<int, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
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<int, IoError> {
fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
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<u64, IoError> {
fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult<u64> {
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<u64, IoError> {
fn tell(&self) -> IoResult<u64> {
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<io::FileStat> {
fn fstat(&mut self) -> IoResult<rtio::FileStat> {
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<uint, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<rtio::RtioPipe:Send> {
@ -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<u64>) {}
fn set_read_timeout(&mut self, _t: Option<u64>) {}
@ -199,16 +187,16 @@ impl rtio::RtioPipe for FileDesc {
}
impl rtio::RtioTTY for FileDesc {
fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<int, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
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<int, IoError> {
fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
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<u64, IoError> {
fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
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<u64, IoError> {
fn tell(&self) -> IoResult<u64> {
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<io::FileStat> {
fn fstat(&mut self) -> IoResult<rtio::FileStat> {
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<FileDesc> {
pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess)
-> IoResult<FileDesc>
{
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<Vec<Path>> {
pub fn readdir(p: &CString) -> IoResult<Vec<CString>> {
use libc::{dirent_t};
use libc::{opendir, readdir_r, closedir};
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<CString> {
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<Path> {
pub fn readlink(p: &CString) -> IoResult<CString> {
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<Path> {
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<io::FileStat> {
pub fn stat(p: &CString) -> IoResult<rtio::FileStat> {
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<io::FileStat> {
}
}
pub fn lstat(p: &CString) -> IoResult<io::FileStat> {
pub fn lstat(p: &CString) -> IoResult<rtio::FileStat> {
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);

View File

@ -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<uint, IoError> {
pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<u64, IoError> {
fn seek_common(&self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
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<uint> {
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<int, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
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<int, IoError> {
fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
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<u64, IoError> {
fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
self.seek_common(pos, style)
}
fn tell(&self) -> Result<u64, IoError> {
self.seek_common(0, io::SeekCur)
fn tell(&self) -> IoResult<u64> {
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<io::FileStat> {
fn fstat(&mut self) -> IoResult<rtio::FileStat> {
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<uint, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<rtio::RtioPipe:Send> {
@ -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<u64>) {}
fn set_read_timeout(&mut self, _t: Option<u64>) {}
@ -236,16 +221,16 @@ impl rtio::RtioPipe for FileDesc {
}
impl rtio::RtioTTY for FileDesc {
fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<FileDesc> {
// 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<Vec<Path>> {
pub fn readdir(p: &CString) -> IoResult<Vec<CString>> {
use std::rt::libc_heap::malloc_raw;
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<CString> {
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<Path> {
pub fn readlink(p: &CString) -> IoResult<CString> {
// 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<Path> {
});
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<io::FileStat> {
pub fn stat(p: &CString) -> IoResult<rtio::FileStat> {
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<io::FileStat> {
})
}
pub fn lstat(_p: &CString) -> IoResult<io::FileStat> {
pub fn lstat(_p: &CString) -> IoResult<rtio::FileStat> {
// FIXME: implementation is missing
Err(super::unimpl())
}

View File

@ -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<M> {
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) {

View File

@ -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<T> = Result<T, IoError>;
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<u64>) -> IoResult<Box<RtioTcpStream:Send>> {
fn tcp_connect(&mut self, addr: rtio::SocketAddr,
timeout: Option<u64>)
-> IoResult<Box<rtio::RtioTcpStream:Send>>
{
net::TcpStream::connect(addr, timeout).map(|s| {
box s as Box<RtioTcpStream:Send>
box s as Box<rtio::RtioTcpStream:Send>
})
}
fn tcp_bind(&mut self, addr: SocketAddr)
-> IoResult<Box<RtioTcpListener:Send>> {
fn tcp_bind(&mut self, addr: rtio::SocketAddr)
-> IoResult<Box<rtio::RtioTcpListener:Send>> {
net::TcpListener::bind(addr).map(|s| {
box s as Box<RtioTcpListener:Send>
box s as Box<rtio::RtioTcpListener:Send>
})
}
fn udp_bind(&mut self, addr: SocketAddr)
-> IoResult<Box<RtioUdpSocket:Send>> {
net::UdpSocket::bind(addr).map(|u| box u as Box<RtioUdpSocket:Send>)
fn udp_bind(&mut self, addr: rtio::SocketAddr)
-> IoResult<Box<rtio::RtioUdpSocket:Send>> {
net::UdpSocket::bind(addr).map(|u| {
box u as Box<rtio::RtioUdpSocket:Send>
})
}
fn unix_bind(&mut self, path: &CString)
-> IoResult<Box<RtioUnixListener:Send>> {
-> IoResult<Box<rtio::RtioUnixListener:Send>> {
pipe::UnixListener::bind(path).map(|s| {
box s as Box<RtioUnixListener:Send>
box s as Box<rtio::RtioUnixListener:Send>
})
}
fn unix_connect(&mut self, path: &CString,
timeout: Option<u64>) -> IoResult<Box<RtioPipe:Send>> {
timeout: Option<u64>) -> IoResult<Box<rtio::RtioPipe:Send>> {
pipe::UnixStream::connect(path, timeout).map(|s| {
box s as Box<RtioPipe:Send>
box s as Box<rtio::RtioPipe:Send>
})
}
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
hint: Option<ai::Hint>) -> IoResult<Vec<ai::Info>> {
hint: Option<rtio::AddrinfoHint>)
-> IoResult<Vec<rtio::AddrinfoInfo>>
{
addrinfo::GetAddrInfoRequest::run(host, servname, hint)
}
// filesystem operations
fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior)
-> Box<RtioFileStream:Send> {
fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior)
-> Box<rtio::RtioFileStream:Send> {
let close = match close {
rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
rtio::DontClose => false
};
box file::FileDesc::new(fd, close) as Box<RtioFileStream:Send>
box file::FileDesc::new(fd, close) as Box<rtio::RtioFileStream:Send>
}
fn fs_open(&mut self, path: &CString, fm: io::FileMode, fa: io::FileAccess)
-> IoResult<Box<RtioFileStream:Send>> {
file::open(path, fm, fa).map(|fd| box fd as Box<RtioFileStream:Send>)
fn fs_open(&mut self, path: &CString, fm: rtio::FileMode,
fa: rtio::FileAccess)
-> IoResult<Box<rtio::RtioFileStream:Send>>
{
file::open(path, fm, fa).map(|fd| box fd as Box<rtio::RtioFileStream:Send>)
}
fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
file::unlink(path)
}
fn fs_stat(&mut self, path: &CString) -> IoResult<io::FileStat> {
fn fs_stat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
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<Vec<Path>> {
fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<Vec<CString>> {
file::readdir(path)
}
fn fs_lstat(&mut self, path: &CString) -> IoResult<io::FileStat> {
fn fs_lstat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
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<Path> {
fn fs_readlink(&mut self, path: &CString) -> IoResult<CString> {
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<Box<RtioTimer:Send>> {
timer::Timer::new().map(|t| box t as Box<RtioTimer:Send>)
fn timer_init(&mut self) -> IoResult<Box<rtio::RtioTimer:Send>> {
timer::Timer::new().map(|t| box t as Box<rtio::RtioTimer:Send>)
}
fn spawn(&mut self, cfg: ProcessConfig)
-> IoResult<(Box<RtioProcess:Send>,
Vec<Option<Box<RtioPipe:Send>>>)> {
fn spawn(&mut self, cfg: rtio::ProcessConfig)
-> IoResult<(Box<rtio::RtioProcess:Send>,
Vec<Option<Box<rtio::RtioPipe:Send>>>)> {
process::Process::spawn(cfg).map(|(p, io)| {
(box p as Box<RtioProcess:Send>,
(box p as Box<rtio::RtioProcess:Send>,
io.move_iter().map(|p| p.map(|p| {
box p as Box<RtioPipe:Send>
box p as Box<rtio::RtioPipe:Send>
})).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<Box<RtioPipe:Send>> {
Ok(box file::FileDesc::new(fd, true) as Box<RtioPipe:Send>)
fn pipe_open(&mut self, fd: c_int) -> IoResult<Box<rtio::RtioPipe:Send>> {
Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioPipe:Send>)
}
fn tty_open(&mut self, fd: c_int, _readable: bool)
-> IoResult<Box<RtioTTY:Send>> {
-> IoResult<Box<rtio::RtioTTY:Send>> {
#[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<RtioTTY:Send>)
Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioTTY:Send>)
} 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<Signum>)
-> IoResult<Box<RtioSignal:Send>> {
fn signal(&mut self, _signal: int, _cb: Box<rtio::Callback>)
-> IoResult<Box<rtio::RtioSignal:Send>> {
Err(unimpl())
}
}

View File

@ -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<sock_t> {
fn socket(addr: rtio::SocketAddr, ty: libc::c_int) -> IoResult<sock_t> {
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<T: Copy>(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<ip::SocketAddr>
-> IoResult<rtio::SocketAddr>
{
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
let mut len = mem::size_of::<libc::sockaddr_storage>() 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<ip::SocketAddr> {
len: uint) -> IoResult<rtio::SocketAddr> {
match storage.ss_family as libc::c_int {
libc::AF_INET => {
assert!(len as uint >= mem::size_of::<libc::sockaddr_in>());
@ -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<u64>) -> IoResult<TcpStream> {
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<ip::SocketAddr> {
fn peer_name(&mut self) -> IoResult<rtio::SocketAddr> {
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<ip::SocketAddr> {
fn socket_name(&mut self) -> IoResult<rtio::SocketAddr> {
sockname(self.fd(), libc::getsockname)
}
}
@ -436,7 +447,7 @@ pub struct TcpListener {
}
impl TcpListener {
pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
pub fn bind(addr: rtio::SocketAddr) -> IoResult<TcpListener> {
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<ip::SocketAddr> {
fn socket_name(&mut self) -> IoResult<rtio::SocketAddr> {
sockname(self.fd(), libc::getsockname)
}
}
@ -512,7 +523,7 @@ impl TcpAcceptor {
}
impl rtio::RtioSocket for TcpAcceptor {
fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
fn socket_name(&mut self) -> IoResult<rtio::SocketAddr> {
sockname(self.fd(), libc::getsockname)
}
}
@ -540,7 +551,7 @@ pub struct UdpSocket {
}
impl UdpSocket {
pub fn bind(addr: ip::SocketAddr) -> IoResult<UdpSocket> {
pub fn bind(addr: rtio::SocketAddr) -> IoResult<UdpSocket> {
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<ip::SocketAddr> {
fn socket_name(&mut self) -> IoResult<rtio::SocketAddr> {
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<T>(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<T>(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(()) => {}

View File

@ -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::<libc::sockaddr_storage>() >=
mem::size_of::<libc::sockaddr_un>());
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::<libc::sockaddr_storage>();
let mut size = size as libc::socklen_t;

View File

@ -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
}

View File

@ -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<p::ProcessExit>,
exit_code: Option<rtio::ProcessExit>,
/// Manually delivered signal
exit_signal: Option<int>,
@ -59,7 +56,7 @@ pub struct Process {
#[cfg(unix)]
enum Req {
NewChild(libc::pid_t, Sender<p::ProcessExit>, u64),
NewChild(libc::pid_t, Sender<rtio::ProcessExit>, 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<Option<file::FileDesc>>), io::IoError>
-> IoResult<(Process, Vec<Option<file::FileDesc>>)>
{
// 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<Option<file::FileDesc>>)
fn get_io(io: rtio::StdioContainer,
ret: &mut Vec<Option<file::FileDesc>>)
-> (Option<os::Pipe>, 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<p::ProcessExit> {
fn wait(&mut self) -> IoResult<rtio::ProcessExit> {
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<p::ProcessExit> {
fn waitpid(pid: pid_t, deadline: u64) -> IoResult<rtio::ProcessExit> {
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<p::ProcessExit> {
}
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<p::ProcessExit> {
}
#[cfg(unix)]
fn waitpid(pid: pid_t, deadline: u64) -> IoResult<p::ProcessExit> {
fn waitpid(pid: pid_t, deadline: u64) -> IoResult<rtio::ProcessExit> {
use std::cmp;
use std::comm;
@ -862,7 +864,7 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult<p::ProcessExit> {
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<p::ProcessExit> {
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<p::ProcessExit> {
fn waitpid_helper(input: libc::c_int,
messages: Receiver<Req>,
(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<p::ProcessExit>, u64)>::new();
let mut active = Vec::<(libc::pid_t, Sender<rtio::ProcessExit>, u64)>::new();
let max = cmp::max(input, read_fd) + 1;
'outer: loop {
@ -1094,22 +1096,23 @@ fn waitpid(pid: pid_t, deadline: u64) -> IoResult<p::ProcessExit> {
}
}
fn waitpid_nowait(pid: pid_t) -> Option<p::ProcessExit> {
fn waitpid_nowait(pid: pid_t) -> Option<rtio::ProcessExit> {
return waitpid_os(pid);
// This code path isn't necessary on windows
#[cfg(windows)]
fn waitpid_os(_pid: pid_t) -> Option<p::ProcessExit> { None }
fn waitpid_os(_pid: pid_t) -> Option<rtio::ProcessExit> { None }
#[cfg(unix)]
fn waitpid_os(pid: pid_t) -> Option<p::ProcessExit> {
fn waitpid_os(pid: pid_t) -> Option<rtio::ProcessExit> {
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),
}
}
}

View File

@ -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<Sender<()>>,
cb: Option<Box<rtio::Callback:Send>>,
interval: u64,
repeat: bool,
target: u64,
@ -119,13 +119,13 @@ fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
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<Req>, _: ()) {
// 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<rtio::Callback:Send>) {
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<rtio::Callback:Send>) {
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;
}
}

View File

@ -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<Req>)
@ -36,7 +36,7 @@ pub struct Timer {
}
pub enum Req {
NewTimer(libc::HANDLE, Sender<()>, bool),
NewTimer(libc::HANDLE, Box<Callback:Send>, bool),
RemoveTimer(libc::HANDLE, Sender<()>),
}
@ -79,8 +79,8 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
}
} 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<Callback:Send>) {
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<Callback:Send>) {
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;
}
}

View File

@ -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)),
})
}
}
}

View File

@ -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<Ops> {
/// 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());
}

View File

@ -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<Vec<Vec<u8>>> { 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<Vec<u8>> {
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) {
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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<Vec<proc():Send>>;
static mut QUEUE: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
static mut RUNNING: atomics::AtomicBool = atomics::INIT_ATOMIC_BOOL;
pub fn init() {
let state: Box<Queue> = 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<Queue> = mem::transmute(queue);
mem::replace(&mut *queue.lock(), Vec::new())
};
for to_run in cur.move_iter() {
to_run();
}
}

View File

@ -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;

View File

@ -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) {

115
src/librustrt/exclusive.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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<T> {
lock: mutex::NativeMutex,
data: Unsafe<T>,
}
/// 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<T: Send> Exclusive<T> {
/// Creates a new `Exclusive` which will protect the data provided.
pub fn new(user_data: T) -> Exclusive<T> {
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<T> for ExclusiveGuard<'a, T> {
fn deref<'a>(&'a self) -> &'a T { &*self._data }
}
impl<'a, T: Send> DerefMut<T> 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);
}
}
}

164
src/librustrt/lib.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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<Task>);
fn maybe_yield(~self, cur_task: Box<Task>);
fn deschedule(~self, times: uint, cur_task: Box<Task>,
f: |BlockedTask| -> Result<(), BlockedTask>);
fn reawaken(~self, to_wake: Box<Task>);
// Miscellaneous calls which are very different depending on what context
// you're in.
fn spawn_sibling(~self,
cur_task: Box<Task>,
opts: TaskOpts,
f: proc():Send);
fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>>;
/// 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<Any>;
}
/// 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};
}

View File

@ -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
}

View File

@ -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<Borrowed> {
@ -52,11 +53,10 @@ impl Local<local_ptr::Borrowed<Task>> 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() {

View File

@ -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<LocalData:Send>;
// 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::<Task>) { 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<T: 'static> KeyValue<T> {
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<T: 'static> Drop for Ref<T> {
#[cfg(test)]
mod tests {
use prelude::*;
use std::prelude::*;
use super::*;
use owned::Box;
use task;
use std::task;
#[test]
fn test_tls_multitask() {

View File

@ -10,55 +10,45 @@
//! The local, garbage collected 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;
use core::prelude::*;
// This has no meaning with out rtdebug also turned on.
#[cfg(rtdebug)]
static TRACK_ALLOCATIONS: int = 0;
#[cfg(rtdebug)]
static MAGIC: u32 = 0xbadc0ffe;
use alloc::libc_heap;
use alloc::util;
use libc::{c_void, free};
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::<Task>).heap.live_allocs
}
#[cfg(test)]
mod bench {
extern crate test;

View File

@ -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<T>() -> Borrowed<T> {
/// 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<tls::Key> {
use realstd;
use realrustrt;
unsafe {
mem::transmute(realstd::rt::shouldnt_be_public::maybe_tls_key())
mem::transmute(realrustrt::shouldnt_be_public::maybe_tls_key())
}
}
}

View File

@ -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)*))
)

View File

@ -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() {

View File

@ -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<T>(f: |io: &mut IoFactory| -> IoResult<T>)
-> IoResult<T>
{
#[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<u64>) -> IoResult<Box<RtioPipe:Send>>;
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
hint: Option<ai::Hint>) -> IoResult<Vec<ai::Info>>;
hint: Option<AddrinfoHint>)
-> IoResult<Vec<AddrinfoInfo>>;
// filesystem operations
fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior)
@ -228,18 +209,16 @@ pub trait IoFactory {
-> IoResult<Box<RtioFileStream:Send>>;
fn fs_unlink(&mut self, path: &CString) -> IoResult<()>;
fn fs_stat(&mut self, path: &CString) -> IoResult<FileStat>;
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<Vec<Path>>;
IoResult<Vec<CString>>;
fn fs_lstat(&mut self, path: &CString) -> IoResult<FileStat>;
fn fs_chown(&mut self, path: &CString, uid: int, gid: int) ->
IoResult<()>;
fn fs_readlink(&mut self, path: &CString) -> IoResult<Path>;
fn fs_readlink(&mut self, path: &CString) -> IoResult<CString>;
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<Box<RtioPipe:Send>>;
fn tty_open(&mut self, fd: c_int, readable: bool)
-> IoResult<Box<RtioTTY:Send>>;
fn signal(&mut self, signal: Signum, channel: Sender<Signum>)
fn signal(&mut self, signal: int, cb: Box<Callback:Send>)
-> IoResult<Box<RtioSignal:Send>>;
}
@ -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<Callback:Send>);
fn period(&mut self, msecs: u64, cb: Box<Callback:Send>);
}
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<String>,
}
pub type IoResult<T> = Result<T, IoError>;
#[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,
}

View File

@ -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

View File

@ -13,30 +13,24 @@
//! local storage, and logging. Even a 'freestanding' Rust would likely want
//! to implement this.
use alloc::arc::Arc;
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<SendStr>,
pub stdout: Option<Box<Writer:Send>>,
pub stderr: Option<Box<Writer:Send>>,
imp: Option<Box<Runtime:Send>>,
}
pub struct TaskOpts {
/// Invoke this procedure with the result of the task when it finishes.
pub on_exit: Option<proc(Result):Send>,
/// A name for the task-to-be, for identification in failure messages
pub name: Option<SendStr>,
/// The size of the stack for the spawned task
pub stack_size: Option<uint>,
}
/// 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<Any:Send>>;
pub struct GarbageCollector;
pub struct LocalStorage(pub Option<local_data::Map>);
@ -69,17 +77,9 @@ pub enum BlockedTask {
Shared(Arc<AtomicUint>),
}
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<TaskResult>),
}
/// Per-task state related to task death, killing, failure, etc.
pub struct Death {
pub on_exit: Option<DeathAction>,
pub on_exit: Option<proc(Result):Send>,
}
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::<Task>);
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::<Task>);
let storage_map = {
drop({
let mut task = Local::borrow(None::<Task>);
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::<Task>);
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::<T>() {
Ok(t) => Some(t),
Err(t) => {
let (_, obj): (uint, uint) = mem::transmute(t);
let data = mem::transmute::<_, raw::TraitObject>(t).data;
let obj: Box<Runtime:Send> =
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<BlockedTask> for BlockedTasks {
fn next(&mut self) -> Option<BlockedTask> {
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<List>>,
@ -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!())
}

View File

@ -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<int> = transmute(get(key));
assert_eq!(value, box 20);
let value = box 30;
set(key, transmute(value));
let value: Box<int> = 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<int> = transmute(get(key));
assert_eq!(value, box 20);
let value = box 30;
set(key, transmute(value));
let value: Box<int> = transmute(get(key));
assert_eq!(value, box 30);
}
}
}

View File

@ -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.
// 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 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 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 uw = rt::libunwind;
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<Box<Any:Send>>,
}
pub type Callback = fn(msg: &Any:Send, file: &'static str, line: uint);
type Queue = Exclusive<Vec<Callback>>;
// 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<Any:Send>> {
use raw::Closure;
use libc::{c_void};
pub unsafe fn try(f: ||) -> ::core::result::Result<(), Box<Any:Send>> {
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<Any:Send>> {
}
}
#[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<u8> }
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<M: Any + Send>(msg: M, file: &'static str, line: uint) -> !
fn begin_unwind_inner(msg: Box<Any:Send>,
file: &'static str,
line: uint) -> ! {
// First up, print the message that we're failing
print_failure(msg, file, line);
let opt_task: Option<Box<Task>> = 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 => {}
}
rust_fail(msg)
}
/// Given a failure message and the location that it occurred, prints the
/// message to the local task's appropriate stream.
///
/// This function currently handles three cases:
///
/// - 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::<String>() {
Some(s) => s.as_slice(),
None => "Box<Any>",
}
};
// 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.
// 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<Task> = 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
}
Some(task) => task,
None => rust_fail(msg),
};
// 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("<unnamed>");
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() }
}
task.unwinder.unwinding = true;
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();
// 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);
}
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);
}
}
/// Register a callback to be invoked when a task unwinds.
///
/// 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.
///
/// 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
}
// 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);
}

129
src/librustrt/util.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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(); }
}

View File

@ -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<ai::Hint>) -> Result<Vec<ai::Info>, UvError> {
hints: Option<rtio::AddrinfoHint>)
-> Result<Vec<rtio::AddrinfoInfo>, 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<ai::Info> {
pub fn accum_addrinfo(addr: &Addrinfo) -> Vec<rtio::AddrinfoInfo> {
unsafe {
let mut addr = addr.handle;
@ -143,35 +122,12 @@ pub fn accum_addrinfo(addr: &Addrinfo) -> Vec<ai::Info> {
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;

View File

@ -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<bool>
exit_flag: Arc<Exclusive<bool>>,
}
struct Payload {
callback: Box<Callback:Send>,
exit_flag: Exclusive<bool>,
exit_flag: Arc<Exclusive<bool>>,
}
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) }
}
}

View File

@ -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<FileStat, UvError> {
pub fn lstat(loop_: &Loop, path: &CString)
-> Result<rtio::FileStat, UvError>
{
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<FileStat, UvError> {
pub fn stat(loop_: &Loop, path: &CString) -> Result<rtio::FileStat, UvError> {
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<FileStat, UvError> {
pub fn fstat(loop_: &Loop, fd: c_int) -> Result<rtio::FileStat, UvError> {
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<Vec<Path>, UvError>
-> Result<Vec<CString>, 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<Path, UvError> {
pub fn readlink(loop_: &Loop, path: &CString) -> Result<CString, UvError> {
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<int, IoError> {
fn base_read(&mut self, buf: &mut [u8], offset: i64) -> IoResult<int> {
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<u64, IoError>{
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<u64>{
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<int, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
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<int, IoError> {
fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
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<u64, IoError> {
fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult<u64> {
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<u64, IoError> {
fn tell(&self) -> IoResult<u64> {
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<FileStat, IoError> {
fn fstat(&mut self) -> IoResult<rtio::FileStat> {
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());

View File

@ -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));

View File

@ -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
let UvError(errcode) = uverr;
IoError {
code: if errcode == uvll::EOF {libc::EOF as uint} else {-errcode as uint},
extra: 0,
detail: Some(uverr.desc()),
}
}
// 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,
#[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<UvError> {
}
}
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;

View File

@ -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::<libc::sockaddr_in>());
@ -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::<libc::sockaddr_in>()
}
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<ip::SocketAddr, IoError> {
handle: *c_void) -> Result<rtio::SocketAddr, IoError> {
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<u64>) -> Result<TcpWatcher, UvError> {
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<ip::SocketAddr, IoError> {
fn socket_name(&mut self) -> Result<rtio::SocketAddr, IoError> {
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<ip::SocketAddr, IoError> {
fn peer_name(&mut self) -> Result<rtio::SocketAddr, IoError> {
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<Box<TcpListener>, UvError> {
let handle = unsafe { uvll::malloc_handle(uvll::UV_TCP) };
assert_eq!(unsafe {
@ -385,7 +383,7 @@ impl UvHandle<uvll::uv_tcp_t> for TcpListener {
}
impl rtio::RtioSocket for TcpListener {
fn socket_name(&mut self) -> Result<ip::SocketAddr, IoError> {
fn socket_name(&mut self) -> Result<rtio::SocketAddr, IoError> {
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<ip::SocketAddr, IoError> {
fn socket_name(&mut self) -> Result<rtio::SocketAddr, IoError> {
let _m = self.fire_homing_missile();
socket_name(Tcp, self.listener.handle)
}
@ -492,7 +490,7 @@ pub struct UdpWatcher {
struct UdpRecvCtx {
task: Option<BlockedTask>,
buf: Option<Buf>,
result: Option<(ssize_t, Option<ip::SocketAddr>)>,
result: Option<(ssize_t, Option<rtio::SocketAddr>)>,
}
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<UdpWatcher, UvError> {
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<ip::SocketAddr, IoError> {
fn socket_name(&mut self) -> Result<rtio::SocketAddr, IoError> {
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::<Receiver<()>>();
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

View File

@ -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<Result<Box<RtioPipe:Send>, IoError>>,
incoming: Receiver<Result<Box<RtioPipe:Send>, IoError>>,
outgoing: Sender<IoResult<Box<rtio::RtioPipe:Send>>>,
incoming: Receiver<IoResult<Box<rtio::RtioPipe:Send>>>,
}
pub struct PipeAcceptor {
@ -111,26 +110,26 @@ impl PipeWatcher {
}
}
impl RtioPipe for PipeWatcher {
fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
impl rtio::RtioPipe for PipeWatcher {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<RtioPipe:Send> {
fn clone(&self) -> Box<rtio::RtioPipe:Send> {
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<RtioPipe:Send>
} as Box<rtio::RtioPipe:Send>
}
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<Box<RtioUnixAcceptor:Send>, IoError> {
impl rtio::RtioUnixListener for PipeListener {
fn listen(~self) -> IoResult<Box<rtio::RtioUnixAcceptor:Send>> {
// 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<RtioUnixAcceptor:Send>),
0 => Ok(acceptor as Box<rtio::RtioUnixAcceptor:Send>),
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<RtioPipe:Send>)
Ok(box client as Box<rtio::RtioPipe:Send>)
}
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<Box<RtioPipe:Send>, IoError> {
impl rtio::RtioUnixAcceptor for PipeAcceptor {
fn accept(&mut self) -> IoResult<Box<rtio::RtioPipe:Send>> {
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();

View File

@ -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<BlockedTask>,
/// Collected from the exit_cb
exit_status: Option<process::ProcessExit>,
exit_status: Option<rtio::ProcessExit>,
/// Lazily initialized timeout timer
timer: Option<Box<TimerWatcher>>,
@ -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<Process>, Vec<Option<PipeWatcher>>), 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<PipeWatcher> {
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<uvll::uv_process_t> 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<process::ProcessExit, IoError> {
fn wait(&mut self) -> IoResult<rtio::ProcessExit> {
// Make sure (on the home scheduler) that we have an exit status listed
let _m = self.fire_homing_missile();
match self.exit_status {

View File

@ -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;

View File

@ -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<Signum>,
signal: Signum,
cb: Box<Callback:Send>,
}
impl SignalWatcher {
pub fn new(io: &mut UvIoFactory, signum: Signum, channel: Sender<Signum>)
pub fn new(io: &mut UvIoFactory, signum: int, cb: Box<Callback:Send>)
-> Result<Box<SignalWatcher>, UvError> {
let s = box SignalWatcher {
handle: UvHandle::alloc(None::<SignalWatcher>, 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
}
}

View File

@ -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};

View File

@ -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<Callback:Send>),
CallMany(Box<Callback:Send>, 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<Callback:Send>) {
// 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<Callback:Send>) {
// 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);
}
}

View File

@ -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<uint, IoError> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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;

View File

@ -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<u64>)
-> Result<Box<rtio::RtioTcpStream:Send>, IoError> {
fn tcp_connect(&mut self, addr: rtio::SocketAddr, timeout: Option<u64>)
-> IoResult<Box<rtio::RtioTcpStream:Send>> {
match TcpWatcher::connect(self, addr, timeout) {
Ok(t) => Ok(box t as Box<rtio::RtioTcpStream:Send>),
Err(e) => Err(uv_error_to_io_error(e)),
}
}
fn tcp_bind(&mut self, addr: SocketAddr)
-> Result<Box<rtio::RtioTcpListener:Send>, IoError> {
fn tcp_bind(&mut self, addr: rtio::SocketAddr)
-> IoResult<Box<rtio::RtioTcpListener:Send>> {
match TcpListener::bind(self, addr) {
Ok(t) => Ok(t as Box<rtio::RtioTcpListener:Send>),
Err(e) => Err(uv_error_to_io_error(e)),
}
}
fn udp_bind(&mut self, addr: SocketAddr)
-> Result<Box<rtio::RtioUdpSocket:Send>, IoError> {
fn udp_bind(&mut self, addr: rtio::SocketAddr)
-> IoResult<Box<rtio::RtioUdpSocket:Send>> {
match UdpWatcher::bind(self, addr) {
Ok(u) => Ok(box u as Box<rtio::RtioUdpSocket:Send>),
Err(e) => Err(uv_error_to_io_error(e)),
}
}
fn timer_init(&mut self) -> Result<Box<rtio::RtioTimer:Send>, IoError> {
fn timer_init(&mut self) -> IoResult<Box<rtio::RtioTimer:Send>> {
Ok(TimerWatcher::new(self) as Box<rtio::RtioTimer:Send>)
}
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
hint: Option<ai::Hint>) -> Result<Vec<ai::Info>, IoError> {
hint: Option<rtio::AddrinfoHint>)
-> IoResult<Vec<rtio::AddrinfoInfo>>
{
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<rtio::RtioFileStream:Send>
}
fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
-> Result<Box<rtio::RtioFileStream:Send>, IoError> {
fn fs_open(&mut self, path: &CString, fm: rtio::FileMode,
fa: rtio::FileAccess)
-> IoResult<Box<rtio::RtioFileStream:Send>>
{
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<FileStat, IoError> {
fn fs_lstat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
let r = FsRequest::lstat(&self.loop_, path);
r.map_err(uv_error_to_io_error)
}
fn fs_stat(&mut self, path: &CString) -> Result<FileStat, IoError> {
fn fs_stat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
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<Vec<Path>, IoError>
-> IoResult<Vec<CString>>
{
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<Path, IoError> {
fn fs_readlink(&mut self, path: &CString) -> IoResult<CString> {
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<rtio::RtioProcess:Send>,
Vec<Option<Box<rtio::RtioPipe:Send>>>),
IoError>
-> IoResult<(Box<rtio::RtioProcess:Send>,
Vec<Option<Box<rtio::RtioPipe:Send>>>)>
{
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<Box<rtio::RtioUnixListener:Send>, IoError> {
-> IoResult<Box<rtio::RtioUnixListener:Send>> {
match PipeListener::bind(self, path) {
Ok(p) => Ok(p as Box<rtio::RtioUnixListener:Send>),
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<u64>)
-> Result<Box<rtio::RtioPipe:Send>, IoError> {
-> IoResult<Box<rtio::RtioPipe:Send>> {
match PipeWatcher::connect(self, path, timeout) {
Ok(p) => Ok(box p as Box<rtio::RtioPipe:Send>),
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<Box<rtio::RtioTTY:Send>, IoError> {
-> IoResult<Box<rtio::RtioTTY:Send>> {
match TtyWatcher::new(self, fd, readable) {
Ok(tty) => Ok(box tty as Box<rtio::RtioTTY:Send>),
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<Box<rtio::RtioPipe:Send>, IoError> {
-> IoResult<Box<rtio::RtioPipe:Send>>
{
match PipeWatcher::open(self, fd) {
Ok(s) => Ok(box s as Box<rtio::RtioPipe:Send>),
Err(e) => Err(uv_error_to_io_error(e))
}
}
fn signal(&mut self, signum: Signum, channel: Sender<Signum>)
-> Result<Box<rtio::RtioSignal:Send>, IoError> {
match SignalWatcher::new(self, signum, channel) {
fn signal(&mut self, signum: int, cb: Box<rtio::Callback:Send>)
-> IoResult<Box<rtio::RtioSignal:Send>>
{
match SignalWatcher::new(self, signum, cb) {
Ok(s) => Ok(s as Box<rtio::RtioSignal:Send>),
Err(e) => Err(uv_error_to_io_error(e)),
}

View File

@ -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;

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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);
}
}

View File

@ -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;

View File

@ -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<T> {

102
src/libstd/failure.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use 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<Writer:Send>)
impl Writer for Stdio {
fn write(&mut self, bytes: &[u8]) -> IoResult<()> {
fn fmt_write<F: fmt::FormatWriter>(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::<String>() {
Some(s) => s.as_slice(),
None => "Box<Any>",
}
};
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::<Task>) {
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::<Task>);
(t.name.take(), t.unwinder.unwinding())
};
{
let n = name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
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::<Task>).name = name;
}

View File

@ -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<File> {
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<FileStat> {
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<FileStat> {
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<FileStat> {
///
/// See `stat`
pub fn lstat(path: &Path) -> IoResult<FileStat> {
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<FileStat> {
/// 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<Path> {
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<Path> {
/// 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<Vec<Path>> {
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<u64> {
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)),
}
}
}

View File

@ -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"),
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
// 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 {

View File

@ -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<Vec<IpAddr>> {
///
/// 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<Hint>)
-> IoResult<Vec<Info>> {
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

View File

@ -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)
}
}
}

View File

@ -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<TcpStream> {
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<SocketAddr> {
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<SocketAddr> {
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<uint> { self.obj.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<TcpListener> {
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<SocketAddr> {
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<TcpStream, TcpAcceptor> for TcpListener {
fn listen(self) -> IoResult<TcpAcceptor> {
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<TcpStream> for TcpAcceptor {
fn accept(&mut self) -> IoResult<TcpStream> {
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);
}
}
})

View File

@ -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<UdpSocket> {
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<SocketAddr> {
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.

View File

@ -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<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
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<uint> { self.obj.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
LocalIo::maybe_raise(|io| {
io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s })
})
}).map_err(IoError::from_rtio_error)
}
}
impl Listener<UnixStream, UnixAcceptor> for UnixListener {
fn listen(self) -> IoResult<UnixAcceptor> {
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<UnixStream> for UnixAcceptor {
fn accept(&mut self) -> IoResult<UnixStream> {
self.obj.accept().map(|s| UnixStream { obj: s })
self.obj.accept().map(|s| {
UnixStream { obj: s }
}).map_err(IoError::from_rtio_error)
}
}

View File

@ -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<PipeStream> {
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<uint> { self.obj.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
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)]

View File

@ -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<Process> {
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<rtio::StdioContainer> =
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<ProcessExit> {
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().

View File

@ -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<Signum>,
}
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))
}
}

View File

@ -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<T>(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<Writer:Send>)
/// 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<Writer:Send>,
f: |&mut Task, Box<Writer:Send>| -> Option<Box<Writer:Send>>)
-> Option<Box<Writer:Send>> {
let mut t = Local::borrow(None::<Task>);
// 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<Writer:Send>,
/// 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<Writer:Send>) -> Option<Box<Writer:Send>> {
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<Writer:Send>) -> Option<Box<Writer:Send>> {
/// 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<Writer:Send>) -> Option<Box<Writer:Send>> {
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<Writer:Send>) -> Option<Box<Writer:Send>> {
// // io1 aliases io2
// })
// })
fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) {
let task: Option<Box<Task>> = 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<Writer:Send>);
}
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::<Task>).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::<Task>) {
let mut my_stdout = local_stdout.replace(None).unwrap_or_else(|| {
box stdout() as Box<Writer:Send>
});
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();

View File

@ -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<RtioTimer:Send>,
}
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<Timer> {
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(());
}
}

View File

@ -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

View File

@ -189,7 +189,7 @@ Accessing environment variables is not generally threadsafe.
Serialize access through a global lock.
*/
fn with_env_lock<T>(f: || -> T) -> T {
use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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<Vec<proc():Send>>;
// 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<Queue> = 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<Queue> = 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();
}
}

View File

@ -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" {

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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 }
}

View File

@ -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<Task>);
fn maybe_yield(~self, cur_task: Box<Task>);
fn deschedule(~self, times: uint, cur_task: Box<Task>,
f: |BlockedTask| -> Result<(), BlockedTask>);
fn reawaken(~self, to_wake: Box<Task>);
// Miscellaneous calls which are very different depending on what context
// you're in.
fn spawn_sibling(~self,
cur_task: Box<Task>,
opts: TaskOpts,
f: proc():Send);
fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>>;
/// 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<Any>;
}
/// 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();
}

View File

@ -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<uint> = 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;
}

View File

@ -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

View File

@ -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<T> {
/// will only use this structure when allocating a new buffer or deallocating a
/// previous one.
pub struct BufferPool<T> {
pool: Exclusive<Vec<Box<Buffer<T>>>>,
pool: Arc<Exclusive<Vec<Box<Buffer<T>>>>>,
}
/// An internal buffer used by the chase-lev deque. This structure is actually
@ -148,7 +148,7 @@ impl<T: Send> BufferPool<T> {
/// Allocates a new buffer pool which in turn can be used to allocate new
/// deques.
pub fn new() -> BufferPool<T> {
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<T: Send> BufferPool<T> {
fn alloc(&self, bits: int) -> Box<Buffer<T>> {
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<Buffer<T>>) {
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),
}
}
}
}

View File

@ -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<Any:Send>>;
/// Task configuration options
pub struct TaskOpts {
/// Enable lifecycle notifications on the given channel
pub notify_chan: Option<Sender<TaskResult>>,
pub notify_chan: Option<Sender<task::Result>>,
/// A name for the task-to-be, for identification in failure messages
pub name: Option<SendStr>,
/// 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<TaskResult> {
pub fn future_result(&mut self) -> Receiver<task::Result> {
// 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);
}
}
/**

View File

@ -224,7 +224,7 @@ pub mod dl {
}
pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, String> {
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

View File

@ -11,7 +11,3 @@
#![doc(hidden)]
pub mod dynamic_lib;
pub mod sync;
pub mod mutex;

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use alloc::arc::Arc;
use clone::Clone;
use kinds::Send;
use ty::Unsafe;
use unstable::mutex::NativeMutex;
struct ExData<T> {
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<T> {
x: Arc<Unsafe<ExData<T>>>
}
impl<T:Send> Clone for Exclusive<T> {
// Duplicate an Exclusive Arc, as std::arc::clone.
fn clone(&self) -> Exclusive<T> {
Exclusive { x: self.x.clone() }
}
}
impl<T:Send> Exclusive<T> {
pub fn new(user_data: T) -> Exclusive<T> {
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<U>(&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<U>(&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));
}
}
}

View File

@ -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;

View File

@ -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!()
}

View File

@ -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) {

View File

@ -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;

View File

@ -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!()
}