about summary refs log tree commit diff
path: root/src/libstd/rt/io
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-24 14:26:15 -0700
committerbors <bors@rust-lang.org>2013-10-24 14:26:15 -0700
commit3f5b2219cc893b30863f9136703166f306fcc684 (patch)
treed7267619b1909f2deaf319c560a64d667d141d35 /src/libstd/rt/io
parent61f8c059c4c6082683d78b2ee3d963f65fa1eb98 (diff)
parent188e471339dfe652b8ff9f3bbe4cc262a040c584 (diff)
downloadrust-3f5b2219cc893b30863f9136703166f306fcc684.tar.gz
rust-3f5b2219cc893b30863f9136703166f306fcc684.zip
auto merge of #9901 : alexcrichton/rust/unix-sockets, r=brson
Large topics:

* Implemented `rt::io::net::unix`. We've got an implementation backed by "named pipes" for windows for free from libuv, so I'm not sure if these should be `cfg(unix)` or whether they'd be better placed in `rt::io::pipe` (which is currently kinda useless), or to leave in `unix`. Regardless, we probably shouldn't deny windows of functionality which it certainly has.
* Fully implemented `net::addrinfo`, or at least fully implemented in the sense of making the best attempt to wrap libuv's `getaddrinfo` api
* Moved standard I/O to a libuv TTY instead of just a plain old file descriptor. I found that this interacted better when closing stdin, and it has the added bonus of getting things like terminal dimentions (someone should make a progress bar now!)
* Migrate to `~Trait` instead of a typedef'd object where possible. There are only two more types which are blocked on this, and those are traits which have a method which takes by-value self (there's an open issue on this)
* Drop `rt::io::support::PathLike` in favor of just `ToCStr`. We recently had a lot of Path work done, but it still wasn't getting passed down to libuv (there was an intermediate string conversion), and this allows true paths to work all the way down to libuv (and anything else that can become a C string).
* Removes `extra::fileinput` and `extra::io_util`


Closes #9895 
Closes #9975
Closes #8330
Closes #6850 (ported lots of libraries away from std::io)
cc #4248 (implemented unix/dns)
cc #9128 (made everything truly trait objects)
Diffstat (limited to 'src/libstd/rt/io')
-rw-r--r--src/libstd/rt/io/extensions.rs121
-rw-r--r--src/libstd/rt/io/file.rs157
-rw-r--r--src/libstd/rt/io/mem.rs86
-rw-r--r--src/libstd/rt/io/mod.rs27
-rw-r--r--src/libstd/rt/io/native/file.rs24
-rw-r--r--src/libstd/rt/io/net/addrinfo.rs126
-rw-r--r--src/libstd/rt/io/net/mod.rs48
-rw-r--r--src/libstd/rt/io/net/tcp.rs60
-rw-r--r--src/libstd/rt/io/net/udp.rs25
-rw-r--r--src/libstd/rt/io/net/unix.rs279
-rw-r--r--src/libstd/rt/io/option.rs30
-rw-r--r--src/libstd/rt/io/pipe.rs60
-rw-r--r--src/libstd/rt/io/process.rs50
-rw-r--r--src/libstd/rt/io/signal.rs220
-rw-r--r--src/libstd/rt/io/stdio.rs198
-rw-r--r--src/libstd/rt/io/support.rs42
-rw-r--r--src/libstd/rt/io/timer.rs31
17 files changed, 1172 insertions, 412 deletions
diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs
index 99634b532b0..4b16f0bc0e1 100644
--- a/src/libstd/rt/io/extensions.rs
+++ b/src/libstd/rt/io/extensions.rs
@@ -18,11 +18,10 @@ use int;
 use iter::Iterator;
 use vec;
 use rt::io::{Reader, Writer, Decorator};
-use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE};
+use rt::io::{io_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE};
 use option::{Option, Some, None};
 use unstable::finally::Finally;
 use cast;
