]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #14638 : alexcrichton/rust/librustrt, r=brson
authorbors <bors@rust-lang.org>
Sat, 7 Jun 2014 06:06:35 +0000 (23:06 -0700)
committerbors <bors@rust-lang.org>
Sat, 7 Jun 2014 06:06:35 +0000 (23:06 -0700)
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.

110 files changed:
mk/crates.mk
mk/rt.mk
src/liballoc/lib.rs
src/liballoc/util.rs
src/libcollections/lib.rs
src/libcollections/slice.rs
src/libcore/macros.rs
src/libgreen/basic.rs
src/libgreen/lib.rs
src/libgreen/sched.rs
src/libgreen/simple.rs
src/libgreen/stack.rs
src/libgreen/task.rs
src/liblibc/lib.rs
src/libnative/io/addrinfo.rs
src/libnative/io/file_unix.rs
src/libnative/io/file_win32.rs
src/libnative/io/helper_thread.rs
src/libnative/io/mod.rs
src/libnative/io/net.rs
src/libnative/io/pipe_unix.rs
src/libnative/io/pipe_win32.rs
src/libnative/io/process.rs
src/libnative/io/timer_unix.rs
src/libnative/io/timer_win32.rs
src/libnative/io/util.rs
src/libnative/task.rs
src/librustrt/args.rs [new file with mode: 0644]
src/librustrt/at_exit_imp.rs [new file with mode: 0644]
src/librustrt/bookkeeping.rs [new file with mode: 0644]
src/librustrt/c_str.rs [new file with mode: 0644]
src/librustrt/exclusive.rs [new file with mode: 0644]
src/librustrt/lib.rs [new file with mode: 0644]
src/librustrt/libunwind.rs [new file with mode: 0644]
src/librustrt/local.rs [new file with mode: 0644]
src/librustrt/local_data.rs [new file with mode: 0644]
src/librustrt/local_heap.rs [new file with mode: 0644]
src/librustrt/local_ptr.rs [new file with mode: 0644]
src/librustrt/macros.rs [new file with mode: 0644]
src/librustrt/mutex.rs [new file with mode: 0644]
src/librustrt/rtio.rs [new file with mode: 0644]
src/librustrt/stack.rs [new file with mode: 0644]
src/librustrt/task.rs [new file with mode: 0644]
src/librustrt/thread_local_storage.rs [new file with mode: 0644]
src/librustrt/unwind.rs [new file with mode: 0644]
src/librustrt/util.rs [new file with mode: 0644]
src/librustuv/addrinfo.rs
src/librustuv/async.rs
src/librustuv/file.rs
src/librustuv/homing.rs
src/librustuv/lib.rs
src/librustuv/net.rs
src/librustuv/pipe.rs
src/librustuv/process.rs
src/librustuv/queue.rs
src/librustuv/signal.rs
src/librustuv/timeout.rs
src/librustuv/timer.rs
src/librustuv/tty.rs
src/librustuv/uvio.rs
src/librustuv/uvll.rs
src/libstd/c_str.rs [deleted file]
src/libstd/cleanup.rs [deleted file]
src/libstd/comm/shared.rs
src/libstd/comm/sync.rs
src/libstd/failure.rs [new file with mode: 0644]
src/libstd/io/fs.rs
src/libstd/io/mod.rs
src/libstd/io/net/addrinfo.rs
src/libstd/io/net/mod.rs
src/libstd/io/net/tcp.rs
src/libstd/io/net/udp.rs
src/libstd/io/net/unix.rs
src/libstd/io/pipe.rs
src/libstd/io/process.rs
src/libstd/io/signal.rs
src/libstd/io/stdio.rs
src/libstd/io/timer.rs
src/libstd/lib.rs
src/libstd/local_data.rs [deleted file]
src/libstd/os.rs
src/libstd/rt/args.rs [deleted file]
src/libstd/rt/at_exit_imp.rs [deleted file]
src/libstd/rt/backtrace.rs
src/libstd/rt/bookkeeping.rs [deleted file]
src/libstd/rt/env.rs [deleted file]
src/libstd/rt/libunwind.rs [deleted file]
src/libstd/rt/local.rs [deleted file]
src/libstd/rt/local_heap.rs [deleted file]
src/libstd/rt/local_ptr.rs [deleted file]
src/libstd/rt/macros.rs [deleted file]
src/libstd/rt/mod.rs
src/libstd/rt/rtio.rs [deleted file]
src/libstd/rt/stack.rs [deleted file]
src/libstd/rt/task.rs [deleted file]
src/libstd/rt/thread_local_storage.rs [deleted file]
src/libstd/rt/unwind.rs [deleted file]
src/libstd/rt/util.rs
src/libstd/rtdeps.rs
src/libstd/sync/deque.rs
src/libstd/task.rs
src/libstd/unstable/dynamic_lib.rs
src/libstd/unstable/mod.rs
src/libstd/unstable/mutex.rs [deleted file]
src/libstd/unstable/sync.rs [deleted file]
src/libsync/mutex.rs
src/test/run-pass/match-ref-binding-in-guard-3256.rs
src/test/run-pass/running-with-no-runtime.rs
src/test/run-pass/tcp-stress.rs
src/test/run-pass/writealias.rs

index 97bf7db5332ce6143ac57e0e27e8b35a0dc5de20..433490f6f5dbfd4985b52b7d53c2bb0ab794c477 100644 (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
index 625e1a8d0c7a711be36f36d9c32595f592ffb8b0..a75cb8aa4deb2f3a88e8dcb38db56b71fed4614d 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -35,8 +35,8 @@
 # that's per-target so you're allowed to conditionally add files based on the
 # target.
 ################################################################################
-NATIVE_LIBS := rustrt hoedown uv_support morestack miniz context_switch \
-               rust_test_helpers
+NATIVE_LIBS := rust_builtin hoedown uv_support morestack miniz context_switch \
+               rustrt_native rust_test_helpers
 
 # $(1) is the target triple
 define NATIVE_LIBRARIES
@@ -52,8 +52,9 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
                        hoedown/src/version.c
 NATIVE_DEPS_uv_support_$(1) := rust_uv.c
 NATIVE_DEPS_miniz_$(1) = miniz.c
-NATIVE_DEPS_rustrt_$(1) := rust_builtin.c \
-                       rust_android_dummy.c \
+NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
+                       rust_android_dummy.c
+NATIVE_DEPS_rustrt_native_$(1) := \
                        rust_try.ll \
                        arch/$$(HOST_$(1))/record_sp.S
 NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
index 511983da4f7f24a8bb07c6ad7d5da220acb2eb65..ca7ed6f4ba05bda7329cc0139c0138d92de67330 100644 (file)
 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 {
index 64d620358903e2864acd4ed5050722c9dacfac7e..7e35af79eab1cf10f8d10699edff49ca73b378ba 100644 (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() {}
-
index a65c06107ce3469268e9b036f4dcb31f849ce710..c46ea84a765cea9adace56d880d220a5f8c6fdb7 100644 (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!()
index e631b8b77cf9cb6ac814fd01e66766d670603d7a..4798218e3ff25dbc9653882f2d64c51c38799b18 100644 (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 @@ fn test_swap_remove() {
     #[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);
index 94901aff001c00b46d8d4af54b4adb77156408d0..7942a1569ed2f491ba8d6c1197113be32920636d 100644 (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();
index 1ebebbe555e8bd5ae74c899ebc945f9dd502a7bf..7f033a1bc6163a5d542767ee4cc11072c3a61102 100644 (file)
@@ -20,7 +20,7 @@
 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 @@ fn new() -> BasicLoop {
             idle_active: None,
             next_remote: 0,
             remotes: vec![],
-            messages: Exclusive::new(vec![]),
+            messages: Arc::new(Exclusive::new(Vec::new())),
         }
     }
 
@@ -61,19 +61,10 @@ fn work(&mut self) {
 
     fn remote_work(&mut self) {
         let messages = unsafe {
-            self.messages.with(|messages| {
-                if messages.len() > 0 {
-                    Some(mem::replace(messages, vec![]))
-                } else {
-                    None
-                }
-            })
-        };
-        let messages = match messages {
-            Some(m) => m, None => return
+            mem::replace(&mut *self.messages.lock(), Vec::new())
         };
-        for message in messages.iter() {
-            self.message(*message);
+        for message in messages.move_iter() {
+            self.message(message);
         }
     }
 
@@ -125,13 +116,13 @@ fn run(&mut self) {
             }
 
             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 @@ fn has_active_io(&self) -> bool { false }
 }
 
 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 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod test {
-    use std::task::TaskOpts;
+    use std::rt::task::TaskOpts;
 
     use basic;
     use PoolConfig;
index c75d69480ce0d99a90856796604709e589b75c57..333ac80907f6a9012a2ea6e5040674e0fddc4983 100644 (file)
 //! # Using a scheduler pool
 //!
 //! ```rust
-//! use std::task::TaskOpts;
+//! use std::rt::task::TaskOpts;
 //! use green::{SchedPool, PoolConfig};
 //! use green::sched::{PinnedTask, TaskFromFriend};
 //!
 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);
 
index e410d2719b14781635435501f7771b5fd438b431..f55dc92eac610c5d58240a93bf8f0b9c43defdd1 100644 (file)
 
 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 @@ fn single_threaded_yield() {
 
     #[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
index 49aef15f93b61bd24d6a091fffc2d09106c3b38e..7b738ed9c7c158d3ac10f0b107e55ef5f2671adb 100644 (file)
 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,
index f42d636cafbddc5caefb63591df6de026feee826..2e385f75e1d3e21c47943bb7b15a0299f76e3f84 100644 (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 @@ pub fn give_stack(&mut self, stack: Stack) {
     }
 }
 
+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;
index f50f65af6f9ebe83a8b9fcbb1ddd3a1341df72dd..91ebad3b3f8ab0418e2cd578c037f13da2f6c77d 100644 (file)
 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 @@ pub fn new_homed(stack_pool: &mut StackPool,
         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 @@ pub fn new_typed(coroutine: Option<Coroutine>,
     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 @@ fn smoke_opts() {
         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 @@ fn smoke_opts() {
     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());
     }
index 5b7f58fcb815c57028c6476bdf585993b5a70458..b833b2a65158d90b26db3ad51b7beb9b411b7d07 100644 (file)
 #[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};
 #[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};
 #[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 extra {
             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;
index 6bc41a9c4c5b2d28b2bdb978573de27e80349bca..255c3f4bd213dd8c510791c6f6adad4dc627bd66 100644 (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 @@ pub fn run(host: Option<&str>, servname: Option<&str>,
         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 @@ fn getaddrinfo(node: *c_char, service: *c_char,
     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),
     }
 }
index b10284a3b6c3f0da7b269c186667bf6cb803ac02..fda9b7b1932b0a4b03477c4ecae18dfa2e4ae0de 100644 (file)
 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 @@ pub fn new(fd: fd_t, close_on_drop: bool) -> 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 @@ pub fn inner_write(&mut self, buf: &[u8]) -> Result<(), IoError> {
     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 @@ fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result<int, IoError> {
             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 @@ fn seek(&mut self, pos: i64, whence: io::SeekStyle) -> Result<u64, IoError> {
             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 @@ fn tell(&self) -> Result<u64, IoError> {
             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 @@ fn os_datasync(fd: c_int) -> c_int {
             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 @@ fn fstat(&mut self) -> IoResult<io::FileStat> {
 }
 
 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 @@ fn clone(&self) -> Box<rtio::RtioPipe:Send> {
     // 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 @@ fn set_write_timeout(&mut self, _t: Option<u64>) {}
 }
 
 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 @@ pub fn new(file: *libc::FILE) -> 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 @@ fn read(&mut self, buf: &mut [u8]) -> Result<int, IoError> {
             }
         });
         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 @@ fn read(&mut self, buf: &mut [u8]) -> Result<int, IoError> {
         }
     }
 
-    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 @@ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
         }
     }
 
-    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 @@ fn seek(&mut self, pos: i64, style: io::SeekStyle) -> Result<u64, IoError> {
             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 @@ fn tell(&self) -> Result<u64, IoError> {
             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 @@ fn drop(&mut self) {
     }
 }
 
-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 gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 }
     #[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 @@ fn test_file_desc() {
         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 @@ fn test_cfile() {
             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);
index 4f1f3b3ca26f726374cbc7e3fcaaf57085da0389..2a5b78e55067cb75e5ef369981b210157f6f2309 100644 (file)
 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 @@ pub fn new(fd: fd_t, close_on_drop: bool) -> 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 @@ pub fn inner_read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
             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 @@ pub fn handle(&self) -> libc::HANDLE {
 
     // 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 @@ fn seek_common(&self, pos: i64, style: io::SeekStyle) -> Result<u64, IoError> {
 
 }
 
-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 @@ fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result<int, IoError> {
             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 @@ fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> Result<(), IoError> {
         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 @@ fn fstat(&mut self) -> IoResult<io::FileStat> {
 }
 
 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 @@ fn clone(&self) -> Box<rtio::RtioPipe:Send> {
     // 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 @@ fn set_write_timeout(&mut self, _t: Option<u64>) {}
 }
 
 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 @@ fn drop(&mut self) {
     }
 }
 
-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())
 }
index 2260d74e1617705c3b3fcfc423f47b0f37d661ec..443c82c6a547c53918a3ebd586783ce604268805 100644 (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 @@ pub fn new() -> (signal, signal) {
     }
 
     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) {
index 240b87fda084d13e39110543d842ac9d9cfdf313..3b0dbe2d0dce978e63be79d4c53ef6cdfd302e2a 100644 (file)
 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;
 #[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 @@ pub fn new() -> 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 @@ fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
     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 @@ fn fs_utime(&mut self, src: &CString, atime: u64,
     }
 
     // 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())
     }
 }
index 26307feae91f0f62e5a41c533a6bab31eccda3bb..24956e514ec83e09cb85ce4234040e270ad2d03d 100644 (file)
 
 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 @@ fn new(fd: sock_t) -> 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 @@ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
             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 @@ fn set_write_timeout(&mut self, timeout: Option<u64>) {
 }
 
 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 @@ fn listen(~self) -> IoResult<Box<rtio::RtioTcpAcceptor:Send>> {
 }
 
 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 @@ pub fn native_accept(&mut self) -> IoResult<TcpStream> {
 }
 
 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 @@ pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> {
                    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 @@ fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
 }
 
 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 @@ fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
 #[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 @@ fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, ip::SocketAddr)> {
         })
     }
 
-    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 @@ fn sendto(&mut self, buf: &[u8], dst: ip::SocketAddr) -> IoResult<()> {
 
         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(()) => {}
index a53a58b6cec434ddc2ad2ad11c930675062d849a..7a1134fbe5956109bed023e09ad0e6997ce1b0d8 100644 (file)
 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 @@ pub fn native_accept(&mut self) -> IoResult<UnixStream> {
         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;
index cd4cbf2c90f32e79f9971e37e6eca3de8d5d20a4..a5694436b97200016f91a4d4463493a7029b6531 100644 (file)
 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 @@ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
         // 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 @@ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
             // 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 @@ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
             // 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 @@ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
 
             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 @@ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
                     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
                 }
index 4b75e1b73599de0763fc6db272291489808d0276..2c2b7cec1dec4806a3d32835de56b458b825d85f 100644 (file)
 
 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 @@ fn set_timeout(&mut self, timeout: Option<u64>) {
         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 @@ fn wait(&mut self) -> IoResult<p::ProcessExit> {
                 // 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 @@ fn wait(&mut self) -> IoResult<p::ProcessExit> {
         }
     }
 
-    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 @@ fn kill(&mut self, signum: int) -> Result<(), io::IoError> {
         // 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 @@ fn drop(&mut self) {
 }
 
 #[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 @@ unsafe fn set_cloexec(fd: c_int) {
                                     (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 @@ pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 }
     }
 
     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 @@ pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 }
  * 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 register_sigchld() -> (libc::c_int, c::sigaction) {
         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 register_sigchld() -> (libc::c_int, c::sigaction) {
     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 drain(fd: libc::c_int) -> bool {
     }
 }
 
-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),
         }
     }
 }
index 8aa8b12b26d271b257debb26fc313d31ba740b66..11f9c4b3d8cb8cebe6ef32cdce12213125a0cbd8 100644 (file)
 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 signal(active: &mut Vec<Box<Inner>>,
         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 signal(active: &mut Vec<Box<Inner>>,
 
                 // 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 @@ pub fn new() -> IoResult<Timer> {
         Ok(Timer {
             id: id,
             inner: Some(box Inner {
-                tx: None,
+                cb: None,
                 interval: 0,
                 target: 0,
                 repeat: false,
@@ -245,38 +245,34 @@ fn inner(&mut self) -> Box<Inner> {
 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;
     }
 }
 
index e7130de05c26d3ffd2027b6e8af5858ff21a4f14..d175060dd98606f04502e01e96c3d240d8e86a93 100644 (file)
 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 @@ fn sleep(&mut self, msecs: u64) {
         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 @@ fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
                                   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 @@ fn period(&mut self, msecs: u64) -> Receiver<()> {
                                   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;
     }
 }
 
index fe7a58a5e6868f705f38dc485239f89839584669..a3c5349fa4582a47be58176939d9a2304b2e499d 100644 (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)),
+                        })
                     }
                 }
             }
