about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-22 09:36:30 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-24 14:22:35 -0700
commit188e471339dfe652b8ff9f3bbe4cc262a040c584 (patch)
treed7267619b1909f2deaf319c560a64d667d141d35
parentd425218395b4a4dd7c6e4f3d680447efd2a3abc6 (diff)
downloadrust-188e471339dfe652b8ff9f3bbe4cc262a040c584.tar.gz
rust-188e471339dfe652b8ff9f3bbe4cc262a040c584.zip
Another round of test fixes and merge conflicts
-rw-r--r--src/libextra/url.rs4
-rw-r--r--src/librustpkg/tests.rs19
-rw-r--r--src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs4
-rw-r--r--src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs11
-rw-r--r--src/libstd/rt/io/signal.rs25
-rw-r--r--src/libstd/rt/io/stdio.rs133
-rw-r--r--src/libstd/rt/rtio.rs16
-rw-r--r--src/libstd/rt/task.rs9
-rw-r--r--src/libstd/rt/uv/file.rs33
-rw-r--r--src/libstd/rt/uv/idle.rs35
-rw-r--r--src/libstd/rt/uv/signal.rs2
-rw-r--r--src/libstd/rt/uv/uvio.rs58
-rw-r--r--src/libstd/rt/uv/uvll.rs50
-rw-r--r--src/libstd/run.rs27
-rw-r--r--src/rt/rust_uv.cpp10
-rw-r--r--src/rt/rustrt.def.in2
16 files changed, 264 insertions, 174 deletions
diff --git a/src/libextra/url.rs b/src/libextra/url.rs
index bfa3934700a..d268b106e5c 100644
--- a/src/libextra/url.rs
+++ b/src/libextra/url.rs
@@ -145,7 +145,7 @@ fn decode_inner(s: &str, full_url: bool) -> ~str {
             let mut bytes = [0, 0];
             match rdr.read(bytes) {
                 Some(2) => {}
-                _ => fail2!() // XXX: malformed url?
+                _ => fail!() // XXX: malformed url?
             }
             let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char;
 
@@ -279,7 +279,7 @@ pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> {
                         let mut bytes = [0, 0];
                         match rdr.read(bytes) {
                             Some(2) => {}
-                            _ => fail2!() // XXX: malformed?
+                            _ => fail!() // XXX: malformed?
                         }
                         uint::parse_bytes(bytes, 16u).unwrap() as u8 as char
                     }
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index 16e13f70092..ce5e81d4109 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -11,7 +11,10 @@
 // rustpkg unit tests
 
 use context::{BuildContext, Context, RustcFlags};
-use std::{io, os, run, str, task};
+use std::{os, run, str, task};
+use std::rt::io;
+use std::rt::io::Writer;
+use std::rt::io::file::FileInfo;
 use extra::arc::Arc;
 use extra::arc::RWArc;
 use extra::tempfile::TempDir;
@@ -81,8 +84,9 @@ fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId {
 }
 
 fn writeFile(file_path: &Path, contents: &str) {
-    let out = io::file_writer(file_path, [io::Create, io::Truncate]).unwrap();
-    out.write_line(contents);
+    let mut out = file_path.open_writer(io::CreateOrTruncate);
+    out.write(contents.as_bytes());
+    out.write(['\n' as u8]);
 }
 
 fn mk_emptier_workspace(tag: &str) -> TempDir {
@@ -550,10 +554,11 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) {
     debug!("Frobbed? {:?}", maybe_p);
     match maybe_p {
         Some(ref p) => {
-            let w = io::file_writer(p, &[io::Append]);
-            match w {
-                Err(s) => { let _ = cond.raise((p.clone(), format!("Bad path: {}", s))); }
-                Ok(w)  => w.write_line("/* hi */")
+            do io::io_error::cond.trap(|e| {
+                cond.raise((p.clone(), format!("Bad path: {}", e.desc)));
+            }).inside {
+                let mut w = p.open_writer(io::Append);
+                w.write(bytes!("/* hi */\n"));
             }
         }
         None => fail!("frob_source_file failed to find a source file in {}",
diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
index b667dc0a576..016635339a9 100644
--- a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
+++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
@@ -11,7 +11,7 @@
 extern mod rustpkg;
 extern mod rustc;
 
-use std::{io, os, task};
+use std::{os, task};
 use rustpkg::api;
 use rustpkg::version::NoVersion;
 use rustpkg::workcache_support::digest_file_with_date;
@@ -36,7 +36,7 @@ pub fn main() {
     }
 
     if args[2] != ~"install" {
-        io::println(format!("Warning: I don't know how to {}", args[2]));
+        println(format!("Warning: I don't know how to {}", args[2]));
         return;
     }
 
diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs
index 0b838b3e0f9..f82c585b1d1 100644
--- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs
+++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs
@@ -11,7 +11,10 @@
 extern mod rustpkg;
 extern mod rustc;
 
-use std::{io, os};
+use std::os;
+use std::rt::io;
+use std::rt::io::Writer;
+use std::rt::io::file::FileInfo;
 use rustpkg::api;
 use rustpkg::version::NoVersion;
 
@@ -42,9 +45,9 @@ pub fn main() {
     let out_path = os::self_exe_path().expect("Couldn't get self_exe path");
 
     debug!("Writing file");
-    let file = io::file_writer(&out_path.join("generated.rs"), [io::Create]).unwrap();
-    file.write_str("pub fn wheeeee() { let xs = [1, 2, 3]; \
-                   for _ in xs.iter() { assert!(true); } }");
+    let mut file = out_path.join("generated.rs").open_writer(io::Create);
+    file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \
+                for _ in xs.iter() { assert!(true); } }".as_bytes());
 
     let context = api::default_context(sysroot, api::default_workspace());
     api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]);
diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs
index 07fe91f57a0..a13fc19d000 100644
--- a/src/libstd/rt/io/signal.rs
+++ b/src/libstd/rt/io/signal.rs
@@ -147,6 +147,7 @@ impl Listener {
 mod test {
     use libc;
     use rt::io::timer;
+    use rt::io;
     use super::*;
 
     // kill is only available on Unixes
@@ -158,7 +159,7 @@ mod test {
         }
     }
 
-    #[test]
+    #[test] #[cfg(unix)]
     fn test_io_signal_smoketest() {
         let mut signal = Listener::new();
         signal.register(Interrupt);
@@ -166,11 +167,11 @@ mod test {
         timer::sleep(10);
         match signal.port.recv() {
             Interrupt => (),
-            s => fail2!("Expected Interrupt, got {:?}", s),
+            s => fail!("Expected Interrupt, got {:?}", s),
         }
     }
 
-    #[test]
+    #[test] #[cfg(unix)]
     fn test_io_signal_two_signal_one_signum() {
         let mut s1 = Listener::new();
         let mut s2 = Listener::new();
@@ -180,15 +181,15 @@ mod test {
         timer::sleep(10);
         match s1.port.recv() {
             Interrupt => (),
-            s => fail2!("Expected Interrupt, got {:?}", s),
+            s => fail!("Expected Interrupt, got {:?}", s),
         }
         match s1.port.recv() {
             Interrupt => (),
-            s => fail2!("Expected Interrupt, got {:?}", s),
+            s => fail!("Expected Interrupt, got {:?}", s),
         }
     }
 
-    #[test]
+    #[test] #[cfg(unix)]
     fn test_io_signal_unregister() {
         let mut s1 = Listener::new();
         let mut s2 = Listener::new();
@@ -198,7 +199,7 @@ mod test {
         sigint();
         timer::sleep(10);
         if s2.port.peek() {
-            fail2!("Unexpected {:?}", s2.port.recv());
+            fail!("Unexpected {:?}", s2.port.recv());
         }
     }
 
@@ -206,8 +207,14 @@ mod test {
     #[test]
     fn test_io_signal_invalid_signum() {
         let mut s = Listener::new();
-        if s.register(User1) {
-            fail2!("Unexpected successful registry of signum {:?}", User1);
+        let mut called = false;
+        do io::io_error::cond.trap(|_| {
+            called = true;
+        }).inside {
+            if s.register(User1) {
+                fail!("Unexpected successful registry of signum {:?}", User1);
+            }
         }
+        assert!(called);
     }
 }
diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs
index e601ece88bb..b922e6400cc 100644
--- a/src/libstd/rt/io/stdio.rs
+++ b/src/libstd/rt/io/stdio.rs
@@ -30,20 +30,57 @@ use fmt;
 use libc;
 use option::{Option, Some, None};
 use result::{Ok, Err};
-use rt::rtio::{IoFactory, RtioTTY, with_local_io, RtioPipe};
-use super::{Reader, Writer, io_error};
+use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
+               CloseAsynchronously};
+use super::{Reader, Writer, io_error, IoError, OtherIoError};
+
+// And so begins the tale of acquiring a uv handle to a stdio stream on all
+// platforms in all situations. Our story begins by splitting the world into two
+// categories, windows and unix. Then one day the creators of unix said let
+// there be redirection! And henceforth there was redirection away from the
+// console for standard I/O streams.
+//
+// After this day, the world split into four factions:
+//
+// 1. Unix with stdout on a terminal.
+// 2. Unix with stdout redirected.
+// 3. Windows with stdout on a terminal.
+// 4. Windows with stdout redirected.
+//
+// Many years passed, and then one day the nation of libuv decided to unify this
+// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
+// These three ideas propagated throughout the lands and the four great factions
+// decided to settle among them.
+//
+// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
+// doing so, they even enhanced themselves further then their Pipe/File
+// brethren, becoming the dominant powers.
+//
+// The group of 4, however, decided to work independently. They abandoned the
+// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
+// The members of the 4th faction decided to only align themselves with File.
+//
+// tl;dr; TTY works on everything but when windows stdout is redirected, in that
+//        case pipe also doesn't work, but magically file does!
+enum StdSource {
+    TTY(~RtioTTY),
+    File(~RtioFileStream),
+}
 
 #[fixed_stack_segment] #[inline(never)]
-fn tty<T>(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T {
+fn src<T>(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T {
     do with_local_io |io| {
-        // Always pass in readable as true, otherwise libuv turns our writes
-        // into blocking writes. We also need to dup the file descriptor because
-        // the tty will be closed when it's dropped.
-        match io.tty_open(unsafe { libc::dup(fd) }, true) {
-            Ok(tty) => Some(f(tty)),
-            Err(e) => {
-                io_error::cond.raise(e);
-                None
+        let fd = unsafe { libc::dup(fd) };
+        match io.tty_open(fd, readable) {
+            Ok(tty) => Some(f(TTY(tty))),
+            Err(_) => {
+                // It's not really that desirable if these handles are closed
+                // synchronously, and because they're squirreled away in a task
+                // structure the destructors will be run when the task is
+                // attempted to get destroyed. This means that if we run a
+                // synchronous destructor we'll attempt to do some scheduling
+                // operations which will just result in sadness.
+                Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously))))
             }
         }
     }.unwrap()
@@ -54,15 +91,7 @@ fn tty<T>(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T {
 /// See `stdout()` for notes about this function.
 #[fixed_stack_segment] #[inline(never)]
 pub fn stdin() -> StdReader {
-    do with_local_io |io| {
-        match io.pipe_open(unsafe { libc::dup(libc::STDIN_FILENO) }) {
-            Ok(stream) => Some(StdReader { inner: stream }),
-            Err(e) => {
-                io_error::cond.raise(e);
-                None
-            }
-        }
-    }.unwrap()
+    do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } }
 }
 
 /// Creates a new non-blocking handle to the stdout of the current process.
@@ -72,14 +101,14 @@ pub fn stdin() -> StdReader {
 /// task context because the stream returned will be a non-blocking object using
 /// the local scheduler to perform the I/O.
 pub fn stdout() -> StdWriter {
-    do tty(libc::STDOUT_FILENO) |tty| { StdWriter { inner: tty } }
+    do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } }
 }
 
 /// Creates a new non-blocking handle to the stderr of the current process.
 ///
 /// See `stdout()` for notes about this function.
 pub fn stderr() -> StdWriter {
-    do tty(libc::STDERR_FILENO) |tty| { StdWriter { inner: tty } }
+    do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } }
 }
 
 /// Prints a string to the stdout of the current process. No newline is emitted
@@ -117,12 +146,16 @@ pub fn println_args(fmt: &fmt::Arguments) {
 
 /// Representation of a reader of a standard input stream
 pub struct StdReader {
-    priv inner: ~RtioPipe
+    priv inner: StdSource
 }
 
 impl Reader for StdReader {
     fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
-        match self.inner.read(buf) {
+        let ret = match self.inner {
+            TTY(ref mut tty) => tty.read(buf),
+            File(ref mut file) => file.read(buf).map_move(|i| i as uint),
+        };
+        match ret {
             Ok(amt) => Some(amt as uint),
             Err(e) => {
                 io_error::cond.raise(e);
@@ -136,7 +169,7 @@ impl Reader for StdReader {
 
 /// Representation of a writer to a standard output stream
 pub struct StdWriter {
-    priv inner: ~RtioTTY
+    priv inner: StdSource
 }
 
 impl StdWriter {
@@ -151,10 +184,22 @@ impl StdWriter {
     /// This function will raise on the `io_error` condition if an error
     /// happens.
     pub fn winsize(&mut self) -> Option<(int, int)> {
-        match self.inner.get_winsize() {
-            Ok(p) => Some(p),
-            Err(e) => {
-                io_error::cond.raise(e);
+        match self.inner {
+            TTY(ref mut tty) => {
+                match tty.get_winsize() {
+                    Ok(p) => Some(p),
+                    Err(e) => {
+                        io_error::cond.raise(e);
+                        None
+                    }
+                }
+            }
+            File(*) => {
+                io_error::cond.raise(IoError {
+                    kind: OtherIoError,
+                    desc: "stream is not a tty",
+                    detail: None,
+                });
                 None
             }
         }
@@ -168,21 +213,41 @@ impl StdWriter {
     /// This function will raise on the `io_error` condition if an error
     /// happens.
     pub fn set_raw(&mut self, raw: bool) {
-        match self.inner.set_raw(raw) {
-            Ok(()) => {},
-            Err(e) => io_error::cond.raise(e),
+        match self.inner {
+            TTY(ref mut tty) => {
+                match tty.set_raw(raw) {
+                    Ok(()) => {},
+                    Err(e) => io_error::cond.raise(e),
+                }
+            }
+            File(*) => {
+                io_error::cond.raise(IoError {
+                    kind: OtherIoError,
+                    desc: "stream is not a tty",
+                    detail: None,
+                });
+            }
         }
     }
 
     /// Returns whether this tream is attached to a TTY instance or not.
     ///
     /// This is similar to libc's isatty() function
-    pub fn isatty(&self) -> bool { self.inner.isatty() }
+    pub fn isatty(&self) -> bool {
+        match self.inner {
+            TTY(ref tty) => tty.isatty(),
+            File(*) => false,
+        }
+    }
 }
 
 impl Writer for StdWriter {
     fn write(&mut self, buf: &[u8]) {
-        match self.inner.write(buf) {
+        let ret = match self.inner {
+            TTY(ref mut tty) => tty.write(buf),
+            File(ref mut file) => file.write(buf),
+        };
+        match ret {
             Ok(()) => {}
             Err(e) => io_error::cond.raise(e)
         }
diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs
index 528be59c54f..66a0676a2f4 100644
--- a/src/libstd/rt/rtio.rs
+++ b/src/libstd/rt/rtio.rs
@@ -58,6 +58,20 @@ pub struct FileOpenConfig {
     priv 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,
+}
+
 pub fn with_local_io<T>(f: &fn(&mut IoFactory) -> Option<T>) -> Option<T> {
     use rt::sched::Scheduler;
     use rt::local::Local;
@@ -84,7 +98,7 @@ pub trait IoFactory {
     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
                           hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError>;
     fn timer_init(&mut self) -> Result<~RtioTimer, IoError>;
-    fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream;
+    fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream;
     fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
         -> Result<~RtioFileStream, IoError>;
     fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>;
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index b3c65ce4749..1ea68bb52d7 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -479,7 +479,6 @@ pub extern "C" fn rust_stack_exhausted() {
     use rt::in_green_task_context;
     use rt::task::Task;
     use rt::local::Local;
-    use rt::logging::Logger;
     use unstable::intrinsics;
 
     unsafe {
@@ -529,8 +528,12 @@ pub extern "C" fn rust_stack_exhausted() {
             do Local::borrow |task: &mut Task| {
                 let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
 
-                format_args!(|args| { task.logger.log(args) },
-                             "task '{}' has overflowed its stack", n);
+                // 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", n);
             }
         } else {
             rterrln!("stack overflow in non-task context");
diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs
index 78b3a88f5f1..d2ca15959b0 100644
--- a/src/libstd/rt/uv/file.rs
+++ b/src/libstd/rt/uv/file.rs
@@ -43,10 +43,11 @@ impl FsRequest {
             let mut me = self;
             me.req_boilerplate(Some(cb))
         };
-        path.with_ref(|p| unsafe {
+        let ret = path.with_ref(|p| unsafe {
             uvll::fs_open(loop_.native_handle(),
                           self.native_handle(), p, flags, mode, complete_cb_ptr)
         });
+        assert_eq!(ret, 0);
     }
 
     pub fn open_sync(self, loop_: &Loop, path: &CString,
@@ -67,10 +68,11 @@ impl FsRequest {
             let mut me = self;
             me.req_boilerplate(Some(cb))
         };
-        path.with_ref(|p| unsafe {
+        let ret = path.with_ref(|p| unsafe {
             uvll::fs_unlink(loop_.native_handle(),
                           self.native_handle(), p, complete_cb_ptr)
         });
+        assert_eq!(ret, 0);
     }
 
     pub fn unlink_sync(self, loop_: &Loop, path: &CString)
@@ -91,10 +93,11 @@ impl FsRequest {
             let mut me = self;
             me.req_boilerplate(Some(cb))
         };
-        path.with_ref(|p| unsafe {
+        let ret = path.with_ref(|p| unsafe {
             uvll::fs_stat(loop_.native_handle(),
                           self.native_handle(), p, complete_cb_ptr)
         });
+        assert_eq!(ret, 0);
     }
 
     pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
@@ -104,11 +107,12 @@ impl FsRequest {
         };
         let base_ptr = buf.base as *c_void;
         let len = buf.len as uint;
-        unsafe {
+        let ret = unsafe {
             uvll::fs_write(loop_.native_handle(), self.native_handle(),
                            fd, base_ptr,
                            len, offset, complete_cb_ptr)
         };
+        assert_eq!(ret, 0);
     }
     pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
           -> Result<c_int, UvError> {
@@ -133,11 +137,12 @@ impl FsRequest {
         };
         let buf_ptr = buf.base as *c_void;
         let len = buf.len as uint;
-        unsafe {
+        let ret = unsafe {
             uvll::fs_read(loop_.native_handle(), self.native_handle(),
                            fd, buf_ptr,
                            len, offset, complete_cb_ptr)
         };
+        assert_eq!(ret, 0);
     }
     pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
           -> Result<c_int, UvError> {
@@ -160,10 +165,11 @@ impl FsRequest {
             let mut me = self;
             me.req_boilerplate(Some(cb))
         };
-        unsafe {
+        let ret = unsafe {
             uvll::fs_close(loop_.native_handle(), self.native_handle(),
                            fd, complete_cb_ptr)
         };
+        assert_eq!(ret, 0);
     }
     pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result<c_int, UvError> {
         let complete_cb_ptr = {
@@ -182,10 +188,11 @@ impl FsRequest {
             let mut me = self;
             me.req_boilerplate(Some(cb))
         };
-        path.with_ref(|p| unsafe {
+        let ret = path.with_ref(|p| unsafe {
             uvll::fs_mkdir(loop_.native_handle(),
-                          self.native_handle(), p, mode, complete_cb_ptr)
+                           self.native_handle(), p, mode, complete_cb_ptr)
         });
+        assert_eq!(ret, 0);
     }
 
     pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) {
@@ -193,10 +200,11 @@ impl FsRequest {
             let mut me = self;
             me.req_boilerplate(Some(cb))
         };
-        path.with_ref(|p| unsafe {
+        let ret = path.with_ref(|p| unsafe {
             uvll::fs_rmdir(loop_.native_handle(),
-                          self.native_handle(), p, complete_cb_ptr)
+                           self.native_handle(), p, complete_cb_ptr)
         });
+        assert_eq!(ret, 0);
     }
 
     pub fn readdir(self, loop_: &Loop, path: &CString,
@@ -205,10 +213,11 @@ impl FsRequest {
             let mut me = self;
             me.req_boilerplate(Some(cb))
         };
-        path.with_ref(|p| unsafe {
+        let ret = path.with_ref(|p| unsafe {
             uvll::fs_readdir(loop_.native_handle(),
-                          self.native_handle(), p, flags, complete_cb_ptr)
+                             self.native_handle(), p, flags, complete_cb_ptr)
         });
+        assert_eq!(ret, 0);
     }
 
     // accessors/utility funcs
diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs
index 9d392583b9e..40f0750b2d0 100644
--- a/src/libstd/rt/uv/idle.rs
+++ b/src/libstd/rt/uv/idle.rs
@@ -20,9 +20,9 @@ impl Watcher for IdleWatcher { }
 impl IdleWatcher {
     pub fn new(loop_: &mut Loop) -> IdleWatcher {
         unsafe {
-            let handle = uvll::idle_new();
+            let handle = uvll::malloc_handle(uvll::UV_IDLE);
             assert!(handle.is_not_null());
-            assert!(0 == uvll::idle_init(loop_.native_handle(), handle));
+            assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0);
             let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
             watcher.install_watcher_data();
             return watcher
@@ -36,29 +36,14 @@ impl IdleWatcher {
         }
 
         unsafe {
-            assert!(0 == uvll::idle_start(self.native_handle(), idle_cb))
-        };
-
-        extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
-            let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
-            let data = idle_watcher.get_watcher_data();
-            let cb: &IdleCallback = data.idle_cb.get_ref();
-            let status = status_to_maybe_uv_error(status);
-            (*cb)(idle_watcher, status);
+            assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
         }
     }
 
     pub fn restart(&mut self) {
         unsafe {
-            assert!(0 == uvll::idle_start(self.native_handle(), idle_cb))
-        };
-
-        extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
-            let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
-            let data = idle_watcher.get_watcher_data();
-            let cb: &IdleCallback = data.idle_cb.get_ref();
-            let status = status_to_maybe_uv_error(status);
-            (*cb)(idle_watcher, status);
+            assert!(self.get_watcher_data().idle_cb.is_some());
+            assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
         }
     }
 
@@ -68,7 +53,7 @@ impl IdleWatcher {
         // free
 
         unsafe {
-            assert!(0 == uvll::idle_stop(self.native_handle()));
+            assert_eq!(uvll::idle_stop(self.native_handle()), 0);
         }
     }
 }
@@ -82,6 +67,14 @@ impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher {
     }
 }
 
+extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
+    let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
+    let data = idle_watcher.get_watcher_data();
+    let cb: &IdleCallback = data.idle_cb.get_ref();
+    let status = status_to_maybe_uv_error(status);
+    (*cb)(idle_watcher, status);
+}
+
 #[cfg(test)]
 mod test {
 
diff --git a/src/libstd/rt/uv/signal.rs b/src/libstd/rt/uv/signal.rs
index e51b7d90d95..3252c89673d 100644
--- a/src/libstd/rt/uv/signal.rs
+++ b/src/libstd/rt/uv/signal.rs
@@ -51,7 +51,7 @@ impl SignalWatcher {
             let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
             let data = watcher.get_watcher_data();
             let cb = data.signal_cb.get_ref();
-            (*cb)(watcher, unsafe { cast::transmute(signum as i64) });
+            (*cb)(watcher, unsafe { cast::transmute(signum as int) });
         }
     }
 
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index 473eec32c67..29370c484eb 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -547,10 +547,10 @@ impl IoFactory for UvIoFactory {
         Ok(~UvTimer::new(watcher, home) as ~RtioTimer)
     }
 
-    fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream {
+    fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream {
         let loop_ = Loop {handle: self.uv_loop().native_handle()};
         let home = get_handle_to_current_scheduler!();
-        ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream
+        ~UvFileStream::new(loop_, fd, close, home) as ~RtioFileStream
     }
 
     fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
@@ -590,7 +590,7 @@ impl IoFactory for UvIoFactory {
                         let home = get_handle_to_current_scheduler!();
                         let fd = req.get_result() as c_int;
                         let fs = ~UvFileStream::new(
-                            loop_, fd, true, home) as ~RtioFileStream;
+                            loop_, fd, CloseSynchronously, home) as ~RtioFileStream;
                         let res = Ok(fs);
                         unsafe { (*result_cell_ptr).put_back(res); }
                         let scheduler: ~Scheduler = Local::take();
@@ -1482,8 +1482,8 @@ impl RtioTimer for UvTimer {
 pub struct UvFileStream {
     priv loop_: Loop,
     priv fd: c_int,
-    priv close_on_drop: bool,
-    priv home: SchedHandle
+    priv close: CloseBehavior,
+    priv home: SchedHandle,
 }
 
 impl HomingIO for UvFileStream {
@@ -1491,13 +1491,13 @@ impl HomingIO for UvFileStream {
 }
 
 impl UvFileStream {
-    fn new(loop_: Loop, fd: c_int, close_on_drop: bool,
+    fn new(loop_: Loop, fd: c_int, close: CloseBehavior,
            home: SchedHandle) -> UvFileStream {
         UvFileStream {
             loop_: loop_,
             fd: fd,
-            close_on_drop: close_on_drop,
-            home: home
+            close: close,
+            home: home,
         }
     }
     fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError> {
@@ -1517,9 +1517,9 @@ impl UvFileStream {
                     unsafe { (*result_cell_ptr).put_back(res); }
                     let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
-                };
-            };
-        };
+                }
+            }
+        }
         result_cell.take()
     }
     fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> {
@@ -1539,9 +1539,9 @@ impl UvFileStream {
                     unsafe { (*result_cell_ptr).put_back(res); }
                     let scheduler: ~Scheduler = Local::take();
                     scheduler.resume_blocked_task_immediately(task_cell.take());
-                };
-            };
-        };
+                }
+            }
+        }
         result_cell.take()
     }
     fn seek_common(&mut self, pos: i64, whence: c_int) ->
@@ -1564,16 +1564,23 @@ impl UvFileStream {
 
 impl Drop for UvFileStream {
     fn drop(&mut self) {
-        if self.close_on_drop {
-            do self.home_for_io_with_sched |self_, scheduler| {
-                do scheduler.deschedule_running_task_and_then |_, task| {
-                    let task_cell = Cell::new(task);
-                    let close_req = file::FsRequest::new();
-                    do close_req.close(&self_.loop_, self_.fd) |_,_| {
-                        let scheduler: ~Scheduler = Local::take();
-                        scheduler.resume_blocked_task_immediately(task_cell.take());
-                    };
-                };
+        match self.close {
+            DontClose => {}
+            CloseAsynchronously => {
+                let close_req = file::FsRequest::new();
+                do close_req.close(&self.loop_, self.fd) |_,_| {}
+            }
+            CloseSynchronously => {
+                do self.home_for_io_with_sched |self_, scheduler| {
+                    do scheduler.deschedule_running_task_and_then |_, task| {
+                        let task_cell = Cell::new(task);
+                        let close_req = file::FsRequest::new();
+                        do close_req.close(&self_.loop_, self_.fd) |_,_| {
+                            let scheduler: ~Scheduler = Local::take();
+                            scheduler.resume_blocked_task_immediately(task_cell.take());
+                        }
+                    }
+                }
             }
         }
     }
@@ -1750,7 +1757,6 @@ impl Drop for UvTTY {
         // scheduler isn't available, so we can't do the normal "take the
         // scheduler and resume once close is done". Instead close operations on
         // a TTY are asynchronous.
-
         self.tty.close_async();
     }
 }
@@ -2465,7 +2471,7 @@ fn uvio_naive_print(input: &str) {
         use libc::{STDOUT_FILENO};
         let io = local_io();
         {
-            let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, false);
+            let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, DontClose);
             let write_buf = input.as_bytes();
             fd.write(write_buf);
         }
diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs
index fa4083657d5..75e6a0c6ca5 100644
--- a/src/libstd/rt/uv/uvll.rs
+++ b/src/libstd/rt/uv/uvll.rs
@@ -235,37 +235,37 @@ pub type socklen_t = c_int;
 #[cfg(target_os = "android")]
 #[cfg(target_os = "linux")]
 pub struct addrinfo {
-    priv ai_flags: c_int,
-    priv ai_family: c_int,
-    priv ai_socktype: c_int,
-    priv ai_protocol: c_int,
-    priv ai_addrlen: socklen_t,
+    ai_flags: c_int,
+    ai_family: c_int,
+    ai_socktype: c_int,
+    ai_protocol: c_int,
+    ai_addrlen: socklen_t,
     ai_addr: *sockaddr,
-    priv ai_canonname: *char,
+    ai_canonname: *char,
     ai_next: *addrinfo
 }
 
 #[cfg(target_os = "macos")]
 #[cfg(target_os = "freebsd")]
 pub struct addrinfo {
-    priv ai_flags: c_int,
-    priv ai_family: c_int,
-    priv ai_socktype: c_int,
-    priv ai_protocol: c_int,
-    priv ai_addrlen: socklen_t,
-    priv ai_canonname: *char,
+    ai_flags: c_int,
+    ai_family: c_int,
+    ai_socktype: c_int,
+    ai_protocol: c_int,
+    ai_addrlen: socklen_t,
+    ai_canonname: *char,
     ai_addr: *sockaddr,
     ai_next: *addrinfo
 }
 
 #[cfg(windows)]
 pub struct addrinfo {
-    priv ai_flags: c_int,
-    priv ai_family: c_int,
-    priv ai_socktype: c_int,
-    priv ai_protocol: c_int,
-    priv ai_addrlen: size_t,
-    priv ai_canonname: *char,
+    ai_flags: c_int,
+    ai_family: c_int,
+    ai_socktype: c_int,
+    ai_protocol: c_int,
+    ai_addrlen: size_t,
+    ai_canonname: *char,
     ai_addr: *sockaddr,
     ai_next: *addrinfo
 }
@@ -423,18 +423,6 @@ pub unsafe fn walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void) {
     rust_uv_walk(loop_handle, cb, arg);
 }
 
-pub unsafe fn idle_new() -> *uv_idle_t {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    rust_uv_idle_new()
-}
-
-pub unsafe fn idle_delete(handle: *uv_idle_t) {
-    #[fixed_stack_segment]; #[inline(never)];
-
-    rust_uv_idle_delete(handle)
-}
-
 pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int {
     #[fixed_stack_segment]; #[inline(never)];
 
@@ -1028,8 +1016,6 @@ extern {
     fn rust_uv_close(handle: *c_void, cb: uv_close_cb);
     fn rust_uv_walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void);
 
-    fn rust_uv_idle_new() -> *uv_idle_t;
-    fn rust_uv_idle_delete(handle: *uv_idle_t);
     fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int;
     fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int;
     fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int;
diff --git a/src/libstd/run.rs b/src/libstd/run.rs
index 650ef491a3b..615ba60e066 100644
--- a/src/libstd/run.rs
+++ b/src/libstd/run.rs
@@ -219,16 +219,27 @@ impl Process {
         let (p, ch) = stream();
         let ch = SharedChan::new(ch);
         let ch_clone = ch.clone();
-        do task::spawn_sched(task::SingleThreaded) {
-            match error.take() {
-                Some(ref mut e) => ch.send((2, e.read_to_end())),
-                None => ch.send((2, ~[]))
+
+        // FIXME(#910, #8674): right now I/O is incredibly brittle when it comes
+        //      to linked failure, so these tasks must be spawn so they're not
+        //      affected by linked failure. If these are removed, then the
+        //      runtime may never exit because linked failure will cause some
+        //      SchedHandle structures to not get destroyed, meaning that
+        //      there's always an async watcher available.
+        do task::spawn_unlinked {
+            do io::ignore_io_error {
+                match error.take() {
+                    Some(ref mut e) => ch.send((2, e.read_to_end())),
+                    None => ch.send((2, ~[]))
+                }
             }
         }
-        do task::spawn_sched(task::SingleThreaded) {
-            match output.take() {
-                Some(ref mut e) => ch_clone.send((1, e.read_to_end())),
-                None => ch_clone.send((1, ~[]))
+        do task::spawn_unlinked {
+            do io::ignore_io_error {
+                match output.take() {
+                    Some(ref mut e) => ch_clone.send((1, e.read_to_end())),
+                    None => ch_clone.send((1, ~[]))
+                }
             }
         }
 
diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp
index c463cf039d3..0cbbb58d02c 100644
--- a/src/rt/rust_uv.cpp
+++ b/src/rt/rust_uv.cpp
@@ -466,16 +466,6 @@ rust_uv_addrinfo_as_sockaddr_in6(addrinfo* input) {
     return (sockaddr_in6*)input->ai_addr;
 }
 
-extern "C" uv_idle_t*
-rust_uv_idle_new() {
-  return new uv_idle_t;
-}
-
-extern "C" void
-rust_uv_idle_delete(uv_idle_t* handle) {
-  delete handle;
-}
-
 extern "C" int
 rust_uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) {
   return uv_idle_init(loop, idle);
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index 3c10e42f743..269da8e7882 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -98,8 +98,6 @@ rust_uv_get_base_from_buf
 rust_uv_get_len_from_buf
 rust_uv_getaddrinfo
 rust_uv_freeaddrinfo
-rust_uv_idle_new
-rust_uv_idle_delete
 rust_uv_idle_init
 rust_uv_idle_start
 rust_uv_idle_stop