-use io::{u64_to_le_bytes, u64_to_be_bytes};
 
 pub trait ReaderUtil {
 
@@ -41,8 +40,8 @@ pub trait ReaderUtil {
     ///
     /// # Failure
     ///
-    /// Raises the same conditions as `read`. Additionally raises `read_error`
-    /// on EOF. If `read_error` is handled then `push_bytes` may push less
+    /// Raises the same conditions as `read`. Additionally raises `io_error`
+    /// on EOF. If `io_error` is handled then `push_bytes` may push less
     /// than the requested number of bytes.
     fn push_bytes(&mut self, buf: &mut ~[u8], len: uint);
 
@@ -50,8 +49,8 @@ pub trait ReaderUtil {
     ///
     /// # Failure
     ///
-    /// Raises the same conditions as `read`. Additionally raises `read_error`
-    /// on EOF. If `read_error` is handled then the returned vector may
+    /// Raises the same conditions as `read`. Additionally raises `io_error`
+    /// on EOF. If `io_error` is handled then the returned vector may
     /// contain less than the requested number of bytes.
     fn read_bytes(&mut self, len: uint) -> ~[u8];
 
@@ -314,7 +313,7 @@ impl<T: Reader> ReaderUtil for T {
                             total_read += nread;
                         }
                         None => {
-                            read_error::cond.raise(standard_error(EndOfFile));
+                            io_error::cond.raise(standard_error(EndOfFile));
                             break;
                         }
                     }
@@ -334,11 +333,11 @@ impl<T: Reader> ReaderUtil for T {
     fn read_to_end(&mut self) -> ~[u8] {
         let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE);
         let mut keep_reading = true;
-        do read_error::cond.trap(|e| {
+        do io_error::cond.trap(|e| {
             if e.kind == EndOfFile {
                 keep_reading = false;
             } else {
-                read_error::cond.raise(e)
+                io_error::cond.raise(e)
             }
         }).inside {
             while keep_reading {
@@ -634,6 +633,88 @@ fn extend_sign(val: u64, nbytes: uint) -> i64 {
     (val << shift) as i64 >> shift
 }
 
+pub fn u64_to_le_bytes<T>(n: u64, size: uint,
+                          f: &fn(v: &[u8]) -> T) -> T {
+    assert!(size <= 8u);
+    match size {
+      1u => f(&[n as u8]),
+      2u => f(&[n as u8,
+              (n >> 8) as u8]),
+      4u => f(&[n as u8,
+              (n >> 8) as u8,
+              (n >> 16) as u8,
+              (n >> 24) as u8]),
+      8u => f(&[n as u8,
+              (n >> 8) as u8,
+              (n >> 16) as u8,
+              (n >> 24) as u8,
+              (n >> 32) as u8,
+              (n >> 40) as u8,
+              (n >> 48) as u8,
+              (n >> 56) as u8]),
+      _ => {
+
+        let mut bytes: ~[u8] = ~[];
+        let mut i = size;
+        let mut n = n;
+        while i > 0u {
+            bytes.push((n & 255_u64) as u8);
+            n >>= 8_u64;
+            i -= 1u;
+        }
+        f(bytes)
+      }
+    }
+}
+
+pub fn u64_to_be_bytes<T>(n: u64, size: uint,
+                           f: &fn(v: &[u8]) -> T) -> T {
+    assert!(size <= 8u);
+    match size {
+      1u => f(&[n as u8]),
+      2u => f(&[(n >> 8) as u8,
+              n as u8]),
+      4u => f(&[(n >> 24) as u8,
+              (n >> 16) as u8,
+              (n >> 8) as u8,
+              n as u8]),
+      8u => f(&[(n >> 56) as u8,
+              (n >> 48) as u8,
+              (n >> 40) as u8,
+              (n >> 32) as u8,
+              (n >> 24) as u8,
+              (n >> 16) as u8,
+              (n >> 8) as u8,
+              n as u8]),
+      _ => {
+        let mut bytes: ~[u8] = ~[];
+        let mut i = size;
+        while i > 0u {
+            let shift = ((i - 1u) * 8u) as u64;
+            bytes.push((n >> shift) as u8);
+            i -= 1u;
+        }
+        f(bytes)
+      }
+    }
+}
+
+pub fn u64_from_be_bytes(data: &[u8],
+                         start: uint,
+                         size: uint)
+                      -> u64 {
+    let mut sz = size;
+    assert!((sz <= 8u));
+    let mut val = 0_u64;
+    let mut pos = start;
+    while sz > 0u {
+        sz -= 1u;
+        val += (data[pos] as u64) << ((sz * 8u) as u64);
+        pos += 1u;
+    }
+    return val;
+}
+
 #[cfg(test)]
 mod test {
     use super::ReaderUtil;
@@ -641,7 +722,7 @@ mod test {
     use cell::Cell;
     use rt::io::mem::{MemReader, MemWriter};
     use rt::io::mock::MockReader;
-    use rt::io::{read_error, placeholder_error};
+    use rt::io::{io_error, placeholder_error};
 
     #[test]
     fn read_byte() {
@@ -681,10 +762,10 @@ mod test {
     fn read_byte_error() {
         let mut reader = MockReader::new();
         reader.read = |_| {
-            read_error::cond.raise(placeholder_error());
+            io_error::cond.raise(placeholder_error());
             None
         };
-        do read_error::cond.trap(|_| {
+        do io_error::cond.trap(|_| {
         }).inside {
             let byte = reader.read_byte();
             assert!(byte == None);
@@ -722,11 +803,11 @@ mod test {
     fn bytes_error() {
         let mut reader = MockReader::new();
         reader.read = |_| {
-            read_error::cond.raise(placeholder_error());
+            io_error::cond.raise(placeholder_error());
             None
         };
         let mut it = reader.bytes();
-        do read_error::cond.trap(|_| ()).inside {
+        do io_error::cond.trap(|_| ()).inside {
             let byte = it.next();
             assert!(byte == None);
         }
@@ -765,7 +846,7 @@ mod test {
     #[test]
     fn read_bytes_eof() {
         let mut reader = MemReader::new(~[10, 11]);
-        do read_error::cond.trap(|_| {
+        do io_error::cond.trap(|_| {
         }).inside {
             assert!(reader.read_bytes(4) == ~[10, 11]);
         }
@@ -806,7 +887,7 @@ mod test {
     fn push_bytes_eof() {
         let mut reader = MemReader::new(~[10, 11]);
         let mut buf = ~[8, 9];
-        do read_error::cond.trap(|_| {
+        do io_error::cond.trap(|_| {
         }).inside {
             reader.push_bytes(&mut buf, 4);
             assert!(buf == ~[8, 9, 10, 11]);
@@ -824,13 +905,13 @@ mod test {
                     buf[0] = 10;
                     Some(1)
                 } else {
-                    read_error::cond.raise(placeholder_error());
+                    io_error::cond.raise(placeholder_error());
                     None
                 }
             }
         };
         let mut buf = ~[8, 9];
-        do read_error::cond.trap(|_| { } ).inside {
+        do io_error::cond.trap(|_| { } ).inside {
             reader.push_bytes(&mut buf, 4);
         }
         assert!(buf == ~[8, 9, 10]);
@@ -850,7 +931,7 @@ mod test {
                     buf[0] = 10;
                     Some(1)
                 } else {
-                    read_error::cond.raise(placeholder_error());
+                    io_error::cond.raise(placeholder_error());
                     None
                 }
             }
@@ -903,7 +984,7 @@ mod test {
                     buf[1] = 11;
                     Some(2)
                 } else {
-                    read_error::cond.raise(placeholder_error());
+                    io_error::cond.raise(placeholder_error());
                     None
                 }
             }
diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs
index a43bcd8142e..d035e2f457c 100644
--- a/src/libstd/rt/io/file.rs
+++ b/src/libstd/rt/io/file.rs
@@ -15,10 +15,11 @@ with regular files & directories on a filesystem.
 
 At the top-level of the module are a set of freestanding functions,
 associated with various filesystem operations. They all operate
-on a `PathLike` object.
+on a `ToCStr` object. This trait is already defined for common
+objects such as strings and `Path` instances.
 
 All operations in this module, including those as part of `FileStream` et al
-block the task during execution. Most will raise `std::rt::io::{io_error,read_error}`
+block the task during execution. Most will raise `std::rt::io::io_error`
 conditions in the event of failure.
 
 Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When
@@ -30,15 +31,14 @@ free function counterparts.
 */
 
 use prelude::*;
-use super::support::PathLike;
+use c_str::ToCStr;
 use super::{Reader, Writer, Seek};
 use super::{SeekStyle, Read, Write};
-use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject};
-use rt::io::{io_error, read_error, EndOfFile,
+use rt::rtio::{RtioFileStream, IoFactory, with_local_io};
+use rt::io::{io_error, EndOfFile,
             FileMode, FileAccess, FileStat, IoError,
             PathAlreadyExists, PathDoesntExist,
             MismatchedFileTypeForOperation, ignore_io_error};
-use rt::local::Local;
 use option::{Some, None};
 use path::Path;
 
@@ -48,7 +48,6 @@ use path::Path;
 ///
 ///     use std;
 ///     use std::path::Path;
-///     use std::rt::io::support::PathLike;
 ///     use std::rt::io::file::open;
 ///     use std::rt::io::{FileMode, FileAccess};
 ///
@@ -87,22 +86,20 @@ use path::Path;
 /// * Attempting to open a file with a `FileAccess` that the user lacks permissions
 ///   for
 /// * Filesystem-level errors (full disk, etc)
-pub fn open<P: PathLike>(path: &P,
-                         mode: FileMode,
-                         access: FileAccess
-                        ) -> Option<FileStream> {
-    let open_result = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_open(path, mode, access)
-    };
-    match open_result {
-        Ok(fd) => Some(FileStream {
-            fd: fd,
-            last_nread: -1
-        }),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
-            None
+pub fn open<P: ToCStr>(path: &P,
+                       mode: FileMode,
+                       access: FileAccess
+                      ) -> Option<FileStream> {
+    do with_local_io |io| {
+        match io.fs_open(&path.to_c_str(), mode, access) {
+            Ok(fd) => Some(FileStream {
+                fd: fd,
+                last_nread: -1
+            }),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
         }
     }
 }
@@ -113,7 +110,6 @@ pub fn open<P: PathLike>(path: &P,
 ///
 ///     use std;
 ///     use std::path::Path;
-///     use std::rt::io::support::PathLike;
 ///     use std::rt::io::file::unlink;
 ///
 ///     let p = &Path("/some/file/path.txt");
@@ -129,17 +125,16 @@ pub fn open<P: PathLike>(path: &P,
 ///
 /// This function will raise an `io_error` condition if the user lacks permissions to
 /// remove the file or if some other filesystem-level error occurs
-pub fn unlink<P: PathLike>(path: &P) {
-    let unlink_result = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_unlink(path)
-    };
-    match unlink_result {
-        Ok(_) => (),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
+pub fn unlink<P: ToCStr>(path: &P) {
+    do with_local_io |io| {
+        match io.fs_unlink(&path.to_c_str()) {
+            Ok(_) => Some(()),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
         }
-    }
+    };
 }
 
 /// Create a new, empty directory at the provided path
@@ -148,7 +143,6 @@ pub fn unlink<P: PathLike>(path: &P) {
 ///
 ///     use std;
 ///     use std::path::Path;
-///     use std::rt::io::support::PathLike;
 ///     use std::rt::io::file::mkdir;
 ///
 ///     let p = &Path("/some/dir");
@@ -159,17 +153,16 @@ pub fn unlink<P: PathLike>(path: &P) {
 ///
 /// This call will raise an `io_error` condition if the user lacks permissions to make a
 /// new directory at the provided path, or if the directory already exists
-pub fn mkdir<P: PathLike>(path: &P) {
-    let mkdir_result = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_mkdir(path)
-    };
-    match mkdir_result {
-        Ok(_) => (),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
+pub fn mkdir<P: ToCStr>(path: &P) {
+    do with_local_io |io| {
+        match io.fs_mkdir(&path.to_c_str()) {
+            Ok(_) => Some(()),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
         }
-    }
+    };
 }
 
 /// Remove an existing, empty directory
@@ -178,7 +171,6 @@ pub fn mkdir<P: PathLike>(path: &P) {
 ///
 ///     use std;
 ///     use std::path::Path;
-///     use std::rt::io::support::PathLike;
 ///     use std::rt::io::file::rmdir;
 ///
 ///     let p = &Path("/some/dir");
@@ -189,23 +181,22 @@ pub fn mkdir<P: PathLike>(path: &P) {
 ///
 /// This call will raise an `io_error` condition if the user lacks permissions to remove the
 /// directory at the provided path, or if the directory isn't empty
-pub fn rmdir<P: PathLike>(path: &P) {
-    let rmdir_result = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_rmdir(path)
-    };
-    match rmdir_result {
-        Ok(_) => (),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
+pub fn rmdir<P: ToCStr>(path: &P) {
+    do with_local_io |io| {
+        match io.fs_rmdir(&path.to_c_str()) {
+            Ok(_) => Some(()),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
         }
-    }
+    };
 }
 
 /// Get information on the file, directory, etc at the provided path
 ///
-/// Given a `rt::io::support::PathLike`, query the file system to get
-/// information about a file, directory, etc.
+/// Given a path, query the file system to get information about a file,
+/// directory, etc.
 ///
 /// Returns a `Some(std::rt::io::PathInfo)` on success
 ///
@@ -213,7 +204,6 @@ pub fn rmdir<P: PathLike>(path: &P) {
 ///
 ///     use std;
 ///     use std::path::Path;
-///     use std::rt::io::support::PathLike;
 ///     use std::rt::io::file::stat;
 ///
 ///     let p = &Path("/some/file/path.txt");
@@ -238,18 +228,14 @@ pub fn rmdir<P: PathLike>(path: &P) {
 /// This call will raise an `io_error` condition if the user lacks the requisite
 /// permissions 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<P: PathLike>(path: &P) -> Option<FileStat> {
-    let open_result = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_stat(path)
-    };
-    match open_result {
-        Ok(p) => {
-            Some(p)
-        },
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
-            None
+pub fn stat<P: ToCStr>(path: &P) -> Option<FileStat> {
+    do with_local_io |io| {
+        match io.fs_stat(&path.to_c_str()) {
+            Ok(p) => Some(p),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
         }
     }
 }
@@ -260,7 +246,6 @@ pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
 ///
 ///     use std;
 ///     use std::path::Path;
-///     use std::rt::io::support::PathLike;
 ///     use std::rt::io::file::readdir;
 ///
 ///     fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
@@ -279,18 +264,14 @@ pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
 /// Will raise an `io_error` condition if the provided `path` doesn't exist,
 /// the process lacks permissions to view the contents or if the `path` points
 /// at a non-directory file
-pub fn readdir<P: PathLike>(path: &P) -> Option<~[Path]> {
-    let readdir_result = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_readdir(path, 0)
-    };
-    match readdir_result {
-        Ok(p) => {
-            Some(p)
-        },
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
-            None
+pub fn readdir<P: ToCStr>(path: &P) -> Option<~[Path]> {
+    do with_local_io |io| {
+        match io.fs_readdir(&path.to_c_str(), 0) {
+            Ok(p) => Some(p),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
         }
     }
 }
@@ -380,7 +361,7 @@ impl Reader for FileStream {
             Err(ioerr) => {
                 // EOF is indicated by returning None
                 if ioerr.kind != EndOfFile {
-                    read_error::cond.raise(ioerr);
+                    io_error::cond.raise(ioerr);
                 }
                 return None;
             }
@@ -407,7 +388,7 @@ impl Writer for FileStream {
         match self.fd.flush() {
             Ok(_) => (),
             Err(ioerr) => {
-                read_error::cond.raise(ioerr);
+                io_error::cond.raise(ioerr);
             }
         }
     }
@@ -420,7 +401,7 @@ impl Seek for FileStream {
         match res {
             Ok(cursor) => cursor,
             Err(ioerr) => {
-                read_error::cond.raise(ioerr);
+                io_error::cond.raise(ioerr);
                 return -1;
             }
         }
@@ -434,7 +415,7 @@ impl Seek for FileStream {
                 ()
             },
             Err(ioerr) => {
-                read_error::cond.raise(ioerr);
+                io_error::cond.raise(ioerr);
             }
         }
     }
diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs
index 5f6b4398c22..0ec37cd3c07 100644
--- a/src/libstd/rt/io/mem.rs
+++ b/src/libstd/rt/io/mem.rs
@@ -22,46 +22,66 @@ use vec;
 
 /// Writes to an owned, growable byte vector
 pub struct MemWriter {
-    priv buf: ~[u8]
+    priv buf: ~[u8],
+    priv pos: uint,
 }
 
 impl MemWriter {
-    pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } }
+    pub fn new() -> MemWriter {
+        MemWriter { buf: vec::with_capacity(128), pos: 0 }
+    }
 }
 
 impl Writer for MemWriter {
     fn write(&mut self, buf: &[u8]) {
-        self.buf.push_all(buf)
+        // Make sure the internal buffer is as least as big as where we
+        // currently are
+        let difference = self.pos as i64 - self.buf.len() as i64;
+        if difference > 0 {
+            self.buf.grow(difference as uint, &0);
+        }
+
+        // Figure out what bytes will be used to overwrite what's currently
+        // there (left), and what will be appended on the end (right)
+        let cap = self.buf.len() - self.pos;
+        let (left, right) = if cap <= buf.len() {
+            (buf.slice_to(cap), buf.slice_from(cap))
+        } else {
+            (buf, &[])
+        };
+
+        // Do the necessary writes
+        if left.len() > 0 {
+            vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos),
+                                    left, left.len());
+        }
+        if right.len() > 0 {
+            self.buf.push_all(right);
+        }
+
+        // Bump us forward
+        self.pos += buf.len();
     }
 
     fn flush(&mut self) { /* no-op */ }
 }
 
 impl Seek for MemWriter {
-    fn tell(&self) -> u64 { self.buf.len() as u64 }
-
-    fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
-}
-
-impl Decorator<~[u8]> for MemWriter {
-
-    fn inner(self) -> ~[u8] {
-        match self {
-            MemWriter { buf: buf } => buf
-        }
-    }
+    fn tell(&self) -> u64 { self.pos as u64 }
 
-    fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
-        match *self {
-            MemWriter { buf: ref buf } => buf
+    fn seek(&mut self, pos: i64, style: SeekStyle) {
+        match style {
+            SeekSet => { self.pos = pos as uint; }
+            SeekEnd => { self.pos = self.buf.len() + pos as uint; }
+            SeekCur => { self.pos += pos as uint; }
         }
     }
+}
 
-    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
-        match *self {
-            MemWriter { buf: ref mut buf } => buf
-        }
-    }
+impl Decorator<~[u8]> for MemWriter {
+    fn inner(self) -> ~[u8] { self.buf }
+    fn inner_ref<'a>(&'a self) -> &'a ~[u8] { &self.buf }
+    fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { &mut self.buf }
 }
 
 /// Reads from an owned byte vector
@@ -208,6 +228,7 @@ pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
 mod test {
     use prelude::*;
     use super::*;
+    use rt::io::*;
 
     #[test]
     fn test_mem_writer() {
@@ -218,7 +239,24 @@ mod test {
         writer.write([1, 2, 3]);
         writer.write([4, 5, 6, 7]);
         assert_eq!(writer.tell(), 8);
-        assert_eq!(writer.inner(), ~[0, 1, 2, 3, 4, 5 , 6, 7]);
+        assert_eq!(*writer.inner_ref(), ~[0, 1, 2, 3, 4, 5, 6, 7]);
+
+        writer.seek(0, SeekSet);
+        assert_eq!(writer.tell(), 0);
+        writer.write([3, 4]);
+        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 3, 4, 5, 6, 7]);
+
+        writer.seek(1, SeekCur);
+        writer.write([0, 1]);
+        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 7]);
+
+        writer.seek(-1, SeekEnd);
+        writer.write([1, 2]);
+        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2]);
+
+        writer.seek(1, SeekEnd);
+        writer.write([1]);
+        assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]);
     }
 
     #[test]
diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs
index a80c1aab398..758c9779165 100644
--- a/src/libstd/rt/io/mod.rs
+++ b/src/libstd/rt/io/mod.rs
@@ -261,7 +261,6 @@ pub use self::net::tcp::TcpListener;
 pub use self::net::tcp::TcpStream;
 pub use self::net::udp::UdpStream;
 pub use self::pipe::PipeStream;
-pub use self::pipe::UnboundPipeStream;
 pub use self::process::Process;
 
 // Some extension traits that all Readers and Writers get.
@@ -299,10 +298,6 @@ pub mod comm_adapters;
 /// Extension traits
 pub mod extensions;
 
-/// Non-I/O things needed by the I/O module
-// XXX: shouldn this really be pub?
-pub mod support;
-
 /// Basic Timer
 pub mod timer;
 
@@ -331,9 +326,11 @@ pub mod native {
 /// Mock implementations for testing
 mod mock;
 
+/// Signal handling
+pub mod signal;
+
 /// The default buffer size for various I/O operations
-/// XXX: Not pub
-pub static DEFAULT_BUF_SIZE: uint = 1024 * 64;
+static DEFAULT_BUF_SIZE: uint = 1024 * 64;
 
 /// The type passed to I/O condition handlers to indicate error
 ///
@@ -375,7 +372,9 @@ pub enum IoErrorKind {
     BrokenPipe,
     PathAlreadyExists,
     PathDoesntExist,
-    MismatchedFileTypeForOperation
+    MismatchedFileTypeForOperation,
+    ResourceUnavailable,
+    IoUnavailable,
 }
 
 // FIXME: #8242 implementing manually because deriving doesn't work for some reason
@@ -395,7 +394,9 @@ impl ToStr for IoErrorKind {
             BrokenPipe => ~"BrokenPipe",
             PathAlreadyExists => ~"PathAlreadyExists",
             PathDoesntExist => ~"PathDoesntExist",
-            MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation"
+            MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation",
+            IoUnavailable => ~"IoUnavailable",
+            ResourceUnavailable => ~"ResourceUnavailable",
         }
     }
 }
@@ -406,12 +407,6 @@ condition! {
     pub io_error: IoError -> ();
 }
 
-// XXX: Can't put doc comments on macros
-// Raised by `read` on error
-condition! {
-    pub read_error: IoError -> ();
-}
-
 /// Helper for wrapper calls where you want to
 /// ignore any io_errors that might be raised
 pub fn ignore_io_error<T>(cb: &fn() -> T) -> T {
@@ -431,7 +426,7 @@ pub trait Reader {
     ///
     /// # Failure
     ///
-    /// Raises the `read_error` condition on error. If the condition
+    /// Raises the `io_error` condition on error. If the condition
     /// is handled then no guarantee is made about the number of bytes
     /// read and the contents of `buf`. If the condition is handled
     /// returns `None` (XXX see below).
diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs
index d6820981181..ba819df071a 100644
--- a/src/libstd/rt/io/native/file.rs
+++ b/src/libstd/rt/io/native/file.rs
@@ -17,13 +17,31 @@ use os;
 use prelude::*;
 use super::super::*;
 
-fn raise_error() {
+#[cfg(windows)]
+fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
+    match errno {
+        libc::EOF => (EndOfFile, "end of file"),
+        _ => (OtherIoError, "unknown error"),
+    }
+}
+
+#[cfg(not(windows))]
+fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
     // XXX: this should probably be a bit more descriptive...
-    let (kind, desc) = match os::errno() as i32 {
+    match errno {
         libc::EOF => (EndOfFile, "end of file"),
+
+        // These two constants can have the same value on some systems, but
+        // different values on others, so we can't use a match clause
+        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+            (ResourceUnavailable, "resource temporarily unavailable"),
+
         _ => (OtherIoError, "unknown error"),
-    };
+    }
+}
 
+fn raise_error() {
+    let (kind, desc) = get_err(os::errno() as i32);
     io_error::cond.raise(IoError {
         kind: kind,
         desc: desc,
diff --git a/src/libstd/rt/io/net/addrinfo.rs b/src/libstd/rt/io/net/addrinfo.rs
new file mode 100644
index 00000000000..27cf9781c9c
--- /dev/null
+++ b/src/libstd/rt/io/net/addrinfo.rs
@@ -0,0 +1,126 @@
+// 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.
+
+/*!
+
+Synchronous DNS Resolution
+
+Contains the functionality to perform DNS resolution in a style related to
+getaddrinfo()
+
+*/
+
+use option::{Option, Some, None};
+use result::{Ok, Err};
+use rt::io::{io_error};
+use rt::io::net::ip::{SocketAddr, IpAddr};
+use rt::rtio::{IoFactory, with_local_io};
+
+/// Hints to the types of sockets that are desired when looking up hosts
+pub enum SocketType {
+    Stream, Datagram, Raw
+}
+
+/// Flags which can be or'd into the `flags` field of a `Hint`. These are used
+/// to manipulate how a query is performed.
+///
+/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo`
+pub enum Flag {
+    AddrConfig,
+    All,
+    CanonName,
+    NumericHost,
+    NumericServ,
+    Passive,
+    V4Mapped,
+}
+
+/// A transport protocol associated with either a hint or a return value of
+/// `lookup`
+pub enum Protocol {
+    TCP, UDP
+}
+
+/// This structure is used to provide hints when fetching addresses for a
+/// remote host to control how the lookup is performed.
+///
+/// For details on these fields, see their corresponding definitions via
+/// `man -s 3 getaddrinfo`
+pub struct Hint {
+    family: uint,
+    socktype: Option<SocketType>,
+    protocol: Option<Protocol>,
+    flags: uint,
+}
+
+pub struct Info {
+    address: SocketAddr,
+    family: uint,
+    socktype: Option<SocketType>,
+    protocol: Option<Protocol>,
+    flags: uint,
+}
+
+/// Easy name resolution. Given a hostname, returns the list of IP addresses for
+/// that hostname.
+///
+/// # Failure
+///
+/// On failure, this will raise on the `io_error` condition.
+pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
+    lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip))
+}
+
+/// Full-fleged resolution. This function will perform a synchronous call to
+/// getaddrinfo, controlled by the parameters
+///
+/// # Arguments
+///
+/// * hostname - an optional hostname to lookup against
+/// * servname - an optional service name, listed in the system services
+/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this
+///          controls lookup
+///
+/// # Failure
+///
+/// On failure, this will raise on the `io_error` condition.
+///
+/// XXX: this is not public because the `Hint` structure is not ready for public
+///      consumption just yet.
+fn lookup(hostname: Option<&str>, servname: Option<&str>,
+          hint: Option<Hint>) -> Option<~[Info]> {
+    do with_local_io |io| {
+        match io.get_host_addresses(hostname, servname, hint) {
+            Ok(i) => Some(i),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use option::Some;
+    use rt::io::net::ip::Ipv4Addr;
+    use super::*;
+
+    #[test]
+    fn dns_smoke_test() {
+        let ipaddrs = get_host_addresses("localhost").unwrap();
+        let mut found_local = false;
+        let local_addr = &Ipv4Addr(127, 0, 0, 1);
+        for addr in ipaddrs.iter() {
+            found_local = found_local || addr == local_addr;
+        }
+        assert!(found_local);
+    }
+}
diff --git a/src/libstd/rt/io/net/mod.rs b/src/libstd/rt/io/net/mod.rs
index f44e879a63a..cf109167089 100644
--- a/src/libstd/rt/io/net/mod.rs
+++ b/src/libstd/rt/io/net/mod.rs
@@ -8,55 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use option::{Option, Some, None};
-use result::{Ok, Err};
-use rt::io::io_error;
-use rt::io::net::ip::IpAddr;
-use rt::rtio::{IoFactory, IoFactoryObject};
-use rt::local::Local;
+pub use self::addrinfo::get_host_addresses;
 
+pub mod addrinfo;
 pub mod tcp;
 pub mod udp;
 pub mod ip;
 #[cfg(unix)]
 pub mod unix;
-
-/// Simplistic name resolution
-pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
-    /*!
-     * Get the IP addresses for a given host name.
-     *
-     * Raises io_error on failure.
-     */
-
-    let ipaddrs = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).get_host_addresses(host)
-    };
-
-    match ipaddrs {
-        Ok(i) => Some(i),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
-            None
-        }
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use option::Some;
-    use rt::io::net::ip::Ipv4Addr;
-    use super::*;
-
-    #[test]
-    fn dns_smoke_test() {
-        let ipaddrs = get_host_addresses("localhost").unwrap();
-        let mut found_local = false;
-        let local_addr = &Ipv4Addr(127, 0, 0, 1);
-        for addr in ipaddrs.iter() {
-            found_local = found_local || addr == local_addr;
-        }
-        assert!(found_local);
-    }
-}
diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs
index f29e17cfc2f..4e841b36a5d 100644
--- a/src/libstd/rt/io/net/tcp.rs
+++ b/src/libstd/rt/io/net/tcp.rs
@@ -12,37 +12,27 @@ use option::{Option, Some, None};
 use result::{Ok, Err};
 use rt::io::net::ip::SocketAddr;
 use rt::io::{Reader, Writer, Listener, Acceptor};
-use rt::io::{io_error, read_error, EndOfFile};
-use rt::rtio::{IoFactory, IoFactoryObject,
-               RtioSocket,
-               RtioTcpListener, RtioTcpListenerObject,
-               RtioTcpAcceptor, RtioTcpAcceptorObject,
-               RtioTcpStream, RtioTcpStreamObject};
-use rt::local::Local;
+use rt::io::{io_error, EndOfFile};
+use rt::rtio::{IoFactory, with_local_io,
+               RtioSocket, RtioTcpListener, RtioTcpAcceptor, RtioTcpStream};
 
 pub struct TcpStream {
-    priv obj: ~RtioTcpStreamObject
+    priv obj: ~RtioTcpStream
 }
 
 impl TcpStream {
-    fn new(s: ~RtioTcpStreamObject) -> TcpStream {
+    fn new(s: ~RtioTcpStream) -> TcpStream {
         TcpStream { obj: s }
     }
 
     pub fn connect(addr: SocketAddr) -> Option<TcpStream> {
-        let stream = unsafe {
-            rtdebug!("borrowing io to connect");
-            let io: *mut IoFactoryObject = Local::unsafe_borrow();
-            rtdebug!("about to connect");
-            (*io).tcp_connect(addr)
-        };
-
-        match stream {
-            Ok(s) => Some(TcpStream::new(s)),
-            Err(ioerr) => {
-                rtdebug!("failed to connect: {:?}", ioerr);
-                io_error::cond.raise(ioerr);
-                None
+        do with_local_io |io| {
+            match io.tcp_connect(addr) {
+                Ok(s) => Some(TcpStream::new(s)),
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
             }
         }
     }
@@ -77,7 +67,7 @@ impl Reader for TcpStream {
             Err(ioerr) => {
                 // EOF is indicated by returning None
                 if ioerr.kind != EndOfFile {
-                    read_error::cond.raise(ioerr);
+                    io_error::cond.raise(ioerr);
                 }
                 return None;
             }
@@ -99,20 +89,18 @@ impl Writer for TcpStream {
 }
 
 pub struct TcpListener {
-    priv obj: ~RtioTcpListenerObject
+    priv obj: ~RtioTcpListener
 }
 
 impl TcpListener {
     pub fn bind(addr: SocketAddr) -> Option<TcpListener> {
-        let listener = unsafe {
-            let io: *mut IoFactoryObject = Local::unsafe_borrow();
-            (*io).tcp_bind(addr)
-        };
-        match listener {
-            Ok(l) => Some(TcpListener { obj: l }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                return None;
+        do with_local_io |io| {
+            match io.tcp_bind(addr) {
+                Ok(l) => Some(TcpListener { obj: l }),
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
             }
         }
     }
@@ -142,7 +130,7 @@ impl Listener<TcpStream, TcpAcceptor> for TcpListener {
 }
 
 pub struct TcpAcceptor {
-    priv obj: ~RtioTcpAcceptorObject
+    priv obj: ~RtioTcpAcceptor
 }
 
 impl Acceptor<TcpStream> for TcpAcceptor {
@@ -320,7 +308,7 @@ mod test {
                 let mut buf = [0];
                 let nread = stream.read(buf);
                 assert!(nread.is_none());
-                do read_error::cond.trap(|e| {
+                do io_error::cond.trap(|e| {
                     if cfg!(windows) {
                         assert_eq!(e.kind, NotConnected);
                     } else {
@@ -355,7 +343,7 @@ mod test {
                 let mut buf = [0];
                 let nread = stream.read(buf);
                 assert!(nread.is_none());
-                do read_error::cond.trap(|e| {
+                do io_error::cond.trap(|e| {
                     if cfg!(windows) {
                         assert_eq!(e.kind, NotConnected);
                     } else {
diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs
index 27faae0838b..2e4ae95d98e 100644
--- a/src/libstd/rt/io/net/udp.rs
+++ b/src/libstd/rt/io/net/udp.rs
@@ -12,25 +12,22 @@ use option::{Option, Some, None};
 use result::{Ok, Err};
 use rt::io::net::ip::SocketAddr;
 use rt::io::{Reader, Writer};
-use rt::io::{io_error, read_error, EndOfFile};
-use rt::rtio::{RtioSocket, RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject};
-use rt::local::Local;
+use rt::io::{io_error, EndOfFile};
+use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, with_local_io};
 
 pub struct UdpSocket {
-    priv obj: ~RtioUdpSocketObject
+    priv obj: ~RtioUdpSocket
 }
 
 impl UdpSocket {
     pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
-        let socket = unsafe {
-            let factory: *mut IoFactoryObject = Local::unsafe_borrow();
-            (*factory).udp_bind(addr)
-        };
-        match socket {
-            Ok(s) => Some(UdpSocket { obj: s }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
+        do with_local_io |io| {
+            match io.udp_bind(addr) {
+                Ok(s) => Some(UdpSocket { obj: s }),
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
             }
         }
     }
@@ -41,7 +38,7 @@ impl UdpSocket {
             Err(ioerr) => {
                 // EOF is indicated by returning None
                 if ioerr.kind != EndOfFile {
-                    read_error::cond.raise(ioerr);
+                    io_error::cond.raise(ioerr);
                 }
                 None
             }
diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs
index 1771a963ba7..e424956e2ff 100644
--- a/src/libstd/rt/io/net/unix.rs
+++ b/src/libstd/rt/io/net/unix.rs
@@ -8,44 +8,289 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*!
+
+Named pipes
+
+This module contains the ability to communicate over named pipes with
+synchronous I/O. On windows, this corresponds to talking over a Named Pipe,
+while on Unix it corresponds to UNIX domain sockets.
+
+These pipes are similar to TCP in the sense that you can have both a stream to a
+server and a server itself. The server provided accepts other `UnixStream`
+instances as clients.
+
+*/
+
 use prelude::*;
-use super::super::*;
-use super::super::support::PathLike;
 
-pub struct UnixStream;
+use c_str::ToCStr;
+use rt::rtio::{IoFactory, RtioUnixListener, with_local_io};
+use rt::rtio::{RtioUnixAcceptor, RtioPipe};
+use rt::io::pipe::PipeStream;
+use rt::io::{io_error, Listener, Acceptor, Reader, Writer};
+
+/// A stream which communicates over a named pipe.
+pub struct UnixStream {
+    priv obj: PipeStream,
+}
 
 impl UnixStream {
-    pub fn connect<P: PathLike>(_path: &P) -> Option<UnixStream> {
-        fail!()
+    fn new(obj: ~RtioPipe) -> UnixStream {
+        UnixStream { obj: PipeStream::new(obj) }
+    }
+
+    /// Connect to a pipe named by `path`. This will attempt to open a
+    /// connection to the underlying socket.
+    ///
+    /// The returned stream will be closed when the object falls out of scope.
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if the connection
+    /// could not be made.
+    ///
+    /// # Example
+    ///
+    ///     use std::rt::io::net::unix::UnixStream;
+    ///
+    ///     let server = Path("path/to/my/socket");
+    ///     let mut stream = UnixStream::connect(&server);
+    ///     stream.write([1, 2, 3]);
+    ///
+    pub fn connect<P: ToCStr>(path: &P) -> Option<UnixStream> {
+        do with_local_io |io| {
+            match io.unix_connect(&path.to_c_str()) {
+                Ok(s) => Some(UnixStream::new(s)),
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
+            }
+        }
     }
 }
 
 impl Reader for UnixStream {
-    fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
-
-    fn eof(&mut self) -> bool { fail!() }
+    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.obj.read(buf) }
+    fn eof(&mut self) -> bool { self.obj.eof() }
 }
 
 impl Writer for UnixStream {
-    fn write(&mut self, _v: &[u8]) { fail!() }
-
-    fn flush(&mut self) { fail!() }
+    fn write(&mut self, buf: &[u8]) { self.obj.write(buf) }
+    fn flush(&mut self) { self.obj.flush() }
 }
 
-pub struct UnixListener;
+pub struct UnixListener {
+    priv obj: ~RtioUnixListener,
+}
 
 impl UnixListener {
-    pub fn bind<P: PathLike>(_path: &P) -> Option<UnixListener> {
-        fail!()
+
+    /// Creates a new listener, ready to receive incoming connections on the
+    /// specified socket. The server will be named by `path`.
+    ///
+    /// This listener will be closed when it falls out of scope.
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if the specified
+    /// path could not be bound.
+    ///
+    /// # Example
+    ///
+    ///     use std::rt::io::net::unix::UnixListener;
+    ///
+    ///     let server = Path("path/to/my/socket");
+    ///     let mut stream = UnixListener::bind(&server);
+    ///     for client in stream.incoming() {
+    ///         let mut client = client;
+    ///         client.write([1, 2, 3, 4]);
+    ///     }
+    ///
+    pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> {
+        do with_local_io |io| {
+            match io.unix_bind(&path.to_c_str()) {
+                Ok(s) => Some(UnixListener{ obj: s }),
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
+            }
+        }
     }
 }
 
 impl Listener<UnixStream, UnixAcceptor> for UnixListener {
-    fn listen(self) -> Option<UnixAcceptor> { fail!() }
+    fn listen(self) -> Option<UnixAcceptor> {
+        match self.obj.listen() {
+            Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
 }
 
-pub struct UnixAcceptor;
+pub struct UnixAcceptor {
+    priv obj: ~RtioUnixAcceptor,
+}
 
 impl Acceptor<UnixStream> for UnixAcceptor {
-    fn accept(&mut self) -> Option<UnixStream> { fail!() }
+    fn accept(&mut self) -> Option<UnixStream> {
+        match self.obj.accept() {
+            Ok(s) => Some(UnixStream::new(s)),
+            Err(ioerr) => {
+                io_error::cond.raise(ioerr);
+                None
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::*;
+    use super::*;
+    use cell::Cell;
+    use rt::test::*;
+    use rt::io::*;
+    use rt::comm::oneshot;
+    use os;
+
+    fn smalltest(server: ~fn(UnixStream), client: ~fn(UnixStream)) {
+        let server = Cell::new(server);
+        let client = Cell::new(client);
+        do run_in_mt_newsched_task {
+            let server = Cell::new(server.take());
+            let client = Cell::new(client.take());
+            let path1 = next_test_unix();
+            let path2 = path1.clone();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
+
+            do spawntask {
+                let mut acceptor = UnixListener::bind(&path1).listen();
+                chan.take().send(());
+                server.take()(acceptor.accept().unwrap());
+            }
+
+            do spawntask {
+                port.take().recv();
+                client.take()(UnixStream::connect(&path2).unwrap());
+            }
+        }
+    }
+
+    #[test]
+    fn bind_error() {
+        do run_in_mt_newsched_task {
+            let mut called = false;
+            do io_error::cond.trap(|e| {
+                assert!(e.kind == PermissionDenied);
+                called = true;
+            }).inside {
+                let listener = UnixListener::bind(&("path/to/nowhere"));
+                assert!(listener.is_none());
+            }
+            assert!(called);
+        }
+    }
+
+    #[test]
+    fn connect_error() {
+        do run_in_mt_newsched_task {
+            let mut called = false;
+            do io_error::cond.trap(|e| {
+                assert_eq!(e.kind, OtherIoError);
+                called = true;
+            }).inside {
+                let stream = UnixStream::connect(&("path/to/nowhere"));
+                assert!(stream.is_none());
+            }
+            assert!(called);
+        }
+    }
+
+    #[test]
+    fn smoke() {
+        smalltest(|mut server| {
+            let mut buf = [0];
+            server.read(buf);
+            assert!(buf[0] == 99);
+        }, |mut client| {
+            client.write([99]);
+        })
+    }
+
+    #[test]
+    fn read_eof() {
+        smalltest(|mut server| {
+            let mut buf = [0];
+            assert!(server.read(buf).is_none());
+            assert!(server.read(buf).is_none());
+        }, |_client| {
+            // drop the client
+        })
+    }
+
+    #[test]
+    fn write_begone() {
+        smalltest(|mut server| {
+            let buf = [0];
+            let mut stop = false;
+            while !stop{
+                do io_error::cond.trap(|e| {
+                    assert_eq!(e.kind, BrokenPipe);
+                    stop = true;
+                }).inside {
+                    server.write(buf);
+                }
+            }
+        }, |_client| {
+            // drop the client
+        })
+    }
+
+    #[test]
+    fn accept_lots() {
+        do run_in_mt_newsched_task {
+            let times = 10;
+            let path1 = next_test_unix();
+            let path2 = path1.clone();
+            let (port, chan) = oneshot();
+            let port = Cell::new(port);
+            let chan = Cell::new(chan);
+
+            do spawntask {
+                let mut acceptor = UnixListener::bind(&path1).listen();
+                chan.take().send(());
+                do times.times {
+                    let mut client = acceptor.accept();
+                    let mut buf = [0];
+                    client.read(buf);
+                    assert_eq!(buf[0], 100);
+                }
+            }
+
+            do spawntask {
+                port.take().recv();
+                do times.times {
+                    let mut stream = UnixStream::connect(&path2);
+                    stream.write([100]);
+                }
+            }
+        }
+    }
+
+    #[test]
+    fn path_exists() {
+        do run_in_mt_newsched_task {
+            let path = next_test_unix();
+            let _acceptor = UnixListener::bind(&path).listen();
+            assert!(os::path_exists(&path));
+        }
+    }
 }
diff --git a/src/libstd/rt/io/option.rs b/src/libstd/rt/io/option.rs
index 2ea1b615483..52699964b62 100644
--- a/src/libstd/rt/io/option.rs
+++ b/src/libstd/rt/io/option.rs
@@ -13,12 +13,10 @@
 //! I/O constructors return option types to allow errors to be handled.
 //! These implementations allow e.g. `Option<FileStream>` to be used
 //! as a `Reader` without unwrapping the option first.
-//!
-//! # XXX Seek and Close
 
 use option::*;
-use super::{Reader, Writer, Listener, Acceptor};
-use super::{standard_error, PreviousIoError, io_error, read_error, IoError};
+use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle};
+use super::{standard_error, PreviousIoError, io_error, IoError};
 
 fn prev_io_error() -> IoError {
     standard_error(PreviousIoError)
@@ -45,7 +43,7 @@ impl<R: Reader> Reader for Option<R> {
         match *self {
             Some(ref mut reader) => reader.read(buf),
             None => {
-                read_error::cond.raise(prev_io_error());
+                io_error::cond.raise(prev_io_error());
                 None
             }
         }
@@ -62,6 +60,24 @@ impl<R: Reader> Reader for Option<R> {
     }
 }
 
+impl<S: Seek> Seek for Option<S> {
+    fn tell(&self) -> u64 {
+        match *self {
+            Some(ref seeker) => seeker.tell(),
+            None => {
+                io_error::cond.raise(prev_io_error());
+                0
+            }
+        }
+    }
+    fn seek(&mut self, pos: i64, style: SeekStyle) {
+        match *self {
+            Some(ref mut seeker) => seeker.seek(pos, style),
+            None => io_error::cond.raise(prev_io_error())
+        }
+    }
+}
+
 impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for Option<L> {
     fn listen(self) -> Option<A> {
         match self {
@@ -91,7 +107,7 @@ mod test {
     use option::*;
     use super::super::mem::*;
     use rt::test::*;
-    use super::super::{PreviousIoError, io_error, read_error};
+    use super::super::{PreviousIoError, io_error, io_error};
 
     #[test]
     fn test_option_writer() {
@@ -145,7 +161,7 @@ mod test {
         let mut buf = [];
 
         let mut called = false;
-        do read_error::cond.trap(|err| {
+        do io_error::cond.trap(|err| {
             assert_eq!(err.kind, PreviousIoError);
             called = true;
         }).inside {
diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs
index d2cd531ed26..ec9a4a0101f 100644
--- a/src/libstd/rt/io/pipe.rs
+++ b/src/libstd/rt/io/pipe.rs
@@ -15,37 +15,47 @@
 
 use prelude::*;
 use super::{Reader, Writer};
-use rt::io::{io_error, read_error, EndOfFile};
-use rt::local::Local;
-use rt::rtio::{RtioPipe, RtioPipeObject, IoFactoryObject, IoFactory};
-use rt::rtio::RtioUnboundPipeObject;
+use rt::io::{io_error, EndOfFile};
+use rt::io::native::file;
+use rt::rtio::{RtioPipe, with_local_io};
 
 pub struct PipeStream {
-    priv obj: RtioPipeObject
+    priv obj: ~RtioPipe,
 }
 
-// This should not be a newtype, but rt::uv::process::set_stdio needs to reach
-// into the internals of this :(
-pub struct UnboundPipeStream(~RtioUnboundPipeObject);
-
 impl PipeStream {
-    /// Creates a new pipe initialized, but not bound to any particular
-    /// source/destination
-    pub fn new() -> Option<UnboundPipeStream> {
-        let pipe = unsafe {
-            let io: *mut IoFactoryObject = Local::unsafe_borrow();
-            (*io).pipe_init(false)
-        };
-        match pipe {
-            Ok(p) => Some(UnboundPipeStream(p)),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
+    /// Consumes a file descriptor to return a pipe stream that will have
+    /// synchronous, but non-blocking reads/writes. This is useful if the file
+    /// descriptor is acquired via means other than the standard methods.
+    ///
+    /// This operation consumes ownership of the file descriptor and it will be
+    /// closed once the object is deallocated.
+    ///
+    /// # Example
+    ///
+    ///     use std::libc;
+    ///     use std::rt::io::pipe;
+    ///
+    ///     let mut pipe = PipeStream::open(libc::STDERR_FILENO);
+    ///     pipe.write(bytes!("Hello, stderr!"));
+    ///
+    /// # Failure
+    ///
+    /// If the pipe cannot be created, an error will be raised on the
+    /// `io_error` condition.
+    pub fn open(fd: file::fd_t) -> Option<PipeStream> {
+        do with_local_io |io| {
+            match io.pipe_open(fd) {
+                Ok(obj) => Some(PipeStream { obj: obj }),
+                Err(e) => {
+                    io_error::cond.raise(e);
+                    None
+                }
             }
         }
     }
 
-    pub fn bind(inner: RtioPipeObject) -> PipeStream {
+    pub fn new(inner: ~RtioPipe) -> PipeStream {
         PipeStream { obj: inner }
     }
 }
@@ -57,14 +67,14 @@ impl Reader for PipeStream {
             Err(ioerr) => {
                 // EOF is indicated by returning None
                 if ioerr.kind != EndOfFile {
-                    read_error::cond.raise(ioerr);
+                    io_error::cond.raise(ioerr);
                 }
                 return None;
             }
         }
     }
 
-    fn eof(&mut self) -> bool { fail!() }
+    fn eof(&mut self) -> bool { false }
 }
 
 impl Writer for PipeStream {
@@ -77,5 +87,5 @@ impl Writer for PipeStream {
         }
     }
 
-    fn flush(&mut self) { fail!() }
+    fn flush(&mut self) {}
 }
diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs
index 5f2453852ee..ae087099d1f 100644
--- a/src/libstd/rt/io/process.rs
+++ b/src/libstd/rt/io/process.rs
@@ -11,12 +11,12 @@
 //! Bindings for executing child processes
 
 use prelude::*;
+use cell::Cell;
 
 use libc;
 use rt::io;
 use rt::io::io_error;
-use rt::local::Local;
-use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};
+use rt::rtio::{RtioProcess, IoFactory, with_local_io};
 
 // windows values don't matter as long as they're at least one of unix's
 // TERM/KILL/INT signals
@@ -26,7 +26,7 @@ use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};
 #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int;
 
 pub struct Process {
-    priv handle: ~RtioProcessObject,
+    priv handle: ~RtioProcess,
     io: ~[Option<io::PipeStream>],
 }
 
@@ -57,7 +57,7 @@ pub struct ProcessConfig<'self> {
     ///     0 - stdin
     ///     1 - stdout
     ///     2 - stderr
-    io: ~[StdioContainer]
+    io: &'self [StdioContainer]
 }
 
 /// Describes what to do with a standard io stream for a child process.
@@ -70,42 +70,32 @@ pub enum StdioContainer {
     /// specified for.
     InheritFd(libc::c_int),
 
-    // XXX: these two shouldn't have libuv-specific implementation details
-
-    /// The specified libuv stream is inherited for the corresponding file
-    /// descriptor it is assigned to.
-    // XXX: this needs to be thought out more.
-    //InheritStream(uv::net::StreamWatcher),
-
-    /// Creates a pipe for the specified file descriptor which will be directed
-    /// into the previously-initialized pipe passed in.
+    /// Creates a pipe for the specified file descriptor which will be created
+    /// when the process is spawned.
     ///
     /// The first boolean argument is whether the pipe is readable, and the
     /// second is whether it is writable. These properties are from the view of
     /// the *child* process, not the parent process.
-    CreatePipe(io::UnboundPipeStream,
-               bool /* readable */,
-               bool /* writable */),
+    CreatePipe(bool /* readable */, bool /* writable */),
 }
 
 impl Process {
     /// Creates a new pipe initialized, but not bound to any particular
     /// source/destination
     pub fn new(config: ProcessConfig) -> Option<Process> {
-        let process = unsafe {
-            let io: *mut IoFactoryObject = Local::unsafe_borrow();
-            (*io).spawn(config)
-        };
-        match process {
-            Ok((p, io)) => Some(Process{
-                handle: p,
-                io: io.move_iter().map(|p|
-                    p.map(|p| io::PipeStream::bind(p))
-                ).collect()
-            }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
+        let config = Cell::new(config);
+        do with_local_io |io| {
+            match io.spawn(config.take()) {
+                Ok((p, io)) => Some(Process{
+                    handle: p,
+                    io: io.move_iter().map(|p|
+                        p.map(|p| io::PipeStream::new(p))
+                    ).collect()
+                }),
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
             }
         }
     }
diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs
new file mode 100644
index 00000000000..a13fc19d000
--- /dev/null
+++ b/src/libstd/rt/io/signal.rs
@@ -0,0 +1,220 @@
+// 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.
+
+/*!
+
+Signal handling
+
+This modules provides bindings to receive signals safely, built on top of the
+local I/O factory. There are a number of defined signals which can be caught,
+but not all signals will work across all platforms (windows doesn't have
+definitions for a number of signals.
+
+*/
+
+use comm::{Port, SharedChan, stream};
+use hashmap;
+use option::{Some, None};
+use result::{Err, Ok};
+use rt::io::io_error;
+use rt::rtio::{IoFactory, RtioSignal, with_local_io};
+
+#[deriving(Eq, IterBytes)]
+pub enum Signum {
+    /// Equivalent to SIGBREAK, delivered when the user presses Ctrl-Break.
+    Break = 21i,
+    /// Equivalent to SIGHUP, delivered when the user closes the terminal
+    /// window. On delivery of HangUp, the program is given approximately
+    /// 10 seconds to perfom any cleanup. After that, Windows will
+    /// unconditionally terminate it.
+    HangUp = 1i,
+    /// Equivalent to SIGINT, delivered when the user presses Ctrl-c.
+    Interrupt = 2i,
+    /// Equivalent to SIGQUIT, delivered when the user presses Ctrl-\.
+    Quit = 3i,
+    /// Equivalent to SIGTSTP, delivered when the user presses Ctrl-z.
+    StopTemporarily = 20i,
+    /// Equivalent to SIGUSR1.
+    User1 = 10i,
+    /// Equivalent to SIGUSR2.
+    User2 = 12i,
+    /// Equivalent to SIGWINCH, delivered when the console has been resized.
+    /// WindowSizeChange may not be delivered in a timely manner; size change
+    /// will only be detected when the cursor is being moved.
+    WindowSizeChange = 28i,
+}
+
+/// Listener provides a port to listen for registered signals.
+///
+/// Listener automatically unregisters its handles once it is out of scope.
+/// However, clients can still unregister signums manually.
+///
+/// # Example
+///
+/// ```rust
+/// use std::rt::io::signal::{Listener, Interrupt};
+///
+/// let mut listener = Listener::new();
+/// listener.register(signal::Interrupt);
+///
+/// do spawn {
+///     loop {
+///         match listener.port.recv() {
+///             Interrupt => println("Got Interrupt'ed"),
+///             _ => (),
+///         }
+///     }
+/// }
+///
+/// ```
+pub struct Listener {
+    /// A map from signums to handles to keep the handles in memory
+    priv handles: hashmap::HashMap<Signum, ~RtioSignal>,
+    /// chan is where all the handles send signums, which are received by
+    /// the clients from port.
+    priv chan: SharedChan<Signum>,
+
+    /// Clients of Listener can `recv()` from this port. This is exposed to
+    /// allow selection over this port as well as manipulation of the port
+    /// directly.
+    port: Port<Signum>,
+}
+
+impl Listener {
+    /// Creates a new listener for signals. Once created, signals are bound via
+    /// the `register` method (otherwise nothing will ever be received)
+    pub fn new() -> Listener {
+        let (port, chan) = stream();
+        Listener {
+            chan: SharedChan::new(chan),
+            port: port,
+            handles: hashmap::HashMap::new(),
+        }
+    }
+
+    /// Listen for a signal, returning true when successfully registered for
+    /// signum. Signals can be received using `recv()`.
+    ///
+    /// Once a signal is registered, this listener will continue to receive
+    /// notifications of signals until it is unregistered. This occurs
+    /// regardless of the number of other listeners registered in other tasks
+    /// (or on this task).
+    ///
+    /// Signals are still received if there is no task actively waiting for
+    /// a signal, and a later call to `recv` will return the signal that was
+    /// received while no task was waiting on it.
+    ///
+    /// # Failure
+    ///
+    /// If this function fails to register a signal handler, then an error will
+    /// be raised on the `io_error` condition and the function will return
+    /// false.
+    pub fn register(&mut self, signum: Signum) -> bool {
+        if self.handles.contains_key(&signum) {
+            return true; // self is already listening to signum, so succeed
+        }
+        do with_local_io |io| {
+            match io.signal(signum, self.chan.clone()) {
+                Ok(w) => {
+                    self.handles.insert(signum, w);
+                    Some(())
+                },
+                Err(ioerr) => {
+                    io_error::cond.raise(ioerr);
+                    None
+                }
+            }
+        }.is_some()
+    }
+
+    /// Unregisters a signal. If this listener currently had a handler
+    /// registered for the signal, then it will stop receiving any more
+    /// notification about the signal. If the signal has already been received,
+    /// it may still be returned by `recv`.
+    pub fn unregister(&mut self, signum: Signum) {
+        self.handles.pop(&signum);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use libc;
+    use rt::io::timer;
+    use rt::io;
+    use super::*;
+
+    // kill is only available on Unixes
+    #[cfg(unix)]
+    #[fixed_stack_segment]
+    fn sigint() {
+        unsafe {
+            libc::funcs::posix88::signal::kill(libc::getpid(), libc::SIGINT);
+        }
+    }
+
+    #[test] #[cfg(unix)]
+    fn test_io_signal_smoketest() {
+        let mut signal = Listener::new();
+        signal.register(Interrupt);
+        sigint();
+        timer::sleep(10);
+        match signal.port.recv() {
+            Interrupt => (),
+            s => fail!("Expected Interrupt, got {:?}", s),
+        }
+    }
+
+    #[test] #[cfg(unix)]
+    fn test_io_signal_two_signal_one_signum() {
+        let mut s1 = Listener::new();
+        let mut s2 = Listener::new();
+        s1.register(Interrupt);
+        s2.register(Interrupt);
+        sigint();
+        timer::sleep(10);
+        match s1.port.recv() {
+            Interrupt => (),
+            s => fail!("Expected Interrupt, got {:?}", s),
+        }
+        match s1.port.recv() {
+            Interrupt => (),
+            s => fail!("Expected Interrupt, got {:?}", s),
+        }
+    }
+
+    #[test] #[cfg(unix)]
+    fn test_io_signal_unregister() {
+        let mut s1 = Listener::new();
+        let mut s2 = Listener::new();
+        s1.register(Interrupt);
+        s2.register(Interrupt);
+        s2.unregister(Interrupt);
+        sigint();
+        timer::sleep(10);
+        if s2.port.peek() {
+            fail!("Unexpected {:?}", s2.port.recv());
+        }
+    }
+
+    #[cfg(windows)]
+    #[test]
+    fn test_io_signal_invalid_signum() {
+        let mut s = Listener::new();
+        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 e6dd9a48099..b922e6400cc 100644
--- a/src/libstd/rt/io/stdio.rs
+++ b/src/libstd/rt/io/stdio.rs
@@ -8,23 +8,90 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*!
+
+This modules provides bindings to the local event loop's TTY interface, using it
+to have synchronous, but non-blocking versions of stdio. These handles can be
+inspected for information about terminal dimensions or related information
+about the stream or terminal that it is attached to.
+
+# Example
+
+```rust
+use std::rt::io;
+
+let mut out = io::stdout();
+out.write(bytes!("Hello, world!"));
+```
+
+*/
+
 use fmt;
 use libc;
 use option::{Option, Some, None};
 use result::{Ok, Err};
-use rt::local::Local;
-use rt::rtio::{RtioFileStream, IoFactoryObject, IoFactory};
-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 src<T>(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T {
+    do with_local_io |io| {
+        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()
+}
 
 /// Creates a new non-blocking handle to the stdin of the current process.
 ///
 /// See `stdout()` for notes about this function.
+#[fixed_stack_segment] #[inline(never)]
 pub fn stdin() -> StdReader {
-    let stream = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_from_raw_fd(libc::STDIN_FILENO, false)
-    };
-    StdReader { inner: stream }
+    do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } }
 }
 
 /// Creates a new non-blocking handle to the stdout of the current process.
@@ -34,22 +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 {
-    let stream = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_from_raw_fd(libc::STDOUT_FILENO, false)
-    };
-    StdWriter { inner: stream }
+    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 {
-    let stream = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_from_raw_fd(libc::STDERR_FILENO, false)
-    };
-    StdWriter { inner: stream }
+    do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } }
 }
 
 /// Prints a string to the stdout of the current process. No newline is emitted
@@ -87,12 +146,16 @@ pub fn println_args(fmt: &fmt::Arguments) {
 
 /// Representation of a reader of a standard input stream
 pub struct StdReader {
-    priv inner: ~RtioFileStream
+    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);
@@ -106,21 +169,102 @@ impl Reader for StdReader {
 
 /// Representation of a writer to a standard output stream
 pub struct StdWriter {
-    priv inner: ~RtioFileStream
+    priv inner: StdSource
+}
+
+impl StdWriter {
+    /// Gets the size of this output window, if possible. This is typically used
+    /// when the writer is attached to something like a terminal, this is used
+    /// to fetch the dimensions of the terminal.
+    ///
+    /// If successful, returns Some((width, height)).
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if an error
+    /// happens.
+    pub fn winsize(&mut self) -> Option<(int, int)> {
+        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
+            }
+        }
+    }
+
+    /// Controls whether this output stream is a "raw stream" or simply a normal
+    /// stream.
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if an error
+    /// happens.
+    pub fn set_raw(&mut self, raw: bool) {
+        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 {
+        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)
         }
     }
 
-    fn flush(&mut self) {
-        match self.inner.flush() {
-            Ok(()) => {}
-            Err(e) => io_error::cond.raise(e)
-        }
+    fn flush(&mut self) { /* nothing to do */ }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn smoke() {
+        // Just make sure we can acquire handles
+        stdin();
+        stdout();
+        stderr();
     }
 }
diff --git a/src/libstd/rt/io/support.rs b/src/libstd/rt/io/support.rs
deleted file mode 100644
index 31040bc51a1..00000000000
--- a/src/libstd/rt/io/support.rs
+++ /dev/null
@@ -1,42 +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 path::*;
-
-pub trait PathLike {
-    fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T;
-}
-
-impl<'self> PathLike for &'self str {
-    fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T {
-        f(*self)
-    }
-}
-
-impl PathLike for Path {
-    fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T {
-        let s = self.as_str().unwrap();
-        f(s)
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use path::*;
-    use super::PathLike;
-
-    #[test]
-    fn path_like_smoke_test() {
-        let expected = if cfg!(unix) { "/home" } else { "C:\\" };
-        let path = Path::new(expected);
-        path.path_as_str(|p| assert!(p == expected));
-        path.path_as_str(|p| assert!(p == expected));
-    }
-}
diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs
index b41d7541a60..fab0062ee00 100644
--- a/src/libstd/rt/io/timer.rs
+++ b/src/libstd/rt/io/timer.rs
@@ -10,13 +10,11 @@
 
 use option::{Option, Some, None};
 use result::{Ok, Err};
-use rt::io::{io_error};
-use rt::rtio::{IoFactory, IoFactoryObject,
-               RtioTimer, RtioTimerObject};
-use rt::local::Local;
+use rt::io::io_error;
+use rt::rtio::{IoFactory, RtioTimer, with_local_io};
 
 pub struct Timer {
-    priv obj: ~RtioTimerObject
+    priv obj: ~RtioTimer
 }
 
 /// Sleep the current task for `msecs` milliseconds.
@@ -28,20 +26,19 @@ pub fn sleep(msecs: u64) {
 
 impl Timer {
 
+    /// Creates a new timer which can be used to put the current task to sleep
+    /// for a number of milliseconds.
     pub fn new() -> Option<Timer> {
-        let timer = unsafe {
-            rtdebug!("Timer::init: borrowing io to init timer");
-            let io: *mut IoFactoryObject = Local::unsafe_borrow();
-            rtdebug!("about to init timer");
-            (*io).timer_init()
-        };
-        match timer {
-            Ok(t) => Some(Timer { obj: t }),
-            Err(ioerr) => {
-                rtdebug!("Timer::init: failed to init: {:?}", ioerr);
-                io_error::cond.raise(ioerr);
-                None
+        do with_local_io |io| {
+            match io.timer_init() {
+                Ok(t) => Some(Timer { obj: t }),
+                Err(ioerr) => {
+                    rtdebug!("Timer::init: failed to init: {:?}", ioerr);
+                    io_error::cond.raise(ioerr);
+                    None
+                }
             }
+
         }
     }