index 4183dec19d02dfe1e074f13e8e50a6cded147ce3..f16c41d4e28f7c1806cda0089d22b7b57447e7ee 100644 (file)
 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 @@ fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>> {
 #[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 @@ fn smoke_opts() {
         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 @@ fn smoke_opts() {
     fn smoke_opts_fail() {
         let mut opts = TaskOpts::new();
         let (tx, rx) = channel();
-        opts.notify_chan = Some(tx);
+        opts.on_exit = Some(proc(r) tx.send(r));
         spawn_opts(opts, proc() { fail!() });
         assert!(rx.recv().is_err());
     }
diff --git a/src/librustrt/args.rs b/src/librustrt/args.rs
new file mode 100644 (file)
index 0000000..0789bf7
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2012-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.
+
+//! Global storage for command line arguments
+//!
+//! The current incarnation of the Rust runtime expects for
+//! the processes `argc` and `argv` arguments to be stored
+//! in a globally-accessible location for use by the `os` module.
+//!
+//! Only valid to call on linux. Mac and Windows use syscalls to
+//! discover the command line arguments.
+//!
+//! FIXME #7756: Would be nice for this to not exist.
+
+use core::prelude::*;
+use collections::vec::Vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: int, argv: **u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Take the global arguments from global storage.
+pub fn take() -> Option<Vec<Vec<u8>>> { imp::take() }
+
+/// Give the global arguments to global storage.
+///
+/// It is an error if the arguments already exist.
+pub fn put(args: Vec<Vec<u8>>) { imp::put(args) }
+
+/// Make a clone of the global arguments.
+pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "android")]
+#[cfg(target_os = "freebsd")]
+mod imp {
+    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;
+
+    pub unsafe fn init(argc: int, argv: **u8) {
+        let args = load_argc_and_argv(argc, argv);
+        put(args);
+    }
+
+    pub unsafe fn cleanup() {
+        rtassert!(take().is_some());
+        lock.destroy();
+    }
+
+    pub fn take() -> Option<Vec<Vec<u8>>> {
+        with_lock(|| unsafe {
+            let ptr = get_global_ptr();
+            let val = mem::replace(&mut *ptr, None);
+            val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
+        })
+    }
+
+    pub fn put(args: Vec<Vec<u8>>) {
+        with_lock(|| unsafe {
+            let ptr = get_global_ptr();
+            rtassert!((*ptr).is_none());
+            (*ptr) = Some(box args.clone());
+        })
+    }
+
+    pub fn clone() -> Option<Vec<Vec<u8>>> {
+        with_lock(|| unsafe {
+            let ptr = get_global_ptr();
+            (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
+        })
+    }
+
+    fn with_lock<T>(f: || -> T) -> T {
+        unsafe {
+            let _guard = lock.lock();
+            f()
+        }
+    }
+
+    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+        unsafe { mem::transmute(&global_args_ptr) }
+    }
+
+    unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> Vec<Vec<u8>> {
+        Vec::from_fn(argc as uint, |i| {
+            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 std::prelude::*;
+        use std::finally::Finally;
+
+        use super::*;
+
+        #[test]
+        fn smoke_test() {
+            // Preserve the actual global state.
+            let saved_value = take();
+
+            let expected = vec![
+                Vec::from_slice(bytes!("happy")),
+                Vec::from_slice(bytes!("today?")),
+            ];
+
+            put(expected.clone());
+            assert!(clone() == Some(expected.clone()));
+            assert!(take() == Some(expected.clone()));
+            assert!(take() == None);
+
+            (|| {
+            }).finally(|| {
+                // Restore the actual global state.
+                match saved_value {
+                    Some(ref args) => put(args.clone()),
+                    None => ()
+                }
+            })
+        }
+    }
+}
+
+#[cfg(target_os = "macos")]
+#[cfg(target_os = "win32")]
+mod imp {
+    use core::prelude::*;
+    use collections::vec::Vec;
+
+    pub unsafe fn init(_argc: int, _argv: **u8) {
+    }
+
+    pub fn cleanup() {
+    }
+
+    pub fn take() -> Option<Vec<Vec<u8>>> {
+        fail!()
+    }
+
+    pub fn put(_args: Vec<Vec<u8>>) {
+        fail!()
+    }
+
+    pub fn clone() -> Option<Vec<Vec<u8>>> {
+        fail!()
+    }
+}
diff --git a/src/librustrt/at_exit_imp.rs b/src/librustrt/at_exit_imp.rs
new file mode 100644 (file)
index 0000000..d38d069
--- /dev/null
@@ -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();
+    }
+}
diff --git a/src/librustrt/bookkeeping.rs b/src/librustrt/bookkeeping.rs
new file mode 100644 (file)
index 0000000..fd29049
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2013-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.
+
+//! Task bookkeeping
+//!
+//! This module keeps track of the number of running tasks so that entry points
+//! with libnative know when it's possible to exit the program (once all tasks
+//! have exited).
+//!
+//! The green counterpart for this is bookkeeping on sched pools, and it's up to
+//! each respective runtime to make sure that they call increment() and
+//! decrement() manually.
+
+use core::atomics;
+
+use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+
+static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
+static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+
+pub fn increment() {
+    let _ = unsafe { TASK_COUNT.fetch_add(1, atomics::SeqCst) };
+}
+
+pub fn decrement() {
+    unsafe {
+        if TASK_COUNT.fetch_sub(1, atomics::SeqCst) == 1 {
+            let guard = TASK_LOCK.lock();
+            guard.signal();
+        }
+    }
+}
+
+/// Waits for all other native tasks in the system to exit. This is only used by
+/// the entry points of native programs
+pub fn wait_for_other_tasks() {
+    unsafe {
+        let guard = TASK_LOCK.lock();
+        while TASK_COUNT.load(atomics::SeqCst) > 0 {
+            guard.wait();
+        }
+    }
+}
diff --git a/src/librustrt/c_str.rs b/src/librustrt/c_str.rs
new file mode 100644 (file)
index 0000000..4234c08
--- /dev/null
@@ -0,0 +1,815 @@
+// 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.
+
+/*!
+
+C-string manipulation and management
+
+This modules provides the basic methods for creating and manipulating
+null-terminated strings for use with FFI calls (back to C). Most C APIs require
+that the string being passed to them is null-terminated, and by default rust's
+string types are *not* null terminated.
+
+The other problem with translating Rust strings to C strings is that Rust
+strings can validly contain a null-byte in the middle of the string (0 is a
+valid unicode codepoint). This means that not all Rust strings can actually be
+translated to C strings.
+
+# Creation of a C string
+
+A C string is managed through the `CString` type defined in this module. It
+"owns" the internal buffer of characters and will automatically deallocate the
+buffer when the string is dropped. The `ToCStr` trait is implemented for `&str`
+and `&[u8]`, but the conversions can fail due to some of the limitations
+explained above.
+
+This also means that currently whenever a C string is created, an allocation
+must be performed to place the data elsewhere (the lifetime of the C string is
+not tied to the lifetime of the original string/data buffer). If C strings are
+heavily used in applications, then caching may be advisable to prevent
+unnecessary amounts of allocations.
+
+An example of creating and using a C string would be:
+
+```rust
+extern crate libc;
+
+extern {
+    fn puts(s: *libc::c_char);
+}
+
+fn main() {
+    let my_string = "Hello, world!";
+
+    // Allocate the C string with an explicit local that owns the string. The
+    // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope.
+    let my_c_string = my_string.to_c_str();
+    my_c_string.with_ref(|c_buffer| {
+        unsafe { puts(c_buffer); }
+    });
+
+    // Don't save off the allocation of the C string, the `c_buffer` will be
+    // deallocated when this block returns!
+    my_string.with_c_str(|c_buffer| {
+        unsafe { puts(c_buffer); }
+    });
+}
+```
+
+*/
+
+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;
+
+/// The representation of a C String.
+///
+/// This structure wraps a `*libc::c_char`, and will automatically free the
+/// memory it is pointing to when it goes out of scope.
+pub struct CString {
+    buf: *libc::c_char,
+    owns_buffer_: bool,
+}
+
+impl Clone for CString {
+    /// Clone this CString into a new, uniquely owned CString. For safety
+    /// reasons, this is always a deep clone, rather than the usual shallow
+    /// clone.
+    fn clone(&self) -> CString {
+        if self.buf.is_null() {
+            CString { buf: self.buf, owns_buffer_: self.owns_buffer_ }
+        } else {
+            let len = self.len() + 1;
+            let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
+            unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
+            CString { buf: buf as *libc::c_char, owns_buffer_: true }
+        }
+    }
+}
+
+impl PartialEq for CString {
+    fn eq(&self, other: &CString) -> bool {
+        if self.buf as uint == other.buf as uint {
+            true
+        } else if self.buf.is_null() || other.buf.is_null() {
+            false
+        } else {
+            unsafe {
+                libc::strcmp(self.buf, other.buf) == 0
+            }
+        }
+    }
+}
+
+impl CString {
+    /// Create a C String from a pointer.
+    pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
+        CString { buf: buf, owns_buffer_: owns_buffer }
+    }
+
+    /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
+    /// Any ownership of the buffer by the `CString` wrapper is forgotten.
+    pub unsafe fn unwrap(self) -> *libc::c_char {
+        let mut c_str = self;
+        c_str.owns_buffer_ = false;
+        c_str.buf
+    }
+
+    /// Calls a closure with a reference to the underlying `*libc::c_char`.
+    ///
+    /// # Failure
+    ///
+    /// Fails if the CString is null.
+    pub fn with_ref<T>(&self, f: |*libc::c_char| -> T) -> T {
+        if self.buf.is_null() { fail!("CString is null!"); }
+        f(self.buf)
+    }
+
+    /// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
+    ///
+    /// # Failure
+    ///
+    /// Fails if the CString is null.
+    pub fn with_mut_ref<T>(&mut self, f: |*mut libc::c_char| -> T) -> T {
+        if self.buf.is_null() { fail!("CString is null!"); }
+        f(self.buf as *mut libc::c_char)
+    }
+
+    /// Returns true if the CString is a null.
+    pub fn is_null(&self) -> bool {
+        self.buf.is_null()
+    }
+
+    /// Returns true if the CString is not null.
+    pub fn is_not_null(&self) -> bool {
+        self.buf.is_not_null()
+    }
+
+    /// Returns whether or not the `CString` owns the buffer.
+    pub fn owns_buffer(&self) -> bool {
+        self.owns_buffer_
+    }
+
+    /// Converts the CString into a `&[u8]` without copying.
+    /// Includes the terminating NUL byte.
+    ///
+    /// # Failure
+    ///
+    /// Fails if the CString is null.
+    #[inline]
+    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
+        if self.buf.is_null() { fail!("CString is null!"); }
+        unsafe {
+            mem::transmute(Slice { data: self.buf, len: self.len() + 1 })
+        }
+    }
+
+    /// Converts the CString into a `&[u8]` without copying.
+    /// Does not include the terminating NUL byte.
+    ///
+    /// # Failure
+    ///
+    /// Fails if the CString is null.
+    #[inline]
+    pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] {
+        if self.buf.is_null() { fail!("CString is null!"); }
+        unsafe {
+            mem::transmute(Slice { data: self.buf, len: self.len() })
+        }
+    }
+
+    /// Converts the CString into a `&str` without copying.
+    /// Returns None if the CString is not UTF-8.
+    ///
+    /// # Failure
+    ///
+    /// Fails if the CString is null.
+    #[inline]
+    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
+        let buf = self.as_bytes_no_nul();
+        str::from_utf8(buf)
+    }
+
+    /// Return a CString iterator.
+    ///
+    /// # Failure
+    ///
+    /// Fails if the CString is null.
+    pub fn iter<'a>(&'a self) -> CChars<'a> {
+        if self.buf.is_null() { fail!("CString is null!"); }
+        CChars {
+            ptr: self.buf,
+            marker: marker::ContravariantLifetime,
+        }
+    }
+}
+
+impl Drop for CString {
+    fn drop(&mut self) {
+        if self.owns_buffer_ {
+            unsafe {
+                libc::free(self.buf as *mut libc::c_void)
+            }
+        }
+    }
+}
+
+impl Container for CString {
+    /// Return the number of bytes in the CString (not including the NUL terminator).
+    ///
+    /// # Failure
+    ///
+    /// Fails if the CString is null.
+    #[inline]
+    fn len(&self) -> uint {
+        if self.buf.is_null() { fail!("CString is null!"); }
+        let mut cur = self.buf;
+        let mut len = 0;
+        unsafe {
+            while *cur != 0 {
+                len += 1;
+                cur = cur.offset(1);
+            }
+        }
+        return len;
+    }
+}
+
+/// A generic trait for converting a value to a CString.
+pub trait ToCStr {
+    /// Copy the receiver into a CString.
+    ///
+    /// # Failure
+    ///
+    /// Fails the task if the receiver has an interior null.
+    fn to_c_str(&self) -> CString;
+
+    /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
+    unsafe fn to_c_str_unchecked(&self) -> CString;
+
+    /// Work with a temporary CString constructed from the receiver.
+    /// The provided `*libc::c_char` will be freed immediately upon return.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// extern crate libc;
+    ///
+    /// fn main() {
+    ///     let s = "PATH".with_c_str(|path| unsafe {
+    ///         libc::getenv(path)
+    ///     });
+    /// }
+    /// ```
+    ///
+    /// # Failure
+    ///
+    /// Fails the task if the receiver has an interior null.
+    #[inline]
+    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.to_c_str().with_ref(f)
+    }
+
+    /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
+    #[inline]
+    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.to_c_str_unchecked().with_ref(f)
+    }
+}
+
+// FIXME (#12938): Until DST lands, we cannot decompose &str into &
+// and str, so we cannot usefully take ToCStr arguments by reference
+// (without forcing an additional & around &str). So we are instead
+// temporarily adding an instance for ~str and String, so that we can
+// take ToCStr as owned. When DST lands, the string instances should
+// be revisted, and arguments bound by ToCStr should be passed by
+// reference.
+
+impl<'a> ToCStr for &'a str {
+    #[inline]
+    fn to_c_str(&self) -> CString {
+        self.as_bytes().to_c_str()
+    }
+
+    #[inline]
+    unsafe fn to_c_str_unchecked(&self) -> CString {
+        self.as_bytes().to_c_str_unchecked()
+    }
+
+    #[inline]
+    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str(f)
+    }
+
+    #[inline]
+    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str_unchecked(f)
+    }
+}
+
+impl ToCStr for String {
+    #[inline]
+    fn to_c_str(&self) -> CString {
+        self.as_bytes().to_c_str()
+    }
+
+    #[inline]
+    unsafe fn to_c_str_unchecked(&self) -> CString {
+        self.as_bytes().to_c_str_unchecked()
+    }
+
+    #[inline]
+    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str(f)
+    }
+
+    #[inline]
+    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str_unchecked(f)
+    }
+}
+
+// The length of the stack allocated buffer for `vec.with_c_str()`
+static BUF_LEN: uint = 128;
+
+impl<'a> ToCStr for &'a [u8] {
+    fn to_c_str(&self) -> CString {
+        let mut cs = unsafe { self.to_c_str_unchecked() };
+        cs.with_mut_ref(|buf| check_for_null(*self, buf));
+        cs
+    }
+
+    unsafe fn to_c_str_unchecked(&self) -> CString {
+        let self_len = self.len();
+        let buf = malloc_raw(self_len + 1);
+
+        ptr::copy_memory(buf, self.as_ptr(), self_len);
+        *buf.offset(self_len as int) = 0;
+
+        CString::new(buf as *libc::c_char, true)
+    }
+
+    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
+        unsafe { with_c_str(*self, true, f) }
+    }
+
+    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
+        with_c_str(*self, false, f)
+    }
+}
+
+// Unsafe function that handles possibly copying the &[u8] into a stack array.
+unsafe fn with_c_str<T>(v: &[u8], checked: bool, f: |*libc::c_char| -> T) -> T {
+    if v.len() < BUF_LEN {
+        let mut buf: [u8, .. BUF_LEN] = mem::uninitialized();
+        slice::bytes::copy_memory(buf, v);
+        buf[v.len()] = 0;
+
+        let buf = buf.as_mut_ptr();
+        if checked {
+            check_for_null(v, buf as *mut libc::c_char);
+        }
+
+        f(buf as *libc::c_char)
+    } else if checked {
+        v.to_c_str().with_ref(f)
+    } else {
+        v.to_c_str_unchecked().with_ref(f)
+    }
+}
+
+#[inline]
+fn check_for_null(v: &[u8], buf: *mut libc::c_char) {
+    for i in range(0, v.len()) {
+        unsafe {
+            let p = buf.offset(i as int);
+            assert!(*p != 0);
+        }
+    }
+}
+
+/// External iterator for a CString's bytes.
+///
+/// Use with the `std::iter` module.
+pub struct CChars<'a> {
+    ptr: *libc::c_char,
+    marker: marker::ContravariantLifetime<'a>,
+}
+
+impl<'a> Iterator<libc::c_char> for CChars<'a> {
+    fn next(&mut self) -> Option<libc::c_char> {
+        let ch = unsafe { *self.ptr };
+        if ch == 0 {
+            None
+        } else {
+            self.ptr = unsafe { self.ptr.offset(1) };
+            Some(ch)
+        }
+    }
+}
+
+/// Parses a C "multistring", eg windows env values or
+/// the req->ptr result in a uv_fs_readdir() call.
+///
+/// Optionally, a `count` can be passed in, limiting the
+/// parsing to only being done `count`-times.
+///
+/// The specified closure is invoked with each string that
+/// is found, and the number of strings found is returned.
+pub unsafe fn from_c_multistring(buf: *libc::c_char,
+                                 count: Option<uint>,
+                                 f: |&CString|) -> uint {
+
+    let mut curr_ptr: uint = buf as uint;
+    let mut ctr = 0;
+    let (limited_count, limit) = match count {
+        Some(limit) => (true, limit),
+        None => (false, 0)
+    };
+    while ((limited_count && ctr < limit) || !limited_count)
+          && *(curr_ptr as *libc::c_char) != 0 as libc::c_char {
+        let cstr = CString::new(curr_ptr as *libc::c_char, false);
+        f(&cstr);
+        curr_ptr += cstr.len() + 1;
+        ctr += 1;
+    }
+    return ctr;
+}
+
+#[cfg(test)]
+mod tests {
+    use std::prelude::*;
+    use std::ptr;
+    use std::task;
+    use libc;
+
+    use super::*;
+
+    #[test]
+    fn test_str_multistring_parsing() {
+        unsafe {
+            let input = bytes!("zero", "\x00", "one", "\x00", "\x00");
+            let ptr = input.as_ptr();
+            let expected = ["zero", "one"];
+            let mut it = expected.iter();
+            let result = from_c_multistring(ptr as *libc::c_char, None, |c| {
+                let cbytes = c.as_bytes_no_nul();
+                assert_eq!(cbytes, it.next().unwrap().as_bytes());
+            });
+            assert_eq!(result, 2);
+            assert!(it.next().is_none());
+        }
+    }
+
+    #[test]
+    fn test_str_to_c_str() {
+        "".to_c_str().with_ref(|buf| {
+            unsafe {
+                assert_eq!(*buf.offset(0), 0);
+            }
+        });
+
+        "hello".to_c_str().with_ref(|buf| {
+            unsafe {
+                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
+                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
+                assert_eq!(*buf.offset(2), 'l' as libc::c_char);
+                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
+                assert_eq!(*buf.offset(4), 'o' as libc::c_char);
+                assert_eq!(*buf.offset(5), 0);
+            }
+        })
+    }
+
+    #[test]
+    fn test_vec_to_c_str() {
+        let b: &[u8] = [];
+        b.to_c_str().with_ref(|buf| {
+            unsafe {
+                assert_eq!(*buf.offset(0), 0);
+            }
+        });
+
+        let _ = bytes!("hello").to_c_str().with_ref(|buf| {
+            unsafe {
+                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
+                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
+                assert_eq!(*buf.offset(2), 'l' as libc::c_char);
+                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
+                assert_eq!(*buf.offset(4), 'o' as libc::c_char);
+                assert_eq!(*buf.offset(5), 0);
+            }
+        });
+
+        let _ = bytes!("foo", 0xff).to_c_str().with_ref(|buf| {
+            unsafe {
+                assert_eq!(*buf.offset(0), 'f' as libc::c_char);
+                assert_eq!(*buf.offset(1), 'o' as libc::c_char);
+                assert_eq!(*buf.offset(2), 'o' as libc::c_char);
+                assert_eq!(*buf.offset(3), 0xff as i8);
+                assert_eq!(*buf.offset(4), 0);
+            }
+        });
+    }
+
+    #[test]
+    fn test_is_null() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        assert!(c_str.is_null());
+        assert!(!c_str.is_not_null());
+    }
+
+    #[test]
+    fn test_unwrap() {
+        let c_str = "hello".to_c_str();
+        unsafe { libc::free(c_str.unwrap() as *mut libc::c_void) }
+    }
+
+    #[test]
+    fn test_with_ref() {
+        let c_str = "hello".to_c_str();
+        let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
+        assert!(!c_str.is_null());
+        assert!(c_str.is_not_null());
+        assert_eq!(len, 5);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_with_ref_empty_fail() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        c_str.with_ref(|_| ());
+    }
+
+    #[test]
+    fn test_iterator() {
+        let c_str = "".to_c_str();
+        let mut iter = c_str.iter();
+        assert_eq!(iter.next(), None);
+
+        let c_str = "hello".to_c_str();
+        let mut iter = c_str.iter();
+        assert_eq!(iter.next(), Some('h' as libc::c_char));
+        assert_eq!(iter.next(), Some('e' as libc::c_char));
+        assert_eq!(iter.next(), Some('l' as libc::c_char));
+        assert_eq!(iter.next(), Some('l' as libc::c_char));
+        assert_eq!(iter.next(), Some('o' as libc::c_char));
+        assert_eq!(iter.next(), None);
+    }
+
+    #[test]
+    fn test_to_c_str_fail() {
+        assert!(task::try(proc() { "he\x00llo".to_c_str() }).is_err());
+    }
+
+    #[test]
+    fn test_to_c_str_unchecked() {
+        unsafe {
+            "he\x00llo".to_c_str_unchecked().with_ref(|buf| {
+                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
+                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
+                assert_eq!(*buf.offset(2), 0);
+                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
+                assert_eq!(*buf.offset(4), 'l' as libc::c_char);
+                assert_eq!(*buf.offset(5), 'o' as libc::c_char);
+                assert_eq!(*buf.offset(6), 0);
+            })
+        }
+    }
+
+    #[test]
+    fn test_as_bytes() {
+        let c_str = "hello".to_c_str();
+        assert_eq!(c_str.as_bytes(), bytes!("hello", 0));
+        let c_str = "".to_c_str();
+        assert_eq!(c_str.as_bytes(), bytes!(0));
+        let c_str = bytes!("foo", 0xff).to_c_str();
+        assert_eq!(c_str.as_bytes(), bytes!("foo", 0xff, 0));
+    }
+
+    #[test]
+    fn test_as_bytes_no_nul() {
+        let c_str = "hello".to_c_str();
+        assert_eq!(c_str.as_bytes_no_nul(), bytes!("hello"));
+        let c_str = "".to_c_str();
+        let exp: &[u8] = [];
+        assert_eq!(c_str.as_bytes_no_nul(), exp);
+        let c_str = bytes!("foo", 0xff).to_c_str();
+        assert_eq!(c_str.as_bytes_no_nul(), bytes!("foo", 0xff));
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_as_bytes_fail() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        c_str.as_bytes();
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_as_bytes_no_nul_fail() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        c_str.as_bytes_no_nul();
+    }
+
+    #[test]
+    fn test_as_str() {
+        let c_str = "hello".to_c_str();
+        assert_eq!(c_str.as_str(), Some("hello"));
+        let c_str = "".to_c_str();
+        assert_eq!(c_str.as_str(), Some(""));
+        let c_str = bytes!("foo", 0xff).to_c_str();
+        assert_eq!(c_str.as_str(), None);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_as_str_fail() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        c_str.as_str();
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_len_fail() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        c_str.len();
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_iter_fail() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        c_str.iter();
+    }
+
+    #[test]
+    fn test_clone() {
+        let a = "hello".to_c_str();
+        let b = a.clone();
+        assert!(a == b);
+    }
+
+    #[test]
+    fn test_clone_noleak() {
+        fn foo(f: |c: &CString|) {
+            let s = "test".to_string();
+            let c = s.to_c_str();
+            // give the closure a non-owned CString
+            let mut c_ = c.with_ref(|c| unsafe { CString::new(c, false) } );
+            f(&c_);
+            // muck with the buffer for later printing
+            c_.with_mut_ref(|c| unsafe { *c = 'X' as libc::c_char } );
+        }
+
+        let mut c_: Option<CString> = None;
+        foo(|c| {
+            c_ = Some(c.clone());
+            c.clone();
+            // force a copy, reading the memory
+            c.as_bytes().to_owned();
+        });
+        let c_ = c_.unwrap();
+        // force a copy, reading the memory
+        c_.as_bytes().to_owned();
+    }
+
+    #[test]
+    fn test_clone_eq_null() {
+        let x = unsafe { CString::new(ptr::null(), false) };
+        let y = x.clone();
+        assert!(x == y);
+    }
+}
+
+#[cfg(test)]
+mod bench {
+    use test::Bencher;
+    use libc;
+    use std::prelude::*;
+
+    #[inline]
+    fn check(s: &str, c_str: *libc::c_char) {
+        let s_buf = s.as_ptr();
+        for i in range(0, s.len()) {
+            unsafe {
+                assert_eq!(
+                    *s_buf.offset(i as int) as libc::c_char,
+                    *c_str.offset(i as int));
+            }
+        }
+    }
+
+    static s_short: &'static str = "Mary";
+    static s_medium: &'static str = "Mary had a little lamb";
+    static s_long: &'static str = "\
+        Mary had a little lamb, Little lamb
+        Mary had a little lamb, Little lamb
+        Mary had a little lamb, Little lamb
+        Mary had a little lamb, Little lamb
+        Mary had a little lamb, Little lamb
+        Mary had a little lamb, Little lamb";
+
+    fn bench_to_str(b: &mut Bencher, s: &str) {
+        b.iter(|| {
+            let c_str = s.to_c_str();
+            c_str.with_ref(|c_str_buf| check(s, c_str_buf))
+        })
+    }
+
+    #[bench]
+    fn bench_to_c_str_short(b: &mut Bencher) {
+        bench_to_str(b, s_short)
+    }
+
+    #[bench]
+    fn bench_to_c_str_medium(b: &mut Bencher) {
+        bench_to_str(b, s_medium)
+    }
+
+    #[bench]
+    fn bench_to_c_str_long(b: &mut Bencher) {
+        bench_to_str(b, s_long)
+    }
+
+    fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) {
+        b.iter(|| {
+            let c_str = unsafe { s.to_c_str_unchecked() };
+            c_str.with_ref(|c_str_buf| check(s, c_str_buf))
+        })
+    }
+
+    #[bench]
+    fn bench_to_c_str_unchecked_short(b: &mut Bencher) {
+        bench_to_c_str_unchecked(b, s_short)
+    }
+
+    #[bench]
+    fn bench_to_c_str_unchecked_medium(b: &mut Bencher) {
+        bench_to_c_str_unchecked(b, s_medium)
+    }
+
+    #[bench]
+    fn bench_to_c_str_unchecked_long(b: &mut Bencher) {
+        bench_to_c_str_unchecked(b, s_long)
+    }
+
+    fn bench_with_c_str(b: &mut Bencher, s: &str) {
+        b.iter(|| {
+            s.with_c_str(|c_str_buf| check(s, c_str_buf))
+        })
+    }
+
+    #[bench]
+    fn bench_with_c_str_short(b: &mut Bencher) {
+        bench_with_c_str(b, s_short)
+    }
+
+    #[bench]
+    fn bench_with_c_str_medium(b: &mut Bencher) {
+        bench_with_c_str(b, s_medium)
+    }
+
+    #[bench]
+    fn bench_with_c_str_long(b: &mut Bencher) {
+        bench_with_c_str(b, s_long)
+    }
+
+    fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) {
+        b.iter(|| {
+            unsafe {
+                s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf))
+            }
+        })
+    }
+
+    #[bench]
+    fn bench_with_c_str_unchecked_short(b: &mut Bencher) {
+        bench_with_c_str_unchecked(b, s_short)
+    }
+
+    #[bench]
+    fn bench_with_c_str_unchecked_medium(b: &mut Bencher) {
+        bench_with_c_str_unchecked(b, s_medium)
+    }
+
+    #[bench]
+    fn bench_with_c_str_unchecked_long(b: &mut Bencher) {
+        bench_with_c_str_unchecked(b, s_long)
+    }
+}
diff --git a/src/librustrt/exclusive.rs b/src/librustrt/exclusive.rs
new file mode 100644 (file)
index 0000000..6231396
--- /dev/null
@@ -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);
+        }
+    }
+}
diff --git a/src/librustrt/lib.rs b/src/librustrt/lib.rs
new file mode 100644 (file)
index 0000000..3158687
--- /dev/null
@@ -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};
+}
diff --git a/src/librustrt/libunwind.rs b/src/librustrt/libunwind.rs
new file mode 100644 (file)
index 0000000..846ec24
--- /dev/null
@@ -0,0 +1,96 @@
+// 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.
+
+//! Unwind library interface
+
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case_functions)]
+#![allow(dead_code)] // these are just bindings
+
+use libc;
+
+#[cfg(not(target_arch = "arm"))]
+#[repr(C)]
+pub enum _Unwind_Action {
+    _UA_SEARCH_PHASE = 1,
+    _UA_CLEANUP_PHASE = 2,
+    _UA_HANDLER_FRAME = 4,
+    _UA_FORCE_UNWIND = 8,
+    _UA_END_OF_STACK = 16,
+}
+
+#[cfg(target_arch = "arm")]
+#[repr(C)]
+pub enum _Unwind_State {
+    _US_VIRTUAL_UNWIND_FRAME = 0,
+    _US_UNWIND_FRAME_STARTING = 1,
+    _US_UNWIND_FRAME_RESUME = 2,
+    _US_ACTION_MASK = 3,
+    _US_FORCE_UNWIND = 8,
+    _US_END_OF_STACK = 16
+}
+
+#[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 type _Unwind_Exception_Class = u64;
+
+pub type _Unwind_Word = libc::uintptr_t;
+
+#[cfg(target_arch = "x86")]
+pub static unwinder_private_data_size: int = 5;
+
+#[cfg(target_arch = "x86_64")]
+pub static unwinder_private_data_size: int = 2;
+
+#[cfg(target_arch = "arm")]
+pub static unwinder_private_data_size: int = 20;
+
+#[cfg(target_arch = "mips")]
+pub static unwinder_private_data_size: int = 2;
+
+pub struct _Unwind_Exception {
+    pub exception_class: _Unwind_Exception_Class,
+    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
+    pub private: [_Unwind_Word, ..unwinder_private_data_size],
+}
+
+pub enum _Unwind_Context {}
+
+pub type _Unwind_Exception_Cleanup_Fn =
+        extern "C" fn(unwind_code: _Unwind_Reason_Code,
+                      exception: *_Unwind_Exception);
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "freebsd")]
+#[cfg(target_os = "win32")]
+#[link(name = "gcc_s")]
+extern {}
+
+#[cfg(target_os = "android")]
+#[link(name = "gcc")]
+extern {}
+
+extern "C" {
+    pub fn _Unwind_RaiseException(exception: *_Unwind_Exception)
+                -> _Unwind_Reason_Code;
+    pub fn _Unwind_DeleteException(exception: *_Unwind_Exception);
+}
diff --git a/src/librustrt/local.rs b/src/librustrt/local.rs
new file mode 100644 (file)
index 0000000..7fe9dbc
--- /dev/null
@@ -0,0 +1,132 @@
+// 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 alloc::owned::Box;
+use local_ptr;
+use task::Task;
+
+/// Encapsulates some task-local data.
+pub trait Local<Borrowed> {
+    fn put(value: Box<Self>);
+    fn take() -> Box<Self>;
+    fn try_take() -> Option<Box<Self>>;
+    fn exists(unused_value: Option<Self>) -> bool;
+    fn borrow(unused_value: Option<Self>) -> Borrowed;
+    unsafe fn unsafe_take() -> Box<Self>;
+    unsafe fn unsafe_borrow() -> *mut Self;
+    unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
+}
+
+#[allow(visible_private_types)]
+impl Local<local_ptr::Borrowed<Task>> for Task {
+    #[inline]
+    fn put(value: Box<Task>) { unsafe { local_ptr::put(value) } }
+    #[inline]
+    fn take() -> Box<Task> { unsafe { local_ptr::take() } }
+    #[inline]
+    fn try_take() -> Option<Box<Task>> { unsafe { local_ptr::try_take() } }
+    fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
+    #[inline]
+    fn borrow(_: Option<Task>) -> local_ptr::Borrowed<Task> {
+        unsafe {
+            local_ptr::borrow::<Task>()
+        }
+    }
+    #[inline]
+    unsafe fn unsafe_take() -> Box<Task> { local_ptr::unsafe_take() }
+    #[inline]
+    unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
+    #[inline]
+    unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
+        local_ptr::try_unsafe_borrow()
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::prelude::*;
+    use std::rt::thread::Thread;
+    use super::*;
+    use task::Task;
+
+    #[test]
+    fn thread_local_task_smoke_test() {
+        Thread::start(proc() {
+            let task = box Task::new();
+            Local::put(task);
+            let task: Box<Task> = Local::take();
+            cleanup_task(task);
+        }).join();
+    }
+
+    #[test]
+    fn thread_local_task_two_instances() {
+        Thread::start(proc() {
+            let task = box Task::new();
+            Local::put(task);
+            let task: Box<Task> = Local::take();
+            cleanup_task(task);
+            let task = box Task::new();
+            Local::put(task);
+            let task: Box<Task> = Local::take();
+            cleanup_task(task);
+        }).join();
+    }
+
+    #[test]
+    fn borrow_smoke_test() {
+        Thread::start(proc() {
+            let task = box Task::new();
+            Local::put(task);
+
+            unsafe {
+                let _task: *mut Task = Local::unsafe_borrow();
+            }
+            let task: Box<Task> = Local::take();
+            cleanup_task(task);
+        }).join();
+    }
+
+    #[test]
+    fn borrow_with_return() {
+        Thread::start(proc() {
+            let task = box Task::new();
+            Local::put(task);
+
+            {
+                let _ = Local::borrow(None::<Task>);
+            }
+
+            let task: Box<Task> = Local::take();
+            cleanup_task(task);
+        }).join();
+    }
+
+    #[test]
+    fn try_take() {
+        Thread::start(proc() {
+            let task = box Task::new();
+            Local::put(task);
+
+            let t: Box<Task> = Local::try_take().unwrap();
+            let u: Option<Box<Task>> = Local::try_take();
+            assert!(u.is_none());
+
+            cleanup_task(t);
+        }).join();
+    }
+
+    fn cleanup_task(mut t: Box<Task>) {
+        t.destroyed = true;
+    }
+
+}
diff --git a/src/librustrt/local_data.rs b/src/librustrt/local_data.rs
new file mode 100644 (file)
index 0000000..6b468bd
--- /dev/null
@@ -0,0 +1,431 @@
+// Copyright 2012-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.
+
+/*!
+
+Task local data management
+
+Allows storing arbitrary types inside task-local-storage (TLS), to be accessed
+anywhere within a task, keyed by a global pointer parameterized over the type of
+the TLS slot.  Useful for dynamic variables, singletons, and interfacing with
+foreign code with bad callback interfaces.
+
+To declare a new key for storing local data of a particular type, use the
+`local_data_key!` macro. This macro will expand to a `static` item appropriately
+named and annotated. This name is then passed to the functions in this module to
+modify/read the slot specified by the key.
+
+```rust
+local_data_key!(key_int: int)
+local_data_key!(key_vector: ~[int])
+
+key_int.replace(Some(3));
+assert_eq!(*key_int.get().unwrap(), 3);
+
+key_vector.replace(Some(~[4]));
+assert_eq!(*key_vector.get().unwrap(), ~[4]);
+```
+
+*/
+
+// Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
+// magic.
+
+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
+ * differentiate keys from one another. The actual type `T` is not used anywhere
+ * as a member of this type, except that it is parameterized with it to define
+ * the type of each key's value.
+ *
+ * The value of each Key is of the singleton enum KeyValue. These also have the
+ * same name as `Key` and their purpose is to take up space in the programs data
+ * sections to ensure that each value of the `Key` type points to a unique
+ * location.
+ */
+pub type Key<T> = &'static KeyValue<T>;
+
+#[allow(missing_doc)]
+pub enum KeyValue<T> { Key }
+
+#[doc(hidden)]
+trait LocalData {}
+impl<T: 'static> LocalData for T {}
+
+// The task-local-map stores all TLS information for the currently running task.
+// It is stored as an owned pointer into the runtime, and it's only allocated
+// when TLS is used for the first time. This map must be very carefully
+// constructed because it has many mutable loans unsoundly handed out on it to
+// the various invocations of TLS requests.
+//
+// One of the most important operations is loaning a value via `get` to a
+// caller. In doing so, the slot that the TLS entry is occupying cannot be
+// invalidated because upon returning its loan state must be updated. Currently
+// the TLS map is a vector, but this is possibly dangerous because the vector
+// can be reallocated/moved when new values are pushed onto it.
+//
+// This problem currently isn't solved in a very elegant way. Inside the `get`
+// function, it internally "invalidates" all references after the loan is
+// finished and looks up into the vector again. In theory this will prevent
+// pointers from being moved under our feet so long as LLVM doesn't go too crazy
+// with the optimizations.
+//
+// n.b. If TLS is used heavily in future, this could be made more efficient with
+//      a proper map.
+#[doc(hidden)]
+pub type Map = Vec<Option<(*u8, TLSValue, uint)>>;
+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> {
+    if !Local::exists(None::<Task>) { return None }
+
+    let task: *mut Task = Local::unsafe_borrow();
+    match &mut (*task).storage {
+        // If the at_exit function is already set, then we just need to take
+        // a loan out on the TLS map stored inside
+        &LocalStorage(Some(ref mut map_ptr)) => {
+            return Some(map_ptr);
+        }
+        // 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::new());
+            match *slot {
+                Some(ref mut map_ptr) => { return Some(map_ptr) }
+                None => fail!("unreachable code"),
+            }
+        }
+    }
+}
+
+fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
+    key as *KeyValue<T> as *u8
+}
+
+/// An RAII immutable reference to a task-local value.
+///
+/// The task-local data can be accessed through this value, and when this
+/// structure is dropped it will return the borrow on the data.
+pub struct Ref<T> {
+    // FIXME #12808: strange names to try to avoid interfering with
+    // field accesses of the contained type via Deref
+    _ptr: &'static T,
+    _key: Key<T>,
+    _index: uint,
+    _nosend: marker::NoSend,
+}
+
+impl<T: 'static> KeyValue<T> {
+    /// Replaces a value in task local storage.
+    ///
+    /// If this key is already present in TLS, then the previous value is
+    /// replaced with the provided data, and then returned.
+    ///
+    /// # Failure
+    ///
+    /// This function will fail if this key is present in TLS and currently on
+    /// loan with the `get` method.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// local_data_key!(foo: int)
+    ///
+    /// assert_eq!(foo.replace(Some(10)), None);
+    /// assert_eq!(foo.replace(Some(4)), Some(10));
+    /// assert_eq!(foo.replace(None), Some(4));
+    /// ```
+    pub fn replace(&'static self, data: Option<T>) -> Option<T> {
+        let map = match unsafe { get_local_map() } {
+            Some(map) => map,
+            None => fail!("must have a local task to insert into TLD"),
+        };
+        let keyval = key_to_key_value(self);
+
+        // When the task-local map is destroyed, all the data needs to be
+        // cleaned up. For this reason we can't do some clever tricks to store
+        // '~T' as a '*c_void' or something like that. To solve the problem, we
+        // cast everything to a trait (LocalData) which is then stored inside
+        // the map.  Upon destruction of the map, all the objects will be
+        // destroyed and the traits have enough information about them to
+        // destroy themselves.
+        //
+        // Additionally, the type of the local data map must ascribe to Send, so
+        // we do the transmute here to add the Send bound back on. This doesn't
+        // actually matter because TLS will always own the data (until its moved
+        // out) and we're not actually sending it to other schedulers or
+        // anything.
+        let newval = data.map(|d| {
+            let d = box d as Box<LocalData>;
+            let d: Box<LocalData:Send> = unsafe { mem::transmute(d) };
+            (keyval, d, 0)
+        });
+
+        let pos = match self.find(map) {
+            Some((i, _, &0)) => Some(i),
+            Some((_, _, _)) => fail!("TLS value cannot be replaced because it \
+                                      is already borrowed"),
+            None => map.iter().position(|entry| entry.is_none()),
+        };
+
+        match pos {
+            Some(i) => {
+                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) };
+                    let alloc: Box<T> = unsafe { mem::transmute(t.data) };
+
+                    // Now that we own `alloc`, we can just move out of it as we
+                    // would with any other data.
+                    *alloc
+                })
+            }
+            None => {
+                map.push(newval);
+                None
+            }
+        }
+    }
+
+    /// Borrows a value from TLS.
+    ///
+    /// If `None` is returned, then this key is not present in TLS. If `Some` is
+    /// returned, then the returned data is a smart pointer representing a new
+    /// loan on this TLS key. While on loan, this key cannot be altered via the
+    /// `replace` method.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// local_data_key!(key: int)
+    ///
+    /// assert!(key.get().is_none());
+    ///
+    /// key.replace(Some(3));
+    /// assert_eq!(*key.get().unwrap(), 3);
+    /// ```
+    pub fn get(&'static self) -> Option<Ref<T>> {
+        let map = match unsafe { get_local_map() } {
+            Some(map) => map,
+            None => return None,
+        };
+
+        self.find(map).map(|(pos, data, loan)| {
+            *loan += 1;
+
+            // data was created with `~T as ~LocalData`, so we extract
+            // pointer part of the trait, (as ~T), and then use
+            // compiler coercions to achieve a '&' pointer.
+            let ptr = unsafe {
+                let data = data as *Box<LocalData:Send> as *raw::TraitObject;
+                &mut *((*data).data as *mut T)
+            };
+            Ref { _ptr: ptr, _index: pos, _nosend: marker::NoSend, _key: self }
+        })
+    }
+
+    fn find<'a>(&'static self,
+                map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
+        let key_value = key_to_key_value(self);
+        map.mut_iter().enumerate().filter_map(|(i, entry)| {
+            match *entry {
+                Some((k, ref data, ref mut loan)) if k == key_value => {
+                    Some((i, data, loan))
+                }
+                _ => None
+            }
+        }).next()
+    }
+}
+
+impl<T: 'static> Deref<T> for Ref<T> {
+    fn deref<'a>(&'a self) -> &'a T { self._ptr }
+}
+
+#[unsafe_destructor]
+impl<T: 'static> Drop for Ref<T> {
+    fn drop(&mut self) {
+        let map = unsafe { get_local_map().unwrap() };
+
+        let (_, _, ref mut loan) = *map.get_mut(self._index).get_mut_ref();
+        *loan -= 1;
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::prelude::*;
+    use super::*;
+    use std::task;
+
+    #[test]
+    fn test_tls_multitask() {
+        static my_key: Key<String> = &Key;
+        my_key.replace(Some("parent data".to_string()));
+        task::spawn(proc() {
+            // TLS shouldn't carry over.
+            assert!(my_key.get().is_none());
+            my_key.replace(Some("child data".to_string()));
+            assert!(my_key.get().get_ref().as_slice() == "child data");
+            // should be cleaned up for us
+        });
+
+        // Must work multiple times
+        assert!(my_key.get().unwrap().as_slice() == "parent data");
+        assert!(my_key.get().unwrap().as_slice() == "parent data");
+        assert!(my_key.get().unwrap().as_slice() == "parent data");
+    }
+
+    #[test]
+    fn test_tls_overwrite() {
+        static my_key: Key<String> = &Key;
+        my_key.replace(Some("first data".to_string()));
+        my_key.replace(Some("next data".to_string())); // Shouldn't leak.
+        assert!(my_key.get().unwrap().as_slice() == "next data");
+    }
+
+    #[test]
+    fn test_tls_pop() {
+        static my_key: Key<String> = &Key;
+        my_key.replace(Some("weasel".to_string()));
+        assert!(my_key.replace(None).unwrap() == "weasel".to_string());
+        // Pop must remove the data from the map.
+        assert!(my_key.replace(None).is_none());
+    }
+
+    #[test]
+    fn test_tls_crust_automorestack_memorial_bug() {
+        // This might result in a stack-canary clobber if the runtime fails to
+        // set sp_limit to 0 when calling the cleanup extern - it might
+        // automatically jump over to the rust stack, which causes next_c_sp
+        // to get recorded as something within a rust stack segment. Then a
+        // subsequent upcall (esp. for logging, think vsnprintf) would run on
+        // a stack smaller than 1 MB.
+        static my_key: Key<String> = &Key;
+        task::spawn(proc() {
+            my_key.replace(Some("hax".to_string()));
+        });
+    }
+
+    #[test]
+    fn test_tls_multiple_types() {
+        static str_key: Key<String> = &Key;
+        static box_key: Key<@()> = &Key;
+        static int_key: Key<int> = &Key;
+        task::spawn(proc() {
+            str_key.replace(Some("string data".to_string()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
+        });
+    }
+
+    #[test]
+    fn test_tls_overwrite_multiple_types() {
+        static str_key: Key<String> = &Key;
+        static box_key: Key<@()> = &Key;
+        static int_key: Key<int> = &Key;
+        task::spawn(proc() {
+            str_key.replace(Some("string data".to_string()));
+            str_key.replace(Some("string data 2".to_string()));
+            box_key.replace(Some(@()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
+            // This could cause a segfault if overwriting-destruction is done
+            // with the crazy polymorphic transmute rather than the provided
+            // finaliser.
+            int_key.replace(Some(31337));
+        });
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_tls_cleanup_on_failure() {
+        static str_key: Key<String> = &Key;
+        static box_key: Key<@()> = &Key;
+        static int_key: Key<int> = &Key;
+        str_key.replace(Some("parent data".to_string()));
+        box_key.replace(Some(@()));
+        task::spawn(proc() {
+            str_key.replace(Some("string data".to_string()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
+            fail!();
+        });
+        // Not quite nondeterministic.
+        int_key.replace(Some(31337));
+        fail!();
+    }
+
+    #[test]
+    fn test_static_pointer() {
+        static key: Key<&'static int> = &Key;
+        static VALUE: int = 0;
+        key.replace(Some(&VALUE));
+    }
+
+    #[test]
+    fn test_owned() {
+        static key: Key<Box<int>> = &Key;
+        key.replace(Some(box 1));
+
+        {
+            let k1 = key.get().unwrap();
+            let k2 = key.get().unwrap();
+            let k3 = key.get().unwrap();
+            assert_eq!(**k1, 1);
+            assert_eq!(**k2, 1);
+            assert_eq!(**k3, 1);
+        }
+        key.replace(Some(box 2));
+        assert_eq!(**key.get().unwrap(), 2);
+    }
+
+    #[test]
+    fn test_same_key_type() {
+        static key1: Key<int> = &Key;
+        static key2: Key<int> = &Key;
+        static key3: Key<int> = &Key;
+        static key4: Key<int> = &Key;
+        static key5: Key<int> = &Key;
+        key1.replace(Some(1));
+        key2.replace(Some(2));
+        key3.replace(Some(3));
+        key4.replace(Some(4));
+        key5.replace(Some(5));
+
+        assert_eq!(*key1.get().unwrap(), 1);
+        assert_eq!(*key2.get().unwrap(), 2);
+        assert_eq!(*key3.get().unwrap(), 3);
+        assert_eq!(*key4.get().unwrap(), 4);
+        assert_eq!(*key5.get().unwrap(), 5);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_nested_get_set1() {
+        static key: Key<int> = &Key;
+        key.replace(Some(4));
+
+        let _k = key.get();
+        key.replace(Some(4));
+    }
+}
diff --git a/src/librustrt/local_heap.rs b/src/librustrt/local_heap.rs
new file mode 100644 (file)
index 0000000..52fe5c3
--- /dev/null
@@ -0,0 +1,330 @@
+// 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.
+
+//! The local, garbage collected heap
+
+use core::prelude::*;
+
+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 {
+    live_allocations: uint,
+}
+
+pub struct LocalHeap {
+    memory_region: MemoryRegion,
+    live_allocs: *mut raw::Box<()>,
+}
+
+impl LocalHeap {
+    pub fn new() -> LocalHeap {
+        LocalHeap {
+            memory_region: MemoryRegion { live_allocations: 0 },
+            live_allocs: ptr::mut_null(),
+        }
+    }
+
+    #[inline]
+    #[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);
+        {
+            // Make sure that we can't use `mybox` outside of this scope
+            let mybox: &mut Box = unsafe { mem::transmute(alloc) };
+            // Clear out this box, and move it to the front of the live
+            // allocations list
+            mybox.drop_glue = drop_glue;
+            mybox.ref_count = 1;
+            mybox.prev = ptr::mut_null();
+            mybox.next = self.live_allocs;
+            if !self.live_allocs.is_null() {
+                unsafe { (*self.live_allocs).prev = alloc; }
+            }
+            self.live_allocs = alloc;
+        }
+        return alloc;
+    }
+
+    #[inline]
+    pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box {
+        // Make sure that we can't use `mybox` outside of this scope
+        let total_size = size + mem::size_of::<Box>();
+        let new_box = self.memory_region.realloc(ptr, total_size);
+        {
+            // Fix links because we could have moved around
+            let mybox: &mut Box = unsafe { mem::transmute(new_box) };
+            if !mybox.prev.is_null() {
+                unsafe { (*mybox.prev).next = new_box; }
+            }
+            if !mybox.next.is_null() {
+                unsafe { (*mybox.next).prev = new_box; }
+            }
+        }
+        if self.live_allocs == ptr {
+            self.live_allocs = new_box;
+        }
+        return new_box;
+    }
+
+    #[inline]
+    pub fn free(&mut self, alloc: *mut Box) {
+        {
+            // Make sure that we can't use `mybox` outside of this scope
+            let mybox: &mut Box = unsafe { mem::transmute(alloc) };
+
+            // Unlink it from the linked list
+            if !mybox.prev.is_null() {
+                unsafe { (*mybox.prev).next = mybox.next; }
+            }
+            if !mybox.next.is_null() {
+                unsafe { (*mybox.next).prev = mybox.prev; }
+            }
+            if self.live_allocs == alloc {
+                self.live_allocs = mybox.next;
+            }
+        }
+
+        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 {
+    fn drop(&mut self) {
+        assert!(self.live_allocs.is_null());
+    }
+}
+
+struct AllocHeader;
+
+impl AllocHeader {
+    fn init(&mut self, _size: u32) {}
+    fn assert_sane(&self) {}
+    fn update_size(&mut self, _size: u32) {}
+
+    fn as_box(&mut self) -> *mut Box {
+        let myaddr: uint = unsafe { mem::transmute(self) };
+        (myaddr + AllocHeader::size()) as *mut Box
+    }
+
+    fn size() -> uint {
+        // For some platforms, 16 byte alignment is required.
+        let ptr_size = 16;
+        let header_size = mem::size_of::<AllocHeader>();
+        return (header_size + ptr_size - 1) / ptr_size * ptr_size;
+    }
+
+    fn from(a_box: *mut Box) -> *mut AllocHeader {
+        (a_box as uint - AllocHeader::size()) as *mut 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 {
+        let total_size = size + AllocHeader::size();
+        let alloc: *AllocHeader = unsafe {
+            libc_heap::malloc_raw(total_size) as *AllocHeader
+        };
+
+        let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) };
+        alloc.init(size as u32);
+        self.claim(alloc);
+        self.live_allocations += 1;
+
+        return alloc.as_box();
+    }
+
+    #[inline]
+    fn realloc(&mut self, alloc: *mut Box, size: uint) -> *mut Box {
+        rtassert!(!alloc.is_null());
+        let orig_alloc = AllocHeader::from(alloc);
+        unsafe { (*orig_alloc).assert_sane(); }
+
+        let total_size = size + AllocHeader::size();
+        let alloc: *AllocHeader = unsafe {
+            libc_heap::realloc_raw(orig_alloc as *mut u8, total_size) as *AllocHeader
+        };
+
+        let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) };
+        alloc.assert_sane();
+        alloc.update_size(size as u32);
+        self.update(alloc, orig_alloc as *AllocHeader);
+        return alloc.as_box();
+    }
+
+    #[inline]
+    fn free(&mut self, alloc: *mut Box) {
+        rtassert!(!alloc.is_null());
+        let alloc = AllocHeader::from(alloc);
+        unsafe {
+            (*alloc).assert_sane();
+            self.release(mem::transmute(alloc));
+            rtassert!(self.live_allocations > 0);
+            self.live_allocations -= 1;
+            free(alloc as *mut c_void)
+        }
+    }
+
+    #[inline]
+    fn claim(&mut self, _alloc: &mut AllocHeader) {}
+    #[inline]
+    fn release(&mut self, _alloc: &AllocHeader) {}
+    #[inline]
+    fn update(&mut self, _alloc: &mut AllocHeader, _orig: *AllocHeader) {}
+}
+
+impl Drop for MemoryRegion {
+    fn drop(&mut self) {
+        if self.live_allocations != 0 {
+            rtabort!("leaked managed memory ({} objects)", self.live_allocations);
+        }
+    }
+}
+
+#[cfg(not(test))]
+#[lang="malloc"]
+#[inline]
+pub unsafe fn local_malloc_(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
+    local_malloc(drop_glue, size, align)
+}
+
+#[inline]
+pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
+    // FIXME: Unsafe borrow for speed. Lame.
+    let task: Option<*mut Task> = Local::try_unsafe_borrow();
+    match task {
+        Some(task) => {
+            (*task).heap.alloc(drop_glue, size, align) as *u8
+        }
+        None => rtabort!("local malloc outside of task")
+    }
+}
+
+#[cfg(not(test))]
+#[lang="free"]
+#[inline]
+pub unsafe fn local_free_(ptr: *u8) {
+    local_free(ptr)
+}
+
+// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
+// inside a landing pad may corrupt the state of the exception handler. If a
+// problem occurs, call exit instead.
+#[inline]
+pub unsafe fn local_free(ptr: *u8) {
+    // FIXME: Unsafe borrow for speed. Lame.
+    let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
+    match task_ptr {
+        Some(task) => {
+            (*task).heap.free(ptr as *mut Box)
+        }
+        None => rtabort!("local free outside of task")
+    }
+}
+
+#[cfg(test)]
+mod bench {
+    extern crate test;
+    use self::test::Bencher;
+
+    #[bench]
+    fn alloc_managed_small(b: &mut Bencher) {
+        b.iter(|| { @10; });
+    }
+
+    #[bench]
+    fn alloc_managed_big(b: &mut Bencher) {
+        b.iter(|| { @([10, ..1000]); });
+    }
+}
diff --git a/src/librustrt/local_ptr.rs b/src/librustrt/local_ptr.rs
new file mode 100644 (file)
index 0000000..91e3409
--- /dev/null
@@ -0,0 +1,404 @@
+// 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.
+
+//! Access to a single thread-local pointer.
+//!
+//! The runtime will use this for storing Box<Task>.
+//!
+//! FIXME: Add runtime checks for usage of inconsistent pointer types.
+//! and for overwriting an existing pointer.
+
+#![allow(dead_code)]
+
+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
+pub use self::native::{init, cleanup, put, take, try_take, unsafe_take, exists,
+                       unsafe_borrow, try_unsafe_borrow};
+
+#[cfg(not(windows), not(target_os = "android"))]
+pub use self::compiled::{init, cleanup, put, take, try_take, unsafe_take, exists,
+                         unsafe_borrow, try_unsafe_borrow};
+
+/// Encapsulates a borrowed value. When this value goes out of scope, the
+/// pointer is returned.
+pub struct Borrowed<T> {
+    val: *(),
+}
+
+#[unsafe_destructor]
+impl<T> Drop for Borrowed<T> {
+    fn drop(&mut self) {
+        unsafe {
+            if self.val.is_null() {
+                rtabort!("Aiee, returning null borrowed object!");
+            }
+            let val: Box<T> = mem::transmute(self.val);
+            put::<T>(val);
+            rtassert!(exists());
+        }
+    }
+}
+
+impl<T> Deref<T> for Borrowed<T> {
+    fn deref<'a>(&'a self) -> &'a T {
+        unsafe { &*(self.val as *T) }
+    }
+}
+
+impl<T> DerefMut<T> for Borrowed<T> {
+    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
+        unsafe { &mut *(self.val as *mut T) }
+    }
+}
+
+/// Borrow the thread-local value from thread-local storage.
+/// While the value is borrowed it is not available in TLS.
+///
+/// # Safety note
+///
+/// Does not validate the pointer type.
+#[inline]
+pub unsafe fn borrow<T>() -> Borrowed<T> {
+    let val: *() = mem::transmute(take::<T>());
+    Borrowed {
+        val: val,
+    }
+}
+
+/// Compiled implementation of accessing the runtime local pointer. This is
+/// implemented using LLVM's thread_local attribute which isn't necessarily
+/// working on all platforms. This implementation is faster, however, so we use
+/// it wherever possible.
+#[cfg(not(windows), not(target_os = "android"))]
+pub mod compiled {
+    use core::prelude::*;
+
+    use alloc::owned::Box;
+    use core::mem;
+
+    #[cfg(test)]
+    pub use realrustrt::shouldnt_be_public::RT_TLS_PTR;
+
+    #[cfg(not(test))]
+    #[thread_local]
+    pub static mut RT_TLS_PTR: *mut u8 = 0 as *mut u8;
+
+    pub fn init() {}
+
+    pub unsafe fn cleanup() {}
+
+    // Rationale for all of these functions being inline(never)
+    //
+    // The #[thread_local] annotation gets propagated all the way through to
+    // LLVM, meaning the global is specially treated by LLVM to lower it to an
+    // efficient sequence of instructions. This also involves dealing with fun
+    // stuff in object files and whatnot. Regardless, it turns out this causes
+    // trouble with green threads and lots of optimizations turned on. The
+    // following case study was done on linux x86_64, but I would imagine that
+    // other platforms are similar.
+    //
+    // On linux, the instruction sequence for loading the tls pointer global
+    // looks like:
+    //
+    //      mov %fs:0x0, %rax
+    //      mov -0x8(%rax), %rbx
+    //
+    // This code leads me to believe that (%fs:0x0) is a table, and then the
+    // table contains the TLS values for the process. Hence, the slot at offset
+    // -0x8 is the task TLS pointer. This leads us to the conclusion that this
+    // table is the actual thread local part of each thread. The kernel sets up
+    // the fs segment selector to point at the right region of memory for each
+    // thread.
+    //
+    // Optimizations lead me to believe that this code is lowered to these
+    // instructions in the LLVM codegen passes, because you'll see code like
+    // this when everything is optimized:
+    //
+    //      mov %fs:0x0, %r14
+    //      mov -0x8(%r14), %rbx
+    //      // do something with %rbx, the rust Task pointer
+    //
+    //      ... // <- do more things
+    //
+    //      mov -0x8(%r14), %rbx
+    //      // do something else with %rbx
+    //
+    // Note that the optimization done here is that the first load is not
+    // duplicated during the lower instructions. This means that the %fs:0x0
+    // memory location is only dereferenced once.
+    //
+    // Normally, this is actually a good thing! With green threads, however,
+    // it's very possible for the code labeled "do more things" to context
+    // switch to another thread. If this happens, then we *must* re-load %fs:0x0
+    // because it's changed (we're on a different thread). If we don't re-load
+    // the table location, then we'll be reading the original thread's TLS
+    // values, not our thread's TLS values.
+    //
+    // Hence, we never inline these functions. By never inlining, we're
+    // guaranteed that loading the table is a local decision which is forced to
+    // *always* happen.
+
+    /// Give a pointer to thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    #[inline(never)] // see comments above
+    pub unsafe fn put<T>(sched: Box<T>) {
+        RT_TLS_PTR = mem::transmute(sched)
+    }
+
+    /// Take ownership of a pointer from thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    #[inline(never)] // see comments above
+    pub unsafe fn take<T>() -> Box<T> {
+        let ptr = RT_TLS_PTR;
+        rtassert!(!ptr.is_null());
+        let ptr: Box<T> = mem::transmute(ptr);
+        // can't use `as`, due to type not matching with `cfg(test)`
+        RT_TLS_PTR = mem::transmute(0);
+        ptr
+    }
+
+    /// Optionally take ownership of a pointer from thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    #[inline(never)] // see comments above
+    pub unsafe fn try_take<T>() -> Option<Box<T>> {
+        let ptr = RT_TLS_PTR;
+        if ptr.is_null() {
+            None
+        } else {
+            let ptr: Box<T> = mem::transmute(ptr);
+            // can't use `as`, due to type not matching with `cfg(test)`
+            RT_TLS_PTR = mem::transmute(0);
+            Some(ptr)
+        }
+    }
+
+    /// Take ownership of a pointer from thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    /// Leaves the old pointer in TLS for speed.
+    #[inline(never)] // see comments above
+    pub unsafe fn unsafe_take<T>() -> Box<T> {
+        mem::transmute(RT_TLS_PTR)
+    }
+
+    /// Check whether there is a thread-local pointer installed.
+    #[inline(never)] // see comments above
+    pub fn exists() -> bool {
+        unsafe {
+            RT_TLS_PTR.is_not_null()
+        }
+    }
+
+    #[inline(never)] // see comments above
+    pub unsafe fn unsafe_borrow<T>() -> *mut T {
+        if RT_TLS_PTR.is_null() {
+            rtabort!("thread-local pointer is null. bogus!");
+        }
+        RT_TLS_PTR as *mut T
+    }
+
+    #[inline(never)] // see comments above
+    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
+        if RT_TLS_PTR.is_null() {
+            None
+        } else {
+            Some(RT_TLS_PTR as *mut T)
+        }
+    }
+}
+
+/// Native implementation of having the runtime thread-local pointer. This
+/// implementation uses the `thread_local_storage` module to provide a
+/// thread-local value.
+pub mod native {
+    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;
+
+    /// Initialize the TLS key. Other ops will fail if this isn't executed
+    /// first.
+    pub fn init() {
+        unsafe {
+            tls::create(&mut RT_TLS_KEY);
+        }
+    }
+
+    pub unsafe fn cleanup() {
+        rtassert!(RT_TLS_KEY != -1);
+        tls::destroy(RT_TLS_KEY);
+    }
+
+    /// Give a pointer to thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    #[inline]
+    pub unsafe fn put<T>(sched: Box<T>) {
+        let key = tls_key();
+        let void_ptr: *mut u8 = mem::transmute(sched);
+        tls::set(key, void_ptr);
+    }
+
+    /// Take ownership of a pointer from thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    #[inline]
+    pub unsafe fn take<T>() -> Box<T> {
+        let key = tls_key();
+        let void_ptr: *mut u8 = tls::get(key);
+        if void_ptr.is_null() {
+            rtabort!("thread-local pointer is null. bogus!");
+        }
+        let ptr: Box<T> = mem::transmute(void_ptr);
+        tls::set(key, ptr::mut_null());
+        return ptr;
+    }
+
+    /// Optionally take ownership of a pointer from thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    #[inline]
+    pub unsafe fn try_take<T>() -> Option<Box<T>> {
+        match maybe_tls_key() {
+            Some(key) => {
+                let void_ptr: *mut u8 = tls::get(key);
+                if void_ptr.is_null() {
+                    None
+                } else {
+                    let ptr: Box<T> = mem::transmute(void_ptr);
+                    tls::set(key, ptr::mut_null());
+                    Some(ptr)
+                }
+            }
+            None => None
+        }
+    }
+
+    /// Take ownership of a pointer from thread-local storage.
+    ///
+    /// # Safety note
+    ///
+    /// Does not validate the pointer type.
+    /// Leaves the old pointer in TLS for speed.
+    #[inline]
+    pub unsafe fn unsafe_take<T>() -> Box<T> {
+        let key = tls_key();
+        let void_ptr: *mut u8 = tls::get(key);
+        if void_ptr.is_null() {
+            rtabort!("thread-local pointer is null. bogus!");
+        }
+        let ptr: Box<T> = mem::transmute(void_ptr);
+        return ptr;
+    }
+
+    /// Check whether there is a thread-local pointer installed.
+    pub fn exists() -> bool {
+        unsafe {
+            match maybe_tls_key() {
+                Some(key) => tls::get(key).is_not_null(),
+                None => false
+            }
+        }
+    }
+
+    /// Borrow a mutable reference to the thread-local value
+    ///
+    /// # Safety Note
+    ///
+    /// Because this leaves the value in thread-local storage it is possible
+    /// For the Scheduler pointer to be aliased
+    pub unsafe fn unsafe_borrow<T>() -> *mut T {
+        let key = tls_key();
+        let void_ptr = tls::get(key);
+        if void_ptr.is_null() {
+            rtabort!("thread-local pointer is null. bogus!");
+        }
+        void_ptr as *mut T
+    }
+
+    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
+        match maybe_tls_key() {
+            Some(key) => {
+                let void_ptr = tls::get(key);
+                if void_ptr.is_null() {
+                    None
+                } else {
+                    Some(void_ptr as *mut T)
+                }
+            }
+            None => None
+        }
+    }
+
+    #[inline]
+    fn tls_key() -> tls::Key {
+        match maybe_tls_key() {
+            Some(key) => key,
+            None => rtabort!("runtime tls key not initialized")
+        }
+    }
+
+    #[inline]
+    #[cfg(not(test))]
+    #[allow(visible_private_types)]
+    pub fn maybe_tls_key() -> Option<tls::Key> {
+        unsafe {
+            // NB: This is a little racy because, while the key is
+            // initialized under a mutex and it's assumed to be initialized
+            // in the Scheduler ctor by any thread that needs to use it,
+            // we are not accessing the key under a mutex.  Threads that
+            // are not using the new Scheduler but still *want to check*
+            // whether they are running under a new Scheduler may see a 0
+            // value here that is in the process of being initialized in
+            // another thread. I think this is fine since the only action
+            // they could take if it was initialized would be to check the
+            // thread-local value and see that it's not set.
+            if RT_TLS_KEY != -1 {
+                return Some(RT_TLS_KEY);
+            } else {
+                return None;
+            }
+        }
+    }
+
+    #[inline] #[cfg(test)]
+    pub fn maybe_tls_key() -> Option<tls::Key> {
+        use realrustrt;
+        unsafe {
+            mem::transmute(realrustrt::shouldnt_be_public::maybe_tls_key())
+        }
+    }
+}
diff --git a/src/librustrt/macros.rs b/src/librustrt/macros.rs
new file mode 100644 (file)
index 0000000..d4e9273
--- /dev/null
@@ -0,0 +1,46 @@
+// 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.
+
+//! Macros used by the runtime.
+//!
+//! These macros call functions which are only accessible in the `rt` module, so
+//! they aren't defined anywhere outside of the `rt` module.
+
+#![macro_escape]
+
+macro_rules! rterrln (
+    ($fmt:expr $($arg:tt)*) => ( {
+        format_args!(::util::dumb_print, concat!($fmt, "\n") $($arg)*)
+    } )
+)
+
+// Some basic logging. Enabled by passing `--cfg rtdebug` to the libstd build.
+macro_rules! rtdebug (
+    ($($arg:tt)*) => ( {
+        if cfg!(rtdebug) {
+            rterrln!($($arg)*)
+        }
+    })
+)
+
+macro_rules! rtassert (
+    ( $arg:expr ) => ( {
+        if ::util::ENFORCE_SANITY {
+            if !$arg {
+                rtabort!(" assertion failed: {}", stringify!($arg));
+            }
+        }
+    } )
+)
+
+
+macro_rules! rtabort (
+    ($($arg:tt)*) => (format_args!(::util::abort, $($arg)*))
+)
diff --git a/src/librustrt/mutex.rs b/src/librustrt/mutex.rs
new file mode 100644 (file)
index 0000000..fccbe4a
--- /dev/null
@@ -0,0 +1,628 @@
+// Copyright 2013-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.
+
+//! A native mutex and condition variable type.
+//!
+//! This module contains bindings to the platform's native mutex/condition
+//! variable primitives. It provides two types: `StaticNativeMutex`, which can
+//! be statically initialized via the `NATIVE_MUTEX_INIT` value, and a simple
+//! wrapper `NativeMutex` that has a destructor to clean up after itself. These
+//! objects serve as both mutexes and condition variables simultaneously.
+//!
+//! The static lock is lazily initialized, but it can only be unsafely
+//! destroyed. A statically initialized lock doesn't necessarily have a time at
+//! which it can get deallocated. For this reason, there is no `Drop`
+//! implementation of the static mutex, but rather the `destroy()` method must
+//! be invoked manually if destruction of the mutex is desired.
+//!
+//! The non-static `NativeMutex` type does have a destructor, but cannot be
+//! statically initialized.
+//!
+//! It is not recommended to use this type for idiomatic rust use. These types
+//! are appropriate where no other options are available, but other rust
+//! concurrency primitives should be used before them: the `sync` crate defines
+//! `StaticMutex` and `Mutex` types.
+//!
+//! # Example
+//!
+//! ```rust
+//! use std::rt::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT};
+//!
+//! // Use a statically initialized mutex
+//! static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+//!
+//! unsafe {
+//!     let _guard = LOCK.lock();
+//! } // automatically unlocked here
+//!
+//! // Use a normally initialized mutex
+//! unsafe {
+//!     let mut lock = NativeMutex::new();
+//!
+//!     {
+//!         let _guard = lock.lock();
+//!     } // unlocked here
+//!
+//!     // sometimes the RAII guard isn't appropriate
+//!     lock.lock_noguard();
+//!     lock.unlock_noguard();
+//! } // `lock` is deallocated here
+//! ```
+
+#![allow(non_camel_case_types)]
+
+use core::prelude::*;
+
+/// A native mutex suitable for storing in statics (that is, it has
+/// the `destroy` method rather than a destructor).
+///
+/// Prefer the `NativeMutex` type where possible, since that does not
+/// require manual deallocation.
+pub struct StaticNativeMutex {
+    inner: imp::Mutex,
+}
+
+/// A native mutex with a destructor for clean-up.
+///
+/// See `StaticNativeMutex` for a version that is suitable for storing in
+/// statics.
+pub struct NativeMutex {
+    inner: StaticNativeMutex
+}
+
+/// Automatically unlocks the mutex that it was created from on
+/// destruction.
+///
+/// Using this makes lock-based code resilient to unwinding/task
+/// failure, because the lock will be automatically unlocked even
+/// then.
+#[must_use]
+pub struct LockGuard<'a> {
+    lock: &'a StaticNativeMutex
+}
+
+pub static NATIVE_MUTEX_INIT: StaticNativeMutex = StaticNativeMutex {
+    inner: imp::MUTEX_INIT,
+};
+
+impl StaticNativeMutex {
+    /// Creates a new mutex.
+    ///
+    /// Note that a mutex created in this way needs to be explicit
+    /// freed with a call to `destroy` or it will leak.
+    /// Also it is important to avoid locking until mutex has stopped moving
+    pub unsafe fn new() -> StaticNativeMutex {
+        StaticNativeMutex { inner: imp::Mutex::new() }
+    }
+
+    /// Acquires this lock. This assumes that the current thread does not
+    /// already hold the lock.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+    /// static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+    /// unsafe {
+    ///     let _guard = LOCK.lock();
+    ///     // critical section...
+    /// } // automatically unlocked in `_guard`'s destructor
+    /// ```
+    pub unsafe fn lock<'a>(&'a self) -> LockGuard<'a> {
+        self.inner.lock();
+
+        LockGuard { lock: self }
+    }
+
+    /// Attempts to acquire the lock. The value returned is `Some` if
+    /// the attempt succeeded.
+    pub unsafe fn trylock<'a>(&'a self) -> Option<LockGuard<'a>> {
+        if self.inner.trylock() {
+            Some(LockGuard { lock: self })
+        } else {
+            None
+        }
+    }
+
+    /// Acquire the lock without creating a `LockGuard`.
+    ///
+    /// These needs to be paired with a call to `.unlock_noguard`. Prefer using
+    /// `.lock`.
+    pub unsafe fn lock_noguard(&self) { self.inner.lock() }
+
+    /// Attempts to acquire the lock without creating a
+    /// `LockGuard`. The value returned is whether the lock was
+    /// acquired or not.
+    ///
+    /// If `true` is returned, this needs to be paired with a call to
+    /// `.unlock_noguard`. Prefer using `.trylock`.
+    pub unsafe fn trylock_noguard(&self) -> bool {
+        self.inner.trylock()
+    }
+
+    /// Unlocks the lock. This assumes that the current thread already holds the
+    /// lock.
+    pub unsafe fn unlock_noguard(&self) { self.inner.unlock() }
+
+    /// Block on the internal condition variable.
+    ///
+    /// This function assumes that the lock is already held. Prefer
+    /// using `LockGuard.wait` since that guarantees that the lock is
+    /// held.
+    pub unsafe fn wait_noguard(&self) { self.inner.wait() }
+
+    /// Signals a thread in `wait` to wake up
+    pub unsafe fn signal_noguard(&self) { self.inner.signal() }
+
+    /// This function is especially unsafe because there are no guarantees made
+    /// that no other thread is currently holding the lock or waiting on the
+    /// condition variable contained inside.
+    pub unsafe fn destroy(&self) { self.inner.destroy() }
+}
+
+impl NativeMutex {
+    /// Creates a new mutex.
+    ///
+    /// The user must be careful to ensure the mutex is not locked when its is
+    /// being destroyed.
+    /// Also it is important to avoid locking until mutex has stopped moving
+    pub unsafe fn new() -> NativeMutex {
+        NativeMutex { inner: StaticNativeMutex::new() }
+    }
+
+    /// Acquires this lock. This assumes that the current thread does not
+    /// already hold the lock.
+    ///
+    /// # Example
+    /// ```rust
+    /// use std::rt::mutex::NativeMutex;
+    /// unsafe {
+    ///     let mut lock = NativeMutex::new();
+    ///
+    ///     {
+    ///         let _guard = lock.lock();
+    ///         // critical section...
+    ///     } // automatically unlocked in `_guard`'s destructor
+    /// }
+    /// ```
+    pub unsafe fn lock<'a>(&'a self) -> LockGuard<'a> {
+        self.inner.lock()
+    }
+
+    /// Attempts to acquire the lock. The value returned is `Some` if
+    /// the attempt succeeded.
+    pub unsafe fn trylock<'a>(&'a self) -> Option<LockGuard<'a>> {
+        self.inner.trylock()
+    }
+
+    /// Acquire the lock without creating a `LockGuard`.
+    ///
+    /// These needs to be paired with a call to `.unlock_noguard`. Prefer using
+    /// `.lock`.
+    pub unsafe fn lock_noguard(&self) { self.inner.lock_noguard() }
+
+    /// Attempts to acquire the lock without creating a
+    /// `LockGuard`. The value returned is whether the lock was
+    /// acquired or not.
+    ///
+    /// If `true` is returned, this needs to be paired with a call to
+    /// `.unlock_noguard`. Prefer using `.trylock`.
+    pub unsafe fn trylock_noguard(&self) -> bool {
+        self.inner.trylock_noguard()
+    }
+
+    /// Unlocks the lock. This assumes that the current thread already holds the
+    /// lock.
+    pub unsafe fn unlock_noguard(&self) { self.inner.unlock_noguard() }
+
+    /// Block on the internal condition variable.
+    ///
+    /// This function assumes that the lock is already held. Prefer
+    /// using `LockGuard.wait` since that guarantees that the lock is
+    /// held.
+    pub unsafe fn wait_noguard(&self) { self.inner.wait_noguard() }
+
+    /// Signals a thread in `wait` to wake up
+    pub unsafe fn signal_noguard(&self) { self.inner.signal_noguard() }
+}
+
+impl Drop for NativeMutex {
+    fn drop(&mut self) {
+        unsafe {self.inner.destroy()}
+    }
+}
+
+impl<'a> LockGuard<'a> {
+    /// Block on the internal condition variable.
+    pub unsafe fn wait(&self) {
+        self.lock.wait_noguard()
+    }
+
+    /// Signals a thread in `wait` to wake up.
+    pub unsafe fn signal(&self) {
+        self.lock.signal_noguard()
+    }
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for LockGuard<'a> {
+    fn drop(&mut self) {
+        unsafe {self.lock.unlock_noguard()}
+    }
+}
+
+#[cfg(unix)]
+mod imp {
+    use libc;
+    use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER,
+                   pthread_mutex_t, pthread_cond_t};
+    use core::ty::Unsafe;
+    use core::kinds::marker;
+
+    type pthread_mutexattr_t = libc::c_void;
+    type pthread_condattr_t = libc::c_void;
+
+    #[cfg(target_os = "freebsd")]
+    mod os {
+        use libc;
+
+        pub type pthread_mutex_t = *libc::c_void;
+        pub type pthread_cond_t = *libc::c_void;
+
+        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t =
+            0 as pthread_mutex_t;
+        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t =
+            0 as pthread_cond_t;
+    }
+
+    #[cfg(target_os = "macos")]
+    mod os {
+        use libc;
+
+        #[cfg(target_arch = "x86_64")]
+        static __PTHREAD_MUTEX_SIZE__: uint = 56;
+        #[cfg(target_arch = "x86_64")]
+        static __PTHREAD_COND_SIZE__: uint = 40;
+        #[cfg(target_arch = "x86")]
+        static __PTHREAD_MUTEX_SIZE__: uint = 40;
+        #[cfg(target_arch = "x86")]
+        static __PTHREAD_COND_SIZE__: uint = 24;
+
+        static _PTHREAD_MUTEX_SIG_init: libc::c_long = 0x32AAABA7;
+        static _PTHREAD_COND_SIG_init: libc::c_long = 0x3CB0B1BB;
+
+        pub struct pthread_mutex_t {
+            __sig: libc::c_long,
+            __opaque: [u8, ..__PTHREAD_MUTEX_SIZE__],
+        }
+        pub struct pthread_cond_t {
+            __sig: libc::c_long,
+            __opaque: [u8, ..__PTHREAD_COND_SIZE__],
+        }
+
+        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
+            __sig: _PTHREAD_MUTEX_SIG_init,
+            __opaque: [0, ..__PTHREAD_MUTEX_SIZE__],
+        };
+        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
+            __sig: _PTHREAD_COND_SIG_init,
+            __opaque: [0, ..__PTHREAD_COND_SIZE__],
+        };
+    }
+
+    #[cfg(target_os = "linux")]
+    mod os {
+        use libc;
+
+        // minus 8 because we have an 'align' field
+        #[cfg(target_arch = "x86_64")]
+        static __SIZEOF_PTHREAD_MUTEX_T: uint = 40 - 8;
+        #[cfg(target_arch = "x86")]
+        static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
+        #[cfg(target_arch = "arm")]
+        static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
+        #[cfg(target_arch = "mips")]
+        static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
+        #[cfg(target_arch = "x86_64")]
+        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
+        #[cfg(target_arch = "x86")]
+        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
+        #[cfg(target_arch = "arm")]
+        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
+        #[cfg(target_arch = "mips")]
+        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
+
+        pub struct pthread_mutex_t {
+            __align: libc::c_longlong,
+            size: [u8, ..__SIZEOF_PTHREAD_MUTEX_T],
+        }
+        pub struct pthread_cond_t {
+            __align: libc::c_longlong,
+            size: [u8, ..__SIZEOF_PTHREAD_COND_T],
+        }
+
+        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
+            __align: 0,
+            size: [0, ..__SIZEOF_PTHREAD_MUTEX_T],
+        };
+        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
+            __align: 0,
+            size: [0, ..__SIZEOF_PTHREAD_COND_T],
+        };
+    }
+    #[cfg(target_os = "android")]
+    mod os {
+        use libc;
+
+        pub struct pthread_mutex_t { value: libc::c_int }
+        pub struct pthread_cond_t { value: libc::c_int }
+
+        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
+            value: 0,
+        };
+        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
+            value: 0,
+        };
+    }
+
+    pub struct Mutex {
+        lock: Unsafe<pthread_mutex_t>,
+        cond: Unsafe<pthread_cond_t>,
+    }
+
+    pub static MUTEX_INIT: Mutex = Mutex {
+        lock: Unsafe {
+            value: PTHREAD_MUTEX_INITIALIZER,
+            marker1: marker::InvariantType,
+        },
+        cond: Unsafe {
+            value: PTHREAD_COND_INITIALIZER,
+            marker1: marker::InvariantType,
+        },
+    };
+
+    impl Mutex {
+        pub unsafe fn new() -> Mutex {
+            // As mutex might be moved and address is changing it
+            // is better to avoid initialization of potentially
+            // opaque OS data before it landed
+            let m = Mutex {
+                lock: Unsafe::new(PTHREAD_MUTEX_INITIALIZER),
+                cond: Unsafe::new(PTHREAD_COND_INITIALIZER),
+            };
+
+            return m;
+        }
+
+        pub unsafe fn lock(&self) { pthread_mutex_lock(self.lock.get()); }
+        pub unsafe fn unlock(&self) { pthread_mutex_unlock(self.lock.get()); }
+        pub unsafe fn signal(&self) { pthread_cond_signal(self.cond.get()); }
+        pub unsafe fn wait(&self) {
+            pthread_cond_wait(self.cond.get(), self.lock.get());
+        }
+        pub unsafe fn trylock(&self) -> bool {
+            pthread_mutex_trylock(self.lock.get()) == 0
+        }
+        pub unsafe fn destroy(&self) {
+            pthread_mutex_destroy(self.lock.get());
+            pthread_cond_destroy(self.cond.get());
+        }
+    }
+
+    extern {
+        fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
+        fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;
+
+        fn pthread_cond_wait(cond: *mut pthread_cond_t,
+                             lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
+    }
+}
+
+#[cfg(windows)]
+mod imp {
+    use alloc::libc_heap::malloc_raw;
+    use core::atomics;
+    use core::ptr;
+    use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
+    use libc;
+
+    type LPCRITICAL_SECTION = *mut c_void;
+    static SPIN_COUNT: DWORD = 4000;
+    #[cfg(target_arch = "x86")]
+    static CRIT_SECTION_SIZE: uint = 24;
+    #[cfg(target_arch = "x86_64")]
+    static CRIT_SECTION_SIZE: uint = 40;
+
+    pub struct Mutex {
+        // pointers for the lock/cond handles, atomically updated
+        lock: atomics::AtomicUint,
+        cond: atomics::AtomicUint,
+    }
+
+    pub static MUTEX_INIT: Mutex = Mutex {
+        lock: atomics::INIT_ATOMIC_UINT,
+        cond: atomics::INIT_ATOMIC_UINT,
+    };
+
+    impl Mutex {
+        pub unsafe fn new() -> Mutex {
+            Mutex {
+                lock: atomics::AtomicUint::new(init_lock()),
+                cond: atomics::AtomicUint::new(init_cond()),
+            }
+        }
+        pub unsafe fn lock(&self) {
+            EnterCriticalSection(self.getlock() as LPCRITICAL_SECTION)
+        }
+        pub unsafe fn trylock(&self) -> bool {
+            TryEnterCriticalSection(self.getlock() as LPCRITICAL_SECTION) != 0
+        }
+        pub unsafe fn unlock(&self) {
+            LeaveCriticalSection(self.getlock() as LPCRITICAL_SECTION)
+        }
+
+        pub unsafe fn wait(&self) {
+            self.unlock();
+            WaitForSingleObject(self.getcond() as HANDLE, libc::INFINITE);
+            self.lock();
+        }
+
+        pub unsafe fn signal(&self) {
+            assert!(SetEvent(self.getcond() as HANDLE) != 0);
+        }
+
+        /// This function is especially unsafe because there are no guarantees made
+        /// that no other thread is currently holding the lock or waiting on the
+        /// condition variable contained inside.
+        pub unsafe fn destroy(&self) {
+            let lock = self.lock.swap(0, atomics::SeqCst);
+            let cond = self.cond.swap(0, atomics::SeqCst);
+            if lock != 0 { free_lock(lock) }
+            if cond != 0 { free_cond(cond) }
+        }
+
+        unsafe fn getlock(&self) -> *mut c_void {
+            match self.lock.load(atomics::SeqCst) {
+                0 => {}
+                n => return n as *mut c_void
+            }
+            let lock = init_lock();
+            match self.lock.compare_and_swap(0, lock, atomics::SeqCst) {
+                0 => return lock as *mut c_void,
+                _ => {}
+            }
+            free_lock(lock);
+            return self.lock.load(atomics::SeqCst) as *mut c_void;
+        }
+
+        unsafe fn getcond(&self) -> *mut c_void {
+            match self.cond.load(atomics::SeqCst) {
+                0 => {}
+                n => return n as *mut c_void
+            }
+            let cond = init_cond();
+            match self.cond.compare_and_swap(0, cond, atomics::SeqCst) {
+                0 => return cond as *mut c_void,
+                _ => {}
+            }
+            free_cond(cond);
+            return self.cond.load(atomics::SeqCst) as *mut c_void;
+        }
+    }
+
+    pub unsafe fn init_lock() -> uint {
+        let block = malloc_raw(CRIT_SECTION_SIZE as uint) as *mut c_void;
+        InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
+        return block as uint;
+    }
+
+    pub unsafe fn init_cond() -> uint {
+        return CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
+                            ptr::null()) as uint;
+    }
+
+    pub unsafe fn free_lock(h: uint) {
+        DeleteCriticalSection(h as LPCRITICAL_SECTION);
+        libc::free(h as *mut c_void);
+    }
+
+    pub unsafe fn free_cond(h: uint) {
+        let block = h as HANDLE;
+        libc::CloseHandle(block);
+    }
+
+    #[allow(non_snake_case_functions)]
+    extern "system" {
+        fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+                        bManualReset: BOOL,
+                        bInitialState: BOOL,
+                        lpName: LPCSTR) -> HANDLE;
+        fn InitializeCriticalSectionAndSpinCount(
+                        lpCriticalSection: LPCRITICAL_SECTION,
+                        dwSpinCount: DWORD) -> BOOL;
+        fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
+        fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
+        fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
+        fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
+        fn SetEvent(hEvent: HANDLE) -> BOOL;
+        fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::prelude::*;
+
+    use std::mem::drop;
+    use super::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+    use std::rt::thread::Thread;
+
+    #[test]
+    fn smoke_lock() {
+        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
+        unsafe {
+            let _guard = lock.lock();
+        }
+    }
+
+    #[test]
+    fn smoke_cond() {
+        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
+        unsafe {
+            let guard = lock.lock();
+            let t = Thread::start(proc() {
+                let guard = lock.lock();
+                guard.signal();
+            });
+            guard.wait();
+            drop(guard);
+
+            t.join();
+        }
+    }
+
+    #[test]
+    fn smoke_lock_noguard() {
+        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
+        unsafe {
+            lock.lock_noguard();
+            lock.unlock_noguard();
+        }
+    }
+
+    #[test]
+    fn smoke_cond_noguard() {
+        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
+        unsafe {
+            lock.lock_noguard();
+            let t = Thread::start(proc() {
+                lock.lock_noguard();
+                lock.signal_noguard();
+                lock.unlock_noguard();
+            });
+            lock.wait_noguard();
+            lock.unlock_noguard();
+
+            t.join();
+        }
+    }
+
+    #[test]
+    fn destroy_immediately() {
+        unsafe {
+            let m = StaticNativeMutex::new();
+            m.destroy();
+        }
+    }
+}
diff --git a/src/librustrt/rtio.rs b/src/librustrt/rtio.rs
new file mode 100644 (file)
index 0000000..00f761b
--- /dev/null
@@ -0,0 +1,449 @@
+// 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.
+
+//! The EventLoop and internal synchronous I/O interface.
+
+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 c_str::CString;
+use local::Local;
+use task::Task;
+
+pub trait EventLoop {
+    fn run(&mut self);
+    fn callback(&mut self, arg: proc():Send);
+    fn pausable_idle_callback(&mut self, Box<Callback:Send>)
+                              -> Box<PausableIdleCallback:Send>;
+    fn remote_callback(&mut self, Box<Callback:Send>)
+                       -> Box<RemoteCallback:Send>;
+
+    /// The asynchronous I/O services. Not all event loops may provide one.
+    fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory>;
+    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
+    /// that, after calling 'fire', the callback will be called at
+    /// least once, but multiple callbacks may be coalesced and
+    /// callbacks may be called more often requested. Destruction also
+    /// triggers the callback.
+    fn fire(&mut self);
+}
+
+/// Description of what to do when a file handle is closed
+pub enum CloseBehavior {
+    /// Do not close this handle when the object is destroyed
+    DontClose,
+    /// Synchronously close the handle, meaning that the task will block when
+    /// the handle is destroyed until it has been fully closed.
+    CloseSynchronously,
+    /// Asynchronously closes a handle, meaning that the task will *not* block
+    /// when the handle is destroyed, but the handle will still get deallocated
+    /// and cleaned up (but this will happen asynchronously on the local event
+    /// loop).
+    CloseAsynchronously,
+}
+
+/// Data needed to spawn a process. Serializes the `std::io::process::Command`
+/// builder.
+pub struct ProcessConfig<'a> {
+    /// Path to the program to run.
+    pub program: &'a CString,
+
+    /// Arguments to pass to the program (doesn't include the program itself).
+    pub args: &'a [CString],
+
+    /// Optional environment to specify for the program. If this is None, then
+    /// it will inherit the current process's environment.
+    pub env: Option<&'a [(CString, CString)]>,
+
+    /// Optional working directory for the new process. If this is None, then
+    /// the current directory of the running process is inherited.
+    pub cwd: Option<&'a CString>,
+
+    /// Configuration for the child process's stdin handle (file descriptor 0).
+    /// This field defaults to `CreatePipe(true, false)` so the input can be
+    /// written to.
+    pub stdin: StdioContainer,
+
+    /// Configuration for the child process's stdout handle (file descriptor 1).
+    /// This field defaults to `CreatePipe(false, true)` so the output can be
+    /// collected.
+    pub stdout: StdioContainer,
+
+    /// Configuration for the child process's stdout handle (file descriptor 2).
+    /// This field defaults to `CreatePipe(false, true)` so the output can be
+    /// collected.
+    pub stderr: StdioContainer,
+
+    /// Any number of streams/file descriptors/pipes may be attached to this
+    /// process. This list enumerates the file descriptors and such for the
+    /// process to be spawned, and the file descriptors inherited will start at
+    /// 3 and go to the length of this array. The first three file descriptors
+    /// (stdin/stdout/stderr) are configured with the `stdin`, `stdout`, and
+    /// `stderr` fields.
+    pub extra_io: &'a [StdioContainer],
+
+    /// Sets the child process's user id. This translates to a `setuid` call in
+    /// the child process. Setting this value on windows will cause the spawn to
+    /// fail. Failure in the `setuid` call on unix will also cause the spawn to
+    /// fail.
+    pub uid: Option<uint>,
+
+    /// Similar to `uid`, but sets the group id of the child process. This has
+    /// the same semantics as the `uid` field.
+    pub gid: Option<uint>,
+
+    /// If true, the child process is spawned in a detached state. On unix, this
+    /// means that the child is the leader of a new process group.
+    pub detach: bool,
+}
+
+pub struct LocalIo<'a> {
+    factory: &'a mut IoFactory,
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for LocalIo<'a> {
+    fn drop(&mut self) {
+        // FIXME(pcwalton): Do nothing here for now, but eventually we may want
+        // something. For now this serves to make `LocalIo` noncopyable.
+    }
+}
+
+impl<'a> LocalIo<'a> {
+    /// Returns the local I/O: either the local scheduler's I/O services or
+    /// the native I/O services.
+    pub fn borrow() -> Option<LocalIo> {
+        // FIXME(#11053): bad
+        //
+        // This is currently very unsafely implemented. We don't actually
+        // *take* the local I/O so there's a very real possibility that we
+        // can have two borrows at once. Currently there is not a clear way
+        // to actually borrow the local I/O factory safely because even if
+        // ownership were transferred down to the functions that the I/O
+        // factory implements it's just too much of a pain to know when to
+        // relinquish ownership back into the local task (but that would be
+        // the safe way of implementing this function).
+        //
+        // In order to get around this, we just transmute a copy out of the task
+        // in order to have what is likely a static lifetime (bad).
+        let mut t: Box<Task> = match Local::try_take() {
+            Some(t) => t,
+            None => return None,
+        };
+        let ret = t.local_io().map(|t| {
+            unsafe { mem::transmute_copy(&t) }
+        });
+        Local::put(t);
+        return ret;
+    }
+
+    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() {
+            Some(mut io) => f(io.get()),
+            None => Err(IoError {
+                code: ERROR as uint,
+                extra: 0,
+                detail: None,
+            }),
+        }
+    }
+
+    pub fn new<'a>(io: &'a mut IoFactory) -> LocalIo<'a> {
+        LocalIo { factory: io }
+    }
+
+    /// Returns the underlying I/O factory as a trait reference.
+    #[inline]
+    pub fn get<'a>(&'a mut self) -> &'a mut IoFactory {
+        let f: &'a mut IoFactory = self.factory;
+        f
+    }
+}
+
+pub trait IoFactory {
+    // networking
+    fn tcp_connect(&mut self, addr: SocketAddr,
+                   timeout: Option<u64>) -> IoResult<Box<RtioTcpStream:Send>>;
+    fn tcp_bind(&mut self, addr: SocketAddr)
+                -> IoResult<Box<RtioTcpListener:Send>>;
+    fn udp_bind(&mut self, addr: SocketAddr)
+                -> IoResult<Box<RtioUdpSocket:Send>>;
+    fn unix_bind(&mut self, path: &CString)
+                 -> IoResult<Box<RtioUnixListener:Send>>;
+    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<AddrinfoHint>)
+                          -> IoResult<Vec<AddrinfoInfo>>;
+
+    // filesystem operations
+    fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior)
+                      -> Box<RtioFileStream:Send>;
+    fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
+               -> 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: 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<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<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) ->
+        IoResult<()>;
+
+    // misc
+    fn timer_init(&mut self) -> IoResult<Box<RtioTimer:Send>>;
+    fn spawn(&mut self, cfg: ProcessConfig)
+            -> IoResult<(Box<RtioProcess:Send>,
+                         Vec<Option<Box<RtioPipe:Send>>>)>;
+    fn kill(&mut self, pid: libc::pid_t, signal: int) -> IoResult<()>;
+    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: int, cb: Box<Callback:Send>)
+        -> IoResult<Box<RtioSignal:Send>>;
+}
+
+pub trait RtioTcpListener : RtioSocket {
+    fn listen(~self) -> IoResult<Box<RtioTcpAcceptor:Send>>;
+}
+
+pub trait RtioTcpAcceptor : RtioSocket {
+    fn accept(&mut self) -> IoResult<Box<RtioTcpStream:Send>>;
+    fn accept_simultaneously(&mut self) -> IoResult<()>;
+    fn dont_accept_simultaneously(&mut self) -> IoResult<()>;
+    fn set_timeout(&mut self, timeout: Option<u64>);
+}
+
+pub trait RtioTcpStream : RtioSocket {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
+    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
+    fn peer_name(&mut self) -> IoResult<SocketAddr>;
+    fn control_congestion(&mut self) -> IoResult<()>;
+    fn nodelay(&mut self) -> IoResult<()>;
+    fn keepalive(&mut self, delay_in_seconds: uint) -> IoResult<()>;
+    fn letdie(&mut self) -> IoResult<()>;
+    fn clone(&self) -> Box<RtioTcpStream:Send>;
+    fn close_write(&mut self) -> IoResult<()>;
+    fn close_read(&mut self) -> IoResult<()>;
+    fn set_timeout(&mut self, timeout_ms: Option<u64>);
+    fn set_read_timeout(&mut self, timeout_ms: Option<u64>);
+    fn set_write_timeout(&mut self, timeout_ms: Option<u64>);
+}
+
+pub trait RtioSocket {
+    fn socket_name(&mut self) -> IoResult<SocketAddr>;
+}
+
+pub trait RtioUdpSocket : RtioSocket {
+    fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)>;
+    fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()>;
+
+    fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()>;
+    fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()>;
+
+    fn loop_multicast_locally(&mut self) -> IoResult<()>;
+    fn dont_loop_multicast_locally(&mut self) -> IoResult<()>;
+
+    fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()>;
+    fn time_to_live(&mut self, ttl: int) -> IoResult<()>;
+
+    fn hear_broadcasts(&mut self) -> IoResult<()>;
+    fn ignore_broadcasts(&mut self) -> IoResult<()>;
+
+    fn clone(&self) -> Box<RtioUdpSocket:Send>;
+    fn set_timeout(&mut self, timeout_ms: Option<u64>);
+    fn set_read_timeout(&mut self, timeout_ms: Option<u64>);
+    fn set_write_timeout(&mut self, timeout_ms: Option<u64>);
+}
+
+pub trait RtioTimer {
+    fn sleep(&mut self, msecs: u64);
+    fn oneshot(&mut self, msecs: u64, cb: Box<Callback:Send>);
+    fn period(&mut self, msecs: u64, cb: Box<Callback:Send>);
+}
+
+pub trait RtioFileStream {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<int>;
+    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
+    fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int>;
+    fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()>;
+    fn seek(&mut self, pos: i64, whence: SeekStyle) -> IoResult<u64>;
+    fn tell(&self) -> IoResult<u64>;
+    fn fsync(&mut self) -> IoResult<()>;
+    fn datasync(&mut self) -> IoResult<()>;
+    fn truncate(&mut self, offset: i64) -> IoResult<()>;
+    fn fstat(&mut self) -> IoResult<FileStat>;
+}
+
+pub trait RtioProcess {
+    fn id(&self) -> libc::pid_t;
+    fn kill(&mut self, signal: int) -> IoResult<()>;
+    fn wait(&mut self) -> IoResult<ProcessExit>;
+    fn set_timeout(&mut self, timeout: Option<u64>);
+}
+
+pub trait RtioPipe {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
+    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
+    fn clone(&self) -> Box<RtioPipe:Send>;
+
+    fn close_write(&mut self) -> IoResult<()>;
+    fn close_read(&mut self) -> IoResult<()>;
+    fn set_timeout(&mut self, timeout_ms: Option<u64>);
+    fn set_read_timeout(&mut self, timeout_ms: Option<u64>);
+    fn set_write_timeout(&mut self, timeout_ms: Option<u64>);
+}
+
+pub trait RtioUnixListener {
+    fn listen(~self) -> IoResult<Box<RtioUnixAcceptor:Send>>;
+}
+
+pub trait RtioUnixAcceptor {
+    fn accept(&mut self) -> IoResult<Box<RtioPipe:Send>>;
+    fn set_timeout(&mut self, timeout: Option<u64>);
+}
+
+pub trait RtioTTY {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
+    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
+    fn set_raw(&mut self, raw: bool) -> IoResult<()>;
+    fn get_winsize(&mut self) -> IoResult<(int, int)>;
+    fn isatty(&self) -> bool;
+}
+
+pub trait PausableIdleCallback {
+    fn pause(&mut self);
+    fn resume(&mut self);
+}
+
+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,
+}
diff --git a/src/librustrt/stack.rs b/src/librustrt/stack.rs
new file mode 100644 (file)
index 0000000..148d93a
--- /dev/null
@@ -0,0 +1,278 @@
+// 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.
+
+//! Rust stack-limit management
+//!
+//! Currently Rust uses a segmented-stack-like scheme in order to detect stack
+//! overflow for rust tasks. In this scheme, the prologue of all functions are
+//! preceded with a check to see whether the current stack limits are being
+//! exceeded.
+//!
+//! This module provides the functionality necessary in order to manage these
+//! stack limits (which are stored in platform-specific locations). The
+//! functions here are used at the borders of the task lifetime in order to
+//! manage these limits.
+//!
+//! This function is an unstable module because this scheme for stack overflow
+//! detection is not guaranteed to continue in the future. Usage of this module
+//! is discouraged unless absolutely necessary.
+
+pub static RED_ZONE: uint = 20 * 1024;
+
+/// This function is invoked from rust's current __morestack function. Segmented
+/// stacks are currently not enabled as segmented stacks, but rather one giant
+/// stack segment. This means that whenever we run out of stack, we want to
+/// truly consider it to be stack overflow rather than allocating a new stack.
+#[cfg(not(test))] // in testing, use the original libstd's version
+#[lang = "stack_exhausted"]
+extern fn stack_exhausted() {
+    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
+        // to call some other rust functions, but if we invoke the functions
+        // right now it'll just trigger this handler being called again. In
+        // order to alleviate this, we move the stack limit to be inside of the
+        // red zone that was allocated for exactly this reason.
+        let limit = get_sp_limit();
+        record_sp_limit(limit - RED_ZONE / 2);
+
+        // This probably isn't the best course of action. Ideally one would want
+        // to unwind the stack here instead of just aborting the entire process.
+        // This is a tricky problem, however. There's a few things which need to
+        // be considered:
+        //
+        //  1. We're here because of a stack overflow, yet unwinding will run
+        //     destructors and hence arbitrary code. What if that code overflows
+        //     the stack? One possibility is to use the above allocation of an
+        //     extra 10k to hope that we don't hit the limit, and if we do then
+        //     abort the whole program. Not the best, but kind of hard to deal
+        //     with unless we want to switch stacks.
+        //
+        //  2. LLVM will optimize functions based on whether they can unwind or
+        //     not. It will flag functions with 'nounwind' if it believes that
+        //     the function cannot trigger unwinding, but if we do unwind on
+        //     stack overflow then it means that we could unwind in any function
+        //     anywhere. We would have to make sure that LLVM only places the
+        //     nounwind flag on functions which don't call any other functions.
+        //
+        //  3. The function that overflowed may have owned arguments. These
+        //     arguments need to have their destructors run, but we haven't even
+        //     begun executing the function yet, so unwinding will not run the
+        //     any landing pads for these functions. If this is ignored, then
+        //     the arguments will just be leaked.
+        //
+        // Exactly what to do here is a very delicate topic, and is possibly
+        // still up in the air for what exactly to do. Some relevant issues:
+        //
+        //  #3555 - out-of-stack failure leaks arguments
+        //  #3695 - should there be a stack limit?
+        //  #9855 - possible strategies which could be taken
+        //  #9854 - unwinding on windows through __morestack has never worked
+        //  #2361 - possible implementation of not using landing pads
+
+        let task: Option<Box<Task>> = Local::try_take();
+        let name = match task {
+            Some(ref task) => {
+                task.name.as_ref().map(|n| n.as_slice())
+            }
+            None => None
+        };
+        let name = name.unwrap_or("<unknown>");
+
+        // See the message below for why this is not emitted to the
+        // task's logger. This has the additional conundrum of the
+        // logger may not be initialized just yet, meaning that an FFI
+        // call would happen to initialized it (calling out to libuv),
+        // and the FFI call needs 2MB of stack when we just ran out.
+        rterrln!("task '{}' has overflowed its stack", name);
+
+        intrinsics::abort();
+    }
+}
+
+#[inline(always)]
+pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) {
+    // When the old runtime had segmented stacks, it used a calculation that was
+    // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
+    // symbol resolution, llvm function calls, etc. In theory this red zone
+    // value is 0, but it matters far less when we have gigantic stacks because
+    // we don't need to be so exact about our stack budget. The "fudge factor"
+    // was because LLVM doesn't emit a stack check for functions < 256 bytes in
+    // size. Again though, we have giant stacks, so we round all these
+    // calculations up to the nice round number of 20k.
+    record_sp_limit(stack_lo + RED_ZONE);
+
+    return target_record_stack_bounds(stack_lo, stack_hi);
+
+    #[cfg(not(windows))] #[cfg(not(target_arch = "x86_64"))] #[inline(always)]
+    unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {}
+    #[cfg(windows, target_arch = "x86_64")] #[inline(always)]
+    unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
+        // Windows compiles C functions which may check the stack bounds. This
+        // means that if we want to perform valid FFI on windows, then we need
+        // to ensure that the stack bounds are what they truly are for this
+        // task. More info can be found at:
+        //   https://github.com/mozilla/rust/issues/3445#issuecomment-26114839
+        //
+        // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
+        asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile");
+        asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile");
+    }
+}
+
+/// Records the current limit of the stack as specified by `end`.
+///
+/// This is stored in an OS-dependent location, likely inside of the thread
+/// local storage. The location that the limit is stored is a pre-ordained
+/// location because it's where LLVM has emitted code to check.
+///
+/// Note that this cannot be called under normal circumstances. This function is
+/// changing the stack limit, so upon returning any further function calls will
+/// possibly be triggering the morestack logic if you're not careful.
+///
+/// Also note that this and all of the inside functions are all flagged as
+/// "inline(always)" because they're messing around with the stack limits.  This
+/// would be unfortunate for the functions themselves to trigger a morestack
+/// invocation (if they were an actual function call).
+#[inline(always)]
+pub unsafe fn record_sp_limit(limit: uint) {
+    return target_record_sp_limit(limit);
+
+    // x86-64
+    #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $$0x60+90*8, %rsi
+              movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile")
+    }
+    #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
+        // store this inside of the "arbitrary data slot", but double the size
+        // because this is 64 bit instead of 32 bit
+        asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile")
+    }
+
+    // x86
+    #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movl $$0x48+90*4, %eax
+              movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
+    }
+    #[cfg(target_arch = "x86", target_os = "linux")]
+    #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
+    }
+    #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
+        // store this inside of the "arbitrary data slot"
+        asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile")
+    }
+
+    // mips, arm - Some brave soul can port these to inline asm, but it's over
+    //             my head personally
+    #[cfg(target_arch = "mips")]
+    #[cfg(target_arch = "arm")] #[inline(always)]
+    unsafe fn target_record_sp_limit(limit: uint) {
+        use libc::c_void;
+        return record_sp_limit(limit as *c_void);
+        extern {
+            fn record_sp_limit(limit: *c_void);
+        }
+    }
+}
+
+/// The counterpart of the function above, this function will fetch the current
+/// stack limit stored in TLS.
+///
+/// Note that all of these functions are meant to be exact counterparts of their
+/// brethren above, except that the operands are reversed.
+///
+/// As with the setter, this function does not have a __morestack header and can
+/// therefore be called in a "we're out of stack" situation.
+#[inline(always)]
+pub unsafe fn get_sp_limit() -> uint {
+    return target_get_sp_limit();
+
+    // x86-64
+    #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq $$0x60+90*8, %rsi
+              movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+
+    // x86
+    #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movl $$0x48+90*4, %eax
+              movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86", target_os = "linux")]
+    #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+    #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        let limit;
+        asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile");
+        return limit;
+    }
+
+    // mips, arm - Some brave soul can port these to inline asm, but it's over
+    //             my head personally
+    #[cfg(target_arch = "mips")]
+    #[cfg(target_arch = "arm")] #[inline(always)]
+    unsafe fn target_get_sp_limit() -> uint {
+        use libc::c_void;
+        return get_sp_limit() as uint;
+        extern {
+            fn get_sp_limit() -> *c_void;
+        }
+    }
+}
diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs
new file mode 100644 (file)
index 0000000..0640b2b
--- /dev/null
@@ -0,0 +1,482 @@
+// Copyright 2013-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.
+
+//! Language-level runtime services that should reasonably expected
+//! to be available 'everywhere'. Local heaps, GC, unwinding,
+//! local storage, and logging. Even a 'freestanding' Rust would likely want
+//! to implement this.
+
+use core::prelude::*;
+
+use alloc::arc::Arc;
+use alloc::owned::{AnyOwnExt, Box};
+use core::any::Any;
+use core::atomics::{AtomicUint, SeqCst};
+use core::finally::Finally;
+use core::iter::Take;
+use core::mem;
+use core::raw;
+
+use local_data;
+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,
+/// however instead of using a subtype we just have a "task_type" field
+/// in the struct. This contains a pointer to another struct that holds
+/// the type-specific state.
+pub struct Task {
+    pub heap: LocalHeap,
+    pub gc: GarbageCollector,
+    pub storage: LocalStorage,
+    pub unwinder: Unwinder,
+    pub death: Death,
+    pub destroyed: bool,
+    pub name: Option<SendStr>,
+
+    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>);
+
+/// A handle to a blocked task. Usually this means having the Box<Task>
+/// pointer by ownership, but if the task is killable, a killer can steal it
+/// at any time.
+pub enum BlockedTask {
+    Owned(Box<Task>),
+    Shared(Arc<AtomicUint>),
+}
+
+/// Per-task state related to task death, killing, failure, etc.
+pub struct Death {
+    pub on_exit: Option<proc(Result):Send>,
+}
+
+pub struct BlockedTasks {
+    inner: Arc<AtomicUint>,
+}
+
+impl Task {
+    pub fn new() -> Task {
+        Task {
+            heap: LocalHeap::new(),
+            gc: GarbageCollector,
+            storage: LocalStorage(None),
+            unwinder: Unwinder::new(),
+            death: Death::new(),
+            destroyed: false,
+            name: None,
+            imp: None,
+        }
+    }
+
+    /// Executes the given closure as if it's running inside this task. The task
+    /// is consumed upon entry, and the destroyed task is returned from this
+    /// function in order for the caller to free. This function is guaranteed to
+    /// not unwind because the closure specified is run inside of a `rust_try`
+    /// block. (this is the only try/catch block in the world).
+    ///
+    /// This function is *not* meant to be abused as a "try/catch" block. This
+    /// is meant to be used at the absolute boundaries of a task's lifetime, and
+    /// only for that purpose.
+    pub fn run(~self, mut f: ||) -> Box<Task> {
+        // Need to put ourselves into TLS, but also need access to the unwinder.
+        // Unsafely get a handle to the task so we can continue to use it after
+        // putting it in tls (so we can invoke the unwinder).
+        let handle: *mut Task = unsafe {
+            *mem::transmute::<&Box<Task>, &*mut Task>(&self)
+        };
+        Local::put(self);
+
+        // The only try/catch block in the world. Attempt to run the task's
+        // client-specified code and catch any failures.
+        let try_block = || {
+
+            // Run the task main function, then do some cleanup.
+            f.finally(|| {
+                // First, destroy task-local storage. This may run user dtors.
+                //
+                // FIXME #8302: Dear diary. I'm so tired and confused.
+                // There's some interaction in rustc between the box
+                // annihilator and the TLS dtor by which TLS is
+                // accessed from annihilated box dtors *after* TLS is
+                // destroyed. Somehow setting TLS back to null, as the
+                // old runtime did, makes this work, but I don't currently
+                // understand how. I would expect that, if the annihilator
+                // reinvokes TLS while TLS is uninitialized, that
+                // TLS would be reinitialized but never destroyed,
+                // but somehow this works. I have no idea what's going
+                // on but this seems to make things magically work. FML.
+                //
+                // (added after initial comment) A possible interaction here is
+                // that the destructors for the objects in TLS themselves invoke
+                // 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...
+                drop({
+                    let mut task = Local::borrow(None::<Task>);
+                    let &LocalStorage(ref mut optmap) = &mut task.storage;
+                    optmap.take()
+                });
+
+                // Destroy remaining boxes. Also may run user dtors.
+                let mut heap = {
+                    let mut task = Local::borrow(None::<Task>);
+                    mem::replace(&mut task.heap, LocalHeap::new())
+                };
+                unsafe { heap.annihilate() }
+                drop(heap);
+            })
+        };
+
+        unsafe { (*handle).unwinder.try(try_block); }
+
+        // Here we must unsafely borrow the task in order to not remove it from
+        // TLS. When collecting failure, we may attempt to send on a channel (or
+        // just run aribitrary code), so we must be sure to still have a local
+        // task in TLS.
+        unsafe {
+            let me: *mut Task = Local::unsafe_borrow();
+            (*me).death.collect_failure((*me).unwinder.result());
+        }
+        let mut me: Box<Task> = Local::take();
+        me.destroyed = true;
+        return me;
+    }
+
+    /// Inserts a runtime object into this task, transferring ownership to the
+    /// task. It is illegal to replace a previous runtime object in this task
+    /// with this argument.
+    pub fn put_runtime(&mut self, ops: Box<Runtime:Send>) {
+        assert!(self.imp.is_none());
+        self.imp = Some(ops);
+    }
+
+    /// Attempts to extract the runtime as a specific type. If the runtime does
+    /// not have the provided type, then the runtime is not removed. If the
+    /// runtime does have the specified type, then it is removed and returned
+    /// (transfer of ownership).
+    ///
+    /// It is recommended to only use this method when *absolutely necessary*.
+    /// This function may not be available in the future.
+    pub fn maybe_take_runtime<T: 'static>(&mut self) -> Option<Box<T>> {
+        // This is a terrible, terrible function. The general idea here is to
+        // take the runtime, cast it to Box<Any>, check if it has the right
+        // type, and then re-cast it back if necessary. The method of doing
+        // this is pretty sketchy and involves shuffling vtables of trait
+        // objects around, but it gets the job done.
+        //
+        // FIXME: This function is a serious code smell and should be avoided at
+        //      all costs. I have yet to think of a method to avoid this
+        //      function, and I would be saddened if more usage of the function
+        //      crops up.
+        unsafe {
+            let imp = self.imp.take_unwrap();
+            let vtable = mem::transmute::<_, &raw::TraitObject>(&imp).vtable;
+            match imp.wrap().move::<T>() {
+                Ok(t) => Some(t),
+                Err(t) => {
+                    let data = mem::transmute::<_, raw::TraitObject>(t).data;
+                    let obj: Box<Runtime:Send> =
+                        mem::transmute(raw::TraitObject {
+                            vtable: vtable,
+                            data: data,
+                        });
+                    self.put_runtime(obj);
+                    None
+                }
+            }
+        }
+    }
+
+    /// Spawns a sibling to this task. The newly spawned task is configured with
+    /// the `opts` structure and will run `f` as the body of its code.
+    pub fn spawn_sibling(mut ~self, opts: TaskOpts, f: proc():Send) {
+        let ops = self.imp.take_unwrap();
+        ops.spawn_sibling(self, opts, f)
+    }
+
+    /// Deschedules the current task, invoking `f` `amt` times. It is not
+    /// 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| -> ::core::result::Result<(), BlockedTask>) {
+        let ops = self.imp.take_unwrap();
+        ops.deschedule(amt, self, f)
+    }
+
+    /// Wakes up a previously blocked task, optionally specifying whether the
+    /// current task can accept a change in scheduling. This function can only
+    /// be called on tasks that were previously blocked in `deschedule`.
+    pub fn reawaken(mut ~self) {
+        let ops = self.imp.take_unwrap();
+        ops.reawaken(self);
+    }
+
+    /// Yields control of this task to another task. This function will
+    /// eventually return, but possibly not immediately. This is used as an
+    /// opportunity to allow other tasks a chance to run.
+    pub fn yield_now(mut ~self) {
+        let ops = self.imp.take_unwrap();
+        ops.yield_now(self);
+    }
+
+    /// Similar to `yield_now`, except that this function may immediately return
+    /// without yielding (depending on what the runtime decides to do).
+    pub fn maybe_yield(mut ~self) {
+        let ops = self.imp.take_unwrap();
+        ops.maybe_yield(self);
+    }
+
+    /// Acquires a handle to the I/O factory that this task contains, normally
+    /// stored in the task's runtime. This factory may not always be available,
+    /// which is why the return type is `Option`
+    pub fn local_io<'a>(&'a mut self) -> Option<LocalIo<'a>> {
+        self.imp.get_mut_ref().local_io()
+    }
+
+    /// Returns the stack bounds for this task in (lo, hi) format. The stack
+    /// bounds may not be known for all tasks, so the return value may be
+    /// `None`.
+    pub fn stack_bounds(&self) -> (uint, uint) {
+        self.imp.get_ref().stack_bounds()
+    }
+
+    /// Returns whether it is legal for this task to block the OS thread that it
+    /// is running on.
+    pub fn can_block(&self) -> bool {
+        self.imp.get_ref().can_block()
+    }
+}
+
+impl Drop for Task {
+    fn drop(&mut self) {
+        rtdebug!("called drop for a task: {}", self as *mut Task as uint);
+        rtassert!(self.destroyed);
+    }
+}
+
+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()))
+    }
+}
+
+impl BlockedTask {
+    /// Returns Some if the task was successfully woken; None if already killed.
+    pub fn wake(self) -> Option<Box<Task>> {
+        match self {
+            Owned(task) => Some(task),
+            Shared(arc) => {
+                match arc.swap(0, SeqCst) {
+                    0 => None,
+                    n => Some(unsafe { mem::transmute(n) }),
+                }
+            }
+        }
+    }
+
+    /// Reawakens this task if ownership is acquired. If finer-grained control
+    /// is desired, use `wake` instead.
+    pub fn reawaken(self) {
+        self.wake().map(|t| t.reawaken());
+    }
+
+    // This assertion has two flavours because the wake involves an atomic op.
+    // In the faster version, destructors will fail dramatically instead.
+    #[cfg(not(test))] pub fn trash(self) { }
+    #[cfg(test)]      pub fn trash(self) { assert!(self.wake().is_none()); }
+
+    /// Create a blocked task, unless the task was already killed.
+    pub fn block(task: Box<Task>) -> BlockedTask {
+        Owned(task)
+    }
+
+    /// Converts one blocked task handle to a list of many handles to the same.
+    pub fn make_selectable(self, num_handles: uint) -> Take<BlockedTasks> {
+        let arc = match self {
+            Owned(task) => {
+                let flag = unsafe { AtomicUint::new(mem::transmute(task)) };
+                Arc::new(flag)
+            }
+            Shared(arc) => arc.clone(),
+        };
+        BlockedTasks{ inner: arc }.take(num_handles)
+    }
+
+    /// Convert to an unsafe uint value. Useful for storing in a pipe's state
+    /// flag.
+    #[inline]
+    pub unsafe fn cast_to_uint(self) -> uint {
+        match self {
+            Owned(task) => {
+                let blocked_task_ptr: uint = mem::transmute(task);
+                rtassert!(blocked_task_ptr & 0x1 == 0);
+                blocked_task_ptr
+            }
+            Shared(arc) => {
+                let blocked_task_ptr: uint = mem::transmute(box arc);
+                rtassert!(blocked_task_ptr & 0x1 == 0);
+                blocked_task_ptr | 0x1
+            }
+        }
+    }
+
+    /// Convert from an unsafe uint value. Useful for retrieving a pipe's state
+    /// flag.
+    #[inline]
+    pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
+        if blocked_task_ptr & 0x1 == 0 {
+            Owned(mem::transmute(blocked_task_ptr))
+        } else {
+            let ptr: Box<Arc<AtomicUint>> =
+                mem::transmute(blocked_task_ptr & !1);
+            Shared(*ptr)
+        }
+    }
+}
+
+impl Death {
+    pub fn new() -> Death {
+        Death { on_exit: None, }
+    }
+
+    /// Collect failure exit codes from children and propagate them to a parent.
+    pub fn collect_failure(&mut self, result: Result) {
+        match self.on_exit.take() {
+            Some(f) => f(result),
+            None => {}
+        }
+    }
+}
+
+impl Drop for Death {
+    fn drop(&mut self) {
+        // make this type noncopyable
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::prelude::*;
+    use std::task;
+
+    #[test]
+    fn local_heap() {
+        let a = @5;
+        let b = a;
+        assert!(*a == 5);
+        assert!(*b == 5);
+    }
+
+    #[test]
+    fn tls() {
+        local_data_key!(key: @String)
+        key.replace(Some(@"data".to_string()));
+        assert_eq!(key.get().unwrap().as_slice(), "data");
+        local_data_key!(key2: @String)
+        key2.replace(Some(@"data".to_string()));
+        assert_eq!(key2.get().unwrap().as_slice(), "data");
+    }
+
+    #[test]
+    fn unwind() {
+        let result = task::try(proc()());
+        rtdebug!("trying first assert");
+        assert!(result.is_ok());
+        let result = task::try::<()>(proc() fail!());
+        rtdebug!("trying second assert");
+        assert!(result.is_err());
+    }
+
+    #[test]
+    fn rng() {
+        use std::rand::{StdRng, Rng};
+        let mut r = StdRng::new().ok().unwrap();
+        let _ = r.next_u32();
+    }
+
+    #[test]
+    fn comm_stream() {
+        let (tx, rx) = channel();
+        tx.send(10);
+        assert!(rx.recv() == 10);
+    }
+
+    #[test]
+    fn comm_shared_chan() {
+        let (tx, rx) = channel();
+        tx.send(10);
+        assert!(rx.recv() == 10);
+    }
+
+    #[test]
+    fn heap_cycles() {
+        use std::cell::RefCell;
+
+        struct List {
+            next: Option<@RefCell<List>>,
+        }
+
+        let a = @RefCell::new(List { next: None });
+        let b = @RefCell::new(List { next: Some(a) });
+
+        {
+            let mut a = a.borrow_mut();
+            a.next = Some(b);
+        }
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_begin_unwind() {
+        use std::rt::unwind::begin_unwind;
+        begin_unwind("cause", file!(), line!())
+    }
+
+    // Task blocking tests
+
+    #[test]
+    fn block_and_wake() {
+        let task = box Task::new();
+        let mut task = BlockedTask::block(task).wake().unwrap();
+        task.destroyed = true;
+    }
+}
diff --git a/src/librustrt/thread_local_storage.rs b/src/librustrt/thread_local_storage.rs
new file mode 100644 (file)
index 0000000..2cdeb21
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2013-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.
+
+#![allow(dead_code)]
+
+#[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!(pthread_key_create(key, null()) == 0);
+}
+
+#[cfg(unix)]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    assert!(pthread_setspecific(key, value) == 0);
+}
+
+#[cfg(unix)]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    pthread_getspecific(key)
+}
+
+#[cfg(unix)]
+pub unsafe fn destroy(key: Key) {
+    assert!(pthread_key_delete(key) == 0);
+}
+
+#[cfg(target_os="macos")]
+#[allow(non_camel_case_types)] // foreign type
+type pthread_key_t = ::libc::c_ulong;
+
+#[cfg(target_os="linux")]
+#[cfg(target_os="freebsd")]
+#[cfg(target_os="android")]
+#[allow(non_camel_case_types)] // foreign type
+type pthread_key_t = ::libc::c_uint;
+
+#[cfg(unix)]
+extern {
+    fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int;
+    fn pthread_key_delete(key: pthread_key_t) -> c_int;
+    fn pthread_getspecific(key: pthread_key_t) -> *mut u8;
+    fn pthread_setspecific(key: pthread_key_t, value: *mut u8) -> c_int;
+}
+
+#[cfg(windows)]
+pub type Key = DWORD;
+
+#[cfg(windows)]
+pub unsafe fn create(key: &mut Key) {
+    static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
+    *key = TlsAlloc();
+    assert!(*key != TLS_OUT_OF_INDEXES);
+}
+
+#[cfg(windows)]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    assert!(0 != TlsSetValue(key, value as *mut ::libc::c_void))
+}
+
+#[cfg(windows)]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    TlsGetValue(key) as *mut u8
+}
+
+#[cfg(windows)]
+pub unsafe fn destroy(key: Key) {
+    assert!(TlsFree(key) != 0);
+}
+
+#[cfg(windows)]
+#[allow(non_snake_case_functions)]
+extern "system" {
+    fn TlsAlloc() -> DWORD;
+    fn TlsFree(dwTlsIndex: DWORD) -> BOOL;
+    fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
+    fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
+}
+
+#[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);
+        }
+    }
+}
diff --git a/src/librustrt/unwind.rs b/src/librustrt/unwind.rs
new file mode 100644 (file)
index 0000000..2fd9f4e
--- /dev/null
@@ -0,0 +1,482 @@
+// 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 Rust stack unwinding
+//!
+//! For background on exception handling and stack unwinding please see
+//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
+//! documents linked from it.
+//! These are also good reads:
+//!     http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
+//!     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
+//!     http://www.airs.com/blog/index.php?s=exception+frames
+//!
+//! ## A brief summary
+//!
+//! Exception handling happens in two phases: a search phase and a cleanup phase.
+//!
+//! In both phases the unwinder walks stack frames from top to bottom using
+//! information from the stack frame unwind sections of the current process's
+//! modules ("module" here refers to an OS module, i.e. an executable or a
+//! dynamic library).
+//!
+//! For each stack frame, it invokes the associated "personality routine", whose
+//! address is also stored in the unwind info section.
+//!
+//! In the search phase, the job of a personality routine is to examine exception
+//! object being thrown, and to decide whether it should be caught at that stack
+//! frame.  Once the handler frame has been identified, cleanup phase begins.
+//!
+//! In the cleanup phase, personality routines invoke cleanup code associated
+//! with their stack frames (i.e. destructors).  Once stack has been unwound down
+//! to the handler frame level, unwinding stops and the last personality routine
+//! transfers control to its' catch block.
+//!
+//! ## Frame unwind info registration
+//!
+//! Each module has its' own frame unwind info section (usually ".eh_frame"), and
+//! unwinder needs to know about all of them in order for unwinding to be able to
+//! cross module boundaries.
+//!
+//! On some platforms, like Linux, this is achieved by dynamically enumerating
+//! currently loaded modules via the dl_iterate_phdr() API and finding all
+//! .eh_frame sections.
+//!
+//! Others, like Windows, require modules to actively register their unwind info
+//! sections by calling __register_frame_info() API at startup.  In the latter
+//! case it is essential that there is only one copy of the unwinder runtime in
+//! the process.  This is usually achieved by linking to the dynamic version of
+//! the unwind runtime.
+//!
+//! Currently Rust uses unwind runtime provided by libgcc.
+
+use core::prelude::*;
+
+use alloc::owned::Box;
+use collections::string::String;
+use collections::vec::Vec;
+use core::any::Any;
+use core::atomics;
+use core::cmp;
+use core::fmt;
+use core::intrinsics;
+use core::mem;
+use core::raw::Closure;
+use libc::c_void;
+
+use local::Local;
+use task::{Task, Result};
+use exclusive::Exclusive;
+
+use uw = libunwind;
+
+pub struct Unwinder {
+    unwinding: bool,
+    cause: Option<Box<Any:Send>>
+}
+
+struct Exception {
+    uwe: uw::_Unwind_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 {
+            unwinding: false,
+            cause: None,
+        }
+    }
+
+    pub fn unwinding(&self) -> bool {
+        self.unwinding
+    }
+
+    pub fn try(&mut self, f: ||) {
+        self.cause = unsafe { try(f) }.err();
+    }
+
+    pub fn result(&mut self) -> Result {
+        if self.unwinding {
+            Err(self.cause.take().unwrap())
+        } else {
+            Ok(())
+        }
+    }
+}
+
+/// Invoke a closure, capturing the cause of failure if one occurs.
+///
+/// This function will return `None` if the closure did not fail, and will
+/// return `Some(cause)` if the closure fails. The `cause` returned is the
+/// object with which failure was originally invoked.
+///
+/// This function also is unsafe for a variety of reasons:
+///
+/// * This is not safe to call in a nested fashion. The unwinding
+///   interface for Rust is designed to have at most one try/catch block per
+///   task, not multiple. No runtime checking is currently performed to uphold
+///   this invariant, so this function is not safe. A nested try/catch block
+///   may result in corruption of the outer try/catch block's state, especially
+///   if this is used within a task itself.
+///
+/// * It is not sound to trigger unwinding while already unwinding. Rust tasks
+///   have runtime checks in place to ensure this invariant, but it is not
+///   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: ||) -> ::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);
+    return if ep.is_null() {
+        Ok(())
+    } else {
+        let my_ep = ep as *mut Exception;
+        rtdebug!("caught {}", (*my_ep).uwe.exception_class);
+        let cause = (*my_ep).cause.take();
+        uw::_Unwind_DeleteException(ep);
+        Err(cause.unwrap())
+    };
+
+    extern fn try_fn(code: *c_void, env: *c_void) {
+        unsafe {
+            let closure: || = mem::transmute(Closure {
+                code: code as *(),
+                env: env as *(),
+            });
+            closure();
+        }
+    }
+
+    #[link(name = "rustrt_native", kind = "static")]
+    extern {
+        // Rust's try-catch
+        // When f(...) returns normally, the return value is null.
+        // When f(...) throws, the return value is a pointer to the caught
+        // exception object.
+        fn rust_try(f: extern "C" fn(*c_void, *c_void),
+                    code: *c_void,
+                    data: *c_void) -> *uw::_Unwind_Exception;
+    }
+}
+
+// An uninlined, unmangled function upon which to slap yer breakpoints
+#[inline(never)]
+#[no_mangle]
+fn rust_fail(cause: Box<Any:Send>) -> ! {
+    rtdebug!("begin_unwind()");
+
+    unsafe {
+        let exception = box Exception {
+            uwe: uw::_Unwind_Exception {
+                exception_class: rust_exception_class(),
+                exception_cleanup: exception_cleanup,
+                private: [0, ..uw::unwinder_private_data_size],
+            },
+            cause: Some(cause),
+        };
+        let error = uw::_Unwind_RaiseException(mem::transmute(exception));
+        rtabort!("Could not unwind stack, error = {}", error as int)
+    }
+
+    extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
+                                exception: *uw::_Unwind_Exception) {
+        rtdebug!("exception_cleanup()");
+        unsafe {
+            let _: Box<Exception> = mem::transmute(exception);
+        }
+    }
+}
+
+// Rust's exception class identifier.  This is used by personality routines to
+// determine whether the exception was thrown by their own runtime.
+fn rust_exception_class() -> uw::_Unwind_Exception_Class {
+    // M O Z \0  R U S T -- vendor, language
+    0x4d4f5a_00_52555354
+}
+
+// We could implement our personality routine in pure Rust, however exception
+// info decoding is tedious.  More importantly, personality routines have to
+// handle various platform quirks, which are not fun to maintain.  For this
+// reason, we attempt to reuse personality routine of the C language:
+// __gcc_personality_v0.
+//
+// Since C does not support exception catching, __gcc_personality_v0 simply
+// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
+// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
+//
+// This is pretty close to Rust's exception handling approach, except that Rust
+// does have a single "catch-all" handler at the bottom of each task's stack.
+// So we have two versions:
+// - rust_eh_personality, used by all cleanup landing pads, which never catches,
+//   so the behavior of __gcc_personality_v0 is perfectly adequate there, and
+// - rust_eh_personality_catch, used only by rust_try(), which always catches.
+//   This is achieved by overriding the return value in search phase to always
+//   say "catch!".
+
+#[cfg(not(target_arch = "arm"), not(test))]
+#[doc(hidden)]
+#[allow(visible_private_types)]
+pub mod eabi {
+    use uw = libunwind;
+    use libc::c_int;
+
+    extern "C" {
+        fn __gcc_personality_v0(version: c_int,
+                                actions: uw::_Unwind_Action,
+                                exception_class: uw::_Unwind_Exception_Class,
+                                ue_header: *uw::_Unwind_Exception,
+                                context: *uw::_Unwind_Context)
+            -> uw::_Unwind_Reason_Code;
+    }
+
+    #[lang="eh_personality"]
+    extern fn eh_personality(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *uw::_Unwind_Exception,
+        context: *uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_v0(version, actions, exception_class, ue_header,
+                                 context)
+        }
+    }
+
+    #[no_mangle] // referenced from rust_try.ll
+    pub extern "C" fn rust_eh_personality_catch(
+        version: c_int,
+        actions: uw::_Unwind_Action,
+        exception_class: uw::_Unwind_Exception_Class,
+        ue_header: *uw::_Unwind_Exception,
+        context: *uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                 __gcc_personality_v0(version, actions, exception_class, ue_header,
+                                      context)
+            }
+        }
+    }
+}
+
+// ARM EHABI uses a slightly different personality routine signature,
+// but otherwise works the same.
+#[cfg(target_arch = "arm", not(test))]
+#[allow(visible_private_types)]
+pub mod eabi {
+    use uw = libunwind;
+    use libc::c_int;
+
+    extern "C" {
+        fn __gcc_personality_v0(state: uw::_Unwind_State,
+                                ue_header: *uw::_Unwind_Exception,
+                                context: *uw::_Unwind_Context)
+            -> uw::_Unwind_Reason_Code;
+    }
+
+    #[lang="eh_personality"]
+    extern "C" fn eh_personality(
+        state: uw::_Unwind_State,
+        ue_header: *uw::_Unwind_Exception,
+        context: *uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        unsafe {
+            __gcc_personality_v0(state, ue_header, context)
+        }
+    }
+
+    #[no_mangle] // referenced from rust_try.ll
+    pub extern "C" fn rust_eh_personality_catch(
+        state: uw::_Unwind_State,
+        ue_header: *uw::_Unwind_Exception,
+        context: *uw::_Unwind_Context
+    ) -> uw::_Unwind_Reason_Code
+    {
+        if (state as c_int & uw::_US_ACTION_MASK as c_int)
+                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
+            uw::_URC_HANDLER_FOUND // catch!
+        }
+        else { // cleanup phase
+            unsafe {
+                 __gcc_personality_v0(state, ue_header, context)
+            }
+        }
+    }
+}
+
+// Entry point of failure from the libcore crate
+#[cfg(not(test))]
+#[lang = "begin_unwind"]
+pub extern fn rust_begin_unwind(msg: &fmt::Arguments,
+                                file: &'static str, line: uint) -> ! {
+    begin_unwind_fmt(msg, file, line)
+}
+
+/// The entry point for unwinding with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `fail!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[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).
+
+    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!().
+#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
+pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> ! {
+    // Note that this should be the only allocation performed in this code path.
+    // Currently this means that fail!() on OOM will invoke this code path,
+    // but then again we're not really ready for failing on OOM anyway. If
+    // we do start doing this, then we should propagate this allocation to
+    // be performed in the parent of this task instead of the task that's
+    // failing.
+
+    // see below for why we do the `Any` coercion here.
+    begin_unwind_inner(box msg, file, line)
+}
+
+
+/// The core of the unwinding.
+///
+/// This is non-generic to avoid instantiation bloat in other crates
+/// (which makes compilation of small crates noticably slower). (Note:
+/// we need the `Any` object anyway, we're not just creating it to
+/// avoid being generic.)
+///
+/// Do this split took the LLVM IR line counts of `fn main() { fail!()
+/// }` from ~1900/3700 (-O/no opts) to 180/590.
+#[inline(never)] #[cold] // this is the slow path, please never inline this
+fn begin_unwind_inner(msg: Box<Any:Send>,
+                      file: &'static str,
+                      line: uint) -> ! {
+    // 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);
+            }
+        }
+    };
+
+    // 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(task) => task,
+        None => rust_fail(msg),
+    };
+
+    if task.unwinder.unwinding {
+        // If a task fails while it's already unwinding then we
+        // have limited options. Currently our preference is to
+        // just abort. In the future we may consider resuming
+        // unwinding or otherwise exiting the task cleanly.
+        rterrln!("task failed during unwinding. aborting.");
+        unsafe { intrinsics::abort() }
+    }
+    task.unwinder.unwinding = true;
+
+    // Put the task back in TLS because the unwinding process may run code which
+    // requires the task. We need a handle to its unwinder, however, so after
+    // this we unsafely extract it and continue along.
+    Local::put(task);
+    rust_fail(msg);
+}
+
+/// 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
+        }
+    }
+}
diff --git a/src/librustrt/util.rs b/src/librustrt/util.rs
new file mode 100644 (file)
index 0000000..c08652c
--- /dev/null
@@ -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(); }
+}
index 1e18f2ea9ec2540153d67f55db017b750a844738..daca3005f12ffcd099463bc3211988121dba6d44 100644 (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 @@ struct Ctx {
 
 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 @@ pub fn run(loop_: &Loop, node: Option<&str>, service: Option<&str>,
         };
 
         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 @@ fn drop(&mut self) {
     }
 }
 
-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;
index 7a16baaa9f2a6bfc8e3713183d6495802e683f47..5167ce5aff2d98430b9646f2f96c6ee2d9c5d333 100644 (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 @@ pub fn new(loop_: &mut Loop, cb: Box<Callback:Send>) -> 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 @@ unsafe fn from_uv_handle<'a>(_: &'a *uvll::uv_async_t) -> &'a mut AsyncWatcher {
     // 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 @@ fn fire(&mut self) {
 
 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) }
     }
 }
 
index 7143f420b08a1b8c5bce0d685f0b1598da356f1c..4b1343045de376219398b7137b5dc6aa689ca338 100644 (file)
@@ -12,9 +12,9 @@
 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 @@ pub fn unlink(loop_: &Loop, path: &CString) -> Result<(), UvError> {
         })
     }
 
-    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 @@ pub fn chmod(loop_: &Loop, path: &CString, mode: c_int)
     }
 
     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 @@ pub fn readdir(loop_: &Loop, path: &CString, flags: c_int)
                                               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 @@ pub fn get_ptr(&self) -> *libc::c_void {
         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 @@ pub fn new(io: &mut UvIoFactory, fd: c_int,
         }
     }
 
-    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 @@ fn drop(&mut self) {
 }
 
 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 @@ fn fstat(&mut self) -> Result<FileStat, IoError> {
 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 @@ fn file_test_mk_rm_dir() {
         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());
 
index 4f565de6791d4f4aa5638c27516eca98444499de..644ac4e45f6569e62ee82b890fd0f23d3898e5a0 100644 (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 @@ fn test_homing_closes_correctly() {
         });
 
         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 @@ fn test_homing_read() {
         });
 
         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));
 
index 20893b9e84c881195d5eb22faed59362d685f645..e2122aea0365ebeb2167df272a4ace6927df9aa8 100644 (file)
 
 use libc::{c_int, c_void};
 use std::fmt;
-use std::io::IoError;
-use std::io;
 use std::mem;
 use std::ptr::null;
 use std::ptr;
 use std::rt::local::Local;
 use std::rt::rtio;
+use std::rt::rtio::{IoResult, IoError};
 use std::rt::task::{BlockedTask, Task};
 use std::str::raw::from_c_str;
-use std::str;
 use std::task;
 
 pub use self::async::AsyncWatcher;
@@ -391,40 +389,40 @@ fn error_smoke_test() {
     assert_eq!(err.to_str(), "EOF: end of file".to_string());
 }
 
+#[cfg(unix)]
 pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
-    unsafe {
-        // Importing error constants
-
-        // uv error descriptions are static
-        let UvError(errcode) = uverr;
-        let c_desc = uvll::uv_strerror(errcode);
-        let desc = str::raw::c_str_to_static_slice(c_desc);
-
-        let kind = match errcode {
-            uvll::UNKNOWN => io::OtherIoError,
-            uvll::OK => io::OtherIoError,
-            uvll::EOF => io::EndOfFile,
-            uvll::EACCES => io::PermissionDenied,
-            uvll::ECONNREFUSED => io::ConnectionRefused,
-            uvll::ECONNRESET => io::ConnectionReset,
-            uvll::ENOTCONN => io::NotConnected,
-            uvll::ENOENT => io::FileNotFound,
-            uvll::EPIPE => io::BrokenPipe,
-            uvll::ECONNABORTED => io::ConnectionAborted,
-            uvll::EADDRNOTAVAIL => io::ConnectionRefused,
-            uvll::ECANCELED => io::TimedOut,
+    let UvError(errcode) = uverr;
+    IoError {
+        code: if errcode == uvll::EOF {libc::EOF as uint} else {-errcode as uint},
+        extra: 0,
+        detail: Some(uverr.desc()),
+    }
+}
+
+#[cfg(windows)]
+pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
+    let UvError(errcode) = uverr;
+    IoError {
+        code: match errcode {
+            uvll::EOF => libc::EOF,
+            uvll::EACCES => libc::ERROR_ACCESS_DENIED,
+            uvll::ECONNREFUSED => libc::WSAECONNREFUSED,
+            uvll::ECONNRESET => libc::WSAECONNRESET,
+            uvll::ENOTCONN => libc::WSAENOTCONN,
+            uvll::ENOENT => libc::ERROR_FILE_NOT_FOUND,
+            uvll::EPIPE => libc::ERROR_NO_DATA,
+            uvll::ECONNABORTED => libc::WSAECONNABORTED,
+            uvll::EADDRNOTAVAIL => libc::WSAEADDRNOTAVAIL,
+            uvll::ECANCELED => libc::ERROR_OPERATION_ABORTED,
+            uvll::EADDRINUSE => libc::WSAEADDRINUSE,
             err => {
                 uvdebug!("uverr.code {}", err as int);
                 // FIXME: Need to map remaining uv error types
-                io::OtherIoError
+                -1
             }
-        };
-
-        IoError {
-            kind: kind,
-            desc: desc,
-            detail: None
-        }
+        } as uint,
+        extra: 0,
+        detail: Some(uverr.desc()),
     }
 }
 
@@ -437,7 +435,7 @@ pub fn status_to_maybe_uv_error(status: c_int) -> Option<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;
index 2f35e48b8476bc55507bf12c381e93bf369ee94c..e7bdc25a1fd91d6bb07ea5021998f1ba52351ccd 100644 (file)
 
 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 @@ fn new_home(loop_: &Loop, home: HomeHandle) -> 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 @@ fn home<'r>(&'r mut self) -> &'r mut HomeHandle { &mut self.home }
 }
 
 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 @@ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
 
         // 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 @@ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
         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 @@ fn drop(&mut self) {
 // 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 @@ fn uv_handle(&self) -> *uvll::uv_tcp_t { self.handle }
 }
 
 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 @@ fn home<'r>(&'r mut self) -> &'r mut HomeHandle { self.listener.home() }
 }
 
 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 @@ fn home<'r>(&'r mut self) -> &'r mut HomeHandle { &mut self.home }
 }
 
 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 @@ fn socket_name(&mut self) -> Result<ip::SocketAddr, IoError> {
 
 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 @@ fn recvfrom(&mut self, buf: &mut [u8])
         }
     }
 
-    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 @@ fn sendto(&mut self, buf: &[u8], dst: ip::SocketAddr) -> Result<(), IoError> {
         }
     }
 
-    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 @@ fn join_multicast(&mut self, multi: ip::IpAddr) -> Result<(), IoError> {
         })
     }
 
-    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 @@ struct Ctx {
 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 @@ fn connect_close_ip4() {
 
     #[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 @@ fn connect_close_ip6() {
 
     #[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 @@ fn udp_bind_close_ip4() {
 
     #[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 @@ fn udp_bind_close_ip6() {
     #[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 @@ fn listen_ip4() {
     #[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 @@ fn listen_ip6() {
     #[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 @@ fn udp_recv_ip4() {
                     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 @@ fn udp_recv_ip4() {
     #[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 @@ fn udp_recv_ip6() {
                     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 @@ fn udp_recv_ip6() {
 
     #[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 @@ fn test_read_read_read() {
         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 @@ fn test_read_read_read() {
     #[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 @@ fn test_udp_twice() {
         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 @@ fn test_udp_many_read() {
                 // 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 @@ fn test_udp_many_read() {
             // 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 @@ fn test_udp_many_read() {
 
     #[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 @@ fn test_read_and_block() {
         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 @@ fn test_read_and_block() {
 
     #[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 @@ fn test_simple_tcp_server_and_client_on_diff_threads() {
         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 @@ fn tcp_stream_fail_cleanup() {
 
     #[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
index cf3d4f672e6183b80d2576b72a57a233712f3927..e5c134b6b92687b7285f3b88935efd9158bbe104 100644 (file)
 
 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 @@ fn unwrap(mut self) -> *uvll::uv_pipe_t {
     }
 }
 
-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 @@ fn clone(&self) -> Box<RtioPipe:Send> {
             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 @@ fn close_read(&mut self) -> Result<(), IoError> {
         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 @@ pub fn bind(io: &mut UvIoFactory, name: &CString)
     }
 }
 
-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 @@ fn listen(~self) -> Result<Box<RtioUnixAcceptor:Send>, IoError> {
         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 @@ fn uv_handle(&self) -> *uvll::uv_pipe_t { self.pipe }
             });
             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 @@ fn drop(&mut self) {
 
 // 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 @@ fn connect() {
 
         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 @@ fn connect() {
         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 @@ fn connect_fail() {
 
         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();
index f6fcf3e48162fa138e251dc4cdb0d6e62862f6bc..aa87582da26d87bca60dd1c7f42b06f935cb06c6 100644 (file)
 
 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 @@ pub fn kill(pid: libc::pid_t, signum: int) -> Result<(), UvError> {
 
     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 @@ pub fn kill(pid: libc::pid_t, signum: int) -> Result<(), UvError> {
 }
 
 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 @@ fn kill(&mut self, signal: int) -> Result<(), IoError> {
         }
     }
 
-    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 {
index 98ae865cb1da32c440c52d1aa8509b2e5d7057d0..a3694bfe9c2beed46199f5a7f825f48fa636b994 100644 (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;
index b2e1c7520128b761509cc0d7baf2043ff1151c25..fd0b6acb8ae746ecef398637aeae07240f4faceb 100644 (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 @@ pub fn new(io: &mut UvIoFactory, signum: Signum, channel: Sender<Signum>)
     }
 }
 
-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 @@ fn drop(&mut self) {
         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
-    }
-}
index 15add60b59c4829e7d25853cc094c520a24a14a8..1c191d476edb9efa27750192bb823d1ea654cc89 100644 (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};
index 525539f8b36f9965699cd11f07676170499994f0..b940774323a2a57dae027e26afaf0fa07da7cfb0 100644 (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 @@ fn sleep(&mut self, msecs: u64) {
         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 @@ fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
             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 @@ fn period(&mut self, msecs: u64) -> Receiver<()> {
             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 @@ fn period(&mut self, msecs: u64) -> Receiver<()> {
             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 @@ fn period(&mut self, msecs: u64) -> Receiver<()> {
             // 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 @@ fn drop(&mut self) {
         };
     }
 }
-
-#[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);
-    }
-}
index f70c3b4c1bd7528bf8d8388a75ddfe0c013bc743..828a3d0c63b0aaea2109647706b625e2723e9cfb 100644 (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 @@ pub fn new(io: &mut UvIoFactory, fd: libc::c_int, readable: bool)
 }
 
 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 @@ fn set_raw(&mut self, raw: bool) -> Result<(), IoError> {
     }
 
     #[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;
index 71589e00fc008e5f08f68877a0e750be5db757d7..cf2a2d73d4d9f11e2b7e2efda60db9366a7e44c3 100644 (file)
 //! 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 @@ fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior)
             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 @@ fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
         }
     }
 
-    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 @@ fn spawn(&mut self, cfg: ProcessConfig)
         }
     }
 
-    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 @@ fn unix_bind(&mut self, path: &CString)
     }
 
     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 @@ fn unix_connect(&mut self, path: &CString, timeout: Option<u64>)
     }
 
     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 @@ fn tty_open(&mut self, fd: c_int, readable: bool)
     }
 
     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)),
         }
index 91c6814725144552b67c74b08e1fef3160740f2a..f6c6d6c9068e0cbbfc46a43811f50d22dd183382 100644 (file)
@@ -38,7 +38,8 @@
 use libc::uintptr_t;
 
 pub use self::errors::{EACCES, ECONNREFUSED, ECONNRESET, EPIPE, ECONNABORTED,
-                       ECANCELED, EBADF, ENOTCONN, ENOENT, EADDRNOTAVAIL};
+                       ECANCELED, EBADF, ENOTCONN, ENOENT, EADDRNOTAVAIL,
+                       EADDRINUSE};
 
 pub static OK: c_int = 0;
 pub static EOF: c_int = -4095;
@@ -61,6 +62,7 @@ pub mod errors {
     pub static ECANCELED: c_int = -4081;
     pub static EBADF: c_int = -4083;
     pub static EADDRNOTAVAIL: c_int = -4090;
+    pub static EADDRINUSE: c_int = -4091;
 }
 #[cfg(not(windows))]
 pub mod errors {
@@ -77,6 +79,7 @@ pub mod errors {
     pub static ECANCELED : c_int = -libc::ECANCELED;
     pub static EBADF : c_int = -libc::EBADF;
     pub static EADDRNOTAVAIL : c_int = -libc::EADDRNOTAVAIL;
+    pub static EADDRINUSE : c_int = -libc::EADDRINUSE;
 }
 
 pub static PROCESS_SETUID: c_int = 1 << 0;
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
deleted file mode 100644 (file)
index 4e39518..0000000
+++ /dev/null
@@ -1,817 +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.
-
-/*!
-
-C-string manipulation and management
-
-This modules provides the basic methods for creating and manipulating
-null-terminated strings for use with FFI calls (back to C). Most C APIs require
-that the string being passed to them is null-terminated, and by default rust's
-string types are *not* null terminated.
-
-The other problem with translating Rust strings to C strings is that Rust
-strings can validly contain a null-byte in the middle of the string (0 is a
-valid unicode codepoint). This means that not all Rust strings can actually be
-translated to C strings.
-
-# Creation of a C string
-
-A C string is managed through the `CString` type defined in this module. It
-"owns" the internal buffer of characters and will automatically deallocate the
-buffer when the string is dropped. The `ToCStr` trait is implemented for `&str`
-and `&[u8]`, but the conversions can fail due to some of the limitations
-explained above.
-
-This also means that currently whenever a C string is created, an allocation
-must be performed to place the data elsewhere (the lifetime of the C string is
-not tied to the lifetime of the original string/data buffer). If C strings are
-heavily used in applications, then caching may be advisable to prevent
-unnecessary amounts of allocations.
-
-An example of creating and using a C string would be:
-
-```rust
-extern crate libc;
-
-extern {
-    fn puts(s: *libc::c_char);
-}
-
-fn main() {
-    let my_string = "Hello, world!";
-
-    // Allocate the C string with an explicit local that owns the string. The
-    // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope.
-    let my_c_string = my_string.to_c_str();
-    my_c_string.with_ref(|c_buffer| {
-        unsafe { puts(c_buffer); }
-    });
-
-    // Don't save off the allocation of the C string, the `c_buffer` will be
-    // deallocated when this block returns!
-    my_string.with_c_str(|c_buffer| {
-        unsafe { puts(c_buffer); }
-    });
-}
-```
-
-*/
-
-use clone::Clone;
-use cmp::PartialEq;
-use container::Container;
-use iter::{Iterator, range};
-use kinds::marker;
-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.
-///
-/// This structure wraps a `*libc::c_char`, and will automatically free the
-/// memory it is pointing to when it goes out of scope.
-pub struct CString {
-    buf: *libc::c_char,
-    owns_buffer_: bool,
-}
-
-impl Clone for CString {
-    /// Clone this CString into a new, uniquely owned CString. For safety
-    /// reasons, this is always a deep clone, rather than the usual shallow
-    /// clone.
-    fn clone(&self) -> CString {
-        if self.buf.is_null() {
-            CString { buf: self.buf, owns_buffer_: self.owns_buffer_ }
-        } else {
-            let len = self.len() + 1;
-            let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
-            unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
-            CString { buf: buf as *libc::c_char, owns_buffer_: true }
-        }
-    }
-}
-
-impl PartialEq for CString {
-    fn eq(&self, other: &CString) -> bool {
-        if self.buf as uint == other.buf as uint {
-            true
-        } else if self.buf.is_null() || other.buf.is_null() {
-            false
-        } else {
-            unsafe {
-                libc::strcmp(self.buf, other.buf) == 0
-            }
-        }
-    }
-}
-
-impl CString {
-    /// Create a C String from a pointer.
-    pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
-        CString { buf: buf, owns_buffer_: owns_buffer }
-    }
-
-    /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
-    /// Any ownership of the buffer by the `CString` wrapper is forgotten.
-    pub unsafe fn unwrap(self) -> *libc::c_char {
-        let mut c_str = self;
-        c_str.owns_buffer_ = false;
-        c_str.buf
-    }
-
-    /// Calls a closure with a reference to the underlying `*libc::c_char`.
-    ///
-    /// # Failure
-    ///
-    /// Fails if the CString is null.
-    pub fn with_ref<T>(&self, f: |*libc::c_char| -> T) -> T {
-        if self.buf.is_null() { fail!("CString is null!"); }
-        f(self.buf)
-    }
-
-    /// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
-    ///
-    /// # Failure
-    ///
-    /// Fails if the CString is null.
-    pub fn with_mut_ref<T>(&mut self, f: |*mut libc::c_char| -> T) -> T {
-        if self.buf.is_null() { fail!("CString is null!"); }
-        f(self.buf as *mut libc::c_char)
-    }
-
-    /// Returns true if the CString is a null.
-    pub fn is_null(&self) -> bool {
-        self.buf.is_null()
-    }
-
-    /// Returns true if the CString is not null.
-    pub fn is_not_null(&self) -> bool {
-        self.buf.is_not_null()
-    }
-
-    /// Returns whether or not the `CString` owns the buffer.
-    pub fn owns_buffer(&self) -> bool {
-        self.owns_buffer_
-    }
-
-    /// Converts the CString into a `&[u8]` without copying.
-    /// Includes the terminating NUL byte.
-    ///
-    /// # Failure
-    ///
-    /// Fails if the CString is null.
-    #[inline]
-    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
-        if self.buf.is_null() { fail!("CString is null!"); }
-        unsafe {
-            mem::transmute(Slice { data: self.buf, len: self.len() + 1 })
-        }
-    }
-
-    /// Converts the CString into a `&[u8]` without copying.
-    /// Does not include the terminating NUL byte.
-    ///
-    /// # Failure
-    ///
-    /// Fails if the CString is null.
-    #[inline]
-    pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] {
-        if self.buf.is_null() { fail!("CString is null!"); }
-        unsafe {
-            mem::transmute(Slice { data: self.buf, len: self.len() })
-        }
-    }
-
-    /// Converts the CString into a `&str` without copying.
-    /// Returns None if the CString is not UTF-8.
-    ///
-    /// # Failure
-    ///
-    /// Fails if the CString is null.
-    #[inline]
-    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
-        let buf = self.as_bytes_no_nul();
-        str::from_utf8(buf)
-    }
-
-    /// Return a CString iterator.
-    ///
-    /// # Failure
-    ///
-    /// Fails if the CString is null.
-    pub fn iter<'a>(&'a self) -> CChars<'a> {
-        if self.buf.is_null() { fail!("CString is null!"); }
-        CChars {
-            ptr: self.buf,
-            marker: marker::ContravariantLifetime,
-        }
-    }
-}
-
-impl Drop for CString {
-    fn drop(&mut self) {
-        if self.owns_buffer_ {
-            unsafe {
-                libc::free(self.buf as *mut libc::c_void)
-            }
-        }
-    }
-}
-
-impl Container for CString {
-    /// Return the number of bytes in the CString (not including the NUL terminator).
-    ///
-    /// # Failure
-    ///
-    /// Fails if the CString is null.
-    #[inline]
-    fn len(&self) -> uint {
-        if self.buf.is_null() { fail!("CString is null!"); }
-        unsafe {
-            ptr::position(self.buf, |c| *c == 0)
-        }
-    }
-}
-
-/// A generic trait for converting a value to a CString.
-pub trait ToCStr {
-    /// Copy the receiver into a CString.
-    ///
-    /// # Failure
-    ///
-    /// Fails the task if the receiver has an interior null.
-    fn to_c_str(&self) -> CString;
-
-    /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
-    unsafe fn to_c_str_unchecked(&self) -> CString;
-
-    /// Work with a temporary CString constructed from the receiver.
-    /// The provided `*libc::c_char` will be freed immediately upon return.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// extern crate libc;
-    ///
-    /// fn main() {
-    ///     let s = "PATH".with_c_str(|path| unsafe {
-    ///         libc::getenv(path)
-    ///     });
-    /// }
-    /// ```
-    ///
-    /// # Failure
-    ///
-    /// Fails the task if the receiver has an interior null.
-    #[inline]
-    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
-        self.to_c_str().with_ref(f)
-    }
-
-    /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
-    #[inline]
-    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
-        self.to_c_str_unchecked().with_ref(f)
-    }
-}
-
-// FIXME (#12938): Until DST lands, we cannot decompose &str into &
-// and str, so we cannot usefully take ToCStr arguments by reference
-// (without forcing an additional & around &str). So we are instead
-// temporarily adding an instance for ~str and String, so that we can
-// take ToCStr as owned. When DST lands, the string instances should
-// be revisted, and arguments bound by ToCStr should be passed by
-// reference.
-
-impl<'a> ToCStr for &'a str {
-    #[inline]
-    fn to_c_str(&self) -> CString {
-        self.as_bytes().to_c_str()
-    }
-
-    #[inline]
-    unsafe fn to_c_str_unchecked(&self) -> CString {
-        self.as_bytes().to_c_str_unchecked()
-    }
-
-    #[inline]
-    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
-        self.as_bytes().with_c_str(f)
-    }
-
-    #[inline]
-    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
-        self.as_bytes().with_c_str_unchecked(f)
-    }
-}
-
-impl ToCStr for String {
-    #[inline]
-    fn to_c_str(&self) -> CString {
-        self.as_bytes().to_c_str()
-    }
-
-    #[inline]
-    unsafe fn to_c_str_unchecked(&self) -> CString {
-        self.as_bytes().to_c_str_unchecked()
-    }
-
-    #[inline]
-    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
-        self.as_bytes().with_c_str(f)
-    }
-
-    #[inline]
-    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
-        self.as_bytes().with_c_str_unchecked(f)
-    }
-}
-
-// The length of the stack allocated buffer for `vec.with_c_str()`
-static BUF_LEN: uint = 128;
-
-impl<'a> ToCStr for &'a [u8] {
-    fn to_c_str(&self) -> CString {
-        let mut cs = unsafe { self.to_c_str_unchecked() };
-        cs.with_mut_ref(|buf| check_for_null(*self, buf));
-        cs
-    }
-
-    unsafe fn to_c_str_unchecked(&self) -> CString {
-        let self_len = self.len();
-        let buf = malloc_raw(self_len + 1);
-
-        ptr::copy_memory(buf, self.as_ptr(), self_len);
-        *buf.offset(self_len as int) = 0;
-
-        CString::new(buf as *libc::c_char, true)
-    }
-
-    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
-        unsafe { with_c_str(*self, true, f) }
-    }
-
-    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
-        with_c_str(*self, false, f)
-    }
-}
-
-// Unsafe function that handles possibly copying the &[u8] into a stack array.
-unsafe fn with_c_str<T>(v: &[u8], checked: bool, f: |*libc::c_char| -> T) -> T {
-    if v.len() < BUF_LEN {
-        let mut buf: [u8, .. BUF_LEN] = mem::uninitialized();
-        slice::bytes::copy_memory(buf, v);
-        buf[v.len()] = 0;
-
-        let buf = buf.as_mut_ptr();
-        if checked {
-            check_for_null(v, buf as *mut libc::c_char);
-        }
-
-        f(buf as *libc::c_char)
-    } else if checked {
-        v.to_c_str().with_ref(f)
-    } else {
-        v.to_c_str_unchecked().with_ref(f)
-    }
-}
-
-#[inline]
-fn check_for_null(v: &[u8], buf: *mut libc::c_char) {
-    for i in range(0, v.len()) {
-        unsafe {
-            let p = buf.offset(i as int);
-            assert!(*p != 0);
-        }
-    }
-}
-
-/// External iterator for a CString's bytes.
-///
-/// Use with the `std::iter` module.
-pub struct CChars<'a> {
-    ptr: *libc::c_char,
-    marker: marker::ContravariantLifetime<'a>,
-}
-
-impl<'a> Iterator<libc::c_char> for CChars<'a> {
-    fn next(&mut self) -> Option<libc::c_char> {
-        let ch = unsafe { *self.ptr };
-        if ch == 0 {
-            None
-        } else {
-            self.ptr = unsafe { self.ptr.offset(1) };
-            Some(ch)
-        }
-    }
-}
-
-/// Parses a C "multistring", eg windows env values or
-/// the req->ptr result in a uv_fs_readdir() call.
-///
-/// Optionally, a `count` can be passed in, limiting the
-/// parsing to only being done `count`-times.
-///
-/// The specified closure is invoked with each string that
-/// is found, and the number of strings found is returned.
-pub unsafe fn from_c_multistring(buf: *libc::c_char,
-                                 count: Option<uint>,
-                                 f: |&CString|) -> uint {
-
-    let mut curr_ptr: uint = buf as uint;
-    let mut ctr = 0;
-    let (limited_count, limit) = match count {
-        Some(limit) => (true, limit),
-        None => (false, 0)
-    };
-    while ((limited_count && ctr < limit) || !limited_count)
-          && *(curr_ptr as *libc::c_char) != 0 as libc::c_char {
-        let cstr = CString::new(curr_ptr as *libc::c_char, false);
-        f(&cstr);
-        curr_ptr += cstr.len() + 1;
-        ctr += 1;
-    }
-    return ctr;
-}
-
-#[cfg(test)]
-mod tests {
-    use prelude::*;
-    use super::*;
-    use libc;
-    use ptr;
-    use str::StrSlice;
-
-    #[test]
-    fn test_str_multistring_parsing() {
-        unsafe {
-            let input = bytes!("zero", "\x00", "one", "\x00", "\x00");
-            let ptr = input.as_ptr();
-            let expected = ["zero", "one"];
-            let mut it = expected.iter();
-            let result = from_c_multistring(ptr as *libc::c_char, None, |c| {
-                let cbytes = c.as_bytes_no_nul();
-                assert_eq!(cbytes, it.next().unwrap().as_bytes());
-            });
-            assert_eq!(result, 2);
-            assert!(it.next().is_none());
-        }
-    }
-
-    #[test]
-    fn test_str_to_c_str() {
-        "".to_c_str().with_ref(|buf| {
-            unsafe {
-                assert_eq!(*buf.offset(0), 0);
-            }
-        });
-
-        "hello".to_c_str().with_ref(|buf| {
-            unsafe {
-                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
-                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
-                assert_eq!(*buf.offset(2), 'l' as libc::c_char);
-                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
-                assert_eq!(*buf.offset(4), 'o' as libc::c_char);
-                assert_eq!(*buf.offset(5), 0);
-            }
-        })
-    }
-
-    #[test]
-    fn test_vec_to_c_str() {
-        let b: &[u8] = [];
-        b.to_c_str().with_ref(|buf| {
-            unsafe {
-                assert_eq!(*buf.offset(0), 0);
-            }
-        });
-
-        let _ = bytes!("hello").to_c_str().with_ref(|buf| {
-            unsafe {
-                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
-                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
-                assert_eq!(*buf.offset(2), 'l' as libc::c_char);
-                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
-                assert_eq!(*buf.offset(4), 'o' as libc::c_char);
-                assert_eq!(*buf.offset(5), 0);
-            }
-        });
-
-        let _ = bytes!("foo", 0xff).to_c_str().with_ref(|buf| {
-            unsafe {
-                assert_eq!(*buf.offset(0), 'f' as libc::c_char);
-                assert_eq!(*buf.offset(1), 'o' as libc::c_char);
-                assert_eq!(*buf.offset(2), 'o' as libc::c_char);
-                assert_eq!(*buf.offset(3), 0xff as i8);
-                assert_eq!(*buf.offset(4), 0);
-            }
-        });
-    }
-
-    #[test]
-    fn test_is_null() {
-        let c_str = unsafe { CString::new(ptr::null(), false) };
-        assert!(c_str.is_null());
-        assert!(!c_str.is_not_null());
-    }
-
-    #[test]
-    fn test_unwrap() {
-        let c_str = "hello".to_c_str();
-        unsafe { libc::free(c_str.unwrap() as *mut libc::c_void) }
-    }
-
-    #[test]
-    fn test_with_ref() {
-        let c_str = "hello".to_c_str();
-        let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
-        assert!(!c_str.is_null());
-        assert!(c_str.is_not_null());
-        assert_eq!(len, 5);
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_with_ref_empty_fail() {
-        let c_str = unsafe { CString::new(ptr::null(), false) };
-        c_str.with_ref(|_| ());
-    }
-
-    #[test]
-    fn test_iterator() {
-        let c_str = "".to_c_str();
-        let mut iter = c_str.iter();
-        assert_eq!(iter.next(), None);
-
-        let c_str = "hello".to_c_str();
-        let mut iter = c_str.iter();
-        assert_eq!(iter.next(), Some('h' as libc::c_char));
-        assert_eq!(iter.next(), Some('e' as libc::c_char));
-        assert_eq!(iter.next(), Some('l' as libc::c_char));
-        assert_eq!(iter.next(), Some('l' as libc::c_char));
-        assert_eq!(iter.next(), Some('o' as libc::c_char));
-        assert_eq!(iter.next(), None);
-    }
-
-    #[test]
-    fn test_to_c_str_fail() {
-        use task;
-        assert!(task::try(proc() { "he\x00llo".to_c_str() }).is_err());
-    }
-
-    #[test]
-    fn test_to_c_str_unchecked() {
-        unsafe {
-            "he\x00llo".to_c_str_unchecked().with_ref(|buf| {
-                assert_eq!(*buf.offset(0), 'h' as libc::c_char);
-                assert_eq!(*buf.offset(1), 'e' as libc::c_char);
-                assert_eq!(*buf.offset(2), 0);
-                assert_eq!(*buf.offset(3), 'l' as libc::c_char);
-                assert_eq!(*buf.offset(4), 'l' as libc::c_char);
-                assert_eq!(*buf.offset(5), 'o' as libc::c_char);
-                assert_eq!(*buf.offset(6), 0);
-            })
-        }
-    }
-
-    #[test]
-    fn test_as_bytes() {
-        let c_str = "hello".to_c_str();
-        assert_eq!(c_str.as_bytes(), bytes!("hello", 0));
-        let c_str = "".to_c_str();
-        assert_eq!(c_str.as_bytes(), bytes!(0));
-        let c_str = bytes!("foo", 0xff).to_c_str();
-        assert_eq!(c_str.as_bytes(), bytes!("foo", 0xff, 0));
-    }
-
-    #[test]
-    fn test_as_bytes_no_nul() {
-        let c_str = "hello".to_c_str();
-        assert_eq!(c_str.as_bytes_no_nul(), bytes!("hello"));
-        let c_str = "".to_c_str();
-        let exp: &[u8] = [];
-        assert_eq!(c_str.as_bytes_no_nul(), exp);
-        let c_str = bytes!("foo", 0xff).to_c_str();
-        assert_eq!(c_str.as_bytes_no_nul(), bytes!("foo", 0xff));
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_as_bytes_fail() {
-        let c_str = unsafe { CString::new(ptr::null(), false) };
-        c_str.as_bytes();
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_as_bytes_no_nul_fail() {
-        let c_str = unsafe { CString::new(ptr::null(), false) };
-        c_str.as_bytes_no_nul();
-    }
-
-    #[test]
-    fn test_as_str() {
-        let c_str = "hello".to_c_str();
-        assert_eq!(c_str.as_str(), Some("hello"));
-        let c_str = "".to_c_str();
-        assert_eq!(c_str.as_str(), Some(""));
-        let c_str = bytes!("foo", 0xff).to_c_str();
-        assert_eq!(c_str.as_str(), None);
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_as_str_fail() {
-        let c_str = unsafe { CString::new(ptr::null(), false) };
-        c_str.as_str();
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_len_fail() {
-        let c_str = unsafe { CString::new(ptr::null(), false) };
-        c_str.len();
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_iter_fail() {
-        let c_str = unsafe { CString::new(ptr::null(), false) };
-        c_str.iter();
-    }
-
-    #[test]
-    fn test_clone() {
-        let a = "hello".to_c_str();
-        let b = a.clone();
-        assert!(a == b);
-    }
-
-    #[test]
-    fn test_clone_noleak() {
-        fn foo(f: |c: &CString|) {
-            let s = "test".to_string();
-            let c = s.to_c_str();
-            // give the closure a non-owned CString
-            let mut c_ = c.with_ref(|c| unsafe { CString::new(c, false) } );
-            f(&c_);
-            // muck with the buffer for later printing
-            c_.with_mut_ref(|c| unsafe { *c = 'X' as libc::c_char } );
-        }
-
-        let mut c_: Option<CString> = None;
-        foo(|c| {
-            c_ = Some(c.clone());
-            c.clone();
-            // force a copy, reading the memory
-            c.as_bytes().to_owned();
-        });
-        let c_ = c_.unwrap();
-        // force a copy, reading the memory
-        c_.as_bytes().to_owned();
-    }
-
-    #[test]
-    fn test_clone_eq_null() {
-        let x = unsafe { CString::new(ptr::null(), false) };
-        let y = x.clone();
-        assert!(x == y);
-    }
-}
-
-#[cfg(test)]
-mod bench {
-    extern crate test;
-    use self::test::Bencher;
-    use libc;
-    use prelude::*;
-
-    #[inline]
-    fn check(s: &str, c_str: *libc::c_char) {
-        let s_buf = s.as_ptr();
-        for i in range(0, s.len()) {
-            unsafe {
-                assert_eq!(
-                    *s_buf.offset(i as int) as libc::c_char,
-                    *c_str.offset(i as int));
-            }
-        }
-    }
-
-    static s_short: &'static str = "Mary";
-    static s_medium: &'static str = "Mary had a little lamb";
-    static s_long: &'static str = "\
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb
-        Mary had a little lamb, Little lamb";
-
-    fn bench_to_str(b: &mut Bencher, s: &str) {
-        b.iter(|| {
-            let c_str = s.to_c_str();
-            c_str.with_ref(|c_str_buf| check(s, c_str_buf))
-        })
-    }
-
-    #[bench]
-    fn bench_to_c_str_short(b: &mut Bencher) {
-        bench_to_str(b, s_short)
-    }
-
-    #[bench]
-    fn bench_to_c_str_medium(b: &mut Bencher) {
-        bench_to_str(b, s_medium)
-    }
-
-    #[bench]
-    fn bench_to_c_str_long(b: &mut Bencher) {
-        bench_to_str(b, s_long)
-    }
-
-    fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) {
-        b.iter(|| {
-            let c_str = unsafe { s.to_c_str_unchecked() };
-            c_str.with_ref(|c_str_buf| check(s, c_str_buf))
-        })
-    }
-
-    #[bench]
-    fn bench_to_c_str_unchecked_short(b: &mut Bencher) {
-        bench_to_c_str_unchecked(b, s_short)
-    }
-
-    #[bench]
-    fn bench_to_c_str_unchecked_medium(b: &mut Bencher) {
-        bench_to_c_str_unchecked(b, s_medium)
-    }
-
-    #[bench]
-    fn bench_to_c_str_unchecked_long(b: &mut Bencher) {
-        bench_to_c_str_unchecked(b, s_long)
-    }
-
-    fn bench_with_c_str(b: &mut Bencher, s: &str) {
-        b.iter(|| {
-            s.with_c_str(|c_str_buf| check(s, c_str_buf))
-        })
-    }
-
-    #[bench]
-    fn bench_with_c_str_short(b: &mut Bencher) {
-        bench_with_c_str(b, s_short)
-    }
-
-    #[bench]
-    fn bench_with_c_str_medium(b: &mut Bencher) {
-        bench_with_c_str(b, s_medium)
-    }
-
-    #[bench]
-    fn bench_with_c_str_long(b: &mut Bencher) {
-        bench_with_c_str(b, s_long)
-    }
-
-    fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) {
-        b.iter(|| {
-            unsafe {
-                s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf))
-            }
-        })
-    }
-
-    #[bench]
-    fn bench_with_c_str_unchecked_short(b: &mut Bencher) {
-        bench_with_c_str_unchecked(b, s_short)
-    }
-
-    #[bench]
-    fn bench_with_c_str_unchecked_medium(b: &mut Bencher) {
-        bench_with_c_str_unchecked(b, s_medium)
-    }
-
-    #[bench]
-    fn bench_with_c_str_unchecked_long(b: &mut Bencher) {
-        bench_with_c_str_unchecked(b, s_long)
-    }
-}
diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs
deleted file mode 100644 (file)
index 2e51931..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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);
-    }
-}
index 3fde584a46f719096f87474a7ea947981e3c4218..f4eeebeeea06fe6f903da27ec7cf325a164d2f06 100644 (file)
 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;
 
index 819e885526cbf5f31852a6a15bec0ac9c470797b..7fe505573b799bb12257a682a043fe6fde04df5d 100644 (file)
 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> {
diff --git a/src/libstd/failure.rs b/src/libstd/failure.rs
new file mode 100644 (file)
index 0000000..903f39c
--- /dev/null
@@ -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;
+}
index a77c7107f282f39785dbf5b795f58eed6f669eaf..49e8d37923661bf2c614768af0ebbb8d139e4a81 100644 (file)
 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 @@ pub fn open_mode(path: &Path,
                     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 @@ pub fn path<'a>(&'a self) -> &'a Path {
     /// 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 @@ pub fn fsync(&mut self) -> IoResult<()> {
     /// 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 @@ pub fn datasync(&mut self) -> IoResult<()> {
     /// 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 @@ pub fn eof(&self) -> bool {
 
     /// 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 @@ pub fn stat(&mut self) -> IoResult<FileStat> {
 /// 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 @@ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
                     _ => 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)),
         }
     }
 }
index 78700d353afd8fd65f3c64e396c1215964ad154a..c72cc0ded9bc3ca7c5f0210de3de15f75c394302 100644 (file)
@@ -225,6 +225,7 @@ fn file_product(p: &Path) -> IoResult<u32> {
 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 @@ fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
                 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 @@ fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
                 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 @@ fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
                 libc::EADDRINUSE => (ConnectionRefused, "address in use"),
                 libc::ENOENT => (FileNotFound, "no such file or directory"),
                 libc::EISDIR => (InvalidInput, "illegal operation on a directory"),
-
-                // These two constants can have the same value on some systems, but
-                // different values on others, so we can't use a match clause
+                libc::ENOSYS => (IoUnavailable, "function not implemented"),
+                libc::EINVAL => (InvalidInput, "invalid argument"),
+                libc::ENOTTY =>
+                    (MismatchedFileTypeForOperation,
+                     "file descriptor is not a TTY"),
+                libc::ETIMEDOUT => (TimedOut, "operation timed out"),
+                libc::ECANCELED => (TimedOut, "operation aborted"),
+
+                // These two constants can have the same value on some systems,
+                // but different values on others, so we can't use a match
+                // clause
                 x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
                     (ResourceUnavailable, "resource temporarily unavailable"),
 
@@ -382,6 +400,17 @@ fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
     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 {
index 879c66e0769d8eaecf80f54ed982df9d26964760..8d5fd2b99fd7b6e2fdff9997ffe3bb8f0a27a722 100644 (file)
 #![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
index 1939d6537521fd3aa90bd76f3dc289d36df655a6..54af83462eed6dd35a3c8272f42ed0b41164e625 100644 (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;
 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)
+        }
+    }
+}
index ac17bc1de13799b1c9da39122f50acc947bee69b..6c773467553d2f055d46a744cc3a251521bd1413 100644 (file)
@@ -32,6 +32,7 @@
 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 @@ pub fn connect(host: &str, port: u16) -> IoResult<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 @@ pub fn connect(host: &str, port: u16) -> IoResult<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 @@ pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> {
             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 @@ pub fn set_keepalive(&mut self, delay_in_seconds: Option<uint>) -> IoResult<()>
         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 @@ pub fn set_keepalive(&mut self, delay_in_seconds: Option<uint>) -> IoResult<()>
     ///
     /// 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 @@ pub fn close_read(&mut self) -> IoResult<()> { self.obj.close_read() }
     ///
     /// 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 @@ fn clone(&self) -> 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 @@ pub fn bind(addr: &str, port: u16) -> IoResult<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 @@ pub fn peer_name(addr: SocketAddr) {
         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);
             }
         }
     })
index 875dd01be823bfcf6f99bb6235824a98e2f65b61..538bba36958115447410a84c59f2ed5e274068d8 100644 (file)
 
 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 @@ pub fn connect(self, other: SocketAddr) -> UdpStream {
 
     /// 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 @@ pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> {
             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 @@ pub fn set_broadast(&mut self, broadcast: bool) -> IoResult<()> {
             self.obj.hear_broadcasts()
         } else {
             self.obj.ignore_broadcasts()
-        }
+        }.map_err(IoError::from_rtio_error)
     }
 
     /// Sets the read/write timeout for this socket.
index 1e320fe1aaed467f115733b9a1327d45d9e7a16e..9715a821e4fcba5d17704f83c4e5de5dcdea4977 100644 (file)
@@ -28,7 +28,7 @@
 
 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 @@ pub fn connect_timeout<P: ToCStr>(path: &P,
         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 @@ pub fn connect_timeout<P: ToCStr>(path: &P,
     ///
     /// 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 @@ pub fn close_read(&mut self) -> IoResult<()> { self.obj.close_read() }
     ///
     /// 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 @@ fn clone(&self) -> 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 @@ pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
 
 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)
     }
 }
 
index fbb0d5bc8d8ed0f8756652230d77a3b401dd99da..11bb27573c29afece830187f28e270c62c839a28 100644 (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 @@ fn clone(&self) -> 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)]
index 1ed465935621899f15f85f8d2ab340fb09f4547c..059286339a6fa2db624ed892dc33b838737e4099 100644 (file)
 
 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 @@ pub fn detached<'a>(&'a mut self) -> &'a mut 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 @@ pub fn spawn(&self) -> IoResult<Process> {
                     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 @@ pub fn id(&self) -> libc::pid_t { self.handle.id() }
     ///
     /// 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 @@ pub fn signal_kill(&mut self) -> IoResult<()> {
     /// `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().
index 05392baff04c30363b5f8a88e66ff03a79db5632..598a8667d41e93a4d4e4fab53a3e702c55b717b9 100644 (file)
@@ -28,7 +28,7 @@
 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 @@ pub fn new() -> 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))
         }
     }
 
index 6de4c6316d1df1112253d07f03e5dc332feae352..5db09076c98e0316e67ecee567d5861e433bbff7 100644 (file)
 
 */
 
+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 @@ fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
                 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 @@ pub fn winsize(&mut self) -> IoResult<(int, int)> {
     /// 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 @@ fn write(&mut self, buf: &[u8]) -> IoResult<()> {
         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();
index d7476dd2de8746d9a3070024c55ab7cdd3cb2623..78b8e55c65174419db0b87f0b26642e1edf4f2de 100644 (file)
 
 */
 
-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 @@ pub fn sleep(&mut self, msecs: u64) {
     /// 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 @@ pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
     /// 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(());
     }
 }
 
index 109832b7c4795b88b0f99fa270dd5a694b103b24..bac4d26b4e49a6e8ce114fd5ce816efd671c449b 100644 (file)
        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]
 
 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";
 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 @@ fn start(argc: int, argv: **u8) -> int {
 
 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 @@ fn start(argc: int, argv: **u8) -> int {
 // but name resolution doesn't work without it being pub.
 #[unstable]
 pub mod rt;
-
-#[doc(hidden)]
-pub fn issue_14344_workaround() { // FIXME #14344 force linkage to happen correctly
-    libc::issue_14344_workaround();
-}
+mod failure;
 
 // A curious inner-module that's not exported that contains the binding
 // 'std' so that macro-expanded references to std::error and such
diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs
deleted file mode 100644 (file)
index 930d1df..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-// Copyright 2012-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.
-
-/*!
-
-Task local data management
-
-Allows storing arbitrary types inside task-local-storage (TLS), to be accessed
-anywhere within a task, keyed by a global pointer parameterized over the type of
-the TLS slot.  Useful for dynamic variables, singletons, and interfacing with
-foreign code with bad callback interfaces.
-
-To declare a new key for storing local data of a particular type, use the
-`local_data_key!` macro. This macro will expand to a `static` item appropriately
-named and annotated. This name is then passed to the functions in this module to
-modify/read the slot specified by the key.
-
-```rust
-local_data_key!(key_int: int)
-local_data_key!(key_vector: ~[int])
-
-key_int.replace(Some(3));
-assert_eq!(*key_int.get().unwrap(), 3);
-
-key_vector.replace(Some(~[4]));
-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;
-
-/**
- * Indexes a task-local data slot. This pointer is used for comparison to
- * differentiate keys from one another. The actual type `T` is not used anywhere
- * as a member of this type, except that it is parameterized with it to define
- * the type of each key's value.
- *
- * The value of each Key is of the singleton enum KeyValue. These also have the
- * same name as `Key` and their purpose is to take up space in the programs data
- * sections to ensure that each value of the `Key` type points to a unique
- * location.
- */
-pub type Key<T> = &'static KeyValue<T>;
-
-#[allow(missing_doc)]
-pub enum KeyValue<T> { Key }
-
-#[doc(hidden)]
-trait LocalData {}
-impl<T: 'static> LocalData for T {}
-
-// The task-local-map stores all TLS information for the currently running task.
-// It is stored as an owned pointer into the runtime, and it's only allocated
-// when TLS is used for the first time. This map must be very carefully
-// constructed because it has many mutable loans unsoundly handed out on it to
-// the various invocations of TLS requests.
-//
-// One of the most important operations is loaning a value via `get` to a
-// caller. In doing so, the slot that the TLS entry is occupying cannot be
-// invalidated because upon returning its loan state must be updated. Currently
-// the TLS map is a vector, but this is possibly dangerous because the vector
-// can be reallocated/moved when new values are pushed onto it.
-//
-// This problem currently isn't solved in a very elegant way. Inside the `get`
-// function, it internally "invalidates" all references after the loan is
-// finished and looks up into the vector again. In theory this will prevent
-// pointers from being moved under our feet so long as LLVM doesn't go too crazy
-// with the optimizations.
-//
-// n.b. If TLS is used heavily in future, this could be made more efficient with
-//      a proper map.
-#[doc(hidden)]
-pub type Map = Vec<Option<(*u8, TLSValue, uint)>>;
-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();
-    match &mut (*task).storage {
-        // If the at_exit function is already set, then we just need to take
-        // a loan out on the TLS map stored inside
-        &LocalStorage(Some(ref mut map_ptr)) => {
-            return Some(map_ptr);
-        }
-        // 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!());
-            match *slot {
-                Some(ref mut map_ptr) => { return Some(map_ptr) }
-                None => unreachable!(),
-            }
-        }
-    }
-}
-
-fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
-    key as *KeyValue<T> as *u8
-}
-
-/// An RAII immutable reference to a task-local value.
-///
-/// The task-local data can be accessed through this value, and when this
-/// structure is dropped it will return the borrow on the data.
-pub struct Ref<T> {
-    // FIXME #12808: strange names to try to avoid interfering with
-    // field accesses of the contained type via Deref
-    _ptr: &'static T,
-    _key: Key<T>,
-    _index: uint,
-    _nosend: marker::NoSend,
-}
-
-impl<T: 'static> KeyValue<T> {
-    /// Replaces a value in task local storage.
-    ///
-    /// If this key is already present in TLS, then the previous value is
-    /// replaced with the provided data, and then returned.
-    ///
-    /// # Failure
-    ///
-    /// This function will fail if this key is present in TLS and currently on
-    /// loan with the `get` method.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// local_data_key!(foo: int)
-    ///
-    /// assert_eq!(foo.replace(Some(10)), None);
-    /// assert_eq!(foo.replace(Some(4)), Some(10));
-    /// assert_eq!(foo.replace(None), Some(4));
-    /// ```
-    pub fn replace(&'static self, data: Option<T>) -> Option<T> {
-        let map = match unsafe { get_local_map() } {
-            Some(map) => map,
-            None => fail!("must have a local task to insert into TLD"),
-        };
-        let keyval = key_to_key_value(self);
-
-        // When the task-local map is destroyed, all the data needs to be
-        // cleaned up. For this reason we can't do some clever tricks to store
-        // '~T' as a '*c_void' or something like that. To solve the problem, we
-        // cast everything to a trait (LocalData) which is then stored inside
-        // the map.  Upon destruction of the map, all the objects will be
-        // destroyed and the traits have enough information about them to
-        // destroy themselves.
-        //
-        // Additionally, the type of the local data map must ascribe to Send, so
-        // we do the transmute here to add the Send bound back on. This doesn't
-        // actually matter because TLS will always own the data (until its moved
-        // out) and we're not actually sending it to other schedulers or
-        // anything.
-        let newval = data.map(|d| {
-            let d = box d as Box<LocalData>;
-            let d: Box<LocalData:Send> = unsafe { mem::transmute(d) };
-            (keyval, d, 0)
-        });
-
-        let pos = match self.find(map) {
-            Some((i, _, &0)) => Some(i),
-            Some((_, _, _)) => fail!("TLS value cannot be replaced because it \
-                                      is already borrowed"),
-            None => map.iter().position(|entry| entry.is_none()),
-        };
-
-        match pos {
-            Some(i) => {
-                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) };
-                    let alloc: Box<T> = unsafe { mem::transmute(t.data) };
-
-                    // Now that we own `alloc`, we can just move out of it as we
-                    // would with any other data.
-                    *alloc
-                })
-            }
-            None => {
-                map.push(newval);
-                None
-            }
-        }
-    }
-
-    /// Borrows a value from TLS.
-    ///
-    /// If `None` is returned, then this key is not present in TLS. If `Some` is
-    /// returned, then the returned data is a smart pointer representing a new
-    /// loan on this TLS key. While on loan, this key cannot be altered via the
-    /// `replace` method.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// local_data_key!(key: int)
-    ///
-    /// assert!(key.get().is_none());
-    ///
-    /// key.replace(Some(3));
-    /// assert_eq!(*key.get().unwrap(), 3);
-    /// ```
-    pub fn get(&'static self) -> Option<Ref<T>> {
-        let map = match unsafe { get_local_map() } {
-            Some(map) => map,
-            None => return None,
-        };
-
-        self.find(map).map(|(pos, data, loan)| {
-            *loan += 1;
-
-            // data was created with `~T as ~LocalData`, so we extract
-            // pointer part of the trait, (as ~T), and then use
-            // compiler coercions to achieve a '&' pointer.
-            let ptr = unsafe {
-                let data = data as *Box<LocalData:Send> as *raw::TraitObject;
-                &mut *((*data).data as *mut T)
-            };
-            Ref { _ptr: ptr, _index: pos, _nosend: marker::NoSend, _key: self }
-        })
-    }
-
-    fn find<'a>(&'static self,
-                map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
-        let key_value = key_to_key_value(self);
-        map.mut_iter().enumerate().filter_map(|(i, entry)| {
-            match *entry {
-                Some((k, ref data, ref mut loan)) if k == key_value => {
-                    Some((i, data, loan))
-                }
-                _ => None
-            }
-        }).next()
-    }
-}
-
-impl<T: 'static> Deref<T> for Ref<T> {
-    fn deref<'a>(&'a self) -> &'a T { self._ptr }
-}
-
-#[unsafe_destructor]
-impl<T: 'static> Drop for Ref<T> {
-    fn drop(&mut self) {
-        let map = unsafe { get_local_map().unwrap() };
-
-        let (_, _, ref mut loan) = *map.get_mut(self._index).get_mut_ref();
-        *loan -= 1;
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use prelude::*;
-    use super::*;
-    use owned::Box;
-    use task;
-
-    #[test]
-    fn test_tls_multitask() {
-        static my_key: Key<String> = &Key;
-        my_key.replace(Some("parent data".to_string()));
-        task::spawn(proc() {
-            // TLS shouldn't carry over.
-            assert!(my_key.get().is_none());
-            my_key.replace(Some("child data".to_string()));
-            assert!(my_key.get().get_ref().as_slice() == "child data");
-            // should be cleaned up for us
-        });
-
-        // Must work multiple times
-        assert!(my_key.get().unwrap().as_slice() == "parent data");
-        assert!(my_key.get().unwrap().as_slice() == "parent data");
-        assert!(my_key.get().unwrap().as_slice() == "parent data");
-    }
-
-    #[test]
-    fn test_tls_overwrite() {
-        static my_key: Key<String> = &Key;
-        my_key.replace(Some("first data".to_string()));
-        my_key.replace(Some("next data".to_string())); // Shouldn't leak.
-        assert!(my_key.get().unwrap().as_slice() == "next data");
-    }
-
-    #[test]
-    fn test_tls_pop() {
-        static my_key: Key<String> = &Key;
-        my_key.replace(Some("weasel".to_string()));
-        assert!(my_key.replace(None).unwrap() == "weasel".to_string());
-        // Pop must remove the data from the map.
-        assert!(my_key.replace(None).is_none());
-    }
-
-    #[test]
-    fn test_tls_crust_automorestack_memorial_bug() {
-        // This might result in a stack-canary clobber if the runtime fails to
-        // set sp_limit to 0 when calling the cleanup extern - it might
-        // automatically jump over to the rust stack, which causes next_c_sp
-        // to get recorded as something within a rust stack segment. Then a
-        // subsequent upcall (esp. for logging, think vsnprintf) would run on
-        // a stack smaller than 1 MB.
-        static my_key: Key<String> = &Key;
-        task::spawn(proc() {
-            my_key.replace(Some("hax".to_string()));
-        });
-    }
-
-    #[test]
-    fn test_tls_multiple_types() {
-        static str_key: Key<String> = &Key;
-        static box_key: Key<@()> = &Key;
-        static int_key: Key<int> = &Key;
-        task::spawn(proc() {
-            str_key.replace(Some("string data".to_string()));
-            box_key.replace(Some(@()));
-            int_key.replace(Some(42));
-        });
-    }
-
-    #[test]
-    fn test_tls_overwrite_multiple_types() {
-        static str_key: Key<String> = &Key;
-        static box_key: Key<@()> = &Key;
-        static int_key: Key<int> = &Key;
-        task::spawn(proc() {
-            str_key.replace(Some("string data".to_string()));
-            str_key.replace(Some("string data 2".to_string()));
-            box_key.replace(Some(@()));
-            box_key.replace(Some(@()));
-            int_key.replace(Some(42));
-            // This could cause a segfault if overwriting-destruction is done
-            // with the crazy polymorphic transmute rather than the provided
-            // finaliser.
-            int_key.replace(Some(31337));
-        });
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_tls_cleanup_on_failure() {
-        static str_key: Key<String> = &Key;
-        static box_key: Key<@()> = &Key;
-        static int_key: Key<int> = &Key;
-        str_key.replace(Some("parent data".to_string()));
-        box_key.replace(Some(@()));
-        task::spawn(proc() {
-            str_key.replace(Some("string data".to_string()));
-            box_key.replace(Some(@()));
-            int_key.replace(Some(42));
-            fail!();
-        });
-        // Not quite nondeterministic.
-        int_key.replace(Some(31337));
-        fail!();
-    }
-
-    #[test]
-    fn test_static_pointer() {
-        static key: Key<&'static int> = &Key;
-        static VALUE: int = 0;
-        key.replace(Some(&VALUE));
-    }
-
-    #[test]
-    fn test_owned() {
-        static key: Key<Box<int>> = &Key;
-        key.replace(Some(box 1));
-
-        {
-            let k1 = key.get().unwrap();
-            let k2 = key.get().unwrap();
-            let k3 = key.get().unwrap();
-            assert_eq!(**k1, 1);
-            assert_eq!(**k2, 1);
-            assert_eq!(**k3, 1);
-        }
-        key.replace(Some(box 2));
-        assert_eq!(**key.get().unwrap(), 2);
-    }
-
-    #[test]
-    fn test_same_key_type() {
-        static key1: Key<int> = &Key;
-        static key2: Key<int> = &Key;
-        static key3: Key<int> = &Key;
-        static key4: Key<int> = &Key;
-        static key5: Key<int> = &Key;
-        key1.replace(Some(1));
-        key2.replace(Some(2));
-        key3.replace(Some(3));
-        key4.replace(Some(4));
-        key5.replace(Some(5));
-
-        assert_eq!(*key1.get().unwrap(), 1);
-        assert_eq!(*key2.get().unwrap(), 2);
-        assert_eq!(*key3.get().unwrap(), 3);
-        assert_eq!(*key4.get().unwrap(), 4);
-        assert_eq!(*key5.get().unwrap(), 5);
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_nested_get_set1() {
-        static key: Key<int> = &Key;
-        key.replace(Some(4));
-
-        let _k = key.get();
-        key.replace(Some(4));
-    }
-}
index 381ebc082006470532e48f591d6bc10643191af4..9a7e061c47282b260cc02b6ec79746e1a1c4d1fa 100644 (file)
@@ -189,7 +189,7 @@ pub fn as_mut_utf16_p<T>(s: &str, f: |*mut u16| -> T) -> T {
 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;
 
diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs
deleted file mode 100644 (file)
index e016c9d..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2012-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.
-
-//! Global storage for command line arguments
-//!
-//! The current incarnation of the Rust runtime expects for
-//! the processes `argc` and `argv` arguments to be stored
-//! in a globally-accessible location for use by the `os` module.
-//!
-//! Only valid to call on linux. Mac and Windows use syscalls to
-//! 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;
-
-/// One-time global initialization.
-pub unsafe fn init(argc: int, argv: **u8) { imp::init(argc, argv) }
-
-/// One-time global cleanup.
-pub unsafe fn cleanup() { imp::cleanup() }
-
-/// Take the global arguments from global storage.
-pub fn take() -> Option<Vec<Vec<u8>>> { imp::take() }
-
-/// Give the global arguments to global storage.
-///
-/// It is an error if the arguments already exist.
-pub fn put(args: Vec<Vec<u8>>) { imp::put(args) }
-
-/// Make a clone of the global arguments.
-pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
-
-#[cfg(target_os = "linux")]
-#[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;
-
-    static mut global_args_ptr: uint = 0;
-    static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
-
-    pub unsafe fn init(argc: int, argv: **u8) {
-        let args = load_argc_and_argv(argc, argv);
-        put(args);
-    }
-
-    pub unsafe fn cleanup() {
-        rtassert!(take().is_some());
-        lock.destroy();
-    }
-
-    pub fn take() -> Option<Vec<Vec<u8>>> {
-        with_lock(|| unsafe {
-            let ptr = get_global_ptr();
-            let val = mem::replace(&mut *ptr, None);
-            val.as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
-        })
-    }
-
-    pub fn put(args: Vec<Vec<u8>>) {
-        with_lock(|| unsafe {
-            let ptr = get_global_ptr();
-            rtassert!((*ptr).is_none());
-            (*ptr) = Some(box args.clone());
-        })
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        with_lock(|| unsafe {
-            let ptr = get_global_ptr();
-            (*ptr).as_ref().map(|s: &Box<Vec<Vec<u8>>>| (**s).clone())
-        })
-    }
-
-    fn with_lock<T>(f: || -> T) -> T {
-        unsafe {
-            let _guard = lock.lock();
-            f()
-        }
-    }
-
-    fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
-        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())
-        })
-    }
-
-    #[cfg(test)]
-    mod tests {
-        use prelude::*;
-        use super::*;
-        use finally::Finally;
-
-        #[test]
-        fn smoke_test() {
-            // Preserve the actual global state.
-            let saved_value = take();
-
-            let expected = vec![
-                Vec::from_slice(bytes!("happy")),
-                Vec::from_slice(bytes!("today?")),
-            ];
-
-            put(expected.clone());
-            assert!(clone() == Some(expected.clone()));
-            assert!(take() == Some(expected.clone()));
-            assert!(take() == None);
-
-            (|| {
-            }).finally(|| {
-                // Restore the actual global state.
-                match saved_value {
-                    Some(ref args) => put(args.clone()),
-                    None => ()
-                }
-            })
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "win32")]
-mod imp {
-    use option::Option;
-    use vec::Vec;
-
-    pub unsafe fn init(_argc: int, _argv: **u8) {
-    }
-
-    pub fn cleanup() {
-    }
-
-    pub fn take() -> Option<Vec<Vec<u8>>> {
-        fail!()
-    }
-
-    pub fn put(_args: Vec<Vec<u8>>) {
-        fail!()
-    }
-
-    pub fn clone() -> Option<Vec<Vec<u8>>> {
-        fail!()
-    }
-}
diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs
deleted file mode 100644 (file)
index c892a73..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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();
-    }
-}
index 94472ee72414c0b4fe65e30d831d25f1406b9512..766901fa04f32f663e559c16cda477b6ee2f9606 100644 (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 @@ fn output(w: &mut Writer, idx: int, addr: *libc::c_void,
         }
         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 @@ fn output(w: &mut Writer, idx: int, addr: *libc::c_void,
 mod imp {
     use c_str::CString;
     use container::Container;
+    use intrinsics;
     use io::{IoResult, Writer};
     use libc;
     use mem;
@@ -511,11 +611,10 @@ mod imp {
     use option::{Some, None};
     use path::Path;
     use result::{Ok, Err};
+    use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
+    use slice::ImmutableVector;
     use str::StrSlice;
     use unstable::dynamic_lib::DynamicLibrary;
-    use intrinsics;
-    use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
-    use slice::ImmutableVector;
 
     #[allow(non_snake_case_functions)]
     extern "system" {
diff --git a/src/libstd/rt/bookkeeping.rs b/src/libstd/rt/bookkeeping.rs
deleted file mode 100644 (file)
index 9e772d8..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2013-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.
-
-//! Task bookkeeping
-//!
-//! This module keeps track of the number of running tasks so that entry points
-//! with libnative know when it's possible to exit the program (once all tasks
-//! have exited).
-//!
-//! The green counterpart for this is bookkeeping on sched pools, and it's up to
-//! each respective runtime to make sure that they call increment() and
-//! decrement() manually.
-
-#![experimental] // this is a massive code smell
-#![doc(hidden)]
-
-use sync::atomics;
-use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
-
-static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
-static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
-
-pub fn increment() {
-    let _ = unsafe { TASK_COUNT.fetch_add(1, atomics::SeqCst) };
-}
-
-pub fn decrement() {
-    unsafe {
-        if TASK_COUNT.fetch_sub(1, atomics::SeqCst) == 1 {
-            let guard = TASK_LOCK.lock();
-            guard.signal();
-        }
-    }
-}
-
-/// Waits for all other native tasks in the system to exit. This is only used by
-/// the entry points of native programs
-pub fn wait_for_other_tasks() {
-    unsafe {
-        let guard = TASK_LOCK.lock();
-        while TASK_COUNT.load(atomics::SeqCst) > 0 {
-            guard.wait();
-        }
-    }
-}
diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs
deleted file mode 100644 (file)
index 7271464..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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 }
-}
diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs
deleted file mode 100644 (file)
index 00301e7..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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.
-
-//! Unwind library interface
-
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case_functions)]
-#![allow(dead_code)] // these are just bindings
-
-use libc;
-
-#[cfg(not(target_arch = "arm"))]
-#[repr(C)]
-pub enum _Unwind_Action {
-    _UA_SEARCH_PHASE = 1,
-    _UA_CLEANUP_PHASE = 2,
-    _UA_HANDLER_FRAME = 4,
-    _UA_FORCE_UNWIND = 8,
-    _UA_END_OF_STACK = 16,
-}
-
-#[cfg(target_arch = "arm")]
-#[repr(C)]
-pub enum _Unwind_State {
-    _US_VIRTUAL_UNWIND_FRAME = 0,
-    _US_UNWIND_FRAME_STARTING = 1,
-    _US_UNWIND_FRAME_RESUME = 2,
-    _US_ACTION_MASK = 3,
-    _US_FORCE_UNWIND = 8,
-    _US_END_OF_STACK = 16
-}
-
-#[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 type _Unwind_Exception_Class = u64;
-
-pub type _Unwind_Word = libc::uintptr_t;
-
-#[cfg(target_arch = "x86")]
-pub static unwinder_private_data_size: int = 5;
-
-#[cfg(target_arch = "x86_64")]
-pub static unwinder_private_data_size: int = 2;
-
-#[cfg(target_arch = "arm")]
-pub static unwinder_private_data_size: int = 20;
-
-#[cfg(target_arch = "mips")]
-pub static unwinder_private_data_size: int = 2;
-
-pub struct _Unwind_Exception {
-    pub exception_class: _Unwind_Exception_Class,
-    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
-    pub private: [_Unwind_Word, ..unwinder_private_data_size],
-}
-
-pub enum _Unwind_Context {}
-
-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")]
-#[link(name = "gcc_s")]
-extern {}
-
-#[cfg(target_os = "android")]
-#[link(name = "gcc")]
-extern {}
-
-extern "C" {
-    pub fn _Unwind_RaiseException(exception: *_Unwind_Exception)
-                -> _Unwind_Reason_Code;
-    pub fn _Unwind_DeleteException(exception: *_Unwind_Exception);
-    pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
-                             trace_argument: *libc::c_void)
-                -> _Unwind_Reason_Code;
-
-    #[cfg(not(target_os = "android"),
-          not(target_os = "linux", target_arch = "arm"))]
-    pub fn _Unwind_GetIP(ctx: *_Unwind_Context) -> libc::uintptr_t;
-    #[cfg(not(target_os = "android"),
-          not(target_os = "linux", target_arch = "arm"))]
-    pub fn _Unwind_FindEnclosingFunction(pc: *libc::c_void) -> *libc::c_void;
-}
-
-// On android, the function _Unwind_GetIP is a macro, and this is the expansion
-// of the macro. This is all copy/pasted directly from the header file with the
-// definition of _Unwind_GetIP.
-#[cfg(target_os = "android")]
-#[cfg(target_os = "linux", target_arch = "arm")]
-pub unsafe fn _Unwind_GetIP(ctx: *_Unwind_Context) -> libc::uintptr_t {
-    #[repr(C)]
-    enum _Unwind_VRS_Result {
-        _UVRSR_OK = 0,
-        _UVRSR_NOT_IMPLEMENTED = 1,
-        _UVRSR_FAILED = 2,
-    }
-    #[repr(C)]
-    enum _Unwind_VRS_RegClass {
-        _UVRSC_CORE = 0,
-        _UVRSC_VFP = 1,
-        _UVRSC_FPA = 2,
-        _UVRSC_WMMXD = 3,
-        _UVRSC_WMMXC = 4,
-    }
-    #[repr(C)]
-    enum _Unwind_VRS_DataRepresentation {
-        _UVRSD_UINT32 = 0,
-        _UVRSD_VFPX = 1,
-        _UVRSD_FPAX = 2,
-        _UVRSD_UINT64 = 3,
-        _UVRSD_FLOAT = 4,
-        _UVRSD_DOUBLE = 5,
-    }
-
-    type _Unwind_Word = libc::c_uint;
-    extern {
-        fn _Unwind_VRS_Get(ctx: *_Unwind_Context,
-                           klass: _Unwind_VRS_RegClass,
-                           word: _Unwind_Word,
-                           repr: _Unwind_VRS_DataRepresentation,
-                           data: *mut libc::c_void) -> _Unwind_VRS_Result;
-    }
-
-    let mut val: _Unwind_Word = 0;
-    let ptr = &mut val as *mut _Unwind_Word;
-    let _ = _Unwind_VRS_Get(ctx, _UVRSC_CORE, 15, _UVRSD_UINT32,
-                            ptr as *mut libc::c_void);
-    (val & !1) as libc::uintptr_t
-}
-
-// This function also doesn't exist on android or arm/linux, so make it a no-op
-#[cfg(target_os = "android")]
-#[cfg(target_os = "linux", target_arch = "arm")]
-pub unsafe fn _Unwind_FindEnclosingFunction(pc: *libc::c_void) -> *libc::c_void {
-    pc
-}
diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs
deleted file mode 100644 (file)
index 9f0ed80..0000000
+++ /dev/null
@@ -1,132 +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 option::Option;
-use owned::Box;
-use rt::task::Task;
-use rt::local_ptr;
-
-/// Encapsulates some task-local data.
-pub trait Local<Borrowed> {
-    fn put(value: Box<Self>);
-    fn take() -> Box<Self>;
-    fn try_take() -> Option<Box<Self>>;
-    fn exists(unused_value: Option<Self>) -> bool;
-    fn borrow(unused_value: Option<Self>) -> Borrowed;
-    unsafe fn unsafe_take() -> Box<Self>;
-    unsafe fn unsafe_borrow() -> *mut Self;
-    unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
-}
-
-#[allow(visible_private_types)]
-impl Local<local_ptr::Borrowed<Task>> for Task {
-    #[inline]
-    fn put(value: Box<Task>) { unsafe { local_ptr::put(value) } }
-    #[inline]
-    fn take() -> Box<Task> { unsafe { local_ptr::take() } }
-    #[inline]
-    fn try_take() -> Option<Box<Task>> { unsafe { local_ptr::try_take() } }
-    fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
-    #[inline]
-    fn borrow(_: Option<Task>) -> local_ptr::Borrowed<Task> {
-        unsafe {
-            local_ptr::borrow::<Task>()
-        }
-    }
-    #[inline]
-    unsafe fn unsafe_take() -> Box<Task> { local_ptr::unsafe_take() }
-    #[inline]
-    unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
-    #[inline]
-    unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
-        local_ptr::try_unsafe_borrow()
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use option::{None, Option};
-    use rt::thread::Thread;
-    use super::*;
-    use owned::Box;
-    use rt::task::Task;
-
-    #[test]
-    fn thread_local_task_smoke_test() {
-        Thread::start(proc() {
-            let task = box Task::new();
-            Local::put(task);
-            let task: Box<Task> = Local::take();
-            cleanup_task(task);
-        }).join();
-    }
-
-    #[test]
-    fn thread_local_task_two_instances() {
-        Thread::start(proc() {
-            let task = box Task::new();
-            Local::put(task);
-            let task: Box<Task> = Local::take();
-            cleanup_task(task);
-            let task = box Task::new();
-            Local::put(task);
-            let task: Box<Task> = Local::take();
-            cleanup_task(task);
-        }).join();
-    }
-
-    #[test]
-    fn borrow_smoke_test() {
-        Thread::start(proc() {
-            let task = box Task::new();
-            Local::put(task);
-
-            unsafe {
-                let _task: *mut Task = Local::unsafe_borrow();
-            }
-            let task: Box<Task> = Local::take();
-            cleanup_task(task);
-        }).join();
-    }
-
-    #[test]
-    fn borrow_with_return() {
-        Thread::start(proc() {
-            let task = box Task::new();
-            Local::put(task);
-
-            {
-                let _ = Local::borrow(None::<Task>);
-            }
-
-            let task: Box<Task> = Local::take();
-            cleanup_task(task);
-        }).join();
-    }
-
-    #[test]
-    fn try_take() {
-        Thread::start(proc() {
-            let task = box Task::new();
-            Local::put(task);
-
-            let t: Box<Task> = Local::try_take().unwrap();
-            let u: Option<Box<Task>> = Local::try_take();
-            assert!(u.is_none());
-
-            cleanup_task(t);
-        }).join();
-    }
-
-    fn cleanup_task(mut t: Box<Task>) {
-        t.destroyed = true;
-    }
-
-}
diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs
deleted file mode 100644 (file)
index 240d137..0000000
+++ /dev/null
@@ -1,339 +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.
-
-//! 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;
-
-// This has no meaning with out rtdebug also turned on.
-#[cfg(rtdebug)]
-static TRACK_ALLOCATIONS: int = 0;
-#[cfg(rtdebug)]
-static MAGIC: u32 = 0xbadc0ffe;
-
-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,
-            live_allocs: ptr::mut_null(),
-        }
-    }
-
-    #[inline]
-    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);
-        {
-            // Make sure that we can't use `mybox` outside of this scope
-            let mybox: &mut Box = unsafe { mem::transmute(alloc) };
-            // Clear out this box, and move it to the front of the live
-            // allocations list
-            mybox.drop_glue = drop_glue;
-            mybox.ref_count = 1;
-            mybox.prev = ptr::mut_null();
-            mybox.next = self.live_allocs;
-            if !self.live_allocs.is_null() {
-                unsafe { (*self.live_allocs).prev = alloc; }
-            }
-            self.live_allocs = alloc;
-        }
-        return alloc;
-    }
-
-    #[inline]
-    pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box {
-        // Make sure that we can't use `mybox` outside of this scope
-        let total_size = size + mem::size_of::<Box>();
-        let new_box = self.memory_region.realloc(ptr, total_size);
-        {
-            // Fix links because we could have moved around
-            let mybox: &mut Box = unsafe { mem::transmute(new_box) };
-            if !mybox.prev.is_null() {
-                unsafe { (*mybox.prev).next = new_box; }
-            }
-            if !mybox.next.is_null() {
-                unsafe { (*mybox.next).prev = new_box; }
-            }
-        }
-        if self.live_allocs == ptr {
-            self.live_allocs = new_box;
-        }
-        return new_box;
-    }
-
-    #[inline]
-    pub fn free(&mut self, alloc: *mut Box) {
-        {
-            // Make sure that we can't use `mybox` outside of this scope
-            let mybox: &mut Box = unsafe { mem::transmute(alloc) };
-
-            // Unlink it from the linked list
-            if !mybox.prev.is_null() {
-                unsafe { (*mybox.prev).next = mybox.next; }
-            }
-            if !mybox.next.is_null() {
-                unsafe { (*mybox.next).prev = mybox.prev; }
-            }
-            if self.live_allocs == alloc {
-                self.live_allocs = mybox.next;
-            }
-        }
-
-        self.memory_region.free(alloc);
-    }
-}
-
-impl Drop for LocalHeap {
-    fn drop(&mut self) {
-        assert!(self.live_allocs.is_null());
-    }
-}
-
-#[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 {
-        let myaddr: uint = unsafe { mem::transmute(self) };
-        (myaddr + AllocHeader::size()) as *mut Box
-    }
-
-    fn size() -> uint {
-        // For some platforms, 16 byte alignment is required.
-        let ptr_size = 16;
-        let header_size = mem::size_of::<AllocHeader>();
-        return (header_size + ptr_size - 1) / ptr_size * ptr_size;
-    }
-
-    fn from(a_box: *mut Box) -> *mut AllocHeader {
-        (a_box as uint - AllocHeader::size()) as *mut AllocHeader
-    }
-}
-
-impl MemoryRegion {
-    #[inline]
-    fn malloc(&mut self, size: uint) -> *mut Box {
-        let total_size = size + AllocHeader::size();
-        let alloc: *AllocHeader = unsafe {
-            libc_heap::malloc_raw(total_size) as *AllocHeader
-        };
-
-        let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) };
-        alloc.init(size as u32);
-        self.claim(alloc);
-        self.live_allocations += 1;
-
-        return alloc.as_box();
-    }
-
-    #[inline]
-    fn realloc(&mut self, alloc: *mut Box, size: uint) -> *mut Box {
-        rtassert!(!alloc.is_null());
-        let orig_alloc = AllocHeader::from(alloc);
-        unsafe { (*orig_alloc).assert_sane(); }
-
-        let total_size = size + AllocHeader::size();
-        let alloc: *AllocHeader = unsafe {
-            libc_heap::realloc_raw(orig_alloc as *mut u8, total_size) as *AllocHeader
-        };
-
-        let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) };
-        alloc.assert_sane();
-        alloc.update_size(size as u32);
-        self.update(alloc, orig_alloc as *AllocHeader);
-        return alloc.as_box();
-    }
-
-    #[inline]
-    fn free(&mut self, alloc: *mut Box) {
-        rtassert!(!alloc.is_null());
-        let alloc = AllocHeader::from(alloc);
-        unsafe {
-            (*alloc).assert_sane();
-            self.release(mem::transmute(alloc));
-            rtassert!(self.live_allocations > 0);
-            self.live_allocations -= 1;
-            free(alloc as *mut c_void)
-        }
-    }
-
-    #[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) {}
-}
-
-impl Drop for MemoryRegion {
-    fn drop(&mut self) {
-        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]
-pub unsafe fn local_malloc_(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
-    local_malloc(drop_glue, size, align)
-}
-
-#[inline]
-pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
-    // FIXME: Unsafe borrow for speed. Lame.
-    let task: Option<*mut Task> = Local::try_unsafe_borrow();
-    match task {
-        Some(task) => {
-            (*task).heap.alloc(drop_glue, size, align) as *u8
-        }
-        None => rtabort!("local malloc outside of task")
-    }
-}
-
-#[cfg(not(test))]
-#[lang="free"]
-#[inline]
-pub unsafe fn local_free_(ptr: *u8) {
-    local_free(ptr)
-}
-
-// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
-// inside a landing pad may corrupt the state of the exception handler. If a
-// problem occurs, call exit instead.
-#[inline]
-pub unsafe fn local_free(ptr: *u8) {
-    // FIXME: Unsafe borrow for speed. Lame.
-    let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
-    match task_ptr {
-        Some(task) => {
-            (*task).heap.free(ptr as *mut Box)
-        }
-        None => rtabort!("local free outside of task")
-    }
-}
-
-pub fn live_allocs() -> *mut Box {
-    Local::borrow(None::<Task>).heap.live_allocs
-}
-
-#[cfg(test)]
-mod bench {
-    extern crate test;
-    use self::test::Bencher;
-
-    #[bench]
-    fn alloc_managed_small(b: &mut Bencher) {
-        b.iter(|| { @10; });
-    }
-
-    #[bench]
-    fn alloc_managed_big(b: &mut Bencher) {
-        b.iter(|| { @([10, ..1000]); });
-    }
-}
diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs
deleted file mode 100644 (file)
index 1197a4c..0000000
+++ /dev/null
@@ -1,404 +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.
-
-//! Access to a single thread-local pointer.
-//!
-//! The runtime will use this for storing Box<Task>.
-//!
-//! FIXME: Add runtime checks for usage of inconsistent pointer types.
-//! and for overwriting an existing pointer.
-
-#![allow(dead_code)]
-
-use mem;
-use ops::{Drop, Deref, DerefMut};
-use owned::Box;
-use ptr::RawPtr;
-
-#[cfg(windows)]               // mingw-w32 doesn't like thread_local things
-#[cfg(target_os = "android")] // see #10686
-pub use self::native::{init, cleanup, put, take, try_take, unsafe_take, exists,
-                       unsafe_borrow, try_unsafe_borrow};
-
-#[cfg(not(windows), not(target_os = "android"))]
-pub use self::compiled::{init, cleanup, put, take, try_take, unsafe_take, exists,
-                         unsafe_borrow, try_unsafe_borrow};
-
-/// Encapsulates a borrowed value. When this value goes out of scope, the
-/// pointer is returned.
-pub struct Borrowed<T> {
-    val: *(),
-}
-
-#[unsafe_destructor]
-impl<T> Drop for Borrowed<T> {
-    fn drop(&mut self) {
-        unsafe {
-            if self.val.is_null() {
-                rtabort!("Aiee, returning null borrowed object!");
-            }
-            let val: Box<T> = mem::transmute(self.val);
-            put::<T>(val);
-            rtassert!(exists());
-        }
-    }
-}
-
-impl<T> Deref<T> for Borrowed<T> {
-    fn deref<'a>(&'a self) -> &'a T {
-        unsafe { &*(self.val as *T) }
-    }
-}
-
-impl<T> DerefMut<T> for Borrowed<T> {
-    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
-        unsafe { &mut *(self.val as *mut T) }
-    }
-}
-
-/// Borrow the thread-local value from thread-local storage.
-/// While the value is borrowed it is not available in TLS.
-///
-/// # Safety note
-///
-/// Does not validate the pointer type.
-#[inline]
-pub unsafe fn borrow<T>() -> Borrowed<T> {
-    let val: *() = mem::transmute(take::<T>());
-    Borrowed {
-        val: val,
-    }
-}
-
-/// Compiled implementation of accessing the runtime local pointer. This is
-/// implemented using LLVM's thread_local attribute which isn't necessarily
-/// working on all platforms. This implementation is faster, however, so we use
-/// 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;
-
-    #[cfg(test)]
-    pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;
-
-    #[cfg(not(test))]
-    #[thread_local]
-    pub static mut RT_TLS_PTR: *mut u8 = 0 as *mut u8;
-
-    pub fn init() {}
-
-    pub unsafe fn cleanup() {}
-
-    // Rationale for all of these functions being inline(never)
-    //
-    // The #[thread_local] annotation gets propagated all the way through to
-    // LLVM, meaning the global is specially treated by LLVM to lower it to an
-    // efficient sequence of instructions. This also involves dealing with fun
-    // stuff in object files and whatnot. Regardless, it turns out this causes
-    // trouble with green threads and lots of optimizations turned on. The
-    // following case study was done on linux x86_64, but I would imagine that
-    // other platforms are similar.
-    //
-    // On linux, the instruction sequence for loading the tls pointer global
-    // looks like:
-    //
-    //      mov %fs:0x0, %rax
-    //      mov -0x8(%rax), %rbx
-    //
-    // This code leads me to believe that (%fs:0x0) is a table, and then the
-    // table contains the TLS values for the process. Hence, the slot at offset
-    // -0x8 is the task TLS pointer. This leads us to the conclusion that this
-    // table is the actual thread local part of each thread. The kernel sets up
-    // the fs segment selector to point at the right region of memory for each
-    // thread.
-    //
-    // Optimizations lead me to believe that this code is lowered to these
-    // instructions in the LLVM codegen passes, because you'll see code like
-    // this when everything is optimized:
-    //
-    //      mov %fs:0x0, %r14
-    //      mov -0x8(%r14), %rbx
-    //      // do something with %rbx, the rust Task pointer
-    //
-    //      ... // <- do more things
-    //
-    //      mov -0x8(%r14), %rbx
-    //      // do something else with %rbx
-    //
-    // Note that the optimization done here is that the first load is not
-    // duplicated during the lower instructions. This means that the %fs:0x0
-    // memory location is only dereferenced once.
-    //
-    // Normally, this is actually a good thing! With green threads, however,
-    // it's very possible for the code labeled "do more things" to context
-    // switch to another thread. If this happens, then we *must* re-load %fs:0x0
-    // because it's changed (we're on a different thread). If we don't re-load
-    // the table location, then we'll be reading the original thread's TLS
-    // values, not our thread's TLS values.
-    //
-    // Hence, we never inline these functions. By never inlining, we're
-    // guaranteed that loading the table is a local decision which is forced to
-    // *always* happen.
-
-    /// Give a pointer to thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    #[inline(never)] // see comments above
-    pub unsafe fn put<T>(sched: Box<T>) {
-        RT_TLS_PTR = mem::transmute(sched)
-    }
-
-    /// Take ownership of a pointer from thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    #[inline(never)] // see comments above
-    pub unsafe fn take<T>() -> Box<T> {
-        let ptr = RT_TLS_PTR;
-        rtassert!(!ptr.is_null());
-        let ptr: Box<T> = mem::transmute(ptr);
-        // can't use `as`, due to type not matching with `cfg(test)`
-        RT_TLS_PTR = mem::transmute(0);
-        ptr
-    }
-
-    /// Optionally take ownership of a pointer from thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    #[inline(never)] // see comments above
-    pub unsafe fn try_take<T>() -> Option<Box<T>> {
-        let ptr = RT_TLS_PTR;
-        if ptr.is_null() {
-            None
-        } else {
-            let ptr: Box<T> = mem::transmute(ptr);
-            // can't use `as`, due to type not matching with `cfg(test)`
-            RT_TLS_PTR = mem::transmute(0);
-            Some(ptr)
-        }
-    }
-
-    /// Take ownership of a pointer from thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    /// Leaves the old pointer in TLS for speed.
-    #[inline(never)] // see comments above
-    pub unsafe fn unsafe_take<T>() -> Box<T> {
-        mem::transmute(RT_TLS_PTR)
-    }
-
-    /// Check whether there is a thread-local pointer installed.
-    #[inline(never)] // see comments above
-    pub fn exists() -> bool {
-        unsafe {
-            RT_TLS_PTR.is_not_null()
-        }
-    }
-
-    #[inline(never)] // see comments above
-    pub unsafe fn unsafe_borrow<T>() -> *mut T {
-        if RT_TLS_PTR.is_null() {
-            rtabort!("thread-local pointer is null. bogus!");
-        }
-        RT_TLS_PTR as *mut T
-    }
-
-    #[inline(never)] // see comments above
-    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
-        if RT_TLS_PTR.is_null() {
-            None
-        } else {
-            Some(RT_TLS_PTR as *mut T)
-        }
-    }
-}
-
-/// Native implementation of having the runtime thread-local pointer. This
-/// 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;
-
-    static mut RT_TLS_KEY: tls::Key = -1;
-
-    /// Initialize the TLS key. Other ops will fail if this isn't executed
-    /// first.
-    pub fn init() {
-        unsafe {
-            tls::create(&mut RT_TLS_KEY);
-        }
-    }
-
-    pub unsafe fn cleanup() {
-        rtassert!(RT_TLS_KEY != -1);
-        tls::destroy(RT_TLS_KEY);
-    }
-
-    /// Give a pointer to thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    #[inline]
-    pub unsafe fn put<T>(sched: Box<T>) {
-        let key = tls_key();
-        let void_ptr: *mut u8 = mem::transmute(sched);
-        tls::set(key, void_ptr);
-    }
-
-    /// Take ownership of a pointer from thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    #[inline]
-    pub unsafe fn take<T>() -> Box<T> {
-        let key = tls_key();
-        let void_ptr: *mut u8 = tls::get(key);
-        if void_ptr.is_null() {
-            rtabort!("thread-local pointer is null. bogus!");
-        }
-        let ptr: Box<T> = mem::transmute(void_ptr);
-        tls::set(key, ptr::mut_null());
-        return ptr;
-    }
-
-    /// Optionally take ownership of a pointer from thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    #[inline]
-    pub unsafe fn try_take<T>() -> Option<Box<T>> {
-        match maybe_tls_key() {
-            Some(key) => {
-                let void_ptr: *mut u8 = tls::get(key);
-                if void_ptr.is_null() {
-                    None
-                } else {
-                    let ptr: Box<T> = mem::transmute(void_ptr);
-                    tls::set(key, ptr::mut_null());
-                    Some(ptr)
-                }
-            }
-            None => None
-        }
-    }
-
-    /// Take ownership of a pointer from thread-local storage.
-    ///
-    /// # Safety note
-    ///
-    /// Does not validate the pointer type.
-    /// Leaves the old pointer in TLS for speed.
-    #[inline]
-    pub unsafe fn unsafe_take<T>() -> Box<T> {
-        let key = tls_key();
-        let void_ptr: *mut u8 = tls::get(key);
-        if void_ptr.is_null() {
-            rtabort!("thread-local pointer is null. bogus!");
-        }
-        let ptr: Box<T> = mem::transmute(void_ptr);
-        return ptr;
-    }
-
-    /// Check whether there is a thread-local pointer installed.
-    pub fn exists() -> bool {
-        unsafe {
-            match maybe_tls_key() {
-                Some(key) => tls::get(key).is_not_null(),
-                None => false
-            }
-        }
-    }
-
-    /// Borrow a mutable reference to the thread-local value
-    ///
-    /// # Safety Note
-    ///
-    /// Because this leaves the value in thread-local storage it is possible
-    /// For the Scheduler pointer to be aliased
-    pub unsafe fn unsafe_borrow<T>() -> *mut T {
-        let key = tls_key();
-        let void_ptr = tls::get(key);
-        if void_ptr.is_null() {
-            rtabort!("thread-local pointer is null. bogus!");
-        }
-        void_ptr as *mut T
-    }
-
-    pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
-        match maybe_tls_key() {
-            Some(key) => {
-                let void_ptr = tls::get(key);
-                if void_ptr.is_null() {
-                    None
-                } else {
-                    Some(void_ptr as *mut T)
-                }
-            }
-            None => None
-        }
-    }
-
-    #[inline]
-    fn tls_key() -> tls::Key {
-        match maybe_tls_key() {
-            Some(key) => key,
-            None => rtabort!("runtime tls key not initialized")
-        }
-    }
-
-    #[inline]
-    #[cfg(not(test))]
-    #[allow(visible_private_types)]
-    pub fn maybe_tls_key() -> Option<tls::Key> {
-        unsafe {
-            // NB: This is a little racy because, while the key is
-            // initialized under a mutex and it's assumed to be initialized
-            // in the Scheduler ctor by any thread that needs to use it,
-            // we are not accessing the key under a mutex.  Threads that
-            // are not using the new Scheduler but still *want to check*
-            // whether they are running under a new Scheduler may see a 0
-            // value here that is in the process of being initialized in
-            // another thread. I think this is fine since the only action
-            // they could take if it was initialized would be to check the
-            // thread-local value and see that it's not set.
-            if RT_TLS_KEY != -1 {
-                return Some(RT_TLS_KEY);
-            } else {
-                return None;
-            }
-        }
-    }
-
-    #[inline] #[cfg(test)]
-    pub fn maybe_tls_key() -> Option<tls::Key> {
-        use realstd;
-        unsafe {
-            mem::transmute(realstd::rt::shouldnt_be_public::maybe_tls_key())
-        }
-    }
-}
diff --git a/src/libstd/rt/macros.rs b/src/libstd/rt/macros.rs
deleted file mode 100644 (file)
index aef41de..0000000
+++ /dev/null
@@ -1,49 +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.
-
-//! Macros used by the runtime.
-//!
-//! These macros call functions which are only accessible in the `rt` module, so
-//! they aren't defined anywhere outside of the `rt` module.
-
-#![macro_escape]
-
-macro_rules! rterrln (
-    ($($arg:tt)*) => ( {
-        format_args!(::rt::util::dumb_println, $($arg)*)
-    } )
-)
-
-// Some basic logging. Enabled by passing `--cfg rtdebug` to the libstd build.
-macro_rules! rtdebug (
-    ($($arg:tt)*) => ( {
-        if cfg!(rtdebug) {
-            rterrln!($($arg)*)
-        }
-    })
-)
-
-macro_rules! rtassert (
-    ( $arg:expr ) => ( {
-        if ::rt::util::ENFORCE_SANITY {
-            if !$arg {
-                rtabort!(" assertion failed: {}", stringify!($arg));
-            }
-        }
-    } )
-)
-
-
-macro_rules! rtabort (
-    ($($arg:tt)*) => ( {
-        use str::Str;
-        ::rt::util::abort(format!($($arg)*).as_slice());
-    } )
-)
index d2131ad44fb301cabf0e674d45b6935aa74739f2..a68a632bc37e0b13cc249d28a0f72c3be1a458df 100644 (file)
 // 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();
 }
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
deleted file mode 100644 (file)
index 06db465..0000000
+++ /dev/null
@@ -1,374 +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.
-
-//! The EventLoop and internal synchronous I/O interface.
-
-use c_str::CString;
-use comm::{Sender, Receiver};
-use kinds::Send;
-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);
-}
-
-pub trait EventLoop {
-    fn run(&mut self);
-    fn callback(&mut self, arg: proc():Send);
-    fn pausable_idle_callback(&mut self, Box<Callback:Send>)
-                              -> Box<PausableIdleCallback:Send>;
-    fn remote_callback(&mut self, Box<Callback:Send>)
-                       -> Box<RemoteCallback:Send>;
-
-    /// The asynchronous I/O services. Not all event loops may provide one.
-    fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory>;
-    fn has_active_io(&self) -> bool;
-}
-
-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
-    /// that, after calling 'fire', the callback will be called at
-    /// least once, but multiple callbacks may be coalesced and
-    /// callbacks may be called more often requested. Destruction also
-    /// triggers the callback.
-    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
-    DontClose,
-    /// Synchronously close the handle, meaning that the task will block when
-    /// the handle is destroyed until it has been fully closed.
-    CloseSynchronously,
-    /// Asynchronously closes a handle, meaning that the task will *not* block
-    /// when the handle is destroyed, but the handle will still get deallocated
-    /// and cleaned up (but this will happen asynchronously on the local event
-    /// loop).
-    CloseAsynchronously,
-}
-
-/// Data needed to spawn a process. Serializes the `std::io::process::Command`
-/// builder.
-pub struct ProcessConfig<'a> {
-    /// Path to the program to run.
-    pub program: &'a CString,
-
-    /// Arguments to pass to the program (doesn't include the program itself).
-    pub args: &'a [CString],
-
-    /// Optional environment to specify for the program. If this is None, then
-    /// it will inherit the current process's environment.
-    pub env: Option<&'a [(CString, CString)]>,
-
-    /// Optional working directory for the new process. If this is None, then
-    /// the current directory of the running process is inherited.
-    pub cwd: Option<&'a CString>,
-
-    /// Configuration for the child process's stdin handle (file descriptor 0).
-    /// This field defaults to `CreatePipe(true, false)` so the input can be
-    /// written to.
-    pub stdin: StdioContainer,
-
-    /// Configuration for the child process's stdout handle (file descriptor 1).
-    /// This field defaults to `CreatePipe(false, true)` so the output can be
-    /// collected.
-    pub stdout: StdioContainer,
-
-    /// Configuration for the child process's stdout handle (file descriptor 2).
-    /// This field defaults to `CreatePipe(false, true)` so the output can be
-    /// collected.
-    pub stderr: StdioContainer,
-
-    /// Any number of streams/file descriptors/pipes may be attached to this
-    /// process. This list enumerates the file descriptors and such for the
-    /// process to be spawned, and the file descriptors inherited will start at
-    /// 3 and go to the length of this array. The first three file descriptors
-    /// (stdin/stdout/stderr) are configured with the `stdin`, `stdout`, and
-    /// `stderr` fields.
-    pub extra_io: &'a [StdioContainer],
-
-    /// Sets the child process's user id. This translates to a `setuid` call in
-    /// the child process. Setting this value on windows will cause the spawn to
-    /// fail. Failure in the `setuid` call on unix will also cause the spawn to
-    /// fail.
-    pub uid: Option<uint>,
-
-    /// Similar to `uid`, but sets the group id of the child process. This has
-    /// the same semantics as the `uid` field.
-    pub gid: Option<uint>,
-
-    /// If true, the child process is spawned in a detached state. On unix, this
-    /// means that the child is the leader of a new process group.
-    pub detach: bool,
-}
-
-pub struct LocalIo<'a> {
-    factory: &'a mut IoFactory,
-}
-
-#[unsafe_destructor]
-impl<'a> Drop for LocalIo<'a> {
-    fn drop(&mut self) {
-        // FIXME(pcwalton): Do nothing here for now, but eventually we may want
-        // something. For now this serves to make `LocalIo` noncopyable.
-    }
-}
-
-impl<'a> LocalIo<'a> {
-    /// Returns the local I/O: either the local scheduler's I/O services or
-    /// the native I/O services.
-    pub fn borrow() -> Option<LocalIo> {
-        // FIXME(#11053): bad
-        //
-        // This is currently very unsafely implemented. We don't actually
-        // *take* the local I/O so there's a very real possibility that we
-        // can have two borrows at once. Currently there is not a clear way
-        // to actually borrow the local I/O factory safely because even if
-        // ownership were transferred down to the functions that the I/O
-        // factory implements it's just too much of a pain to know when to
-        // relinquish ownership back into the local task (but that would be
-        // the safe way of implementing this function).
-        //
-        // In order to get around this, we just transmute a copy out of the task
-        // in order to have what is likely a static lifetime (bad).
-        let mut t: Box<Task> = match Local::try_take() {
-            Some(t) => t,
-            None => return None,
-        };
-        let ret = t.local_io().map(|t| {
-            unsafe { mem::transmute_copy(&t) }
-        });
-        Local::put(t);
-        return ret;
-    }
-
-    pub fn maybe_raise<T>(f: |io: &mut IoFactory| -> IoResult<T>)
-        -> IoResult<T>
-    {
-        match LocalIo::borrow() {
-            None => Err(io::standard_error(io::IoUnavailable)),
-            Some(mut io) => f(io.get()),
-        }
-    }
-
-    pub fn new<'a>(io: &'a mut IoFactory) -> LocalIo<'a> {
-        LocalIo { factory: io }
-    }
-
-    /// 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)
-        }
-    }
-}
-
-pub trait IoFactory {
-    // networking
-    fn tcp_connect(&mut self, addr: SocketAddr,
-                   timeout: Option<u64>) -> IoResult<Box<RtioTcpStream:Send>>;
-    fn tcp_bind(&mut self, addr: SocketAddr)
-                -> IoResult<Box<RtioTcpListener:Send>>;
-    fn udp_bind(&mut self, addr: SocketAddr)
-                -> IoResult<Box<RtioUdpSocket:Send>>;
-    fn unix_bind(&mut self, path: &CString)
-                 -> IoResult<Box<RtioUnixListener:Send>>;
-    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>>;
-
-    // filesystem operations
-    fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior)
-                      -> Box<RtioFileStream:Send>;
-    fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
-               -> 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_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>>;
-    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_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) ->
-        IoResult<()>;
-
-    // misc
-    fn timer_init(&mut self) -> IoResult<Box<RtioTimer:Send>>;
-    fn spawn(&mut self, cfg: ProcessConfig)
-            -> IoResult<(Box<RtioProcess:Send>,
-                         Vec<Option<Box<RtioPipe:Send>>>)>;
-    fn kill(&mut self, pid: libc::pid_t, signal: int) -> IoResult<()>;
-    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>)
-        -> IoResult<Box<RtioSignal:Send>>;
-}
-
-pub trait RtioTcpListener : RtioSocket {
-    fn listen(~self) -> IoResult<Box<RtioTcpAcceptor:Send>>;
-}
-
-pub trait RtioTcpAcceptor : RtioSocket {
-    fn accept(&mut self) -> IoResult<Box<RtioTcpStream:Send>>;
-    fn accept_simultaneously(&mut self) -> IoResult<()>;
-    fn dont_accept_simultaneously(&mut self) -> IoResult<()>;
-    fn set_timeout(&mut self, timeout: Option<u64>);
-}
-
-pub trait RtioTcpStream : RtioSocket {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
-    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
-    fn peer_name(&mut self) -> IoResult<SocketAddr>;
-    fn control_congestion(&mut self) -> IoResult<()>;
-    fn nodelay(&mut self) -> IoResult<()>;
-    fn keepalive(&mut self, delay_in_seconds: uint) -> IoResult<()>;
-    fn letdie(&mut self) -> IoResult<()>;
-    fn clone(&self) -> Box<RtioTcpStream:Send>;
-    fn close_write(&mut self) -> IoResult<()>;
-    fn close_read(&mut self) -> IoResult<()>;
-    fn set_timeout(&mut self, timeout_ms: Option<u64>);
-    fn set_read_timeout(&mut self, timeout_ms: Option<u64>);
-    fn set_write_timeout(&mut self, timeout_ms: Option<u64>);
-}
-
-pub trait RtioSocket {
-    fn socket_name(&mut self) -> IoResult<SocketAddr>;
-}
-
-pub trait RtioUdpSocket : RtioSocket {
-    fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)>;
-    fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()>;
-
-    fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()>;
-    fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()>;
-
-    fn loop_multicast_locally(&mut self) -> IoResult<()>;
-    fn dont_loop_multicast_locally(&mut self) -> IoResult<()>;
-
-    fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()>;
-    fn time_to_live(&mut self, ttl: int) -> IoResult<()>;
-
-    fn hear_broadcasts(&mut self) -> IoResult<()>;
-    fn ignore_broadcasts(&mut self) -> IoResult<()>;
-
-    fn clone(&self) -> Box<RtioUdpSocket:Send>;
-    fn set_timeout(&mut self, timeout_ms: Option<u64>);
-    fn set_read_timeout(&mut self, timeout_ms: Option<u64>);
-    fn set_write_timeout(&mut self, timeout_ms: Option<u64>);
-}
-
-pub trait RtioTimer {
-    fn sleep(&mut self, msecs: u64);
-    fn oneshot(&mut self, msecs: u64) -> Receiver<()>;
-    fn period(&mut self, msecs: u64) -> Receiver<()>;
-}
-
-pub trait RtioFileStream {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<int>;
-    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
-    fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int>;
-    fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()>;
-    fn seek(&mut self, pos: i64, whence: SeekStyle) -> IoResult<u64>;
-    fn tell(&self) -> IoResult<u64>;
-    fn fsync(&mut self) -> IoResult<()>;
-    fn datasync(&mut self) -> IoResult<()>;
-    fn truncate(&mut self, offset: i64) -> IoResult<()>;
-    fn fstat(&mut self) -> IoResult<FileStat>;
-}
-
-pub trait RtioProcess {
-    fn id(&self) -> libc::pid_t;
-    fn kill(&mut self, signal: int) -> IoResult<()>;
-    fn wait(&mut self) -> IoResult<ProcessExit>;
-    fn set_timeout(&mut self, timeout: Option<u64>);
-}
-
-pub trait RtioPipe {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
-    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
-    fn clone(&self) -> Box<RtioPipe:Send>;
-
-    fn close_write(&mut self) -> IoResult<()>;
-    fn close_read(&mut self) -> IoResult<()>;
-    fn set_timeout(&mut self, timeout_ms: Option<u64>);
-    fn set_read_timeout(&mut self, timeout_ms: Option<u64>);
-    fn set_write_timeout(&mut self, timeout_ms: Option<u64>);
-}
-
-pub trait RtioUnixListener {
-    fn listen(~self) -> IoResult<Box<RtioUnixAcceptor:Send>>;
-}
-
-pub trait RtioUnixAcceptor {
-    fn accept(&mut self) -> IoResult<Box<RtioPipe:Send>>;
-    fn set_timeout(&mut self, timeout: Option<u64>);
-}
-
-pub trait RtioTTY {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
-    fn write(&mut self, buf: &[u8]) -> IoResult<()>;
-    fn set_raw(&mut self, raw: bool) -> IoResult<()>;
-    fn get_winsize(&mut self) -> IoResult<(int, int)>;
-    fn isatty(&self) -> bool;
-}
-
-pub trait PausableIdleCallback {
-    fn pause(&mut self);
-    fn resume(&mut self);
-}
-
-pub trait RtioSignal {}
diff --git a/src/libstd/rt/stack.rs b/src/libstd/rt/stack.rs
deleted file mode 100644 (file)
index dc6ab49..0000000
+++ /dev/null
@@ -1,279 +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.
-
-//! Rust stack-limit management
-//!
-//! Currently Rust uses a segmented-stack-like scheme in order to detect stack
-//! overflow for rust tasks. In this scheme, the prologue of all functions are
-//! preceded with a check to see whether the current stack limits are being
-//! exceeded.
-//!
-//! This module provides the functionality necessary in order to manage these
-//! stack limits (which are stored in platform-specific locations). The
-//! functions here are used at the borders of the task lifetime in order to
-//! manage these limits.
-//!
-//! This function is an unstable module because this scheme for stack overflow
-//! detection is not guaranteed to continue in the future. Usage of this module
-//! is discouraged unless absolutely necessary.
-
-pub static RED_ZONE: uint = 20 * 1024;
-
-/// This function is invoked from rust's current __morestack function. Segmented
-/// stacks are currently not enabled as segmented stacks, but rather one giant
-/// stack segment. This means that whenever we run out of stack, we want to
-/// truly consider it to be stack overflow rather than allocating a new stack.
-#[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;
-
-    unsafe {
-        // We're calling this function because the stack just ran out. We need
-        // to call some other rust functions, but if we invoke the functions
-        // right now it'll just trigger this handler being called again. In
-        // order to alleviate this, we move the stack limit to be inside of the
-        // red zone that was allocated for exactly this reason.
-        let limit = get_sp_limit();
-        record_sp_limit(limit - RED_ZONE / 2);
-
-        // This probably isn't the best course of action. Ideally one would want
-        // to unwind the stack here instead of just aborting the entire process.
-        // This is a tricky problem, however. There's a few things which need to
-        // be considered:
-        //
-        //  1. We're here because of a stack overflow, yet unwinding will run
-        //     destructors and hence arbitrary code. What if that code overflows
-        //     the stack? One possibility is to use the above allocation of an
-        //     extra 10k to hope that we don't hit the limit, and if we do then
-        //     abort the whole program. Not the best, but kind of hard to deal
-        //     with unless we want to switch stacks.
-        //
-        //  2. LLVM will optimize functions based on whether they can unwind or
-        //     not. It will flag functions with 'nounwind' if it believes that
-        //     the function cannot trigger unwinding, but if we do unwind on
-        //     stack overflow then it means that we could unwind in any function
-        //     anywhere. We would have to make sure that LLVM only places the
-        //     nounwind flag on functions which don't call any other functions.
-        //
-        //  3. The function that overflowed may have owned arguments. These
-        //     arguments need to have their destructors run, but we haven't even
-        //     begun executing the function yet, so unwinding will not run the
-        //     any landing pads for these functions. If this is ignored, then
-        //     the arguments will just be leaked.
-        //
-        // Exactly what to do here is a very delicate topic, and is possibly
-        // still up in the air for what exactly to do. Some relevant issues:
-        //
-        //  #3555 - out-of-stack failure leaks arguments
-        //  #3695 - should there be a stack limit?
-        //  #9855 - possible strategies which could be taken
-        //  #9854 - unwinding on windows through __morestack has never worked
-        //  #2361 - possible implementation of not using landing pads
-
-        let task: Option<Box<Task>> = Local::try_take();
-        let name = match task {
-            Some(ref task) => {
-                task.name.as_ref().map(|n| n.as_slice())
-            }
-            None => None
-        };
-        let name = name.unwrap_or("<unknown>");
-
-        // See the message below for why this is not emitted to the
-        // task's logger. This has the additional conundrum of the
-        // logger may not be initialized just yet, meaning that an FFI
-        // call would happen to initialized it (calling out to libuv),
-        // and the FFI call needs 2MB of stack when we just ran out.
-        rterrln!("task '{}' has overflowed its stack", name);
-
-        intrinsics::abort();
-    }
-}
-
-#[inline(always)]
-pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) {
-    // When the old runtime had segmented stacks, it used a calculation that was
-    // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
-    // symbol resolution, llvm function calls, etc. In theory this red zone
-    // value is 0, but it matters far less when we have gigantic stacks because
-    // we don't need to be so exact about our stack budget. The "fudge factor"
-    // was because LLVM doesn't emit a stack check for functions < 256 bytes in
-    // size. Again though, we have giant stacks, so we round all these
-    // calculations up to the nice round number of 20k.
-    record_sp_limit(stack_lo + RED_ZONE);
-
-    return target_record_stack_bounds(stack_lo, stack_hi);
-
-    #[cfg(not(windows))] #[cfg(not(target_arch = "x86_64"))] #[inline(always)]
-    unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {}
-    #[cfg(windows, target_arch = "x86_64")] #[inline(always)]
-    unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
-        // Windows compiles C functions which may check the stack bounds. This
-        // means that if we want to perform valid FFI on windows, then we need
-        // to ensure that the stack bounds are what they truly are for this
-        // task. More info can be found at:
-        //   https://github.com/mozilla/rust/issues/3445#issuecomment-26114839
-        //
-        // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
-        asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile");
-        asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile");
-    }
-}
-
-/// Records the current limit of the stack as specified by `end`.
-///
-/// This is stored in an OS-dependent location, likely inside of the thread
-/// local storage. The location that the limit is stored is a pre-ordained
-/// location because it's where LLVM has emitted code to check.
-///
-/// Note that this cannot be called under normal circumstances. This function is
-/// changing the stack limit, so upon returning any further function calls will
-/// possibly be triggering the morestack logic if you're not careful.
-///
-/// Also note that this and all of the inside functions are all flagged as
-/// "inline(always)" because they're messing around with the stack limits.  This
-/// would be unfortunate for the functions themselves to trigger a morestack
-/// invocation (if they were an actual function call).
-#[inline(always)]
-pub unsafe fn record_sp_limit(limit: uint) {
-    return target_record_sp_limit(limit);
-
-    // x86-64
-    #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        asm!("movq $$0x60+90*8, %rsi
-              movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile")
-    }
-    #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile")
-    }
-    #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
-        // store this inside of the "arbitrary data slot", but double the size
-        // because this is 64 bit instead of 32 bit
-        asm!("movq $0, %gs:0x28" :: "r"(limit) :: "volatile")
-    }
-    #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile")
-    }
-
-    // x86
-    #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        asm!("movl $$0x48+90*4, %eax
-              movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
-    }
-    #[cfg(target_arch = "x86", target_os = "linux")]
-    #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
-    }
-    #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        // see: http://en.wikipedia.org/wiki/Win32_Thread_Information_Block
-        // store this inside of the "arbitrary data slot"
-        asm!("movl $0, %fs:0x14" :: "r"(limit) :: "volatile")
-    }
-
-    // mips, arm - Some brave soul can port these to inline asm, but it's over
-    //             my head personally
-    #[cfg(target_arch = "mips")]
-    #[cfg(target_arch = "arm")] #[inline(always)]
-    unsafe fn target_record_sp_limit(limit: uint) {
-        use libc::c_void;
-        return record_sp_limit(limit as *c_void);
-        extern {
-            fn record_sp_limit(limit: *c_void);
-        }
-    }
-}
-
-/// The counterpart of the function above, this function will fetch the current
-/// stack limit stored in TLS.
-///
-/// Note that all of these functions are meant to be exact counterparts of their
-/// brethren above, except that the operands are reversed.
-///
-/// As with the setter, this function does not have a __morestack header and can
-/// therefore be called in a "we're out of stack" situation.
-#[inline(always)]
-pub unsafe fn get_sp_limit() -> uint {
-    return target_get_sp_limit();
-
-    // x86-64
-    #[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        let limit;
-        asm!("movq $$0x60+90*8, %rsi
-              movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
-        return limit;
-    }
-    #[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        let limit;
-        asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
-        return limit;
-    }
-    #[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        let limit;
-        asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile");
-        return limit;
-    }
-    #[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        let limit;
-        asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
-        return limit;
-    }
-
-    // x86
-    #[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        let limit;
-        asm!("movl $$0x48+90*4, %eax
-              movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
-        return limit;
-    }
-    #[cfg(target_arch = "x86", target_os = "linux")]
-    #[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        let limit;
-        asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
-        return limit;
-    }
-    #[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        let limit;
-        asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile");
-        return limit;
-    }
-
-    // mips, arm - Some brave soul can port these to inline asm, but it's over
-    //             my head personally
-    #[cfg(target_arch = "mips")]
-    #[cfg(target_arch = "arm")] #[inline(always)]
-    unsafe fn target_get_sp_limit() -> uint {
-        use libc::c_void;
-        return get_sp_limit() as uint;
-        extern {
-            fn get_sp_limit() -> *c_void;
-        }
-    }
-}
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
deleted file mode 100644 (file)
index 7f492a0..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright 2013-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.
-
-//! Language-level runtime services that should reasonably expected
-//! to be available 'everywhere'. Local heaps, GC, unwinding,
-//! local storage, and logging. Even a 'freestanding' Rust would likely want
-//! to implement this.
-
-use alloc::arc::Arc;
-
-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;
-
-/// The Task struct represents all state associated with a rust
-/// task. There are at this point two primary "subtypes" of task,
-/// however instead of using a subtype we just have a "task_type" field
-/// in the struct. This contains a pointer to another struct that holds
-/// the type-specific state.
-pub struct Task {
-    pub heap: LocalHeap,
-    pub gc: GarbageCollector,
-    pub storage: LocalStorage,
-    pub unwinder: Unwinder,
-    pub death: Death,
-    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 GarbageCollector;
-pub struct LocalStorage(pub Option<local_data::Map>);
-
-/// A handle to a blocked task. Usually this means having the Box<Task>
-/// pointer by ownership, but if the task is killable, a killer can steal it
-/// at any time.
-pub enum BlockedTask {
-    Owned(Box<Task>),
-    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 struct BlockedTasks {
-    inner: Arc<AtomicUint>,
-}
-
-impl Task {
-    pub fn new() -> Task {
-        Task {
-            heap: LocalHeap::new(),
-            gc: GarbageCollector,
-            storage: LocalStorage(None),
-            unwinder: Unwinder::new(),
-            death: Death::new(),
-            destroyed: false,
-            name: None,
-            stdout: None,
-            stderr: None,
-            imp: None,
-        }
-    }
-
-    /// Executes the given closure as if it's running inside this task. The task
-    /// is consumed upon entry, and the destroyed task is returned from this
-    /// function in order for the caller to free. This function is guaranteed to
-    /// not unwind because the closure specified is run inside of a `rust_try`
-    /// block. (this is the only try/catch block in the world).
-    ///
-    /// This function is *not* meant to be abused as a "try/catch" block. This
-    /// is meant to be used at the absolute boundaries of a task's lifetime, and
-    /// only for that purpose.
-    pub fn run(~self, mut f: ||) -> Box<Task> {
-        // Need to put ourselves into TLS, but also need access to the unwinder.
-        // Unsafely get a handle to the task so we can continue to use it after
-        // putting it in tls (so we can invoke the unwinder).
-        let handle: *mut Task = unsafe {
-            *mem::transmute::<&Box<Task>, &*mut Task>(&self)
-        };
-        Local::put(self);
-
-        // The only try/catch block in the world. Attempt to run the task's
-        // client-specified code and catch any failures.
-        let try_block = || {
-
-            // 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.
-                // There's some interaction in rustc between the box
-                // annihilator and the TLS dtor by which TLS is
-                // accessed from annihilated box dtors *after* TLS is
-                // destroyed. Somehow setting TLS back to null, as the
-                // old runtime did, makes this work, but I don't currently
-                // understand how. I would expect that, if the annihilator
-                // reinvokes TLS while TLS is uninitialized, that
-                // TLS would be reinitialized but never destroyed,
-                // but somehow this works. I have no idea what's going
-                // on but this seems to make things magically work. FML.
-                //
-                // (added after initial comment) A possible interaction here is
-                // that the destructors for the objects in TLS themselves invoke
-                // 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 = {
-                    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();
-            })
-        };
-
-        unsafe { (*handle).unwinder.try(try_block); }
-
-        // Here we must unsafely borrow the task in order to not remove it from
-        // TLS. When collecting failure, we may attempt to send on a channel (or
-        // just run aribitrary code), so we must be sure to still have a local
-        // task in TLS.
-        unsafe {
-            let me: *mut Task = Local::unsafe_borrow();
-            (*me).death.collect_failure((*me).unwinder.result());
-        }
-        let mut me: Box<Task> = Local::take();
-        me.destroyed = true;
-        return me;
-    }
-
-    /// Inserts a runtime object into this task, transferring ownership to the
-    /// task. It is illegal to replace a previous runtime object in this task
-    /// with this argument.
-    pub fn put_runtime(&mut self, ops: Box<Runtime:Send>) {
-        assert!(self.imp.is_none());
-        self.imp = Some(ops);
-    }
-
-    /// Attempts to extract the runtime as a specific type. If the runtime does
-    /// not have the provided type, then the runtime is not removed. If the
-    /// runtime does have the specified type, then it is removed and returned
-    /// (transfer of ownership).
-    ///
-    /// It is recommended to only use this method when *absolutely necessary*.
-    /// This function may not be available in the future.
-    pub fn maybe_take_runtime<T: 'static>(&mut self) -> Option<Box<T>> {
-        // This is a terrible, terrible function. The general idea here is to
-        // take the runtime, cast it to Box<Any>, check if it has the right
-        // type, and then re-cast it back if necessary. The method of doing
-        // this is pretty sketchy and involves shuffling vtables of trait
-        // objects around, but it gets the job done.
-        //
-        // FIXME: This function is a serious code smell and should be avoided at
-        //      all costs. I have yet to think of a method to avoid this
-        //      function, and I would be saddened if more usage of the function
-        //      crops up.
-        unsafe {
-            let imp = self.imp.take_unwrap();
-            let &(vtable, _): &(uint, uint) = mem::transmute(&imp);
-            match imp.wrap().move::<T>() {
-                Ok(t) => Some(t),
-                Err(t) => {
-                    let (_, obj): (uint, uint) = mem::transmute(t);
-                    let obj: Box<Runtime:Send> =
-                        mem::transmute((vtable, obj));
-                    self.put_runtime(obj);
-                    None
-                }
-            }
-        }
-    }
-
-    /// Spawns a sibling to this task. The newly spawned task is configured with
-    /// the `opts` structure and will run `f` as the body of its code.
-    pub fn spawn_sibling(mut ~self, opts: TaskOpts, f: proc():Send) {
-        let ops = self.imp.take_unwrap();
-        ops.spawn_sibling(self, opts, f)
-    }
-
-    /// Deschedules the current task, invoking `f` `amt` times. It is not
-    /// 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>) {
-        let ops = self.imp.take_unwrap();
-        ops.deschedule(amt, self, f)
-    }
-
-    /// Wakes up a previously blocked task, optionally specifying whether the
-    /// current task can accept a change in scheduling. This function can only
-    /// be called on tasks that were previously blocked in `deschedule`.
-    pub fn reawaken(mut ~self) {
-        let ops = self.imp.take_unwrap();
-        ops.reawaken(self);
-    }
-
-    /// Yields control of this task to another task. This function will
-    /// eventually return, but possibly not immediately. This is used as an
-    /// opportunity to allow other tasks a chance to run.
-    pub fn yield_now(mut ~self) {
-        let ops = self.imp.take_unwrap();
-        ops.yield_now(self);
-    }
-
-    /// Similar to `yield_now`, except that this function may immediately return
-    /// without yielding (depending on what the runtime decides to do).
-    pub fn maybe_yield(mut ~self) {
-        let ops = self.imp.take_unwrap();
-        ops.maybe_yield(self);
-    }
-
-    /// Acquires a handle to the I/O factory that this task contains, normally
-    /// stored in the task's runtime. This factory may not always be available,
-    /// which is why the return type is `Option`
-    pub fn local_io<'a>(&'a mut self) -> Option<LocalIo<'a>> {
-        self.imp.get_mut_ref().local_io()
-    }
-
-    /// Returns the stack bounds for this task in (lo, hi) format. The stack
-    /// bounds may not be known for all tasks, so the return value may be
-    /// `None`.
-    pub fn stack_bounds(&self) -> (uint, uint) {
-        self.imp.get_ref().stack_bounds()
-    }
-
-    /// Returns whether it is legal for this task to block the OS thread that it
-    /// is running on.
-    pub fn can_block(&self) -> bool {
-        self.imp.get_ref().can_block()
-    }
-}
-
-impl Drop for Task {
-    fn drop(&mut self) {
-        rtdebug!("called drop for a task: {}", self as *mut Task as uint);
-        rtassert!(self.destroyed);
-    }
-}
-
-impl Iterator<BlockedTask> for BlockedTasks {
-    fn next(&mut self) -> Option<BlockedTask> {
-        Some(Shared(self.inner.clone()))
-    }
-}
-
-impl BlockedTask {
-    /// Returns Some if the task was successfully woken; None if already killed.
-    pub fn wake(self) -> Option<Box<Task>> {
-        match self {
-            Owned(task) => Some(task),
-            Shared(arc) => {
-                match arc.swap(0, SeqCst) {
-                    0 => None,
-                    n => Some(unsafe { mem::transmute(n) }),
-                }
-            }
-        }
-    }
-
-    /// Reawakens this task if ownership is acquired. If finer-grained control
-    /// is desired, use `wake` instead.
-    pub fn reawaken(self) {
-        self.wake().map(|t| t.reawaken());
-    }
-
-    // This assertion has two flavours because the wake involves an atomic op.
-    // In the faster version, destructors will fail dramatically instead.
-    #[cfg(not(test))] pub fn trash(self) { }
-    #[cfg(test)]      pub fn trash(self) { assert!(self.wake().is_none()); }
-
-    /// Create a blocked task, unless the task was already killed.
-    pub fn block(task: Box<Task>) -> BlockedTask {
-        Owned(task)
-    }
-
-    /// Converts one blocked task handle to a list of many handles to the same.
-    pub fn make_selectable(self, num_handles: uint) -> Take<BlockedTasks> {
-        let arc = match self {
-            Owned(task) => {
-                let flag = unsafe { AtomicUint::new(mem::transmute(task)) };
-                Arc::new(flag)
-            }
-            Shared(arc) => arc.clone(),
-        };
-        BlockedTasks{ inner: arc }.take(num_handles)
-    }
-
-    /// Convert to an unsafe uint value. Useful for storing in a pipe's state
-    /// flag.
-    #[inline]
-    pub unsafe fn cast_to_uint(self) -> uint {
-        match self {
-            Owned(task) => {
-                let blocked_task_ptr: uint = mem::transmute(task);
-                rtassert!(blocked_task_ptr & 0x1 == 0);
-                blocked_task_ptr
-            }
-            Shared(arc) => {
-                let blocked_task_ptr: uint = mem::transmute(box arc);
-                rtassert!(blocked_task_ptr & 0x1 == 0);
-                blocked_task_ptr | 0x1
-            }
-        }
-    }
-
-    /// Convert from an unsafe uint value. Useful for retrieving a pipe's state
-    /// flag.
-    #[inline]
-    pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
-        if blocked_task_ptr & 0x1 == 0 {
-            Owned(mem::transmute(blocked_task_ptr))
-        } else {
-            let ptr: Box<Arc<AtomicUint>> =
-                mem::transmute(blocked_task_ptr & !1);
-            Shared(*ptr)
-        }
-    }
-}
-
-impl Death {
-    pub fn new() -> Death {
-        Death { on_exit: None, }
-    }
-
-    /// Collect failure exit codes from children and propagate them to a parent.
-    pub fn collect_failure(&mut self, result: TaskResult) {
-        match self.on_exit.take() {
-            Some(Execute(f)) => f(result),
-            Some(SendMessage(ch)) => { let _ = ch.send_opt(result); }
-            None => {}
-        }
-    }
-}
-
-impl Drop for Death {
-    fn drop(&mut self) {
-        // make this type noncopyable
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-    use prelude::*;
-    use task;
-
-    #[test]
-    fn local_heap() {
-        let a = @5;
-        let b = a;
-        assert!(*a == 5);
-        assert!(*b == 5);
-    }
-
-    #[test]
-    fn tls() {
-        local_data_key!(key: @String)
-        key.replace(Some(@"data".to_string()));
-        assert_eq!(key.get().unwrap().as_slice(), "data");
-        local_data_key!(key2: @String)
-        key2.replace(Some(@"data".to_string()));
-        assert_eq!(key2.get().unwrap().as_slice(), "data");
-    }
-
-    #[test]
-    fn unwind() {
-        let result = task::try(proc()());
-        rtdebug!("trying first assert");
-        assert!(result.is_ok());
-        let result = task::try::<()>(proc() fail!());
-        rtdebug!("trying second assert");
-        assert!(result.is_err());
-    }
-
-    #[test]
-    fn rng() {
-        use 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();
-        tx.send(10);
-        assert!(rx.recv() == 10);
-    }
-
-    #[test]
-    fn comm_shared_chan() {
-        let (tx, rx) = channel();
-        tx.send(10);
-        assert!(rx.recv() == 10);
-    }
-
-    #[test]
-    fn heap_cycles() {
-        use cell::RefCell;
-        use option::{Option, Some, None};
-
-        struct List {
-            next: Option<@RefCell<List>>,
-        }
-
-        let a = @RefCell::new(List { next: None });
-        let b = @RefCell::new(List { next: Some(a) });
-
-        {
-            let mut a = a.borrow_mut();
-            a.next = Some(b);
-        }
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_begin_unwind() {
-        use rt::unwind::begin_unwind;
-        begin_unwind("cause", file!(), line!())
-    }
-
-    // Task blocking tests
-
-    #[test]
-    fn block_and_wake() {
-        let task = box Task::new();
-        let mut task = BlockedTask::block(task).wake().unwrap();
-        task.destroyed = true;
-    }
-}
diff --git a/src/libstd/rt/thread_local_storage.rs b/src/libstd/rt/thread_local_storage.rs
deleted file mode 100644 (file)
index a3ebcba..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2013-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.
-
-#![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)]
-pub type Key = pthread_key_t;
-
-#[cfg(unix)]
-pub unsafe fn create(key: &mut Key) {
-    assert_eq!(0, pthread_key_create(key, null()));
-}
-
-#[cfg(unix)]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    assert_eq!(0, pthread_setspecific(key, value));
-}
-
-#[cfg(unix)]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    pthread_getspecific(key)
-}
-
-#[cfg(unix)]
-pub unsafe fn destroy(key: Key) {
-    assert_eq!(0, pthread_key_delete(key));
-}
-
-#[cfg(target_os="macos")]
-#[allow(non_camel_case_types)] // foreign type
-type pthread_key_t = ::libc::c_ulong;
-
-#[cfg(target_os="linux")]
-#[cfg(target_os="freebsd")]
-#[cfg(target_os="android")]
-#[allow(non_camel_case_types)] // foreign type
-type pthread_key_t = ::libc::c_uint;
-
-#[cfg(unix)]
-extern {
-    fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int;
-    fn pthread_key_delete(key: pthread_key_t) -> c_int;
-    fn pthread_getspecific(key: pthread_key_t) -> *mut u8;
-    fn pthread_setspecific(key: pthread_key_t, value: *mut u8) -> c_int;
-}
-
-#[cfg(windows)]
-pub type Key = DWORD;
-
-#[cfg(windows)]
-pub unsafe fn create(key: &mut Key) {
-    static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
-    *key = TlsAlloc();
-    assert!(*key != TLS_OUT_OF_INDEXES);
-}
-
-#[cfg(windows)]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    assert!(0 != TlsSetValue(key, value as *mut ::libc::c_void))
-}
-
-#[cfg(windows)]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    TlsGetValue(key) as *mut u8
-}
-
-#[cfg(windows)]
-pub unsafe fn destroy(key: Key) {
-    assert!(TlsFree(key) != 0);
-}
-
-#[cfg(windows)]
-#[allow(non_snake_case_functions)]
-extern "system" {
-    fn TlsAlloc() -> DWORD;
-    fn TlsFree(dwTlsIndex: DWORD) -> BOOL;
-    fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
-    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);
-    }
-}
diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs
deleted file mode 100644 (file)
index af73e61..0000000
+++ /dev/null
@@ -1,494 +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.
-
-//! Stack unwinding
-
-// Implementation of Rust stack unwinding
-//
-// For background on exception handling and stack unwinding please see
-// "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
-// documents linked from it.
-// These are also good reads:
-//     http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
-//     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
-//     http://www.airs.com/blog/index.php?s=exception+frames
-//
-// ~~~ A brief summary ~~~
-// Exception handling happens in two phases: a search phase and a cleanup phase.
-//
-// In both phases the unwinder walks stack frames from top to bottom using
-// information from the stack frame unwind sections of the current process's
-// modules ("module" here refers to an OS module, i.e. an executable or a
-// dynamic library).
-//
-// For each stack frame, it invokes the associated "personality routine", whose
-// address is also stored in the unwind info section.
-//
-// In the search phase, the job of a personality routine is to examine exception
-// object being thrown, and to decide whether it should be caught at that stack
-// frame.  Once the handler frame has been identified, cleanup phase begins.
-//
-// In the cleanup phase, personality routines invoke cleanup code associated
-// with their stack frames (i.e. destructors).  Once stack has been unwound down
-// to the handler frame level, unwinding stops and the last personality routine
-// transfers control to its' catch block.
-//
-// ~~~ Frame unwind info registration ~~~
-// Each module has its' own frame unwind info section (usually ".eh_frame"), and
-// unwinder needs to know about all of them in order for unwinding to be able to
-// cross module boundaries.
-//
-// On some platforms, like Linux, this is achieved by dynamically enumerating
-// currently loaded modules via the dl_iterate_phdr() API and finding all
-// .eh_frame sections.
-//
-// Others, like Windows, require modules to actively register their unwind info
-// sections by calling __register_frame_info() API at startup.  In the latter
-// case it is essential that there is only one copy of the unwinder runtime in
-// the process.  This is usually achieved by linking to the dynamic version of
-// the unwind runtime.
-//
-// Currently Rust uses unwind runtime provided by libgcc.
-
-use any::{Any, AnyRefExt};
-use fmt;
-use intrinsics;
-use kinds::Send;
-use mem;
-use option::{Some, None, Option};
-use owned::Box;
-use prelude::drop;
-use ptr::RawPtr;
-use result::{Err, Ok, Result};
-use rt::backtrace;
-use rt::local::Local;
-use rt::task::Task;
-use str::Str;
-use string::String;
-use task::TaskResult;
-
-use uw = rt::libunwind;
-
-pub struct Unwinder {
-    unwinding: bool,
-    cause: Option<Box<Any:Send>>
-}
-
-struct Exception {
-    uwe: uw::_Unwind_Exception,
-    cause: Option<Box<Any:Send>>,
-}
-
-impl Unwinder {
-    pub fn new() -> Unwinder {
-        Unwinder {
-            unwinding: false,
-            cause: None,
-        }
-    }
-
-    pub fn unwinding(&self) -> bool {
-        self.unwinding
-    }
-
-    pub fn try(&mut self, f: ||) {
-        self.cause = unsafe { try(f) }.err();
-    }
-
-    pub fn result(&mut self) -> TaskResult {
-        if self.unwinding {
-            Err(self.cause.take().unwrap())
-        } else {
-            Ok(())
-        }
-    }
-}
-
-/// Invoke a closure, capturing the cause of failure if one occurs.
-///
-/// This function will return `None` if the closure did not fail, and will
-/// return `Some(cause)` if the closure fails. The `cause` returned is the
-/// object with which failure was originally invoked.
-///
-/// This function also is unsafe for a variety of reasons:
-///
-/// * This is not safe to call in a nested fashion. The unwinding
-///   interface for Rust is designed to have at most one try/catch block per
-///   task, not multiple. No runtime checking is currently performed to uphold
-///   this invariant, so this function is not safe. A nested try/catch block
-///   may result in corruption of the outer try/catch block's state, especially
-///   if this is used within a task itself.
-///
-/// * It is not sound to trigger unwinding while already unwinding. Rust tasks
-///   have runtime checks in place to ensure this invariant, but it is not
-///   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};
-
-    let closure: Closure = mem::transmute(f);
-    let ep = rust_try(try_fn, closure.code as *c_void,
-                      closure.env as *c_void);
-    return if ep.is_null() {
-        Ok(())
-    } else {
-        let my_ep = ep as *mut Exception;
-        rtdebug!("caught {}", (*my_ep).uwe.exception_class);
-        let cause = (*my_ep).cause.take();
-        uw::_Unwind_DeleteException(ep);
-        Err(cause.unwrap())
-    };
-
-    extern fn try_fn(code: *c_void, env: *c_void) {
-        unsafe {
-            let closure: || = mem::transmute(Closure {
-                code: code as *(),
-                env: env as *(),
-            });
-            closure();
-        }
-    }
-
-    extern {
-        // Rust's try-catch
-        // When f(...) returns normally, the return value is null.
-        // When f(...) throws, the return value is a pointer to the caught
-        // exception object.
-        fn rust_try(f: extern "C" fn(*c_void, *c_void),
-                    code: *c_void,
-                    data: *c_void) -> *uw::_Unwind_Exception;
-    }
-}
-
-// An uninlined, unmangled function upon which to slap yer breakpoints
-#[inline(never)]
-#[no_mangle]
-fn rust_fail(cause: Box<Any:Send>) -> ! {
-    rtdebug!("begin_unwind()");
-
-    unsafe {
-        let exception = box Exception {
-            uwe: uw::_Unwind_Exception {
-                exception_class: rust_exception_class(),
-                exception_cleanup: exception_cleanup,
-                private: [0, ..uw::unwinder_private_data_size],
-            },
-            cause: Some(cause),
-        };
-        let error = uw::_Unwind_RaiseException(mem::transmute(exception));
-        rtabort!("Could not unwind stack, error = {}", error as int)
-    }
-
-    extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
-                                exception: *uw::_Unwind_Exception) {
-        rtdebug!("exception_cleanup()");
-        unsafe {
-            let _: Box<Exception> = mem::transmute(exception);
-        }
-    }
-}
-
-// Rust's exception class identifier.  This is used by personality routines to
-// determine whether the exception was thrown by their own runtime.
-fn rust_exception_class() -> uw::_Unwind_Exception_Class {
-    // M O Z \0  R U S T -- vendor, language
-    0x4d4f5a_00_52555354
-}
-
-// We could implement our personality routine in pure Rust, however exception
-// info decoding is tedious.  More importantly, personality routines have to
-// handle various platform quirks, which are not fun to maintain.  For this
-// reason, we attempt to reuse personality routine of the C language:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each task's stack.
-// So we have two versions:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-//   so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//   This is achieved by overriding the return value in search phase to always
-//   say "catch!".
-
-#[cfg(not(target_arch = "arm"), not(test))]
-#[doc(hidden)]
-#[allow(visible_private_types)]
-pub mod eabi {
-    use uw = rt::libunwind;
-    use libc::c_int;
-
-    extern "C" {
-        fn __gcc_personality_v0(version: c_int,
-                                actions: uw::_Unwind_Action,
-                                exception_class: uw::_Unwind_Exception_Class,
-                                ue_header: *uw::_Unwind_Exception,
-                                context: *uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
-    }
-
-    #[lang="eh_personality"]
-    extern fn eh_personality(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *uw::_Unwind_Exception,
-        context: *uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                 context)
-        }
-    }
-
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
-        version: c_int,
-        actions: uw::_Unwind_Action,
-        exception_class: uw::_Unwind_Exception_Class,
-        ue_header: *uw::_Unwind_Exception,
-        context: *uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                 __gcc_personality_v0(version, actions, exception_class, ue_header,
-                                      context)
-            }
-        }
-    }
-}
-
-// ARM EHABI uses a slightly different personality routine signature,
-// but otherwise works the same.
-#[cfg(target_arch = "arm", not(test))]
-#[allow(visible_private_types)]
-pub mod eabi {
-    use uw = rt::libunwind;
-    use libc::c_int;
-
-    extern "C" {
-        fn __gcc_personality_v0(state: uw::_Unwind_State,
-                                ue_header: *uw::_Unwind_Exception,
-                                context: *uw::_Unwind_Context)
-            -> uw::_Unwind_Reason_Code;
-    }
-
-    #[lang="eh_personality"]
-    extern "C" fn eh_personality(
-        state: uw::_Unwind_State,
-        ue_header: *uw::_Unwind_Exception,
-        context: *uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        unsafe {
-            __gcc_personality_v0(state, ue_header, context)
-        }
-    }
-
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
-        state: uw::_Unwind_State,
-        ue_header: *uw::_Unwind_Exception,
-        context: *uw::_Unwind_Context
-    ) -> uw::_Unwind_Reason_Code
-    {
-        if (state as c_int & uw::_US_ACTION_MASK as c_int)
-                           == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
-            uw::_URC_HANDLER_FOUND // catch!
-        }
-        else { // cleanup phase
-            unsafe {
-                 __gcc_personality_v0(state, ue_header, context)
-            }
-        }
-    }
-}
-
-// Entry point of failure from the libcore crate
-#[cfg(not(test))]
-#[lang = "begin_unwind"]
-pub extern fn rust_begin_unwind(msg: &fmt::Arguments,
-                                file: &'static str, line: uint) -> ! {
-    begin_unwind_fmt(msg, file, line)
-}
-
-/// The entry point for unwinding with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `fail!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[inline(never)] #[cold]
-pub fn begin_unwind_fmt(msg: &fmt::Arguments, file: &'static str,
-                        line: uint) -> ! {
-    // 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)
-}
-
-/// This is the entry point of unwinding for fail!() and assert!().
-#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> ! {
-    // Note that this should be the only allocation performed in this code path.
-    // Currently this means that fail!() on OOM will invoke this code path,
-    // but then again we're not really ready for failing on OOM anyway. If
-    // we do start doing this, then we should propagate this allocation to
-    // be performed in the parent of this task instead of the task that's
-    // failing.
-
-    // see below for why we do the `Any` coercion here.
-    begin_unwind_inner(box msg, file, line)
-}
-
-
-/// The core of the unwinding.
-///
-/// This is non-generic to avoid instantiation bloat in other crates
-/// (which makes compilation of small crates noticably slower). (Note:
-/// we need the `Any` object anyway, we're not just creating it to
-/// avoid being generic.)
-///
-/// Do this split took the LLVM IR line counts of `fn main() { fail!()
-/// }` from ~1900/3700 (-O/no opts) to 180/590.
-#[inline(never)] #[cold] // this is the slow path, please never inline this
-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() }
-            }
-
-            // 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.
-    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
-        }
-    };
-
-    // 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>");
-
-        match task.stderr.take() {
-            Some(mut stderr) => {
-                Local::put(task);
-                // FIXME: what to do when the task printing fails?
-                let _err = write!(stderr,
-                                  "task '{}' failed at '{}', {}:{}\n",
-                                  n, msg, file, line);
-                if backtrace::log_enabled() {
-                    let _err = backtrace::write(stderr);
-                }
-                task = Local::take();
-
-                match mem::replace(&mut task.stderr, Some(stderr)) {
-                    Some(prev) => {
-                        Local::put(task);
-                        drop(prev);
-                        task = Local::take();
-                    }
-                    None => {}
-                }
-            }
-            None => {
-                rterrln!("task '{}' failed at '{}', {}:{}", n, msg, file, line);
-                if backtrace::log_enabled() {
-                    let mut err = ::rt::util::Stderr;
-                    let _err = backtrace::write(&mut err);
-                }
-            }
-        }
-    }
-    task.name = name;
-    Local::put(task);
-}
index 103fbdc0bc93d2f58ce9f1e51595a375f4826757..670d4aa2061f1e0f477c077edd2c56041e6daf33 100644 (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;
-}
index f954bcabe5aa9d4271aaa9d99a004f8cbf11b678..c804918ae4b411fd74f364cb702ff6d73dc5d189 100644 (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
index ea4c12f44019876141480bff73ba5cc760f0ccec..39e420685abd971c0d6e02fbbe0405f161b0ba6a 100644 (file)
@@ -63,7 +63,7 @@
 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 @@ pub fn deque(&self) -> (Worker<T>, Stealer<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),
+            }
         }
     }
 }
index 3b573b875744b635e1bcaf1895a42d35dc926da8..9ee62ee3d81b6c5269e1b2ecc06d5c4b993ea5ea 100644 (file)
 
 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};
 
 #[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 @@ pub fn new() -> 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 @@ pub fn spawn(mut self, f: proc():Send) {
             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);
+        }
     }
 
     /**
index 6c406a7c8472e4e432164487cb4c3b4f7345c694..c05cdc85cc53affe5cc9d29ca52ccad48bedfa00 100644 (file)
@@ -224,7 +224,7 @@ pub unsafe fn open_internal() -> *u8 {
     }
 
     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
index d8de6463fabbd73c7feb9da30b987f5daec9b4c2..985ef2e142cfd2f6b2bd1422e252deb738110a0e 100644 (file)
@@ -11,7 +11,3 @@
 #![doc(hidden)]
 
 pub mod dynamic_lib;
-
-pub mod sync;
-pub mod mutex;
-
diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs
deleted file mode 100644 (file)
index 4e51e71..0000000
+++ /dev/null
@@ -1,629 +0,0 @@
-// Copyright 2013-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.
-
-//! A native mutex and condition variable type.
-//!
-//! This module contains bindings to the platform's native mutex/condition
-//! variable primitives. It provides two types: `StaticNativeMutex`, which can
-//! be statically initialized via the `NATIVE_MUTEX_INIT` value, and a simple
-//! wrapper `NativeMutex` that has a destructor to clean up after itself. These
-//! objects serve as both mutexes and condition variables simultaneously.
-//!
-//! The static lock is lazily initialized, but it can only be unsafely
-//! destroyed. A statically initialized lock doesn't necessarily have a time at
-//! which it can get deallocated. For this reason, there is no `Drop`
-//! implementation of the static mutex, but rather the `destroy()` method must
-//! be invoked manually if destruction of the mutex is desired.
-//!
-//! The non-static `NativeMutex` type does have a destructor, but cannot be
-//! statically initialized.
-//!
-//! It is not recommended to use this type for idiomatic rust use. These types
-//! are appropriate where no other options are available, but other rust
-//! concurrency primitives should be used before them: the `sync` crate defines
-//! `StaticMutex` and `Mutex` types.
-//!
-//! # Example
-//!
-//! ```rust
-//! use std::unstable::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT};
-//!
-//! // Use a statically initialized mutex
-//! static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
-//!
-//! unsafe {
-//!     let _guard = LOCK.lock();
-//! } // automatically unlocked here
-//!
-//! // Use a normally initialized mutex
-//! unsafe {
-//!     let mut lock = NativeMutex::new();
-//!
-//!     {
-//!         let _guard = lock.lock();
-//!     } // unlocked here
-//!
-//!     // sometimes the RAII guard isn't appropriate
-//!     lock.lock_noguard();
-//!     lock.unlock_noguard();
-//! } // `lock` is deallocated here
-//! ```
-
-#![allow(non_camel_case_types)]
-
-use option::{Option, None, Some};
-use ops::Drop;
-
-/// A native mutex suitable for storing in statics (that is, it has
-/// the `destroy` method rather than a destructor).
-///
-/// Prefer the `NativeMutex` type where possible, since that does not
-/// require manual deallocation.
-pub struct StaticNativeMutex {
-    inner: imp::Mutex,
-}
-
-/// A native mutex with a destructor for clean-up.
-///
-/// See `StaticNativeMutex` for a version that is suitable for storing in
-/// statics.
-pub struct NativeMutex {
-    inner: StaticNativeMutex
-}
-
-/// Automatically unlocks the mutex that it was created from on
-/// destruction.
-///
-/// Using this makes lock-based code resilient to unwinding/task
-/// failure, because the lock will be automatically unlocked even
-/// then.
-#[must_use]
-pub struct LockGuard<'a> {
-    lock: &'a StaticNativeMutex
-}
-
-pub static NATIVE_MUTEX_INIT: StaticNativeMutex = StaticNativeMutex {
-    inner: imp::MUTEX_INIT,
-};
-
-impl StaticNativeMutex {
-    /// Creates a new mutex.
-    ///
-    /// Note that a mutex created in this way needs to be explicit
-    /// freed with a call to `destroy` or it will leak.
-    /// Also it is important to avoid locking until mutex has stopped moving
-    pub unsafe fn new() -> StaticNativeMutex {
-        StaticNativeMutex { inner: imp::Mutex::new() }
-    }
-
-    /// Acquires this lock. This assumes that the current thread does not
-    /// already hold the lock.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
-    /// static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
-    /// unsafe {
-    ///     let _guard = LOCK.lock();
-    ///     // critical section...
-    /// } // automatically unlocked in `_guard`'s destructor
-    /// ```
-    pub unsafe fn lock<'a>(&'a self) -> LockGuard<'a> {
-        self.inner.lock();
-
-        LockGuard { lock: self }
-    }
-
-    /// Attempts to acquire the lock. The value returned is `Some` if
-    /// the attempt succeeded.
-    pub unsafe fn trylock<'a>(&'a self) -> Option<LockGuard<'a>> {
-        if self.inner.trylock() {
-            Some(LockGuard { lock: self })
-        } else {
-            None
-        }
-    }
-
-    /// Acquire the lock without creating a `LockGuard`.
-    ///
-    /// These needs to be paired with a call to `.unlock_noguard`. Prefer using
-    /// `.lock`.
-    pub unsafe fn lock_noguard(&self) { self.inner.lock() }
-
-    /// Attempts to acquire the lock without creating a
-    /// `LockGuard`. The value returned is whether the lock was
-    /// acquired or not.
-    ///
-    /// If `true` is returned, this needs to be paired with a call to
-    /// `.unlock_noguard`. Prefer using `.trylock`.
-    pub unsafe fn trylock_noguard(&self) -> bool {
-        self.inner.trylock()
-    }
-
-    /// Unlocks the lock. This assumes that the current thread already holds the
-    /// lock.
-    pub unsafe fn unlock_noguard(&self) { self.inner.unlock() }
-
-    /// Block on the internal condition variable.
-    ///
-    /// This function assumes that the lock is already held. Prefer
-    /// using `LockGuard.wait` since that guarantees that the lock is
-    /// held.
-    pub unsafe fn wait_noguard(&self) { self.inner.wait() }
-
-    /// Signals a thread in `wait` to wake up
-    pub unsafe fn signal_noguard(&self) { self.inner.signal() }
-
-    /// This function is especially unsafe because there are no guarantees made
-    /// that no other thread is currently holding the lock or waiting on the
-    /// condition variable contained inside.
-    pub unsafe fn destroy(&self) { self.inner.destroy() }
-}
-
-impl NativeMutex {
-    /// Creates a new mutex.
-    ///
-    /// The user must be careful to ensure the mutex is not locked when its is
-    /// being destroyed.
-    /// Also it is important to avoid locking until mutex has stopped moving
-    pub unsafe fn new() -> NativeMutex {
-        NativeMutex { inner: StaticNativeMutex::new() }
-    }
-
-    /// Acquires this lock. This assumes that the current thread does not
-    /// already hold the lock.
-    ///
-    /// # Example
-    /// ```rust
-    /// use std::unstable::mutex::NativeMutex;
-    /// unsafe {
-    ///     let mut lock = NativeMutex::new();
-    ///
-    ///     {
-    ///         let _guard = lock.lock();
-    ///         // critical section...
-    ///     } // automatically unlocked in `_guard`'s destructor
-    /// }
-    /// ```
-    pub unsafe fn lock<'a>(&'a self) -> LockGuard<'a> {
-        self.inner.lock()
-    }
-
-    /// Attempts to acquire the lock. The value returned is `Some` if
-    /// the attempt succeeded.
-    pub unsafe fn trylock<'a>(&'a self) -> Option<LockGuard<'a>> {
-        self.inner.trylock()
-    }
-
-    /// Acquire the lock without creating a `LockGuard`.
-    ///
-    /// These needs to be paired with a call to `.unlock_noguard`. Prefer using
-    /// `.lock`.
-    pub unsafe fn lock_noguard(&self) { self.inner.lock_noguard() }
-
-    /// Attempts to acquire the lock without creating a
-    /// `LockGuard`. The value returned is whether the lock was
-    /// acquired or not.
-    ///
-    /// If `true` is returned, this needs to be paired with a call to
-    /// `.unlock_noguard`. Prefer using `.trylock`.
-    pub unsafe fn trylock_noguard(&self) -> bool {
-        self.inner.trylock_noguard()
-    }
-
-    /// Unlocks the lock. This assumes that the current thread already holds the
-    /// lock.
-    pub unsafe fn unlock_noguard(&self) { self.inner.unlock_noguard() }
-
-    /// Block on the internal condition variable.
-    ///
-    /// This function assumes that the lock is already held. Prefer
-    /// using `LockGuard.wait` since that guarantees that the lock is
-    /// held.
-    pub unsafe fn wait_noguard(&self) { self.inner.wait_noguard() }
-
-    /// Signals a thread in `wait` to wake up
-    pub unsafe fn signal_noguard(&self) { self.inner.signal_noguard() }
-}
-
-impl Drop for NativeMutex {
-    fn drop(&mut self) {
-        unsafe {self.inner.destroy()}
-    }
-}
-
-impl<'a> LockGuard<'a> {
-    /// Block on the internal condition variable.
-    pub unsafe fn wait(&self) {
-        self.lock.wait_noguard()
-    }
-
-    /// Signals a thread in `wait` to wake up.
-    pub unsafe fn signal(&self) {
-        self.lock.signal_noguard()
-    }
-}
-
-#[unsafe_destructor]
-impl<'a> Drop for LockGuard<'a> {
-    fn drop(&mut self) {
-        unsafe {self.lock.unlock_noguard()}
-    }
-}
-
-#[cfg(unix)]
-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;
-
-    type pthread_mutexattr_t = libc::c_void;
-    type pthread_condattr_t = libc::c_void;
-
-    #[cfg(target_os = "freebsd")]
-    mod os {
-        use libc;
-
-        pub type pthread_mutex_t = *libc::c_void;
-        pub type pthread_cond_t = *libc::c_void;
-
-        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t =
-            0 as pthread_mutex_t;
-        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t =
-            0 as pthread_cond_t;
-    }
-
-    #[cfg(target_os = "macos")]
-    mod os {
-        use libc;
-
-        #[cfg(target_arch = "x86_64")]
-        static __PTHREAD_MUTEX_SIZE__: uint = 56;
-        #[cfg(target_arch = "x86_64")]
-        static __PTHREAD_COND_SIZE__: uint = 40;
-        #[cfg(target_arch = "x86")]
-        static __PTHREAD_MUTEX_SIZE__: uint = 40;
-        #[cfg(target_arch = "x86")]
-        static __PTHREAD_COND_SIZE__: uint = 24;
-
-        static _PTHREAD_MUTEX_SIG_init: libc::c_long = 0x32AAABA7;
-        static _PTHREAD_COND_SIG_init: libc::c_long = 0x3CB0B1BB;
-
-        pub struct pthread_mutex_t {
-            __sig: libc::c_long,
-            __opaque: [u8, ..__PTHREAD_MUTEX_SIZE__],
-        }
-        pub struct pthread_cond_t {
-            __sig: libc::c_long,
-            __opaque: [u8, ..__PTHREAD_COND_SIZE__],
-        }
-
-        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
-            __sig: _PTHREAD_MUTEX_SIG_init,
-            __opaque: [0, ..__PTHREAD_MUTEX_SIZE__],
-        };
-        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
-            __sig: _PTHREAD_COND_SIG_init,
-            __opaque: [0, ..__PTHREAD_COND_SIZE__],
-        };
-    }
-
-    #[cfg(target_os = "linux")]
-    mod os {
-        use libc;
-
-        // minus 8 because we have an 'align' field
-        #[cfg(target_arch = "x86_64")]
-        static __SIZEOF_PTHREAD_MUTEX_T: uint = 40 - 8;
-        #[cfg(target_arch = "x86")]
-        static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
-        #[cfg(target_arch = "arm")]
-        static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
-        #[cfg(target_arch = "mips")]
-        static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
-        #[cfg(target_arch = "x86_64")]
-        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-        #[cfg(target_arch = "x86")]
-        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-        #[cfg(target_arch = "arm")]
-        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-        #[cfg(target_arch = "mips")]
-        static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
-
-        pub struct pthread_mutex_t {
-            __align: libc::c_longlong,
-            size: [u8, ..__SIZEOF_PTHREAD_MUTEX_T],
-        }
-        pub struct pthread_cond_t {
-            __align: libc::c_longlong,
-            size: [u8, ..__SIZEOF_PTHREAD_COND_T],
-        }
-
-        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
-            __align: 0,
-            size: [0, ..__SIZEOF_PTHREAD_MUTEX_T],
-        };
-        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
-            __align: 0,
-            size: [0, ..__SIZEOF_PTHREAD_COND_T],
-        };
-    }
-    #[cfg(target_os = "android")]
-    mod os {
-        use libc;
-
-        pub struct pthread_mutex_t { value: libc::c_int }
-        pub struct pthread_cond_t { value: libc::c_int }
-
-        pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
-            value: 0,
-        };
-        pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
-            value: 0,
-        };
-    }
-
-    pub struct Mutex {
-        lock: Unsafe<pthread_mutex_t>,
-        cond: Unsafe<pthread_cond_t>,
-    }
-
-    pub static MUTEX_INIT: Mutex = Mutex {
-        lock: Unsafe {
-            value: PTHREAD_MUTEX_INITIALIZER,
-            marker1: marker::InvariantType,
-        },
-        cond: Unsafe {
-            value: PTHREAD_COND_INITIALIZER,
-            marker1: marker::InvariantType,
-        },
-    };
-
-    impl Mutex {
-        pub unsafe fn new() -> Mutex {
-            // As mutex might be moved and address is changing it
-            // is better to avoid initialization of potentially
-            // opaque OS data before it landed
-            let m = Mutex {
-                lock: Unsafe::new(PTHREAD_MUTEX_INITIALIZER),
-                cond: Unsafe::new(PTHREAD_COND_INITIALIZER),
-            };
-
-            return m;
-        }
-
-        pub unsafe fn lock(&self) { pthread_mutex_lock(self.lock.get()); }
-        pub unsafe fn unlock(&self) { pthread_mutex_unlock(self.lock.get()); }
-        pub unsafe fn signal(&self) { pthread_cond_signal(self.cond.get()); }
-        pub unsafe fn wait(&self) {
-            pthread_cond_wait(self.cond.get(), self.lock.get());
-        }
-        pub unsafe fn trylock(&self) -> bool {
-            pthread_mutex_trylock(self.lock.get()) == 0
-        }
-        pub unsafe fn destroy(&self) {
-            pthread_mutex_destroy(self.lock.get());
-            pthread_cond_destroy(self.cond.get());
-        }
-    }
-
-    extern {
-        fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
-        fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;
-
-        fn pthread_cond_wait(cond: *mut pthread_cond_t,
-                             lock: *mut pthread_mutex_t) -> libc::c_int;
-        fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
-    }
-}
-
-#[cfg(windows)]
-mod imp {
-    use rt::libc_heap::malloc_raw;
-    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;
-    #[cfg(target_arch = "x86")]
-    static CRIT_SECTION_SIZE: uint = 24;
-    #[cfg(target_arch = "x86_64")]
-    static CRIT_SECTION_SIZE: uint = 40;
-
-    pub struct Mutex {
-        // pointers for the lock/cond handles, atomically updated
-        lock: atomics::AtomicUint,
-        cond: atomics::AtomicUint,
-    }
-
-    pub static MUTEX_INIT: Mutex = Mutex {
-        lock: atomics::INIT_ATOMIC_UINT,
-        cond: atomics::INIT_ATOMIC_UINT,
-    };
-
-    impl Mutex {
-        pub unsafe fn new() -> Mutex {
-            Mutex {
-                lock: atomics::AtomicUint::new(init_lock()),
-                cond: atomics::AtomicUint::new(init_cond()),
-            }
-        }
-        pub unsafe fn lock(&self) {
-            EnterCriticalSection(self.getlock() as LPCRITICAL_SECTION)
-        }
-        pub unsafe fn trylock(&self) -> bool {
-            TryEnterCriticalSection(self.getlock() as LPCRITICAL_SECTION) != 0
-        }
-        pub unsafe fn unlock(&self) {
-            LeaveCriticalSection(self.getlock() as LPCRITICAL_SECTION)
-        }
-
-        pub unsafe fn wait(&self) {
-            self.unlock();
-            WaitForSingleObject(self.getcond() as HANDLE, libc::INFINITE);
-            self.lock();
-        }
-
-        pub unsafe fn signal(&self) {
-            assert!(SetEvent(self.getcond() as HANDLE) != 0);
-        }
-
-        /// This function is especially unsafe because there are no guarantees made
-        /// that no other thread is currently holding the lock or waiting on the
-        /// condition variable contained inside.
-        pub unsafe fn destroy(&self) {
-            let lock = self.lock.swap(0, atomics::SeqCst);
-            let cond = self.cond.swap(0, atomics::SeqCst);
-            if lock != 0 { free_lock(lock) }
-            if cond != 0 { free_cond(cond) }
-        }
-
-        unsafe fn getlock(&self) -> *mut c_void {
-            match self.lock.load(atomics::SeqCst) {
-                0 => {}
-                n => return n as *mut c_void
-            }
-            let lock = init_lock();
-            match self.lock.compare_and_swap(0, lock, atomics::SeqCst) {
-                0 => return lock as *mut c_void,
-                _ => {}
-            }
-            free_lock(lock);
-            return self.lock.load(atomics::SeqCst) as *mut c_void;
-        }
-
-        unsafe fn getcond(&self) -> *mut c_void {
-            match self.cond.load(atomics::SeqCst) {
-                0 => {}
-                n => return n as *mut c_void
-            }
-            let cond = init_cond();
-            match self.cond.compare_and_swap(0, cond, atomics::SeqCst) {
-                0 => return cond as *mut c_void,
-                _ => {}
-            }
-            free_cond(cond);
-            return self.cond.load(atomics::SeqCst) as *mut c_void;
-        }
-    }
-
-    pub unsafe fn init_lock() -> uint {
-        let block = malloc_raw(CRIT_SECTION_SIZE as uint) as *mut c_void;
-        InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
-        return block as uint;
-    }
-
-    pub unsafe fn init_cond() -> uint {
-        return CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
-                            ptr::null()) as uint;
-    }
-
-    pub unsafe fn free_lock(h: uint) {
-        DeleteCriticalSection(h as LPCRITICAL_SECTION);
-        libc::free(h as *mut c_void);
-    }
-
-    pub unsafe fn free_cond(h: uint) {
-        let block = h as HANDLE;
-        libc::CloseHandle(block);
-    }
-
-    #[allow(non_snake_case_functions)]
-    extern "system" {
-        fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
-                        bManualReset: BOOL,
-                        bInitialState: BOOL,
-                        lpName: LPCSTR) -> HANDLE;
-        fn InitializeCriticalSectionAndSpinCount(
-                        lpCriticalSection: LPCRITICAL_SECTION,
-                        dwSpinCount: DWORD) -> BOOL;
-        fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-        fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-        fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
-        fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
-        fn SetEvent(hEvent: HANDLE) -> BOOL;
-        fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use prelude::*;
-
-    use mem::drop;
-    use super::{StaticNativeMutex, NATIVE_MUTEX_INIT};
-    use rt::thread::Thread;
-
-    #[test]
-    fn smoke_lock() {
-        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
-        unsafe {
-            let _guard = lock.lock();
-        }
-    }
-
-    #[test]
-    fn smoke_cond() {
-        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
-        unsafe {
-            let guard = lock.lock();
-            let t = Thread::start(proc() {
-                let guard = lock.lock();
-                guard.signal();
-            });
-            guard.wait();
-            drop(guard);
-
-            t.join();
-        }
-    }
-
-    #[test]
-    fn smoke_lock_noguard() {
-        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
-        unsafe {
-            lock.lock_noguard();
-            lock.unlock_noguard();
-        }
-    }
-
-    #[test]
-    fn smoke_cond_noguard() {
-        static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
-        unsafe {
-            lock.lock_noguard();
-            let t = Thread::start(proc() {
-                lock.lock_noguard();
-                lock.signal_noguard();
-                lock.unlock_noguard();
-            });
-            lock.wait_noguard();
-            lock.unlock_noguard();
-
-            t.join();
-        }
-    }
-
-    #[test]
-    fn destroy_immediately() {
-        unsafe {
-            let m = StaticNativeMutex::new();
-            m.destroy();
-        }
-    }
-}
diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs
deleted file mode 100644 (file)
index f0f7e40..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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));
-        }
-    }
-}
index ee7fa525e79f56d8c5aeb32fe6cf003f1cc90c2b..bcf5a43fb6b3e684fee7634bde5d8abfac82e436 100644 (file)
@@ -64,7 +64,7 @@
 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;
 
index de4da6e3b06d7aca0a707cf3447f3508ca2374fd..4fdbdf8f5c7ae58ea08a0036d683e2aede790bff 100644 (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!()
         }
index 1fe99336bc9cad496271e1624d2c7dee5289550e..0ef48c9978251e09cbde006d0ab789fe1e0fc35c 100644 (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) {
index 4034c2571cd078094dd910adf4a283f25b382a99..a9a6e25adf38b88809efe909b35e9f4eee1f09a8 100644 (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;
index 8142cafd89e9195b177d3beaee93fcd7b9f484c4..f2d29c97f155e0c4329a601194afc3e4ba374f7a 100644 (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 @@ struct Point {x: int, y: int, z: int}
 
 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!()
         }