about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/fs.rs304
-rw-r--r--src/libstd/io/mod.rs104
-rw-r--r--src/libstd/io/net/addrinfo.rs32
-rw-r--r--src/libstd/io/net/mod.rs45
-rw-r--r--src/libstd/io/net/pipe.rs65
-rw-r--r--src/libstd/io/net/tcp.rs105
-rw-r--r--src/libstd/io/net/udp.rs60
-rw-r--r--src/libstd/io/pipe.rs58
-rw-r--r--src/libstd/io/process.rs228
-rw-r--r--src/libstd/io/stdio.rs28
-rw-r--r--src/libstd/io/timer.rs19
-rw-r--r--src/libstd/lib.rs7
-rw-r--r--src/libstd/os.rs190
-rw-r--r--src/libstd/sys/common/helper_thread.rs131
-rw-r--r--src/libstd/sys/common/mod.rs100
-rw-r--r--src/libstd/sys/common/net.rs911
-rw-r--r--src/libstd/sys/unix/c.rs262
-rw-r--r--src/libstd/sys/unix/fs.rs392
-rw-r--r--src/libstd/sys/unix/helper_signal.rs29
-rw-r--r--src/libstd/sys/unix/mod.rs146
-rw-r--r--src/libstd/sys/unix/os.rs112
-rw-r--r--src/libstd/sys/unix/pipe.rs321
-rw-r--r--src/libstd/sys/unix/process.rs587
-rw-r--r--src/libstd/sys/unix/tcp.rs157
-rw-r--r--src/libstd/sys/unix/timer.rs282
-rw-r--r--src/libstd/sys/unix/tty.rs47
-rw-r--r--src/libstd/sys/unix/udp.rs11
-rw-r--r--src/libstd/sys/windows/c.rs250
-rw-r--r--src/libstd/sys/windows/fs.rs460
-rw-r--r--src/libstd/sys/windows/helper_signal.rs38
-rw-r--r--src/libstd/sys/windows/mod.rs190
-rw-r--r--src/libstd/sys/windows/os.rs103
-rw-r--r--src/libstd/sys/windows/pipe.rs751
-rw-r--r--src/libstd/sys/windows/process.rs511
-rw-r--r--src/libstd/sys/windows/tcp.rs219
-rw-r--r--src/libstd/sys/windows/timer.rs208
-rw-r--r--src/libstd/sys/windows/tty.rs166
-rw-r--r--src/libstd/sys/windows/udp.rs11
38 files changed, 6796 insertions, 844 deletions
diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs
index e76046bac05..5c2a5c3512d 100644
--- a/src/libstd/io/fs.rs
+++ b/src/libstd/io/fs.rs
@@ -52,28 +52,25 @@ fs::unlink(&path);
 
 */
 
-use c_str::ToCStr;
 use clone::Clone;
 use io::standard_error;
-use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
+use io::{FilePermission, Write, Open, FileAccess, FileMode};
 use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader};
-use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
+use io::{Read, Truncate, ReadWrite, Append};
 use io::UpdateIoError;
 use io;
 use iter::{Iterator, Extend};
-use kinds::Send;
-use libc;
 use option::{Some, None, Option};
-use boxed::Box;
 use path::{Path, GenericPath};
 use path;
 use result::{Err, Ok};
-use rt::rtio::LocalIo;
-use rt::rtio;
 use slice::SlicePrelude;
 use string::String;
 use vec::Vec;
 
+use sys::fs as fs_imp;
+use sys_common;
+
 /// Unconstrained file access type that exposes read and write operations
 ///
 /// Can be constructed via `File::open()`, `File::create()`, and
@@ -86,11 +83,17 @@ use vec::Vec;
 /// configured at creation time, via the `FileAccess` parameter to
 /// `File::open_mode()`.
 pub struct File {
-    fd: Box<rtio::RtioFileStream + Send>,
+    fd: fs_imp::FileDesc,
     path: Path,
     last_nread: int,
 }
 
+impl sys_common::AsFileDesc for File {
+    fn as_fd(&self) -> &fs_imp::FileDesc {
+        &self.fd
+    }
+}
+
 impl File {
     /// Open a file at `path` in the mode specified by the `mode` and `access`
     /// arguments
@@ -133,26 +136,13 @@ impl File {
     pub fn open_mode(path: &Path,
                      mode: FileMode,
                      access: FileAccess) -> IoResult<File> {
-        let rtio_mode = match mode {
-            Open => rtio::Open,
-            Append => rtio::Append,
-            Truncate => rtio::Truncate,
-        };
-        let rtio_access = match access {
-            Read => rtio::Read,
-            Write => rtio::Write,
-            ReadWrite => rtio::ReadWrite,
-        };
-        let err = LocalIo::maybe_raise(|io| {
-            io.fs_open(&path.to_c_str(), rtio_mode, rtio_access).map(|fd| {
-                File {
-                    path: path.clone(),
-                    fd: fd,
-                    last_nread: -1
-                }
-            })
-        }).map_err(IoError::from_rtio_error);
-        err.update_err("couldn't open file", |e| {
+        fs_imp::open(path, mode, access).map(|fd| {
+            File {
+                path: path.clone(),
+                fd: fd,
+                last_nread: -1
+            }
+        }).update_err("couldn't open file", |e| {
             format!("{}; path={}; mode={}; access={}", e, path.display(),
                 mode_string(mode), access_string(access))
         })
@@ -194,7 +184,7 @@ impl File {
     /// ```
     pub fn create(path: &Path) -> IoResult<File> {
         File::open_mode(path, Truncate, Write)
-            .update_desc("couldn't create file")
+             .update_desc("couldn't create file")
     }
 
     /// Returns the original path which was used to open this file.
@@ -206,9 +196,9 @@ impl File {
     /// device. This will flush any internal buffers necessary to perform this
     /// operation.
     pub fn fsync(&mut self) -> IoResult<()> {
-        let err = self.fd.fsync().map_err(IoError::from_rtio_error);
-        err.update_err("couldn't fsync file",
-                       |e| format!("{}; path={}", e, self.path.display()))
+        self.fd.fsync()
+            .update_err("couldn't fsync file",
+                        |e| format!("{}; path={}", e, self.path.display()))
     }
 
     /// This function is similar to `fsync`, except that it may not synchronize
@@ -216,9 +206,9 @@ impl File {
     /// must synchronize content, but don't need the metadata on disk. The goal
     /// of this method is to reduce disk operations.
     pub fn datasync(&mut self) -> IoResult<()> {
-        let err = self.fd.datasync().map_err(IoError::from_rtio_error);
-        err.update_err("couldn't datasync file",
-                       |e| format!("{}; path={}", e, self.path.display()))
+        self.fd.datasync()
+            .update_err("couldn't datasync file",
+                        |e| format!("{}; path={}", e, self.path.display()))
     }
 
     /// Either truncates or extends the underlying file, updating the size of
@@ -230,10 +220,9 @@ impl File {
     /// will be extended to `size` and have all of the intermediate data filled
     /// in with 0s.
     pub fn truncate(&mut self, size: i64) -> IoResult<()> {
-        let err = self.fd.truncate(size).map_err(IoError::from_rtio_error);
-        err.update_err("couldn't truncate file", |e| {
-            format!("{}; path={}; size={}", e, self.path.display(), size)
-        })
+        self.fd.truncate(size)
+            .update_err("couldn't truncate file", |e|
+                format!("{}; path={}; size={}", e, self.path.display(), size))
     }
 
     /// Returns true if the stream has reached the end of the file.
@@ -251,12 +240,9 @@ impl File {
 
     /// Queries information about the underlying file.
     pub fn stat(&mut self) -> IoResult<FileStat> {
-        let err = match self.fd.fstat() {
-            Ok(s) => Ok(from_rtio(s)),
-            Err(e) => Err(IoError::from_rtio_error(e)),
-        };
-        err.update_err("couldn't fstat file",
-                       |e| format!("{}; path={}", e, self.path.display()))
+        self.fd.fstat()
+            .update_err("couldn't fstat file", |e|
+                format!("{}; path={}", e, self.path.display()))
     }
 }
 
@@ -282,41 +268,9 @@ impl File {
 /// user lacks permissions to remove the file, or if some other filesystem-level
 /// error occurs.
 pub fn unlink(path: &Path) -> IoResult<()> {
-    return match do_unlink(path) {
-        Ok(()) => Ok(()),
-        Err(e) => {
-            // On unix, a readonly file can be successfully removed. On windows,
-            // however, it cannot. To keep the two platforms in line with
-            // respect to their behavior, catch this case on windows, attempt to
-            // change it to read-write, and then remove the file.
-            if cfg!(windows) && e.kind == io::PermissionDenied {
-                let stat = match stat(path) {
-                    Ok(stat) => stat,
-                    Err(..) => return Err(e),
-                };
-                if stat.perm.intersects(io::USER_WRITE) { return Err(e) }
-
-                match chmod(path, stat.perm | io::USER_WRITE) {
-                    Ok(()) => do_unlink(path),
-                    Err(..) => {
-                        // Try to put it back as we found it
-                        let _ = chmod(path, stat.perm);
-                        Err(e)
-                    }
-                }
-            } else {
-                Err(e)
-            }
-        }
-    };
-
-    fn do_unlink(path: &Path) -> IoResult<()> {
-        let err = LocalIo::maybe_raise(|io| {
-            io.fs_unlink(&path.to_c_str())
-        }).map_err(IoError::from_rtio_error);
-        err.update_err("couldn't unlink path",
-                       |e| format!("{}; path={}", e, path.display()))
-    }
+    fs_imp::unlink(path)
+           .update_err("couldn't unlink path", |e|
+               format!("{}; path={}", e, path.display()))
 }
 
 /// Given a path, query the file system to get information about a file,
@@ -341,12 +295,9 @@ pub fn unlink(path: &Path) -> IoResult<()> {
 /// to perform a `stat` call on the given `path` or if there is no entry in the
 /// filesystem at the provided path.
 pub fn stat(path: &Path) -> IoResult<FileStat> {
-    let err = match LocalIo::maybe_raise(|io| io.fs_stat(&path.to_c_str())) {
-        Ok(s) => Ok(from_rtio(s)),
-        Err(e) => Err(IoError::from_rtio_error(e)),
-    };
-    err.update_err("couldn't stat path",
-                   |e| format!("{}; path={}", e, path.display()))
+    fs_imp::stat(path)
+           .update_err("couldn't stat path", |e|
+               format!("{}; path={}", e, path.display()))
 }
 
 /// Perform the same operation as the `stat` function, except that this
@@ -358,53 +309,9 @@ pub fn stat(path: &Path) -> IoResult<FileStat> {
 ///
 /// See `stat`
 pub fn lstat(path: &Path) -> IoResult<FileStat> {
-    let err = match LocalIo::maybe_raise(|io| io.fs_lstat(&path.to_c_str())) {
-        Ok(s) => Ok(from_rtio(s)),
-        Err(e) => Err(IoError::from_rtio_error(e)),
-    };
-    err.update_err("couldn't lstat path",
-                   |e| format!("{}; path={}", e, path.display()))
-}
-
-fn from_rtio(s: rtio::FileStat) -> FileStat {
-    #[cfg(windows)]
-    type Mode = libc::c_int;
-    #[cfg(unix)]
-    type Mode = libc::mode_t;
-
-    let rtio::FileStat {
-        size, kind, perm, created, modified,
-        accessed, device, inode, rdev,
-        nlink, uid, gid, blksize, blocks, flags, gen
-    } = s;
-
-    FileStat {
-        size: size,
-        kind: match (kind as Mode) & libc::S_IFMT {
-            libc::S_IFREG => io::TypeFile,
-            libc::S_IFDIR => io::TypeDirectory,
-            libc::S_IFIFO => io::TypeNamedPipe,
-            libc::S_IFBLK => io::TypeBlockSpecial,
-            libc::S_IFLNK => io::TypeSymlink,
-            _ => io::TypeUnknown,
-        },
-        perm: FilePermission::from_bits_truncate(perm as u32),
-        created: created,
-        modified: modified,
-        accessed: accessed,
-        unstable: UnstableFileStat {
-            device: device,
-            inode: inode,
-            rdev: rdev,
-            nlink: nlink,
-            uid: uid,
-            gid: gid,
-            blksize: blksize,
-            blocks: blocks,
-            flags: flags,
-            gen: gen,
-        },
-    }
+    fs_imp::lstat(path)
+           .update_err("couldn't lstat path", |e|
+               format!("{}; path={}", e, path.display()))
 }
 
 /// Rename a file or directory to a new name.
@@ -424,12 +331,9 @@ fn from_rtio(s: rtio::FileStat) -> FileStat {
 /// the process lacks permissions to view the contents, or if some other
 /// intermittent I/O error occurs.
 pub fn rename(from: &Path, to: &Path) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_rename(&from.to_c_str(), &to.to_c_str())
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't rename path", |e| {
-        format!("{}; from={}; to={}", e, from.display(), to.display())
-    })
+    fs_imp::rename(from, to)
+           .update_err("couldn't rename path", |e|
+               format!("{}; from={}; to={}", e, from.display(), to.display()))
 }
 
 /// Copies the contents of one file to another. This function will also
@@ -462,8 +366,9 @@ pub fn rename(from: &Path, to: &Path) -> IoResult<()> {
 /// being created and then destroyed by this operation.
 pub fn copy(from: &Path, to: &Path) -> IoResult<()> {
     fn update_err<T>(result: IoResult<T>, from: &Path, to: &Path) -> IoResult<T> {
-        result.update_err("couldn't copy path",
-            |e| format!("{}; from={}; to={}", e, from.display(), to.display()))
+        result.update_err("couldn't copy path", |e| {
+            format!("{}; from={}; to={}", e, from.display(), to.display())
+        })
     }
 
     if !from.is_file() {
@@ -512,45 +417,33 @@ pub fn copy(from: &Path, to: &Path) -> IoResult<()> {
 /// the process lacks permissions to change the attributes of the file, or if
 /// some other I/O error is encountered.
 pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_chmod(&path.to_c_str(), mode.bits() as uint)
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't chmod path", |e| {
-        format!("{}; path={}; mode={}", e, path.display(), mode)
-    })
+    fs_imp::chmod(path, mode.bits() as uint)
+           .update_err("couldn't chmod path", |e|
+               format!("{}; path={}; mode={}", e, path.display(), mode))
 }
 
 /// Change the user and group owners of a file at the specified path.
 pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_chown(&path.to_c_str(), uid, gid)
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't chown path", |e| {
-        format!("{}; path={}; uid={}; gid={}", e, path.display(), uid, gid)
-    })
+    fs_imp::chown(path, uid, gid)
+           .update_err("couldn't chown path", |e|
+               format!("{}; path={}; uid={}; gid={}", e, path.display(), uid, gid))
 }
 
 /// Creates a new hard link on the filesystem. The `dst` path will be a
 /// link pointing to the `src` path. Note that systems often require these
 /// two paths to both be located on the same filesystem.
 pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_link(&src.to_c_str(), &dst.to_c_str())
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't link path", |e| {
-        format!("{}; src={}; dest={}", e, src.display(), dst.display())
-    })
+    fs_imp::link(src, dst)
+           .update_err("couldn't link path", |e|
+               format!("{}; src={}; dest={}", e, src.display(), dst.display()))
 }
 
 /// Creates a new symbolic link on the filesystem. The `dst` path will be a
 /// symlink pointing to the `src` path.
 pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_symlink(&src.to_c_str(), &dst.to_c_str())
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't symlink path", |e| {
-        format!("{}; src={}; dest={}", e, src.display(), dst.display())
-    })
+    fs_imp::symlink(src, dst)
+           .update_err("couldn't symlink path", |e|
+               format!("{}; src={}; dest={}", e, src.display(), dst.display()))
 }
 
 /// Reads a symlink, returning the file that the symlink points to.
@@ -560,11 +453,9 @@ pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
 /// This function will return an error on failure. Failure conditions include
 /// reading a file that does not exist or reading a file which is not a symlink.
 pub fn readlink(path: &Path) -> IoResult<Path> {
-    let err = LocalIo::maybe_raise(|io| {
-        Ok(Path::new(try!(io.fs_readlink(&path.to_c_str()))))
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't resolve symlink for path",
-                   |e| format!("{}; path={}", e, path.display()))
+    fs_imp::readlink(path)
+           .update_err("couldn't resolve symlink for path", |e|
+               format!("{}; path={}", e, path.display()))
 }
 
 /// Create a new, empty directory at the provided path
@@ -585,12 +476,9 @@ pub fn readlink(path: &Path) -> IoResult<Path> {
 /// This function will return an error if the user lacks permissions to make a
 /// new directory at the provided `path`, or if the directory already exists.
 pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_mkdir(&path.to_c_str(), mode.bits() as uint)
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't create directory", |e| {
-        format!("{}; path={}; mode={}", e, path.display(), mode)
-    })
+    fs_imp::mkdir(path, mode.bits() as uint)
+           .update_err("couldn't create directory", |e|
+               format!("{}; path={}; mode={}", e, path.display(), mode))
 }
 
 /// Remove an existing, empty directory
@@ -610,11 +498,9 @@ pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> {
 /// This function will return an error if the user lacks permissions to remove
 /// the directory at the provided `path`, or if the directory isn't empty.
 pub fn rmdir(path: &Path) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_rmdir(&path.to_c_str())
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't remove directory",
-                   |e| format!("{}; path={}", e, path.display()))
+    fs_imp::rmdir(path)
+           .update_err("couldn't remove directory", |e|
+               format!("{}; path={}", e, path.display()))
 }
 
 /// Retrieve a vector containing all entries within a provided directory
@@ -650,13 +536,9 @@ pub fn rmdir(path: &Path) -> IoResult<()> {
 /// the process lacks permissions to view the contents or if the `path` points
 /// at a non-directory file
 pub fn readdir(path: &Path) -> IoResult<Vec<Path>> {
-    let err = LocalIo::maybe_raise(|io| {
-        Ok(try!(io.fs_readdir(&path.to_c_str(), 0)).into_iter().map(|a| {
-            Path::new(a)
-        }).collect())
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't read directory",
-                   |e| format!("{}; path={}", e, path.display()))
+    fs_imp::readdir(path)
+           .update_err("couldn't read directory",
+                       |e| format!("{}; path={}", e, path.display()))
 }
 
 /// Returns an iterator which will recursively walk the directory structure
@@ -666,8 +548,7 @@ pub fn readdir(path: &Path) -> IoResult<Vec<Path>> {
 pub fn walk_dir(path: &Path) -> IoResult<Directories> {
     Ok(Directories {
         stack: try!(readdir(path).update_err("couldn't walk directory",
-                                             |e| format!("{}; path={}",
-                                                         e, path.display())))
+                                             |e| format!("{}; path={}", e, path.display())))
     })
 }
 
@@ -681,12 +562,7 @@ impl Iterator<Path> for Directories {
         match self.stack.pop() {
             Some(path) => {
                 if path.is_dir() {
-                    let result = readdir(&path)
-                        .update_err("couldn't advance Directories iterator",
-                                    |e| format!("{}; path={}",
-                                                e, path.display()));
-
-                    match result {
+                    match readdir(&path) {
                         Ok(dirs) => { self.stack.extend(dirs.into_iter()); }
                         Err(..) => {}
                     }
@@ -804,11 +680,9 @@ pub fn rmdir_recursive(path: &Path) -> IoResult<()> {
 /// be in milliseconds.
 // FIXME(#10301) these arguments should not be u64
 pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> {
-    let err = LocalIo::maybe_raise(|io| {
-        io.fs_utime(&path.to_c_str(), atime, mtime)
-    }).map_err(IoError::from_rtio_error);
-    err.update_err("couldn't change_file_times",
-                   |e| format!("{}; path={}", e, path.display()))
+    fs_imp::utime(path, atime, mtime)
+           .update_err("couldn't change_file_times", |e|
+               format!("{}; path={}", e, path.display()))
 }
 
 impl Reader for File {
@@ -819,12 +693,11 @@ impl Reader for File {
                                           e, file.path.display()))
         }
 
-        let result = update_err(self.fd.read(buf)
-                                    .map_err(IoError::from_rtio_error), self);
+        let result = update_err(self.fd.read(buf), self);
 
         match result {
             Ok(read) => {
-                self.last_nread = read;
+                self.last_nread = read as int;
                 match read {
                     0 => update_err(Err(standard_error(io::EndOfFile)), self),
                     _ => Ok(read as uint)
@@ -837,32 +710,27 @@ impl Reader for File {
 
 impl Writer for File {
     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        let err = self.fd.write(buf).map_err(IoError::from_rtio_error);
-        err.update_err("couldn't write to file",
-                       |e| format!("{}; path={}", e, self.path.display()))
+        self.fd.write(buf)
+            .update_err("couldn't write to file",
+                        |e| format!("{}; path={}", e, self.path.display()))
     }
 }
 
 impl Seek for File {
     fn tell(&self) -> IoResult<u64> {
-        let err = self.fd.tell().map_err(IoError::from_rtio_error);
-        err.update_err("couldn't retrieve file cursor (`tell`)",
-                       |e| format!("{}; path={}", e, self.path.display()))
+        self.fd.tell()
+            .update_err("couldn't retrieve file cursor (`tell`)",
+                        |e| format!("{}; path={}", e, self.path.display()))
     }
 
     fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
-        let style = match style {
-            SeekSet => rtio::SeekSet,
-            SeekCur => rtio::SeekCur,
-            SeekEnd => rtio::SeekEnd,
-        };
         let err = match self.fd.seek(pos, style) {
             Ok(_) => {
                 // successful seek resets EOF indicator
                 self.last_nread = -1;
                 Ok(())
             }
-            Err(e) => Err(IoError::from_rtio_error(e)),
+            Err(e) => Err(e),
         };
         err.update_err("couldn't seek in file",
                        |e| format!("{}; path={}", e, self.path.display()))
@@ -942,6 +810,8 @@ fn access_string(access: FileAccess) -> &'static str {
 
 #[cfg(test)]
 #[allow(unused_imports)]
+#[allow(unused_variables)]
+#[allow(unused_mut)]
 mod test {
     use prelude::*;
     use io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite};
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index c404741b7c3..31eab4363d0 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -228,14 +228,13 @@ use error::{FromError, Error};
 use fmt;
 use int;
 use iter::Iterator;
-use libc;
 use mem::transmute;
 use ops::{BitOr, BitXor, BitAnd, Sub, Not};
 use option::{Option, Some, None};
 use os;
 use boxed::Box;
 use result::{Ok, Err, Result};
-use rt::rtio;
+use sys;
 use slice::{AsSlice, SlicePrelude};
 use str::{Str, StrPrelude};
 use str;
@@ -312,92 +311,12 @@ impl IoError {
     /// struct is filled with an allocated string describing the error
     /// in more detail, retrieved from the operating system.
     pub fn from_errno(errno: uint, detail: bool) -> IoError {
-
-        #[cfg(windows)]
-        fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
-            match errno {
-                libc::EOF => (EndOfFile, "end of file"),
-                libc::ERROR_NO_DATA => (BrokenPipe, "the pipe is being closed"),
-                libc::ERROR_FILE_NOT_FOUND => (FileNotFound, "file not found"),
-                libc::ERROR_INVALID_NAME => (InvalidInput, "invalid file name"),
-                libc::WSAECONNREFUSED => (ConnectionRefused, "connection refused"),
-                libc::WSAECONNRESET => (ConnectionReset, "connection reset"),
-                libc::ERROR_ACCESS_DENIED | libc::WSAEACCES =>
-                    (PermissionDenied, "permission denied"),
-                libc::WSAEWOULDBLOCK => {
-                    (ResourceUnavailable, "resource temporarily unavailable")
-                }
-                libc::WSAENOTCONN => (NotConnected, "not connected"),
-                libc::WSAECONNABORTED => (ConnectionAborted, "connection aborted"),
-                libc::WSAEADDRNOTAVAIL => (ConnectionRefused, "address not available"),
-                libc::WSAEADDRINUSE => (ConnectionRefused, "address in use"),
-                libc::ERROR_BROKEN_PIPE => (EndOfFile, "the pipe has ended"),
-                libc::ERROR_OPERATION_ABORTED =>
-                    (TimedOut, "operation timed out"),
-                libc::WSAEINVAL => (InvalidInput, "invalid argument"),
-                libc::ERROR_CALL_NOT_IMPLEMENTED =>
-                    (IoUnavailable, "function not implemented"),
-                libc::ERROR_INVALID_HANDLE =>
-                    (MismatchedFileTypeForOperation,
-                     "invalid handle provided to function"),
-                libc::ERROR_NOTHING_TO_TERMINATE =>
-                    (InvalidInput, "no process to kill"),
-
-                // libuv maps this error code to EISDIR. we do too. if it is found
-                // to be incorrect, we can add in some more machinery to only
-                // return this message when ERROR_INVALID_FUNCTION after certain
-                // Windows calls.
-                libc::ERROR_INVALID_FUNCTION => (InvalidInput,
-                                                 "illegal operation on a directory"),
-
-                _ => (OtherIoError, "unknown error")
-            }
-        }
-
-        #[cfg(not(windows))]
-        fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
-            // FIXME: this should probably be a bit more descriptive...
-            match errno {
-                libc::EOF => (EndOfFile, "end of file"),
-                libc::ECONNREFUSED => (ConnectionRefused, "connection refused"),
-                libc::ECONNRESET => (ConnectionReset, "connection reset"),
-                libc::EPERM | libc::EACCES =>
-                    (PermissionDenied, "permission denied"),
-                libc::EPIPE => (BrokenPipe, "broken pipe"),
-                libc::ENOTCONN => (NotConnected, "not connected"),
-                libc::ECONNABORTED => (ConnectionAborted, "connection aborted"),
-                libc::EADDRNOTAVAIL => (ConnectionRefused, "address not available"),
-                libc::EADDRINUSE => (ConnectionRefused, "address in use"),
-                libc::ENOENT => (FileNotFound, "no such file or directory"),
-                libc::EISDIR => (InvalidInput, "illegal operation on a directory"),
-                libc::ENOSYS => (IoUnavailable, "function not implemented"),
-                libc::EINVAL => (InvalidInput, "invalid argument"),
-                libc::ENOTTY =>
-                    (MismatchedFileTypeForOperation,
-                     "file descriptor is not a TTY"),
-                libc::ETIMEDOUT => (TimedOut, "operation timed out"),
-                libc::ECANCELED => (TimedOut, "operation aborted"),
-
-                // These two constants can have the same value on some systems,
-                // but different values on others, so we can't use a match
-                // clause
-                x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
-                    (ResourceUnavailable, "resource temporarily unavailable"),
-
-                _ => (OtherIoError, "unknown error")
-            }
-        }
-
-        let (kind, desc) = get_err(errno as i32);
-        IoError {
-            kind: kind,
-            desc: desc,
-            detail: if detail && kind == OtherIoError {
-                Some(os::error_string(errno).as_slice().chars().map(|c| c.to_lowercase()).collect())
-            } else {
-                None
-            },
+        let mut err = sys::decode_error(errno as i32);
+        if detail && err.kind == OtherIoError {
+            err.detail = Some(os::error_string(errno).as_slice().chars()
+                                 .map(|c| c.to_lowercase()).collect())
         }
+        err
     }
 
     /// Retrieve the last error to occur as a (detailed) IoError.
@@ -409,17 +328,6 @@ impl IoError {
     pub fn last_error() -> IoError {
         IoError::from_errno(os::errno() as uint, true)
     }
-
-    fn from_rtio_error(err: rtio::IoError) -> IoError {
-        let rtio::IoError { code, extra, detail } = err;
-        let mut ioerr = IoError::from_errno(code, false);
-        ioerr.detail = detail;
-        ioerr.kind = match ioerr.kind {
-            TimedOut if extra > 0 => ShortWrite(extra),
-            k => k,
-        };
-        return ioerr;
-    }
 }
 
 impl fmt::Show for IoError {
diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs
index 3c72f58b10d..22775d54eff 100644
--- a/src/libstd/io/net/addrinfo.rs
+++ b/src/libstd/io/net/addrinfo.rs
@@ -20,12 +20,10 @@ getaddrinfo()
 #![allow(missing_docs)]
 
 use iter::Iterator;
-use io::{IoResult, IoError};
+use io::{IoResult};
 use io::net::ip::{SocketAddr, IpAddr};
 use option::{Option, Some, None};
-use result::{Ok, Err};
-use rt::rtio::{IoFactory, LocalIo};
-use rt::rtio;
+use sys;
 use vec::Vec;
 
 /// Hints to the types of sockets that are desired when looking up hosts
@@ -94,31 +92,7 @@ pub fn get_host_addresses(host: &str) -> IoResult<Vec<IpAddr>> {
 #[allow(unused_variables)]
 fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>)
           -> IoResult<Vec<Info>> {
-    let hint = hint.map(|Hint { family, socktype, protocol, flags }| {
-        rtio::AddrinfoHint {
-            family: family,
-            socktype: 0, // FIXME: this should use the above variable
-            protocol: 0, // FIXME: this should use the above variable
-            flags: flags,
-        }
-    });
-    match LocalIo::maybe_raise(|io| {
-        io.get_host_addresses(hostname, servname, hint)
-    }) {
-        Ok(v) => Ok(v.into_iter().map(|info| {
-            Info {
-                address: SocketAddr {
-                    ip: super::from_rtio(info.address.ip),
-                    port: info.address.port,
-                },
-                family: info.family,
-                socktype: None, // FIXME: this should use the above variable
-                protocol: None, // FIXME: this should use the above variable
-                flags: info.flags,
-            }
-        }).collect()),
-        Err(e) => Err(IoError::from_rtio_error(e)),
-    }
+    sys::addrinfo::get_host_addresses(hostname, servname, hint)
 }
 
 // Ignored on android since we cannot give tcp/ip
diff --git a/src/libstd/io/net/mod.rs b/src/libstd/io/net/mod.rs
index b9b50a55a10..5b1747876d7 100644
--- a/src/libstd/io/net/mod.rs
+++ b/src/libstd/io/net/mod.rs
@@ -12,9 +12,8 @@
 
 use io::{IoError, IoResult, InvalidInput};
 use option::None;
-use result::{Result, Ok, Err};
-use rt::rtio;
-use self::ip::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr, ToSocketAddr};
+use result::{Ok, Err};
+use self::ip::{SocketAddr, ToSocketAddr};
 
 pub use self::addrinfo::get_host_addresses;
 
@@ -24,46 +23,6 @@ pub mod udp;
 pub mod ip;
 pub mod pipe;
 
-fn to_rtio(ip: IpAddr) -> rtio::IpAddr {
-    match ip {
-        Ipv4Addr(a, b, c, d) => rtio::Ipv4Addr(a, b, c, d),
-        Ipv6Addr(a, b, c, d, e, f, g, h) => {
-            rtio::Ipv6Addr(a, b, c, d, e, f, g, h)
-        }
-    }
-}
-
-fn from_rtio(ip: rtio::IpAddr) -> IpAddr {
-    match ip {
-        rtio::Ipv4Addr(a, b, c, d) => Ipv4Addr(a, b, c, d),
-        rtio::Ipv6Addr(a, b, c, d, e, f, g, h) => {
-            Ipv6Addr(a, b, c, d, e, f, g, h)
-        }
-    }
-}
-
-fn with_addresses_io<A: ToSocketAddr, T>(
-    addr: A,
-    action: |&mut rtio::IoFactory, rtio::SocketAddr| -> Result<T, rtio::IoError>
-) -> Result<T, IoError> {
-    const DEFAULT_ERROR: IoError = IoError {
-        kind: InvalidInput,
-        desc: "no addresses found for hostname",
-        detail: None
-    };
-
-    let addresses = try!(addr.to_socket_addr_all());
-    let mut err = DEFAULT_ERROR;
-    for addr in addresses.into_iter() {
-        let addr = rtio::SocketAddr { ip: to_rtio(addr.ip), port: addr.port };
-        match rtio::LocalIo::maybe_raise(|io| action(io, addr)) {
-            Ok(r) => return Ok(r),
-            Err(e) => err = IoError::from_rtio_error(e)
-        }
-    }
-    Err(err)
-}
-
 fn with_addresses<A: ToSocketAddr, T>(addr: A, action: |SocketAddr| -> IoResult<T>)
     -> IoResult<T> {
     const DEFAULT_ERROR: IoError = IoError {
diff --git a/src/libstd/io/net/pipe.rs b/src/libstd/io/net/pipe.rs
index 8c7deadebea..111b0f2b081 100644
--- a/src/libstd/io/net/pipe.rs
+++ b/src/libstd/io/net/pipe.rs
@@ -26,17 +26,20 @@ instances as clients.
 
 use prelude::*;
 
-use io::{Listener, Acceptor, IoResult, IoError, TimedOut, standard_error};
-use rt::rtio::{IoFactory, LocalIo, RtioUnixListener};
-use rt::rtio::{RtioUnixAcceptor, RtioPipe};
+use io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
 use time::Duration;
 
+use sys::pipe::UnixStream as UnixStreamImp;
+use sys::pipe::UnixListener as UnixListenerImp;
+use sys::pipe::UnixAcceptor as UnixAcceptorImp;
+
 /// A stream which communicates over a named pipe.
 pub struct UnixStream {
-    obj: Box<RtioPipe + Send>,
+    inner: UnixStreamImp,
 }
 
 impl UnixStream {
+
     /// Connect to a pipe named by `path`. This will attempt to open a
     /// connection to the underlying socket.
     ///
@@ -53,9 +56,8 @@ impl UnixStream {
     /// stream.write([1, 2, 3]);
     /// ```
     pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
-        LocalIo::maybe_raise(|io| {
-            io.unix_connect(&path.to_c_str(), None).map(|p| UnixStream { obj: p })
-        }).map_err(IoError::from_rtio_error)
+        UnixStreamImp::connect(&path.to_c_str(), None)
+            .map(|inner| UnixStream { inner: inner })
     }
 
     /// Connect to a pipe named by `path`, timing out if the specified number of
@@ -73,10 +75,8 @@ impl UnixStream {
             return Err(standard_error(TimedOut));
         }
 
-        LocalIo::maybe_raise(|io| {
-            let s = io.unix_connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64));
-            s.map(|p| UnixStream { obj: p })
-        }).map_err(IoError::from_rtio_error)
+        UnixStreamImp::connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64))
+            .map(|inner| UnixStream { inner: inner })
     }
 
 
@@ -88,7 +88,7 @@ impl UnixStream {
     /// Note that this method affects all cloned handles associated with this
     /// stream, not just this one handle.
     pub fn close_read(&mut self) -> IoResult<()> {
-        self.obj.close_read().map_err(IoError::from_rtio_error)
+        self.inner.close_read()
     }
 
     /// Closes the writing half of this connection.
@@ -99,7 +99,7 @@ impl UnixStream {
     /// Note that this method affects all cloned handles associated with this
     /// stream, not just this one handle.
     pub fn close_write(&mut self) -> IoResult<()> {
-        self.obj.close_write().map_err(IoError::from_rtio_error)
+        self.inner.close_write()
     }
 
     /// Sets the read/write timeout for this socket.
@@ -107,7 +107,7 @@ impl UnixStream {
     /// For more information, see `TcpStream::set_timeout`
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_timeout(timeout_ms)
+        self.inner.set_timeout(timeout_ms)
     }
 
     /// Sets the read timeout for this socket.
@@ -115,7 +115,7 @@ impl UnixStream {
     /// For more information, see `TcpStream::set_timeout`
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_read_timeout(timeout_ms)
+        self.inner.set_read_timeout(timeout_ms)
     }
 
     /// Sets the write timeout for this socket.
@@ -123,36 +123,35 @@ impl UnixStream {
     /// For more information, see `TcpStream::set_timeout`
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_write_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_write_timeout(timeout_ms)
+        self.inner.set_write_timeout(timeout_ms)
     }
 }
 
 impl Clone for UnixStream {
     fn clone(&self) -> UnixStream {
-        UnixStream { obj: self.obj.clone() }
+        UnixStream { inner: self.inner.clone() }
     }
 }
 
 impl Reader for UnixStream {
     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.obj.read(buf).map_err(IoError::from_rtio_error)
+        self.inner.read(buf)
     }
 }
 
 impl Writer for UnixStream {
     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.obj.write(buf).map_err(IoError::from_rtio_error)
+        self.inner.write(buf)
     }
 }
 
 /// A value that can listen for incoming named pipe connection requests.
 pub struct UnixListener {
     /// The internal, opaque runtime Unix listener.
-    obj: Box<RtioUnixListener + Send>,
+    inner: UnixListenerImp,
 }
 
 impl UnixListener {
-
     /// Creates a new listener, ready to receive incoming connections on the
     /// specified socket. The server will be named by `path`.
     ///
@@ -175,24 +174,22 @@ impl UnixListener {
     /// # }
     /// ```
     pub fn bind<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
-        LocalIo::maybe_raise(|io| {
-            io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s })
-        }).map_err(IoError::from_rtio_error)
+        UnixListenerImp::bind(&path.to_c_str())
+            .map(|inner| UnixListener { inner: inner })
     }
 }
 
 impl Listener<UnixStream, UnixAcceptor> for UnixListener {
     fn listen(self) -> IoResult<UnixAcceptor> {
-        self.obj.listen().map(|obj| {
-            UnixAcceptor { obj: obj }
-        }).map_err(IoError::from_rtio_error)
+        self.inner.listen()
+            .map(|inner| UnixAcceptor { inner: inner })
     }
 }
 
 /// A value that can accept named pipe connections, returned from `listen()`.
 pub struct UnixAcceptor {
     /// The internal, opaque runtime Unix acceptor.
-    obj: Box<RtioUnixAcceptor + Send>,
+    inner: UnixAcceptorImp
 }
 
 impl UnixAcceptor {
@@ -210,7 +207,7 @@ impl UnixAcceptor {
     #[experimental = "the name and arguments to this function are likely \
                       to change"]
     pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_timeout(timeout_ms)
+        self.inner.set_timeout(timeout_ms)
     }
 
     /// Closes the accepting capabilities of this acceptor.
@@ -219,15 +216,15 @@ impl UnixAcceptor {
     /// more information can be found in that documentation.
     #[experimental]
     pub fn close_accept(&mut self) -> IoResult<()> {
-        self.obj.close_accept().map_err(IoError::from_rtio_error)
+        self.inner.close_accept()
     }
 }
 
 impl Acceptor<UnixStream> for UnixAcceptor {
     fn accept(&mut self) -> IoResult<UnixStream> {
-        self.obj.accept().map(|s| {
-            UnixStream { obj: s }
-        }).map_err(IoError::from_rtio_error)
+        self.inner.accept().map(|s| {
+            UnixStream { inner: s }
+        })
     }
 }
 
@@ -246,7 +243,7 @@ impl Clone for UnixAcceptor {
     /// This function is useful for creating a handle to invoke `close_accept`
     /// on to wake up any other task blocked in `accept`.
     fn clone(&self) -> UnixAcceptor {
-        UnixAcceptor { obj: self.obj.clone() }
+        UnixAcceptor { inner: self.inner.clone() }
     }
 }
 
diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs
index 928c8586739..2545e07cbb5 100644
--- a/src/libstd/io/net/tcp.rs
+++ b/src/libstd/io/net/tcp.rs
@@ -20,19 +20,17 @@
 use clone::Clone;
 use io::IoResult;
 use iter::Iterator;
-use result::{Ok,Err};
+use result::Err;
 use io::net::ip::{SocketAddr, ToSocketAddr};
-use io::IoError;
 use io::{Reader, Writer, Listener, Acceptor};
 use io::{standard_error, TimedOut};
-use kinds::Send;
 use option::{None, Some, Option};
-use boxed::Box;
-use rt::rtio::{IoFactory, RtioSocket, RtioTcpListener};
-use rt::rtio::{RtioTcpAcceptor, RtioTcpStream};
-use rt::rtio;
 use time::Duration;
 
+use sys::tcp::TcpStream as TcpStreamImp;
+use sys::tcp::TcpListener as TcpListenerImp;
+use sys::tcp::TcpAcceptor as TcpAcceptorImp;
+
 /// A structure which represents a TCP stream between a local socket and a
 /// remote socket.
 ///
@@ -50,12 +48,12 @@ use time::Duration;
 /// drop(stream); // close the connection
 /// ```
 pub struct TcpStream {
-    obj: Box<RtioTcpStream + Send>,
+    inner: TcpStreamImp,
 }
 
 impl TcpStream {
-    fn new(s: Box<RtioTcpStream + Send>) -> TcpStream {
-        TcpStream { obj: s }
+    fn new(s: TcpStreamImp) -> TcpStream {
+        TcpStream { inner: s }
     }
 
     /// Open a TCP connection to a remote host.
@@ -64,7 +62,9 @@ impl TcpStream {
     /// trait can be supplied for the address; see this trait documentation for
     /// concrete examples.
     pub fn connect<A: ToSocketAddr>(addr: A) -> IoResult<TcpStream> {
-        super::with_addresses_io(addr, |io, addr| io.tcp_connect(addr, None).map(TcpStream::new))
+        super::with_addresses(addr, |addr| {
+            TcpStreamImp::connect(addr, None).map(TcpStream::new)
+        })
     }
 
     /// Creates a TCP connection to a remote socket address, timing out after
@@ -86,39 +86,26 @@ impl TcpStream {
             return Err(standard_error(TimedOut));
         }
 
-        super::with_addresses_io(addr, |io, addr|
-            io.tcp_connect(addr, Some(timeout.num_milliseconds() as u64)).map(TcpStream::new)
-        )
+        super::with_addresses(addr, |addr| {
+            TcpStreamImp::connect(addr, Some(timeout.num_milliseconds() as u64))
+                .map(TcpStream::new)
+        })
     }
 
     /// Returns the socket address of the remote peer of this TCP connection.
     pub fn peer_name(&mut self) -> IoResult<SocketAddr> {
-        match self.obj.peer_name() {
-            Ok(rtio::SocketAddr { ip, port }) => {
-                Ok(SocketAddr { ip: super::from_rtio(ip), port: port })
-            }
-            Err(e) => Err(IoError::from_rtio_error(e)),
-        }
+        self.inner.peer_name()
     }
 
     /// Returns the socket address of the local half of this TCP connection.
     pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
-        match self.obj.socket_name() {
-            Ok(rtio::SocketAddr { ip, port }) => {
-                Ok(SocketAddr { ip: super::from_rtio(ip), port: port })
-            }
-            Err(e) => Err(IoError::from_rtio_error(e)),
-        }
+        self.inner.socket_name()
     }
 
     /// Sets the nodelay flag on this connection to the boolean specified
     #[experimental]
     pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> {
-        if nodelay {
-            self.obj.nodelay()
-        } else {
-            self.obj.control_congestion()
-        }.map_err(IoError::from_rtio_error)
+        self.inner.set_nodelay(nodelay)
     }
 
     /// Sets the keepalive timeout to the timeout specified.
@@ -128,10 +115,7 @@ impl TcpStream {
     /// specified time, in seconds.
     #[experimental]
     pub fn set_keepalive(&mut self, delay_in_seconds: Option<uint>) -> IoResult<()> {
-        match delay_in_seconds {
-            Some(i) => self.obj.keepalive(i),
-            None => self.obj.letdie(),
-        }.map_err(IoError::from_rtio_error)
+        self.inner.set_keepalive(delay_in_seconds)
     }
 
     /// Closes the reading half of this connection.
@@ -165,7 +149,7 @@ impl TcpStream {
     /// Note that this method affects all cloned handles associated with this
     /// stream, not just this one handle.
     pub fn close_read(&mut self) -> IoResult<()> {
-        self.obj.close_read().map_err(IoError::from_rtio_error)
+        self.inner.close_read()
     }
 
     /// Closes the writing half of this connection.
@@ -176,7 +160,7 @@ impl TcpStream {
     /// Note that this method affects all cloned handles associated with this
     /// stream, not just this one handle.
     pub fn close_write(&mut self) -> IoResult<()> {
-        self.obj.close_write().map_err(IoError::from_rtio_error)
+        self.inner.close_write()
     }
 
     /// Sets a timeout, in milliseconds, for blocking operations on this stream.
@@ -198,7 +182,7 @@ impl TcpStream {
     /// take a look at `set_read_timeout` and `set_write_timeout`.
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_timeout(timeout_ms)
+        self.inner.set_timeout(timeout_ms)
     }
 
     /// Sets the timeout for read operations on this stream.
@@ -215,7 +199,7 @@ impl TcpStream {
     /// during the timeout period.
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_read_timeout(timeout_ms)
+        self.inner.set_read_timeout(timeout_ms)
     }
 
     /// Sets the timeout for write operations on this stream.
@@ -242,7 +226,7 @@ impl TcpStream {
     /// asynchronous fashion after the call to write returns.
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_write_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_write_timeout(timeout_ms)
+        self.inner.set_write_timeout(timeout_ms)
     }
 }
 
@@ -256,19 +240,19 @@ impl Clone for TcpStream {
     /// Instead, the first read will receive the first packet received, and the
     /// second read will receive the second packet.
     fn clone(&self) -> TcpStream {
-        TcpStream { obj: self.obj.clone() }
+        TcpStream { inner: self.inner.clone() }
     }
 }
 
 impl Reader for TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.obj.read(buf).map_err(IoError::from_rtio_error)
+        self.inner.read(buf)
     }
 }
 
 impl Writer for TcpStream {
     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.obj.write(buf).map_err(IoError::from_rtio_error)
+        self.inner.write(buf)
     }
 }
 
@@ -309,7 +293,7 @@ impl Writer for TcpStream {
 /// # }
 /// ```
 pub struct TcpListener {
-    obj: Box<RtioTcpListener + Send>,
+    inner: TcpListenerImp,
 }
 
 impl TcpListener {
@@ -324,26 +308,20 @@ impl TcpListener {
     /// The address type can be any implementor of `ToSocketAddr` trait. See its
     /// documentation for concrete examples.
     pub fn bind<A: ToSocketAddr>(addr: A) -> IoResult<TcpListener> {
-        super::with_addresses_io(addr, |io, addr| io.tcp_bind(addr).map(|l| TcpListener { obj: l }))
+        super::with_addresses(addr, |addr| {
+            TcpListenerImp::bind(addr).map(|inner| TcpListener { inner: inner })
+        })
     }
 
     /// Returns the local socket address of this listener.
     pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
-        match self.obj.socket_name() {
-            Ok(rtio::SocketAddr { ip, port }) => {
-                Ok(SocketAddr { ip: super::from_rtio(ip), port: port })
-            }
-            Err(e) => Err(IoError::from_rtio_error(e)),
-        }
+        self.inner.socket_name()
     }
 }
 
 impl Listener<TcpStream, TcpAcceptor> for TcpListener {
     fn listen(self) -> IoResult<TcpAcceptor> {
-        match self.obj.listen() {
-            Ok(acceptor) => Ok(TcpAcceptor { obj: acceptor }),
-            Err(e) => Err(IoError::from_rtio_error(e)),
-        }
+        self.inner.listen(128).map(|a| TcpAcceptor { inner: a })
     }
 }
 
@@ -351,7 +329,7 @@ impl Listener<TcpStream, TcpAcceptor> for TcpListener {
 /// a `TcpListener`'s `listen` method, and this object can be used to accept new
 /// `TcpStream` instances.
 pub struct TcpAcceptor {
-    obj: Box<RtioTcpAcceptor + Send>,
+    inner: TcpAcceptorImp,
 }
 
 impl TcpAcceptor {
@@ -399,7 +377,7 @@ impl TcpAcceptor {
     /// ```
     #[experimental = "the type of the argument and name of this function are \
                       subject to change"]
-    pub fn set_timeout(&mut self, ms: Option<u64>) { self.obj.set_timeout(ms); }
+    pub fn set_timeout(&mut self, ms: Option<u64>) { self.inner.set_timeout(ms); }
 
     /// Closes the accepting capabilities of this acceptor.
     ///
@@ -445,16 +423,13 @@ impl TcpAcceptor {
     /// ```
     #[experimental]
     pub fn close_accept(&mut self) -> IoResult<()> {
-        self.obj.close_accept().map_err(IoError::from_rtio_error)
+        self.inner.close_accept()
     }
 }
 
 impl Acceptor<TcpStream> for TcpAcceptor {
     fn accept(&mut self) -> IoResult<TcpStream> {
-        match self.obj.accept(){
-            Ok(s) => Ok(TcpStream::new(s)),
-            Err(e) => Err(IoError::from_rtio_error(e)),
-        }
+        self.inner.accept().map(TcpStream::new)
     }
 }
 
@@ -473,7 +448,7 @@ impl Clone for TcpAcceptor {
     /// This function is useful for creating a handle to invoke `close_accept`
     /// on to wake up any other task blocked in `accept`.
     fn clone(&self) -> TcpAcceptor {
-        TcpAcceptor { obj: self.obj.clone() }
+        TcpAcceptor { inner: self.inner.clone() }
     }
 }
 
@@ -1112,8 +1087,6 @@ mod test {
 
     #[test]
     fn shutdown_smoke() {
-        use rt::rtio::RtioTcpStream;
-
         let addr = next_test_ip4();
         let a = TcpListener::bind(addr).unwrap().listen();
         spawn(proc() {
@@ -1124,7 +1097,7 @@ mod test {
         });
 
         let mut s = TcpStream::connect(addr).unwrap();
-        assert!(s.obj.close_write().is_ok());
+        assert!(s.inner.close_write().is_ok());
         assert!(s.write([1]).is_err());
         assert_eq!(s.read_to_end(), Ok(vec!(1)));
     }
diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs
index 4ae054beadb..31b61989647 100644
--- a/src/libstd/io/net/udp.rs
+++ b/src/libstd/io/net/udp.rs
@@ -17,13 +17,10 @@
 
 use clone::Clone;
 use io::net::ip::{SocketAddr, IpAddr, ToSocketAddr};
-use io::{Reader, Writer, IoResult, IoError};
-use kinds::Send;
-use boxed::Box;
+use io::{Reader, Writer, IoResult};
 use option::Option;
 use result::{Ok, Err};
-use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory};
-use rt::rtio;
+use sys::udp::UdpSocket as UdpSocketImp;
 
 /// A User Datagram Protocol socket.
 ///
@@ -60,7 +57,7 @@ use rt::rtio;
 /// }
 /// ```
 pub struct UdpSocket {
-    obj: Box<RtioUdpSocket + Send>,
+    inner: UdpSocketImp,
 }
 
 impl UdpSocket {
@@ -69,18 +66,15 @@ impl UdpSocket {
     /// Address type can be any implementor of `ToSocketAddr` trait. See its
     /// documentation for concrete examples.
     pub fn bind<A: ToSocketAddr>(addr: A) -> IoResult<UdpSocket> {
-        super::with_addresses_io(addr, |io, addr| io.udp_bind(addr).map(|s| UdpSocket { obj: s }))
+        super::with_addresses(addr, |addr| {
+            UdpSocketImp::bind(addr).map(|s| UdpSocket { inner: s })
+        })
     }
 
     /// Receives data from the socket. On success, returns the number of bytes
     /// read and the address from whence the data came.
     pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> {
-        match self.obj.recv_from(buf) {
-            Ok((amt, rtio::SocketAddr { ip, port })) => {
-                Ok((amt, SocketAddr { ip: super::from_rtio(ip), port: port }))
-            }
-            Err(e) => Err(IoError::from_rtio_error(e)),
-        }
+        self.inner.recv_from(buf)
     }
 
     /// Sends data on the socket to the given address. Returns nothing on
@@ -89,10 +83,7 @@ impl UdpSocket {
     /// Address type can be any implementor of `ToSocketAddr` trait. See its
     /// documentation for concrete examples.
     pub fn send_to<A: ToSocketAddr>(&mut self, buf: &[u8], addr: A) -> IoResult<()> {
-        super::with_addresses(addr, |addr| self.obj.send_to(buf, rtio::SocketAddr {
-            ip: super::to_rtio(addr.ip),
-            port: addr.port,
-        }).map_err(IoError::from_rtio_error))
+        super::with_addresses(addr, |addr| self.inner.send_to(buf, addr))
     }
 
     /// Creates a `UdpStream`, which allows use of the `Reader` and `Writer`
@@ -112,24 +103,19 @@ impl UdpSocket {
 
     /// Returns the socket address that this socket was created from.
     pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
-        match self.obj.socket_name() {
-            Ok(a) => Ok(SocketAddr { ip: super::from_rtio(a.ip), port: a.port }),
-            Err(e) => Err(IoError::from_rtio_error(e))
-        }
+        self.inner.socket_name()
     }
 
     /// Joins a multicast IP address (becomes a member of it)
     #[experimental]
     pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
-        let e = self.obj.join_multicast(super::to_rtio(multi));
-        e.map_err(IoError::from_rtio_error)
+        self.inner.join_multicast(multi)
     }
 
     /// Leaves a multicast IP address (drops membership from it)
     #[experimental]
     pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
-        let e = self.obj.leave_multicast(super::to_rtio(multi));
-        e.map_err(IoError::from_rtio_error)
+        self.inner.leave_multicast(multi)
     }
 
     /// Set the multicast loop flag to the specified value
@@ -137,33 +123,25 @@ impl UdpSocket {
     /// This lets multicast packets loop back to local sockets (if enabled)
     #[experimental]
     pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> {
-        if on {
-            self.obj.loop_multicast_locally()
-        } else {
-            self.obj.dont_loop_multicast_locally()
-        }.map_err(IoError::from_rtio_error)
+        self.inner.set_multicast_loop(on)
     }
 
     /// Sets the multicast TTL
     #[experimental]
     pub fn set_multicast_ttl(&mut self, ttl: int) -> IoResult<()> {
-        self.obj.multicast_time_to_live(ttl).map_err(IoError::from_rtio_error)
+        self.inner.multicast_time_to_live(ttl)
     }
 
     /// Sets this socket's TTL
     #[experimental]
     pub fn set_ttl(&mut self, ttl: int) -> IoResult<()> {
-        self.obj.time_to_live(ttl).map_err(IoError::from_rtio_error)
+        self.inner.time_to_live(ttl)
     }
 
     /// Sets the broadcast flag on or off
     #[experimental]
     pub fn set_broadcast(&mut self, broadcast: bool) -> IoResult<()> {
-        if broadcast {
-            self.obj.hear_broadcasts()
-        } else {
-            self.obj.ignore_broadcasts()
-        }.map_err(IoError::from_rtio_error)
+        self.inner.set_broadcast(broadcast)
     }
 
     /// Sets the read/write timeout for this socket.
@@ -171,7 +149,7 @@ impl UdpSocket {
     /// For more information, see `TcpStream::set_timeout`
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_timeout(timeout_ms)
+        self.inner.set_timeout(timeout_ms)
     }
 
     /// Sets the read timeout for this socket.
@@ -179,7 +157,7 @@ impl UdpSocket {
     /// For more information, see `TcpStream::set_timeout`
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_read_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_read_timeout(timeout_ms)
+        self.inner.set_read_timeout(timeout_ms)
     }
 
     /// Sets the write timeout for this socket.
@@ -187,7 +165,7 @@ impl UdpSocket {
     /// For more information, see `TcpStream::set_timeout`
     #[experimental = "the timeout argument may change in type and value"]
     pub fn set_write_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.obj.set_write_timeout(timeout_ms)
+        self.inner.set_write_timeout(timeout_ms)
     }
 }
 
@@ -201,7 +179,7 @@ impl Clone for UdpSocket {
     /// received, and the second read will receive the second packet.
     fn clone(&self) -> UdpSocket {
         UdpSocket {
-            obj: self.obj.clone(),
+            inner: self.inner.clone(),
         }
     }
 }
diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs
index c77cffd561e..64b2518fab1 100644
--- a/src/libstd/io/pipe.rs
+++ b/src/libstd/io/pipe.rs
@@ -17,15 +17,17 @@
 
 use prelude::*;
 
-use io::{IoResult, IoError};
+use io::IoResult;
 use libc;
-use os;
-use rt::rtio::{RtioPipe, LocalIo};
+use sync::Arc;
+
+use sys_common;
+use sys;
+use sys::fs::FileDesc as FileDesc;
 
 /// A synchronous, in-memory pipe.
 pub struct PipeStream {
-    /// The internal, opaque runtime pipe object.
-    obj: Box<RtioPipe + Send>,
+    inner: Arc<FileDesc>
 }
 
 pub struct PipePair {
@@ -55,14 +57,14 @@ impl PipeStream {
     /// }
     /// ```
     pub fn open(fd: libc::c_int) -> IoResult<PipeStream> {
-        LocalIo::maybe_raise(|io| {
-            io.pipe_open(fd).map(|obj| PipeStream { obj: obj })
-        }).map_err(IoError::from_rtio_error)
+        Ok(PipeStream::from_filedesc(FileDesc::new(fd, true)))
     }
 
+    // FIXME: expose this some other way
+    /// Wrap a FileDesc directly, taking ownership.
     #[doc(hidden)]
-    pub fn new(inner: Box<RtioPipe + Send>) -> PipeStream {
-        PipeStream { obj: inner }
+    pub fn from_filedesc(fd: FileDesc) -> PipeStream {
+        PipeStream { inner: Arc::new(fd) }
     }
 
     /// Creates a pair of in-memory OS pipes for a unidirectional communication
@@ -76,43 +78,35 @@ impl PipeStream {
     /// This function can fail to succeed if the underlying OS has run out of
     /// available resources to allocate a new pipe.
     pub fn pair() -> IoResult<PipePair> {
-        struct Closer { fd: libc::c_int }
-
-        let os::Pipe { reader, writer } = try!(unsafe { os::pipe() });
-        let mut reader = Closer { fd: reader };
-        let mut writer = Closer { fd: writer };
-
-        let io_reader = try!(PipeStream::open(reader.fd));
-        reader.fd = -1;
-        let io_writer = try!(PipeStream::open(writer.fd));
-        writer.fd = -1;
-        return Ok(PipePair { reader: io_reader, writer: io_writer });
-
-        impl Drop for Closer {
-            fn drop(&mut self) {
-                if self.fd != -1 {
-                    let _ = unsafe { libc::close(self.fd) };
-                }
-            }
-        }
+        let (reader, writer) = try!(unsafe { sys::os::pipe() });
+        Ok(PipePair {
+            reader: PipeStream::from_filedesc(reader),
+            writer: PipeStream::from_filedesc(writer),
+        })
+    }
+}
+
+impl sys_common::AsFileDesc for PipeStream {
+    fn as_fd(&self) -> &sys::fs::FileDesc {
+        &*self.inner
     }
 }
 
 impl Clone for PipeStream {
     fn clone(&self) -> PipeStream {
-        PipeStream { obj: self.obj.clone() }
+        PipeStream { inner: self.inner.clone() }
     }
 }
 
 impl Reader for PipeStream {
     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.obj.read(buf).map_err(IoError::from_rtio_error)
+        self.inner.read(buf)
     }
 }
 
 impl Writer for PipeStream {
     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.obj.write(buf).map_err(IoError::from_rtio_error)
+        self.inner.write(buf)
     }
 }
 
diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs
index 698e0a3460f..d71bab0b48f 100644
--- a/src/libstd/io/process.rs
+++ b/src/libstd/io/process.rs
@@ -20,14 +20,17 @@ use os;
 use io::{IoResult, IoError};
 use io;
 use libc;
-use mem;
-use rt::rtio::{RtioProcess, ProcessConfig, IoFactory, LocalIo};
-use rt::rtio;
 use c_str::CString;
 use collections::HashMap;
 use hash::Hash;
 #[cfg(windows)]
 use std::hash::sip::SipState;
+use io::pipe::{PipeStream, PipePair};
+use path::BytesContainer;
+
+use sys;
+use sys::fs::FileDesc;
+use sys::process::Process as ProcessImp;
 
 /// Signal a process to exit, without forcibly killing it. Corresponds to
 /// SIGTERM on unix platforms.
@@ -62,24 +65,29 @@ use std::hash::sip::SipState;
 /// assert!(child.wait().unwrap().success());
 /// ```
 pub struct Process {
-    handle: Box<RtioProcess + Send>,
+    handle: ProcessImp,
     forget: bool,
 
+    /// None until wait() is called.
+    exit_code: Option<ProcessExit>,
+
+    /// Manually delivered signal
+    exit_signal: Option<int>,
+
+    /// Deadline after which wait() will return
+    deadline: u64,
+
     /// Handle to the child's stdin, if the `stdin` field of this process's
     /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
-    pub stdin: Option<io::PipeStream>,
+    pub stdin: Option<PipeStream>,
 
     /// Handle to the child's stdout, if the `stdout` field of this process's
     /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
-    pub stdout: Option<io::PipeStream>,
+    pub stdout: Option<PipeStream>,
 
     /// Handle to the child's stderr, if the `stderr` field of this process's
     /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`.
-    pub stderr: Option<io::PipeStream>,
-
-    /// Extra I/O handles as configured by the original `ProcessConfig` when
-    /// this process was created. This is by default empty.
-    pub extra_io: Vec<Option<io::PipeStream>>,
+    pub stderr: Option<PipeStream>,
 }
 
 /// A representation of environment variable name
@@ -130,6 +138,13 @@ impl PartialEq for EnvKey {
     }
 }
 
+impl BytesContainer for EnvKey {
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        let &EnvKey(ref k) = self;
+        k.container_as_bytes()
+    }
+}
+
 /// A HashMap representation of environment variables.
 pub type EnvMap = HashMap<EnvKey, CString>;
 
@@ -160,7 +175,6 @@ pub struct Command {
     stdin: StdioContainer,
     stdout: StdioContainer,
     stderr: StdioContainer,
-    extra_io: Vec<StdioContainer>,
     uid: Option<uint>,
     gid: Option<uint>,
     detach: bool,
@@ -194,7 +208,6 @@ impl Command {
             stdin: CreatePipe(true, false),
             stdout: CreatePipe(false, true),
             stderr: CreatePipe(false, true),
-            extra_io: Vec::new(),
             uid: None,
             gid: None,
             detach: false,
@@ -281,14 +294,6 @@ impl Command {
         self.stderr = cfg;
         self
     }
-    /// Attaches a stream/file descriptor/pipe to the child process. Inherited
-    /// file descriptors are numbered consecutively, starting at 3; the first
-    /// three file descriptors (stdin/stdout/stderr) are configured with the
-    /// `stdin`, `stdout`, and `stderr` methods.
-    pub fn extra_io<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
-        self.extra_io.push(cfg);
-        self
-    }
 
     /// Sets the child process's user id. This translates to a `setuid` call in
     /// the child process. Setting this value on windows will cause the spawn to
@@ -315,50 +320,23 @@ impl Command {
 
     /// Executes the command as a child process, which is returned.
     pub fn spawn(&self) -> IoResult<Process> {
-        fn to_rtio(p: StdioContainer) -> rtio::StdioContainer {
-            match p {
-                Ignored => rtio::Ignored,
-                InheritFd(fd) => rtio::InheritFd(fd),
-                CreatePipe(a, b) => rtio::CreatePipe(a, b),
-            }
-        }
-        let extra_io: Vec<rtio::StdioContainer> =
-            self.extra_io.iter().map(|x| to_rtio(*x)).collect();
-        LocalIo::maybe_raise(|io| {
-            let env = match self.env {
-                None => None,
-                Some(ref env_map) =>
-                    Some(env_map.iter()
-                                .map(|(&EnvKey(ref key), val)| (key, val))
-                                .collect::<Vec<_>>())
-            };
-            let cfg = ProcessConfig {
-                program: &self.program,
-                args: self.args.as_slice(),
-                env: env.as_ref().map(|e| e.as_slice()),
-                cwd: self.cwd.as_ref(),
-                stdin: to_rtio(self.stdin),
-                stdout: to_rtio(self.stdout),
-                stderr: to_rtio(self.stderr),
-                extra_io: extra_io.as_slice(),
-                uid: self.uid,
-                gid: self.gid,
-                detach: self.detach,
-            };
-            io.spawn(cfg).map(|(p, io)| {
-                let mut io = io.into_iter().map(|p| {
-                    p.map(|p| io::PipeStream::new(p))
-                });
-                Process {
-                    handle: p,
-                    forget: false,
-                    stdin: io.next().unwrap(),
-                    stdout: io.next().unwrap(),
-                    stderr: io.next().unwrap(),
-                    extra_io: io.collect(),
-                }
+        let (their_stdin, our_stdin) = try!(setup_io(self.stdin));
+        let (their_stdout, our_stdout) = try!(setup_io(self.stdout));
+        let (their_stderr, our_stderr) = try!(setup_io(self.stderr));
+
+        match ProcessImp::spawn(self, their_stdin, their_stdout, their_stderr) {
+            Err(e) => Err(e),
+            Ok(handle) => Ok(Process {
+                handle: handle,
+                forget: false,
+                exit_code: None,
+                exit_signal: None,
+                deadline: 0,
+                stdin: our_stdin,
+                stdout: our_stdout,
+                stderr: our_stderr,
             })
-        }).map_err(IoError::from_rtio_error)
+        }
     }
 
     /// Executes the command as a child process, waiting for it to finish and
@@ -415,6 +393,58 @@ impl fmt::Show for Command {
     }
 }
 
+fn setup_io(io: StdioContainer) -> IoResult<(Option<PipeStream>, Option<PipeStream>)> {
+    let ours;
+    let theirs;
+    match io {
+        Ignored => {
+            theirs = None;
+            ours = None;
+        }
+        InheritFd(fd) => {
+            theirs = Some(PipeStream::from_filedesc(FileDesc::new(fd, false)));
+            ours = None;
+        }
+        CreatePipe(readable, _writable) => {
+            let PipePair { reader, writer } = try!(PipeStream::pair());
+            if readable {
+                theirs = Some(reader);
+                ours = Some(writer);
+            } else {
+                theirs = Some(writer);
+                ours = Some(reader);
+            }
+        }
+    }
+    Ok((theirs, ours))
+}
+
+// Allow the sys module to get access to the Command state
+impl sys::process::ProcessConfig<EnvKey, CString> for Command {
+    fn program(&self) -> &CString {
+        &self.program
+    }
+    fn args(&self) -> &[CString] {
+        self.args.as_slice()
+    }
+    fn env(&self) -> Option<&EnvMap> {
+        self.env.as_ref()
+    }
+    fn cwd(&self) -> Option<&CString> {
+        self.cwd.as_ref()
+    }
+    fn uid(&self) -> Option<uint> {
+        self.uid.clone()
+    }
+    fn gid(&self) -> Option<uint> {
+        self.gid.clone()
+    }
+    fn detach(&self) -> bool {
+        self.detach
+    }
+
+}
+
 /// The output of a finished process.
 #[deriving(PartialEq, Eq, Clone)]
 pub struct ProcessOutput {
@@ -494,9 +524,7 @@ impl Process {
     /// be successfully delivered if the child has exited, but not yet been
     /// reaped.
     pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> {
-        LocalIo::maybe_raise(|io| {
-            io.kill(id, signal)
-        }).map_err(IoError::from_rtio_error)
+        unsafe { ProcessImp::killpid(id, signal) }
     }
 
     /// Returns the process id of this child process
@@ -518,7 +546,42 @@ impl Process {
     ///
     /// If the signal delivery fails, the corresponding error is returned.
     pub fn signal(&mut self, signal: int) -> IoResult<()> {
-        self.handle.kill(signal).map_err(IoError::from_rtio_error)
+        #[cfg(unix)] fn collect_status(p: &mut Process) {
+            // On Linux (and possibly other unices), a process that has exited will
+            // continue to accept signals because it is "defunct". The delivery of
+            // signals will only fail once the child has been reaped. For this
+            // reason, if the process hasn't exited yet, then we attempt to collect
+            // their status with WNOHANG.
+            if p.exit_code.is_none() {
+                match p.handle.try_wait() {
+                    Some(code) => { p.exit_code = Some(code); }
+                    None => {}
+                }
+            }
+        }
+        #[cfg(windows)] fn collect_status(_p: &mut Process) {}
+
+        collect_status(self);
+
+        // if the process has finished, and therefore had waitpid called,
+        // and we kill it, then on unix we might ending up killing a
+        // newer process that happens to have the same (re-used) id
+        if self.exit_code.is_some() {
+            return Err(IoError {
+                kind: io::InvalidInput,
+                desc: "invalid argument: can't kill an exited process",
+                detail: None,
+            })
+        }
+
+        // A successfully delivered signal that isn't 0 (just a poll for being
+        // alive) is recorded for windows (see wait())
+        match unsafe { self.handle.kill(signal) } {
+            Ok(()) if signal == 0 => Ok(()),
+            Ok(()) => { self.exit_signal = Some(signal); Ok(()) }
+            Err(e) => Err(e),
+        }
+
     }
 
     /// Sends a signal to this child requesting that it exits. This is
@@ -545,10 +608,21 @@ impl Process {
     /// `set_timeout` and the timeout expires before the child exits.
     pub fn wait(&mut self) -> IoResult<ProcessExit> {
         drop(self.stdin.take());
-        match self.handle.wait() {
-            Ok(rtio::ExitSignal(s)) => Ok(ExitSignal(s)),
-            Ok(rtio::ExitStatus(s)) => Ok(ExitStatus(s)),
-            Err(e) => Err(IoError::from_rtio_error(e)),
+        match self.exit_code {
+            Some(code) => Ok(code),
+            None => {
+                let code = try!(self.handle.wait(self.deadline));
+                // On windows, waitpid will never return a signal. If a signal
+                // was successfully delivered to the process, however, we can
+                // consider it as having died via a signal.
+                let code = match self.exit_signal {
+                    None => code,
+                    Some(signal) if cfg!(windows) => ExitSignal(signal),
+                    Some(..) => code,
+                };
+                self.exit_code = Some(code);
+                Ok(code)
+            }
         }
     }
 
@@ -594,7 +668,7 @@ impl Process {
     /// ```
     #[experimental = "the type of the timeout is likely to change"]
     pub fn set_timeout(&mut self, timeout_ms: Option<u64>) {
-        self.handle.set_timeout(timeout_ms)
+        self.deadline = timeout_ms.map(|i| i + sys::timer::now()).unwrap_or(0);
     }
 
     /// Simultaneously wait for the child to exit and collect all remaining
@@ -653,7 +727,6 @@ impl Drop for Process {
         drop(self.stdin.take());
         drop(self.stdout.take());
         drop(self.stderr.take());
-        drop(mem::replace(&mut self.extra_io, Vec::new()));
 
         self.set_timeout(None);
         let _ = self.wait().unwrap();
@@ -1109,8 +1182,7 @@ mod tests {
 
     #[test]
     fn dont_close_fd_on_command_spawn() {
-        use std::rt::rtio::{Truncate, Write};
-        use self::native::io::file;
+        use sys::fs;
 
         let path = if cfg!(windows) {
             Path::new("NUL")
@@ -1118,7 +1190,7 @@ mod tests {
             Path::new("/dev/null")
         };
 
-        let mut fdes = match file::open(&path.to_c_str(), Truncate, Write) {
+        let mut fdes = match fs::open(&path, Truncate, Write) {
             Ok(f) => f,
             Err(_) => panic!("failed to open file descriptor"),
         };
@@ -1126,7 +1198,7 @@ mod tests {
         let mut cmd = pwd_cmd();
         let _ = cmd.stdout(InheritFd(fdes.fd()));
         assert!(cmd.status().unwrap().success());
-        assert!(fdes.inner_write("extra write\n".as_bytes()).is_ok());
+        assert!(fdes.write("extra write\n".as_bytes()).is_ok());
     }
 
     #[test]
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index 7bae67c0aa6..158d596ea13 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -36,11 +36,11 @@ use kinds::Send;
 use libc;
 use option::{Option, Some, None};
 use boxed::Box;
+use sys::{fs, tty};
 use result::{Ok, Err};
 use rt;
 use rt::local::Local;
 use rt::task::Task;
-use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
 use slice::SlicePrelude;
 use str::StrPrelude;
 use uint;
@@ -74,17 +74,15 @@ use uint;
 // 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(Box<RtioTTY + Send>),
-    File(Box<RtioFileStream + Send>),
+    TTY(tty::TTY),
+    File(fs::FileDesc),
 }
 
-fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
-    LocalIo::maybe_raise(|io| {
-        Ok(match io.tty_open(fd, readable) {
-            Ok(tty) => f(TTY(tty)),
-            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
-        })
-    }).map_err(IoError::from_rtio_error).unwrap()
+fn src<T>(fd: libc::c_int, _readable: bool, f: |StdSource| -> T) -> T {
+    match tty::TTY::new(fd) {
+        Ok(tty) => f(TTY(tty)),
+        Err(_) => f(File(fs::FileDesc::new(fd, false))),
+    }
 }
 
 local_data_key!(local_stdout: Box<Writer + Send>)
@@ -278,10 +276,10 @@ impl Reader for StdReader {
                 // print!'d prompt not being shown until after the user hits
                 // enter.
                 flush();
-                tty.read(buf)
+                tty.read(buf).map(|i| i as uint)
             },
             File(ref mut file) => file.read(buf).map(|i| i as uint),
-        }.map_err(IoError::from_rtio_error);
+        };
         match ret {
             // When reading a piped stdin, libuv will return 0-length reads when
             // stdin reaches EOF. For pretty much all other streams it will
@@ -313,7 +311,7 @@ impl StdWriter {
     pub fn winsize(&mut self) -> IoResult<(int, int)> {
         match self.inner {
             TTY(ref mut tty) => {
-                tty.get_winsize().map_err(IoError::from_rtio_error)
+                tty.get_winsize()
             }
             File(..) => {
                 Err(IoError {
@@ -335,7 +333,7 @@ impl StdWriter {
     pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
         match self.inner {
             TTY(ref mut tty) => {
-                tty.set_raw(raw).map_err(IoError::from_rtio_error)
+                tty.set_raw(raw)
             }
             File(..) => {
                 Err(IoError {
@@ -374,7 +372,7 @@ impl Writer for StdWriter {
             try!(match self.inner {
                 TTY(ref mut tty) => tty.write(chunk),
                 File(ref mut file) => file.write(chunk),
-            }.map_err(IoError::from_rtio_error))
+            })
         }
         Ok(())
     }
diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs
index d16199da77f..ec588f13478 100644
--- a/src/libstd/io/timer.rs
+++ b/src/libstd/io/timer.rs
@@ -21,10 +21,9 @@ and create receivers which will receive notifications after a period of time.
 
 use comm::{Receiver, Sender, channel};
 use time::Duration;
-use io::{IoResult, IoError};
-use kinds::Send;
-use boxed::Box;
-use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};
+use io::IoResult;
+use sys::timer::Callback;
+use sys::timer::Timer as TimerImp;
 
 /// A synchronous timer object
 ///
@@ -69,7 +68,7 @@ use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};
 /// # }
 /// ```
 pub struct Timer {
-    obj: Box<RtioTimer + Send>,
+    inner: TimerImp,
 }
 
 struct TimerCallback { tx: Sender<()> }
@@ -90,9 +89,7 @@ impl Timer {
     /// for a number of milliseconds, or to possibly create channels which will
     /// get notified after an amount of time has passed.
     pub fn new() -> IoResult<Timer> {
-        LocalIo::maybe_raise(|io| {
-            io.timer_init().map(|t| Timer { obj: t })
-        }).map_err(IoError::from_rtio_error)
+        TimerImp::new().map(|t| Timer { inner: t })
     }
 
     /// Blocks the current task for the specified duration.
@@ -106,7 +103,7 @@ impl Timer {
         // Short-circuit the timer backend for 0 duration
         let ms = in_ms_u64(duration);
         if ms == 0 { return }
-        self.obj.sleep(ms);
+        self.inner.sleep(ms);
     }
 
     /// Creates a oneshot receiver which will have a notification sent when
@@ -152,7 +149,7 @@ impl Timer {
         let (tx, rx) = channel();
         // Short-circuit the timer backend for 0 duration
         if in_ms_u64(duration) != 0 {
-            self.obj.oneshot(in_ms_u64(duration), box TimerCallback { tx: tx });
+            self.inner.oneshot(in_ms_u64(duration), box TimerCallback { tx: tx });
         } else {
             tx.send(());
         }
@@ -213,7 +210,7 @@ impl Timer {
         // not clear what use a 0ms period is anyway...
         let ms = if ms == 0 { 1 } else { ms };
         let (tx, rx) = channel();
-        self.obj.period(ms, box TimerCallback { tx: tx });
+        self.inner.period(ms, box TimerCallback { tx: tx });
         return rx
     }
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index f10a1d5e5ed..7eac455f97f 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -242,6 +242,13 @@ pub mod io;
 pub mod path;
 pub mod fmt;
 
+#[cfg(unix)]
+#[path = "sys/unix/mod.rs"] mod sys;
+#[cfg(windows)]
+#[path = "sys/windows/mod.rs"] mod sys;
+
+#[path = "sys/common/mod.rs"] mod sys_common;
+
 // FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
 // but name resolution doesn't work without it being pub.
 pub mod rt;
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 0042a3ae205..ea42117bab6 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -34,7 +34,7 @@
 use clone::Clone;
 use error::{FromError, Error};
 use fmt;
-use io::{IoResult, IoError};
+use io::IoResult;
 use iter::Iterator;
 use libc::{c_void, c_int};
 use libc;
@@ -43,6 +43,8 @@ use ops::Drop;
 use option::{Some, None, Option};
 use os;
 use path::{Path, GenericPath, BytesContainer};
+use sys;
+use sys::os as os_imp;
 use ptr::RawPtr;
 use ptr;
 use result::{Err, Ok, Result};
@@ -602,35 +604,11 @@ pub struct Pipe {
 /// descriptors to be closed, the file descriptors will leak. For safe handling
 /// of this scenario, use `std::io::PipeStream` instead.
 pub unsafe fn pipe() -> IoResult<Pipe> {
-    return _pipe();
-
-    #[cfg(unix)]
-    unsafe fn _pipe() -> IoResult<Pipe> {
-        let mut fds = [0, ..2];
-        match libc::pipe(fds.as_mut_ptr()) {
-            0 => Ok(Pipe { reader: fds[0], writer: fds[1] }),
-            _ => Err(IoError::last_error()),
-        }
-    }
-
-    #[cfg(windows)]
-    unsafe fn _pipe() -> IoResult<Pipe> {
-        // Windows pipes work subtly differently than unix pipes, and their
-        // inheritance has to be handled in a different way that I do not
-        // fully understand. Here we explicitly make the pipe non-inheritable,
-        // which means to pass it to a subprocess they need to be duplicated
-        // first, as in std::run.
-        let mut fds = [0, ..2];
-        match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
-                         (libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
-            0 => {
-                assert!(fds[0] != -1 && fds[0] != 0);
-                assert!(fds[1] != -1 && fds[1] != 0);
-                Ok(Pipe { reader: fds[0], writer: fds[1] })
-            }
-            _ => Err(IoError::last_error()),
-        }
-    }
+    let (reader, writer) = try!(sys::os::pipe());
+    Ok(Pipe {
+        reader: reader.unwrap(),
+        writer: writer.unwrap(),
+    })
 }
 
 /// Returns the proper dll filename for the given basename of a file
@@ -905,59 +883,9 @@ pub fn change_dir(p: &Path) -> bool {
     }
 }
 
-#[cfg(unix)]
-/// Returns the platform-specific value of errno
-pub fn errno() -> int {
-    #[cfg(any(target_os = "macos",
-              target_os = "ios",
-              target_os = "freebsd"))]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __error() -> *const c_int;
-        }
-        unsafe {
-            __error()
-        }
-    }
-
-    #[cfg(target_os = "dragonfly")]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __dfly_error() -> *const c_int;
-        }
-        unsafe {
-            __dfly_error()
-        }
-    }
-
-    #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn errno_location() -> *const c_int {
-        extern {
-            fn __errno_location() -> *const c_int;
-        }
-        unsafe {
-            __errno_location()
-        }
-    }
-
-    unsafe {
-        (*errno_location()) as int
-    }
-}
-
-#[cfg(windows)]
 /// Returns the platform-specific value of errno
 pub fn errno() -> uint {
-    use libc::types::os::arch::extra::DWORD;
-
-    #[link_name = "kernel32"]
-    extern "system" {
-        fn GetLastError() -> DWORD;
-    }
-
-    unsafe {
-        GetLastError() as uint
-    }
+    os_imp::errno() as uint
 }
 
 /// Return the string corresponding to an `errno()` value of `errnum`.
@@ -969,105 +897,7 @@ pub fn errno() -> uint {
 /// println!("{}", os::error_string(os::errno() as uint));
 /// ```
 pub fn error_string(errnum: uint) -> String {
-    return strerror(errnum);
-
-    #[cfg(unix)]
-    fn strerror(errnum: uint) -> String {
-        #[cfg(any(target_os = "macos",
-                  target_os = "ios",
-                  target_os = "android",
-                  target_os = "freebsd",
-                  target_os = "dragonfly"))]
-        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
-                      -> c_int {
-            extern {
-                fn strerror_r(errnum: c_int, buf: *mut c_char,
-                              buflen: libc::size_t) -> c_int;
-            }
-            unsafe {
-                strerror_r(errnum, buf, buflen)
-            }
-        }
-
-        // GNU libc provides a non-compliant version of strerror_r by default
-        // and requires macros to instead use the POSIX compliant variant.
-        // So we just use __xpg_strerror_r which is always POSIX compliant
-        #[cfg(target_os = "linux")]
-        fn strerror_r(errnum: c_int, buf: *mut c_char,
-                      buflen: libc::size_t) -> c_int {
-            extern {
-                fn __xpg_strerror_r(errnum: c_int,
-                                    buf: *mut c_char,
-                                    buflen: libc::size_t)
-                                    -> c_int;
-            }
-            unsafe {
-                __xpg_strerror_r(errnum, buf, buflen)
-            }
-        }
-
-        let mut buf = [0 as c_char, ..TMPBUF_SZ];
-
-        let p = buf.as_mut_ptr();
-        unsafe {
-            if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
-                panic!("strerror_r failure");
-            }
-
-            ::string::raw::from_buf(p as *const u8)
-        }
-    }
-
-    #[cfg(windows)]
-    fn strerror(errnum: uint) -> String {
-        use libc::types::os::arch::extra::DWORD;
-        use libc::types::os::arch::extra::LPWSTR;
-        use libc::types::os::arch::extra::LPVOID;
-        use libc::types::os::arch::extra::WCHAR;
-
-        #[link_name = "kernel32"]
-        extern "system" {
-            fn FormatMessageW(flags: DWORD,
-                              lpSrc: LPVOID,
-                              msgId: DWORD,
-                              langId: DWORD,
-                              buf: LPWSTR,
-                              nsize: DWORD,
-                              args: *const c_void)
-                              -> DWORD;
-        }
-
-        static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
-        static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
-
-        // This value is calculated from the macro
-        // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
-        let langId = 0x0800 as DWORD;
-
-        let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
-
-        unsafe {
-            let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
-                                     FORMAT_MESSAGE_IGNORE_INSERTS,
-                                     ptr::null_mut(),
-                                     errnum as DWORD,
-                                     langId,
-                                     buf.as_mut_ptr(),
-                                     buf.len() as DWORD,
-                                     ptr::null());
-            if res == 0 {
-                // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
-                let fm_err = errno();
-                return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
-            }
-
-            let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf));
-            match msg {
-                Some(msg) => format!("OS Error {}: {}", errnum, msg),
-                None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
-            }
-        }
-    }
+    return os_imp::error_string(errnum as i32);
 }
 
 /// Get a string representing the platform-dependent last error
diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs
new file mode 100644
index 00000000000..87907fde277
--- /dev/null
+++ b/src/libstd/sys/common/helper_thread.rs
@@ -0,0 +1,131 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Implementation of the helper thread for the timer module
+//!
+//! This module contains the management necessary for the timer worker thread.
+//! This thread is responsible for performing the send()s on channels for timers
+//! that are using channels instead of a blocking call.
+//!
+//! The timer thread is lazily initialized, and it's shut down via the
+//! `shutdown` function provided. It must be maintained as an invariant that
+//! `shutdown` is only called when the entire program is finished. No new timers
+//! can be created in the future and there must be no active timers at that
+//! time.
+
+use mem;
+use rt::bookkeeping;
+use rt::mutex::StaticNativeMutex;
+use rt;
+use cell::UnsafeCell;
+use sys::helper_signal;
+use prelude::*;
+
+use task;
+
+/// A structure for management of a helper thread.
+///
+/// This is generally a static structure which tracks the lifetime of a helper
+/// thread.
+///
+/// The fields of this helper are all public, but they should not be used, this
+/// is for static initialization.
+pub struct Helper<M> {
+    /// Internal lock which protects the remaining fields
+    pub lock: StaticNativeMutex,
+
+    // You'll notice that the remaining fields are UnsafeCell<T>, and this is
+    // because all helper thread operations are done through &self, but we need
+    // these to be mutable (once `lock` is held).
+
+    /// Lazily allocated channel to send messages to the helper thread.
+    pub chan: UnsafeCell<*mut Sender<M>>,
+
+    /// OS handle used to wake up a blocked helper thread
+    pub signal: UnsafeCell<uint>,
+
+    /// Flag if this helper thread has booted and been initialized yet.
+    pub initialized: UnsafeCell<bool>,
+}
+
+impl<M: Send> Helper<M> {
+    /// Lazily boots a helper thread, becoming a no-op if the helper has already
+    /// been spawned.
+    ///
+    /// This function will check to see if the thread has been initialized, and
+    /// if it has it returns quickly. If initialization has not happened yet,
+    /// the closure `f` will be run (inside of the initialization lock) and
+    /// passed to the helper thread in a separate task.
+    ///
+    /// This function is safe to be called many times.
+    pub fn boot<T: Send>(&'static self,
+                         f: || -> T,
+                         helper: fn(helper_signal::signal, Receiver<M>, T)) {
+        unsafe {
+            let _guard = self.lock.lock();
+            if !*self.initialized.get() {
+                let (tx, rx) = channel();
+                *self.chan.get() = mem::transmute(box tx);
+                let (receive, send) = helper_signal::new();
+                *self.signal.get() = send as uint;
+
+                let t = f();
+                task::spawn(proc() {
+                    bookkeeping::decrement();
+                    helper(receive, rx, t);
+                    self.lock.lock().signal()
+                });
+
+                rt::at_exit(proc() { self.shutdown() });
+                *self.initialized.get() = true;
+            }
+        }
+    }
+
+    /// Sends a message to a spawned worker thread.
+    ///
+    /// This is only valid if the worker thread has previously booted
+    pub fn send(&'static self, msg: M) {
+        unsafe {
+            let _guard = self.lock.lock();
+
+            // Must send and *then* signal to ensure that the child receives the
+            // message. Otherwise it could wake up and go to sleep before we
+            // send the message.
+            assert!(!self.chan.get().is_null());
+            (**self.chan.get()).send(msg);
+            helper_signal::signal(*self.signal.get() as helper_signal::signal);
+        }
+    }
+
+    fn shutdown(&'static self) {
+        unsafe {
+            // Shut down, but make sure this is done inside our lock to ensure
+            // that we'll always receive the exit signal when the thread
+            // returns.
+            let guard = self.lock.lock();
+
+            // Close the channel by destroying it
+            let chan: Box<Sender<M>> = mem::transmute(*self.chan.get());
+            *self.chan.get() = 0 as *mut Sender<M>;
+            drop(chan);
+            helper_signal::signal(*self.signal.get() as helper_signal::signal);
+
+            // Wait for the child to exit
+            guard.wait();
+            drop(guard);
+
+            // Clean up after ourselves
+            self.lock.destroy();
+            helper_signal::close(*self.signal.get() as helper_signal::signal);
+            *self.signal.get() = 0;
+        }
+    }
+}
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs
new file mode 100644
index 00000000000..c5f8214a5c3
--- /dev/null
+++ b/src/libstd/sys/common/mod.rs
@@ -0,0 +1,100 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(missing_doc)]
+#![allow(dead_code)]
+
+use io::{mod, IoError, IoResult};
+use prelude::*;
+use num;
+use sys::{last_error, retry, fs};
+use c_str::CString;
+use path::BytesContainer;
+use collections;
+
+pub mod net;
+pub mod helper_thread;
+
+// common error constructors
+
+pub fn eof() -> IoError {
+    IoError {
+        kind: io::EndOfFile,
+        desc: "end of file",
+        detail: None,
+    }
+}
+
+pub fn timeout(desc: &'static str) -> IoError {
+    IoError {
+        kind: io::TimedOut,
+        desc: desc,
+        detail: None,
+    }
+}
+
+pub fn short_write(n: uint, desc: &'static str) -> IoError {
+    IoError {
+        kind: if n == 0 { io::TimedOut } else { io::ShortWrite(n) },
+        desc: desc,
+        detail: None,
+    }
+}
+
+pub fn unimpl() -> IoError {
+    IoError {
+        kind: io::IoUnavailable,
+        desc: "operations not yet supported",
+        detail: None,
+    }
+}
+
+// unix has nonzero values as errors
+pub fn mkerr_libc<Int: num::Zero>(ret: Int) -> IoResult<()> {
+    if !ret.is_zero() {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
+pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
+    let origamt = data.len();
+    let mut data = data.as_ptr();
+    let mut amt = origamt;
+    while amt > 0 {
+        let ret = retry(|| f(data, amt));
+        if ret == 0 {
+            break
+        } else if ret != -1 {
+            amt -= ret as uint;
+            data = unsafe { data.offset(ret as int) };
+        } else {
+            return ret;
+        }
+    }
+    return (origamt - amt) as i64;
+}
+
+// traits for extracting representations from
+
+pub trait AsFileDesc {
+    fn as_fd(&self) -> &fs::FileDesc;
+}
+
+pub trait ProcessConfig<K: BytesContainer, V: BytesContainer> {
+    fn program(&self) -> &CString;
+    fn args(&self) -> &[CString];
+    fn env(&self) -> Option<&collections::HashMap<K, V>>;
+    fn cwd(&self) -> Option<&CString>;
+    fn uid(&self) -> Option<uint>;
+    fn gid(&self) -> Option<uint>;
+    fn detach(&self) -> bool;
+}
diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs
new file mode 100644
index 00000000000..7c44142d93c
--- /dev/null
+++ b/src/libstd/sys/common/net.rs
@@ -0,0 +1,911 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use alloc::arc::Arc;
+use libc::{mod, c_char, c_int};
+use mem;
+use ptr::{mod, null, null_mut};
+use rt::mutex;
+use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
+use io::net::addrinfo;
+use io::{IoResult, IoError};
+use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock,
+          wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
+          decode_error_detailed};
+use sys_common::{mod, keep_going, short_write, timeout};
+use prelude::*;
+use cmp;
+use io;
+
+// FIXME: move uses of Arc and deadline tracking to std::io
+
+#[deriving(Show)]
+pub enum SocketStatus {
+    Readable,
+    Writable,
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// sockaddr and misc bindings
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn htons(u: u16) -> u16 {
+    u.to_be()
+}
+pub fn ntohs(u: u16) -> u16 {
+    Int::from_be(u)
+}
+
+pub enum InAddr {
+    In4Addr(libc::in_addr),
+    In6Addr(libc::in6_addr),
+}
+
+pub fn ip_to_inaddr(ip: IpAddr) -> InAddr {
+    match ip {
+        Ipv4Addr(a, b, c, d) => {
+            let ip = (a as u32 << 24) |
+                     (b as u32 << 16) |
+                     (c as u32 <<  8) |
+                     (d as u32 <<  0);
+            In4Addr(libc::in_addr {
+                s_addr: Int::from_be(ip)
+            })
+        }
+        Ipv6Addr(a, b, c, d, e, f, g, h) => {
+            In6Addr(libc::in6_addr {
+                s6_addr: [
+                    htons(a),
+                    htons(b),
+                    htons(c),
+                    htons(d),
+                    htons(e),
+                    htons(f),
+                    htons(g),
+                    htons(h),
+                ]
+            })
+        }
+    }
+}
+
+pub fn addr_to_sockaddr(addr: SocketAddr,
+                    storage: &mut libc::sockaddr_storage)
+                    -> libc::socklen_t {
+    unsafe {
+        let len = match ip_to_inaddr(addr.ip) {
+            In4Addr(inaddr) => {
+                let storage = storage as *mut _ as *mut libc::sockaddr_in;
+                (*storage).sin_family = libc::AF_INET as libc::sa_family_t;
+                (*storage).sin_port = htons(addr.port);
+                (*storage).sin_addr = inaddr;
+                mem::size_of::<libc::sockaddr_in>()
+            }
+            In6Addr(inaddr) => {
+                let storage = storage as *mut _ as *mut libc::sockaddr_in6;
+                (*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t;
+                (*storage).sin6_port = htons(addr.port);
+                (*storage).sin6_addr = inaddr;
+                mem::size_of::<libc::sockaddr_in6>()
+            }
+        };
+        return len as libc::socklen_t;
+    }
+}
+
+pub fn socket(addr: SocketAddr, ty: libc::c_int) -> IoResult<sock_t> {
+    unsafe {
+        let fam = match addr.ip {
+            Ipv4Addr(..) => libc::AF_INET,
+            Ipv6Addr(..) => libc::AF_INET6,
+        };
+        match libc::socket(fam, ty, 0) {
+            -1 => Err(last_net_error()),
+            fd => Ok(fd),
+        }
+    }
+}
+
+pub fn setsockopt<T>(fd: sock_t, opt: libc::c_int, val: libc::c_int,
+                 payload: T) -> IoResult<()> {
+    unsafe {
+        let payload = &payload as *const T as *const libc::c_void;
+        let ret = libc::setsockopt(fd, opt, val,
+                                   payload,
+                                   mem::size_of::<T>() as libc::socklen_t);
+        if ret != 0 {
+            Err(last_net_error())
+        } else {
+            Ok(())
+        }
+    }
+}
+
+pub fn getsockopt<T: Copy>(fd: sock_t, opt: libc::c_int,
+                           val: libc::c_int) -> IoResult<T> {
+    unsafe {
+        let mut slot: T = mem::zeroed();
+        let mut len = mem::size_of::<T>() as libc::socklen_t;
+        let ret = c::getsockopt(fd, opt, val,
+                                &mut slot as *mut _ as *mut _,
+                                &mut len);
+        if ret != 0 {
+            Err(last_net_error())
+        } else {
+            assert!(len as uint == mem::size_of::<T>());
+            Ok(slot)
+        }
+    }
+}
+
+pub fn sockname(fd: sock_t,
+            f: unsafe extern "system" fn(sock_t, *mut libc::sockaddr,
+                                         *mut libc::socklen_t) -> libc::c_int)
+    -> IoResult<SocketAddr>
+{
+    let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+    let mut len = mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
+    unsafe {
+        let storage = &mut storage as *mut libc::sockaddr_storage;
+        let ret = f(fd,
+                    storage as *mut libc::sockaddr,
+                    &mut len as *mut libc::socklen_t);
+        if ret != 0 {
+            return Err(last_net_error())
+        }
+    }
+    return sockaddr_to_addr(&storage, len as uint);
+}
+
+pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
+                        len: uint) -> IoResult<SocketAddr> {
+    match storage.ss_family as libc::c_int {
+        libc::AF_INET => {
+            assert!(len as uint >= mem::size_of::<libc::sockaddr_in>());
+            let storage: &libc::sockaddr_in = unsafe {
+                mem::transmute(storage)
+            };
+            let ip = (storage.sin_addr.s_addr as u32).to_be();
+            let a = (ip >> 24) as u8;
+            let b = (ip >> 16) as u8;
+            let c = (ip >>  8) as u8;
+            let d = (ip >>  0) as u8;
+            Ok(SocketAddr {
+                ip: Ipv4Addr(a, b, c, d),
+                port: ntohs(storage.sin_port),
+            })
+        }
+        libc::AF_INET6 => {
+            assert!(len as uint >= mem::size_of::<libc::sockaddr_in6>());
+            let storage: &libc::sockaddr_in6 = unsafe {
+                mem::transmute(storage)
+            };
+            let a = ntohs(storage.sin6_addr.s6_addr[0]);
+            let b = ntohs(storage.sin6_addr.s6_addr[1]);
+            let c = ntohs(storage.sin6_addr.s6_addr[2]);
+            let d = ntohs(storage.sin6_addr.s6_addr[3]);
+            let e = ntohs(storage.sin6_addr.s6_addr[4]);
+            let f = ntohs(storage.sin6_addr.s6_addr[5]);
+            let g = ntohs(storage.sin6_addr.s6_addr[6]);
+            let h = ntohs(storage.sin6_addr.s6_addr[7]);
+            Ok(SocketAddr {
+                ip: Ipv6Addr(a, b, c, d, e, f, g, h),
+                port: ntohs(storage.sin6_port),
+            })
+        }
+        _ => {
+            Err(IoError {
+                kind: io::InvalidInput,
+                desc: "invalid argument",
+                detail: None,
+            })
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// get_host_addresses
+////////////////////////////////////////////////////////////////////////////////
+
+extern "system" {
+    fn getaddrinfo(node: *const c_char, service: *const c_char,
+                   hints: *const libc::addrinfo,
+                   res: *mut *mut libc::addrinfo) -> c_int;
+    fn freeaddrinfo(res: *mut libc::addrinfo);
+}
+
+pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>,
+                          hint: Option<addrinfo::Hint>)
+                          -> Result<Vec<addrinfo::Info>, IoError>
+{
+    sys::init_net();
+
+    assert!(host.is_some() || servname.is_some());
+
+    let c_host = host.map(|x| x.to_c_str());
+    let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
+    let c_serv = servname.map(|x| x.to_c_str());
+    let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null());
+
+    let hint = hint.map(|hint| {
+        libc::addrinfo {
+            ai_flags: hint.flags as c_int,
+            ai_family: hint.family as c_int,
+            ai_socktype: 0,
+            ai_protocol: 0,
+            ai_addrlen: 0,
+            ai_canonname: null_mut(),
+            ai_addr: null_mut(),
+            ai_next: null_mut()
+        }
+    });
+
+    let hint_ptr = hint.as_ref().map_or(null(), |x| {
+        x as *const libc::addrinfo
+    });
+    let mut res = null_mut();
+
+    // Make the call
+    let s = unsafe {
+        getaddrinfo(c_host, c_serv, hint_ptr, &mut res)
+    };
+
+    // Error?
+    if s != 0 {
+        return Err(last_gai_error(s));
+    }
+
+    // Collect all the results we found
+    let mut addrs = Vec::new();
+    let mut rp = res;
+    while rp.is_not_null() {
+        unsafe {
+            let addr = try!(sockaddr_to_addr(mem::transmute((*rp).ai_addr),
+                                             (*rp).ai_addrlen as uint));
+            addrs.push(addrinfo::Info {
+                address: addr,
+                family: (*rp).ai_family as uint,
+                socktype: None,
+                protocol: None,
+                flags: (*rp).ai_flags as uint
+            });
+
+            rp = (*rp).ai_next as *mut libc::addrinfo;
+        }
+    }
+
+    unsafe { freeaddrinfo(res); }
+
+    Ok(addrs)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Timeout helpers
+//
+// The read/write functions below are the helpers for reading/writing a socket
+// with a possible deadline specified. This is generally viewed as a timed out
+// I/O operation.
+//
+// From the application's perspective, timeouts apply to the I/O object, not to
+// the underlying file descriptor (it's one timeout per object). This means that
+// we can't use the SO_RCVTIMEO and corresponding send timeout option.
+//
+// The next idea to implement timeouts would be to use nonblocking I/O. An
+// invocation of select() would wait (with a timeout) for a socket to be ready.
+// Once its ready, we can perform the operation. Note that the operation *must*
+// be nonblocking, even though select() says the socket is ready. This is
+// because some other thread could have come and stolen our data (handles can be
+// cloned).
+//
+// To implement nonblocking I/O, the first option we have is to use the
+// O_NONBLOCK flag. Remember though that this is a global setting, affecting all
+// I/O objects, so this was initially viewed as unwise.
+//
+// It turns out that there's this nifty MSG_DONTWAIT flag which can be passed to
+// send/recv, but the niftiness wears off once you realize it only works well on
+// Linux [1] [2]. This means that it's pretty easy to get a nonblocking
+// operation on Linux (no flag fiddling, no affecting other objects), but not on
+// other platforms.
+//
+// To work around this constraint on other platforms, we end up using the
+// original strategy of flipping the O_NONBLOCK flag. As mentioned before, this
+// could cause other objects' blocking operations to suddenly become
+// nonblocking. To get around this, a "blocking operation" which returns EAGAIN
+// falls back to using the same code path as nonblocking operations, but with an
+// infinite timeout (select + send/recv). This helps emulate blocking
+// reads/writes despite the underlying descriptor being nonblocking, as well as
+// optimizing the fast path of just hitting one syscall in the good case.
+//
+// As a final caveat, this implementation uses a mutex so only one thread is
+// doing a nonblocking operation at at time. This is the operation that comes
+// after the select() (at which point we think the socket is ready). This is
+// done for sanity to ensure that the state of the O_NONBLOCK flag is what we
+// expect (wouldn't want someone turning it on when it should be off!). All
+// operations performed in the lock are *nonblocking* to avoid holding the mutex
+// forever.
+//
+// So, in summary, Linux uses MSG_DONTWAIT and doesn't need mutexes, everyone
+// else uses O_NONBLOCK and mutexes with some trickery to make sure blocking
+// reads/writes are still blocking.
+//
+// Fun, fun!
+//
+// [1] http://twistedmatrix.com/pipermail/twisted-commits/2012-April/034692.html
+// [2] http://stackoverflow.com/questions/19819198/does-send-msg-dontwait
+
+pub fn read<T>(fd: sock_t,
+               deadline: u64,
+               lock: || -> T,
+               read: |bool| -> libc::c_int) -> IoResult<uint> {
+    let mut ret = -1;
+    if deadline == 0 {
+        ret = retry(|| read(false));
+    }
+
+    if deadline != 0 || (ret == -1 && wouldblock()) {
+        let deadline = match deadline {
+            0 => None,
+            n => Some(n),
+        };
+        loop {
+            // With a timeout, first we wait for the socket to become
+            // readable using select(), specifying the relevant timeout for
+            // our previously set deadline.
+            try!(await([fd], deadline, Readable));
+
+            // At this point, we're still within the timeout, and we've
+            // determined that the socket is readable (as returned by
+            // select). We must still read the socket in *nonblocking* mode
+            // because some other thread could come steal our data. If we
+            // fail to read some data, we retry (hence the outer loop) and
+            // wait for the socket to become readable again.
+            let _guard = lock();
+            match retry(|| read(deadline.is_some())) {
+                -1 if wouldblock() => {}
+                -1 => return Err(last_net_error()),
+               n => { ret = n; break }
+            }
+        }
+    }
+
+    match ret {
+        0 => Err(sys_common::eof()),
+        n if n < 0 => Err(last_net_error()),
+        n => Ok(n as uint)
+    }
+}
+
+pub fn write<T>(fd: sock_t,
+                deadline: u64,
+                buf: &[u8],
+                write_everything: bool,
+                lock: || -> T,
+                write: |bool, *const u8, uint| -> i64) -> IoResult<uint> {
+    let mut ret = -1;
+    let mut written = 0;
+    if deadline == 0 {
+        if write_everything {
+            ret = keep_going(buf, |inner, len| {
+                written = buf.len() - len;
+                write(false, inner, len)
+            });
+        } else {
+            ret = retry(|| { write(false, buf.as_ptr(), buf.len()) });
+            if ret > 0 { written = ret as uint; }
+        }
+    }
+
+    if deadline != 0 || (ret == -1 && wouldblock()) {
+        let deadline = match deadline {
+            0 => None,
+            n => Some(n),
+        };
+        while written < buf.len() && (write_everything || written == 0) {
+            // As with read(), first wait for the socket to be ready for
+            // the I/O operation.
+            match await([fd], deadline, Writable) {
+                Err(ref e) if e.kind == io::EndOfFile && written > 0 => {
+                    assert!(deadline.is_some());
+                    return Err(short_write(written, "short write"))
+                }
+                Err(e) => return Err(e),
+                Ok(()) => {}
+            }
+
+            // Also as with read(), we use MSG_DONTWAIT to guard ourselves
+            // against unforeseen circumstances.
+            let _guard = lock();
+            let ptr = buf[written..].as_ptr();
+            let len = buf.len() - written;
+            match retry(|| write(deadline.is_some(), ptr, len)) {
+                -1 if wouldblock() => {}
+                -1 => return Err(last_net_error()),
+                n => { written += n as uint; }
+            }
+        }
+        ret = 0;
+    }
+    if ret < 0 {
+        Err(last_net_error())
+    } else {
+        Ok(written)
+    }
+}
+
+// See http://developerweb.net/viewtopic.php?id=3196 for where this is
+// derived from.
+pub fn connect_timeout(fd: sock_t,
+                       addrp: *const libc::sockaddr,
+                       len: libc::socklen_t,
+                       timeout_ms: u64) -> IoResult<()> {
+    #[cfg(unix)]    use libc::EINPROGRESS as INPROGRESS;
+    #[cfg(windows)] use libc::WSAEINPROGRESS as INPROGRESS;
+    #[cfg(unix)]    use libc::EWOULDBLOCK as WOULDBLOCK;
+    #[cfg(windows)] use libc::WSAEWOULDBLOCK as WOULDBLOCK;
+
+    // Make sure the call to connect() doesn't block
+    try!(set_nonblocking(fd, true));
+
+    let ret = match unsafe { libc::connect(fd, addrp, len) } {
+        // If the connection is in progress, then we need to wait for it to
+        // finish (with a timeout). The current strategy for doing this is
+        // to use select() with a timeout.
+        -1 if os::errno() as int == INPROGRESS as int ||
+              os::errno() as int == WOULDBLOCK as int => {
+            let mut set: c::fd_set = unsafe { mem::zeroed() };
+            c::fd_set(&mut set, fd);
+            match await(fd, &mut set, timeout_ms) {
+                0 => Err(timeout("connection timed out")),
+                -1 => Err(last_net_error()),
+                _ => {
+                    let err: libc::c_int = try!(
+                        getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR));
+                    if err == 0 {
+                        Ok(())
+                    } else {
+                        Err(decode_error_detailed(err))
+                    }
+                }
+            }
+        }
+
+        -1 => Err(last_net_error()),
+        _ => Ok(()),
+    };
+
+    // be sure to turn blocking I/O back on
+    try!(set_nonblocking(fd, false));
+    return ret;
+
+    #[cfg(unix)]
+    fn await(fd: sock_t, set: &mut c::fd_set, timeout: u64) -> libc::c_int {
+        let start = timer::now();
+        retry(|| unsafe {
+            // Recalculate the timeout each iteration (it is generally
+            // undefined what the value of the 'tv' is after select
+            // returns EINTR).
+            let mut tv = ms_to_timeval(timeout - (timer::now() - start));
+            c::select(fd + 1, ptr::null_mut(), set as *mut _,
+                      ptr::null_mut(), &mut tv)
+        })
+    }
+    #[cfg(windows)]
+    fn await(_fd: sock_t, set: &mut c::fd_set, timeout: u64) -> libc::c_int {
+        let mut tv = ms_to_timeval(timeout);
+        unsafe { c::select(1, ptr::null_mut(), set, ptr::null_mut(), &mut tv) }
+    }
+}
+
+pub fn await(fds: &[sock_t], deadline: Option<u64>,
+             status: SocketStatus) -> IoResult<()> {
+    let mut set: c::fd_set = unsafe { mem::zeroed() };
+    let mut max = 0;
+    for &fd in fds.iter() {
+        c::fd_set(&mut set, fd);
+        max = cmp::max(max, fd + 1);
+    }
+    if cfg!(windows) {
+        max = fds.len() as sock_t;
+    }
+
+    let (read, write) = match status {
+        Readable => (&mut set as *mut _, ptr::null_mut()),
+        Writable => (ptr::null_mut(), &mut set as *mut _),
+    };
+    let mut tv: libc::timeval = unsafe { mem::zeroed() };
+
+    match retry(|| {
+        let now = timer::now();
+        let tvp = match deadline {
+            None => ptr::null_mut(),
+            Some(deadline) => {
+                // If we're past the deadline, then pass a 0 timeout to
+                // select() so we can poll the status
+                let ms = if deadline < now {0} else {deadline - now};
+                tv = ms_to_timeval(ms);
+                &mut tv as *mut _
+            }
+        };
+        let r = unsafe {
+            c::select(max as libc::c_int, read, write, ptr::null_mut(), tvp)
+        };
+        r
+    }) {
+        -1 => Err(last_net_error()),
+        0 => Err(timeout("timed out")),
+        _ => Ok(()),
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Basic socket representation
+////////////////////////////////////////////////////////////////////////////////
+
+struct Inner {
+    fd: sock_t,
+
+    // Unused on Linux, where this lock is not necessary.
+    #[allow(dead_code)]
+    lock: mutex::NativeMutex
+}
+
+impl Inner {
+    fn new(fd: sock_t) -> Inner {
+        Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } }
+    }
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) { unsafe { close_sock(self.fd); } }
+}
+
+pub struct Guard<'a> {
+    pub fd: sock_t,
+    pub guard: mutex::LockGuard<'a>,
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for Guard<'a> {
+    fn drop(&mut self) {
+        assert!(set_nonblocking(self.fd, false).is_ok());
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpStream {
+    inner: Arc<Inner>,
+    read_deadline: u64,
+    write_deadline: u64,
+}
+
+impl TcpStream {
+    pub fn connect(addr: SocketAddr, timeout: Option<u64>) -> IoResult<TcpStream> {
+        sys::init_net();
+
+        let fd = try!(socket(addr, libc::SOCK_STREAM));
+        let ret = TcpStream::new(fd);
+
+        let mut storage = unsafe { mem::zeroed() };
+        let len = addr_to_sockaddr(addr, &mut storage);
+        let addrp = &storage as *const _ as *const libc::sockaddr;
+
+        match timeout {
+            Some(timeout) => {
+                try!(connect_timeout(fd, addrp, len, timeout));
+                Ok(ret)
+            },
+            None => {
+                match retry(|| unsafe { libc::connect(fd, addrp, len) }) {
+                    -1 => Err(last_error()),
+                    _ => Ok(ret),
+                }
+            }
+        }
+    }
+
+    pub fn new(fd: sock_t) -> TcpStream {
+        TcpStream {
+            inner: Arc::new(Inner::new(fd)),
+            read_deadline: 0,
+            write_deadline: 0,
+        }
+    }
+
+    pub fn fd(&self) -> sock_t { self.inner.fd }
+
+    pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> {
+        setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_NODELAY,
+                   nodelay as libc::c_int)
+    }
+
+    pub fn set_keepalive(&mut self, seconds: Option<uint>) -> IoResult<()> {
+        let ret = setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_KEEPALIVE,
+                             seconds.is_some() as libc::c_int);
+        match seconds {
+            Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
+            None => ret,
+        }
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> {
+        setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
+                   seconds as libc::c_int)
+    }
+    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+    fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> {
+        setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
+                   seconds as libc::c_int)
+    }
+    #[cfg(not(any(target_os = "macos",
+                  target_os = "ios",
+                  target_os = "freebsd",
+                  target_os = "dragonfly")))]
+    fn set_tcp_keepalive(&mut self, _seconds: uint) -> IoResult<()> {
+        Ok(())
+    }
+
+    #[cfg(target_os = "linux")]
+    fn lock_nonblocking(&self) {}
+
+    #[cfg(not(target_os = "linux"))]
+    fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
+        let ret = Guard {
+            fd: self.fd(),
+            guard: unsafe { self.inner.lock.lock() },
+        };
+        assert!(set_nonblocking(self.fd(), true).is_ok());
+        ret
+    }
+
+    pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        let fd = self.fd();
+        let dolock = || self.lock_nonblocking();
+        let doread = |nb| unsafe {
+            let flags = if nb {c::MSG_DONTWAIT} else {0};
+            libc::recv(fd,
+                       buf.as_mut_ptr() as *mut libc::c_void,
+                       buf.len() as wrlen,
+                       flags) as libc::c_int
+        };
+        read(fd, self.read_deadline, dolock, doread)
+    }
+
+    pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        let fd = self.fd();
+        let dolock = || self.lock_nonblocking();
+        let dowrite = |nb: bool, buf: *const u8, len: uint| unsafe {
+            let flags = if nb {c::MSG_DONTWAIT} else {0};
+            libc::send(fd,
+                       buf as *const _,
+                       len as wrlen,
+                       flags) as i64
+        };
+        write(fd, self.write_deadline, buf, true, dolock, dowrite).map(|_| ())
+    }
+    pub fn peer_name(&mut self) -> IoResult<SocketAddr> {
+        sockname(self.fd(), libc::getpeername)
+    }
+
+    pub fn close_write(&mut self) -> IoResult<()> {
+        super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
+    }
+    pub fn close_read(&mut self) -> IoResult<()> {
+        super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+        self.read_deadline = deadline;
+        self.write_deadline = deadline;
+    }
+    pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
+        self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+    pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
+        self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+
+    pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
+        sockname(self.fd(), libc::getsockname)
+    }
+}
+
+impl Clone for TcpStream {
+    fn clone(&self) -> TcpStream {
+        TcpStream {
+            inner: self.inner.clone(),
+            read_deadline: 0,
+            write_deadline: 0,
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// UDP
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UdpSocket {
+    inner: Arc<Inner>,
+    read_deadline: u64,
+    write_deadline: u64,
+}
+
+impl UdpSocket {
+    pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> {
+        sys::init_net();
+
+        let fd = try!(socket(addr, libc::SOCK_DGRAM));
+        let ret = UdpSocket {
+            inner: Arc::new(Inner::new(fd)),
+            read_deadline: 0,
+            write_deadline: 0,
+        };
+
+        let mut storage = unsafe { mem::zeroed() };
+        let len = addr_to_sockaddr(addr, &mut storage);
+        let addrp = &storage as *const _ as *const libc::sockaddr;
+
+        match unsafe { libc::bind(fd, addrp, len) } {
+            -1 => Err(last_error()),
+            _ => Ok(ret),
+        }
+    }
+
+    pub fn fd(&self) -> sock_t { self.inner.fd }
+
+    pub fn set_broadcast(&mut self, on: bool) -> IoResult<()> {
+        setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_BROADCAST,
+                   on as libc::c_int)
+    }
+
+    pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> {
+        setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP,
+                   on as libc::c_int)
+    }
+
+    pub fn set_membership(&mut self, addr: IpAddr, opt: libc::c_int) -> IoResult<()> {
+        match ip_to_inaddr(addr) {
+            In4Addr(addr) => {
+                let mreq = libc::ip_mreq {
+                    imr_multiaddr: addr,
+                    // interface == INADDR_ANY
+                    imr_interface: libc::in_addr { s_addr: 0x0 },
+                };
+                setsockopt(self.fd(), libc::IPPROTO_IP, opt, mreq)
+            }
+            In6Addr(addr) => {
+                let mreq = libc::ip6_mreq {
+                    ipv6mr_multiaddr: addr,
+                    ipv6mr_interface: 0,
+                };
+                setsockopt(self.fd(), libc::IPPROTO_IPV6, opt, mreq)
+            }
+        }
+    }
+
+    #[cfg(target_os = "linux")]
+    fn lock_nonblocking(&self) {}
+
+    #[cfg(not(target_os = "linux"))]
+    fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
+        let ret = Guard {
+            fd: self.fd(),
+            guard: unsafe { self.inner.lock.lock() },
+        };
+        assert!(set_nonblocking(self.fd(), true).is_ok());
+        ret
+    }
+
+    pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
+        sockname(self.fd(), libc::getsockname)
+    }
+
+    pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> {
+        let fd = self.fd();
+        let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+        let storagep = &mut storage as *mut _ as *mut libc::sockaddr;
+        let mut addrlen: libc::socklen_t =
+                mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
+
+        let dolock = || self.lock_nonblocking();
+        let n = try!(read(fd, self.read_deadline, dolock, |nb| unsafe {
+            let flags = if nb {c::MSG_DONTWAIT} else {0};
+            libc::recvfrom(fd,
+                           buf.as_mut_ptr() as *mut libc::c_void,
+                           buf.len() as msglen_t,
+                           flags,
+                           storagep,
+                           &mut addrlen) as libc::c_int
+        }));
+        sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| {
+            Ok((n as uint, addr))
+        })
+    }
+
+    pub fn send_to(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
+        let mut storage = unsafe { mem::zeroed() };
+        let dstlen = addr_to_sockaddr(dst, &mut storage);
+        let dstp = &storage as *const _ as *const libc::sockaddr;
+
+        let fd = self.fd();
+        let dolock = || self.lock_nonblocking();
+        let dowrite = |nb, buf: *const u8, len: uint| unsafe {
+            let flags = if nb {c::MSG_DONTWAIT} else {0};
+            libc::sendto(fd,
+                         buf as *const libc::c_void,
+                         len as msglen_t,
+                         flags,
+                         dstp,
+                         dstlen) as i64
+        };
+
+        let n = try!(write(fd, self.write_deadline, buf, false, dolock, dowrite));
+        if n != buf.len() {
+            Err(short_write(n, "couldn't send entire packet at once"))
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
+        match multi {
+            Ipv4Addr(..) => {
+                self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
+            }
+            Ipv6Addr(..) => {
+                self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
+            }
+        }
+    }
+    pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> {
+        match multi {
+            Ipv4Addr(..) => {
+                self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
+            }
+            Ipv6Addr(..) => {
+                self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
+            }
+        }
+    }
+
+    pub fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()> {
+        setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
+                   ttl as libc::c_int)
+    }
+    pub fn time_to_live(&mut self, ttl: int) -> IoResult<()> {
+        setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_TTL, ttl as libc::c_int)
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+        self.read_deadline = deadline;
+        self.write_deadline = deadline;
+    }
+    pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
+        self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+    pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
+        self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+}
+
+impl Clone for UdpSocket {
+    fn clone(&self) -> UdpSocket {
+        UdpSocket {
+            inner: self.inner.clone(),
+            read_deadline: 0,
+            write_deadline: 0,
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs
new file mode 100644
index 00000000000..e76f2a2b872
--- /dev/null
+++ b/src/libstd/sys/unix/c.rs
@@ -0,0 +1,262 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! C definitions used by libnative that don't belong in liblibc
+
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+pub use self::select::fd_set;
+pub use self::signal::{sigaction, siginfo, sigset_t};
+pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP};
+pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};
+
+use libc;
+
+#[cfg(any(target_os = "macos",
+          target_os = "ios",
+          target_os = "freebsd",
+          target_os = "dragonfly"))]
+pub const FIONBIO: libc::c_ulong = 0x8004667e;
+#[cfg(any(all(target_os = "linux",
+              any(target_arch = "x86",
+                  target_arch = "x86_64",
+                  target_arch = "arm")),
+          target_os = "android"))]
+pub const FIONBIO: libc::c_ulong = 0x5421;
+#[cfg(all(target_os = "linux",
+          any(target_arch = "mips", target_arch = "mipsel")))]
+pub const FIONBIO: libc::c_ulong = 0x667e;
+
+#[cfg(any(target_os = "macos",
+          target_os = "ios",
+          target_os = "freebsd",
+          target_os = "dragonfly"))]
+pub const FIOCLEX: libc::c_ulong = 0x20006601;
+#[cfg(any(all(target_os = "linux",
+              any(target_arch = "x86",
+                  target_arch = "x86_64",
+                  target_arch = "arm")),
+          target_os = "android"))]
+pub const FIOCLEX: libc::c_ulong = 0x5451;
+#[cfg(all(target_os = "linux",
+          any(target_arch = "mips", target_arch = "mipsel")))]
+pub const FIOCLEX: libc::c_ulong = 0x6601;
+
+#[cfg(any(target_os = "macos",
+          target_os = "ios",
+          target_os = "freebsd",
+          target_os = "dragonfly"))]
+pub const MSG_DONTWAIT: libc::c_int = 0x80;
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub const MSG_DONTWAIT: libc::c_int = 0x40;
+
+pub const WNOHANG: libc::c_int = 1;
+
+extern {
+    pub fn gettimeofday(timeval: *mut libc::timeval,
+                        tzp: *mut libc::c_void) -> libc::c_int;
+    pub fn select(nfds: libc::c_int,
+                  readfds: *mut fd_set,
+                  writefds: *mut fd_set,
+                  errorfds: *mut fd_set,
+                  timeout: *mut libc::timeval) -> libc::c_int;
+    pub fn getsockopt(sockfd: libc::c_int,
+                      level: libc::c_int,
+                      optname: libc::c_int,
+                      optval: *mut libc::c_void,
+                      optlen: *mut libc::socklen_t) -> libc::c_int;
+    pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;
+
+
+    pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int,
+                   options: libc::c_int) -> libc::pid_t;
+
+    pub fn sigaction(signum: libc::c_int,
+                     act: *const sigaction,
+                     oldact: *mut sigaction) -> libc::c_int;
+
+    pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
+    pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
+    pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+mod select {
+    pub const FD_SETSIZE: uint = 1024;
+
+    #[repr(C)]
+    pub struct fd_set {
+        fds_bits: [i32, ..(FD_SETSIZE / 32)]
+    }
+
+    pub fn fd_set(set: &mut fd_set, fd: i32) {
+        set.fds_bits[(fd / 32) as uint] |= 1 << ((fd % 32) as uint);
+    }
+}
+
+#[cfg(any(target_os = "android",
+          target_os = "freebsd",
+          target_os = "dragonfly",
+          target_os = "linux"))]
+mod select {
+    use uint;
+    use libc;
+
+    pub const FD_SETSIZE: uint = 1024;
+
+    #[repr(C)]
+    pub struct fd_set {
+        // FIXME: shouldn't this be a c_ulong?
+        fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)]
+    }
+
+    pub fn fd_set(set: &mut fd_set, fd: i32) {
+        let fd = fd as uint;
+        set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
+    }
+}
+
+#[cfg(any(all(target_os = "linux",
+              any(target_arch = "x86",
+                  target_arch = "x86_64",
+                  target_arch = "arm")),
+          target_os = "android"))]
+mod signal {
+    use libc;
+
+    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
+    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002;
+    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
+    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
+    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
+    pub const SA_RESTART: libc::c_ulong = 0x10000000;
+    pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
+    pub const SIGCHLD: libc::c_int = 17;
+
+    // This definition is not as accurate as it could be, {pid, uid, status} is
+    // actually a giant union. Currently we're only interested in these fields,
+    // however.
+    #[repr(C)]
+    pub struct siginfo {
+        si_signo: libc::c_int,
+        si_errno: libc::c_int,
+        si_code: libc::c_int,
+        pub pid: libc::pid_t,
+        pub uid: libc::uid_t,
+        pub status: libc::c_int,
+    }
+
+    #[repr(C)]
+    pub struct sigaction {
+        pub sa_handler: extern fn(libc::c_int),
+        pub sa_mask: sigset_t,
+        pub sa_flags: libc::c_ulong,
+        sa_restorer: *mut libc::c_void,
+    }
+
+    #[repr(C)]
+    #[cfg(target_word_size = "32")]
+    pub struct sigset_t {
+        __val: [libc::c_ulong, ..32],
+    }
+
+    #[repr(C)]
+    #[cfg(target_word_size = "64")]
+    pub struct sigset_t {
+        __val: [libc::c_ulong, ..16],
+    }
+}
+
+#[cfg(all(target_os = "linux",
+          any(target_arch = "mips", target_arch = "mipsel")))]
+mod signal {
+    use libc;
+
+    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
+    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000;
+    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
+    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
+    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
+    pub const SA_RESTART: libc::c_ulong = 0x10000000;
+    pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
+    pub const SIGCHLD: libc::c_int = 18;
+
+    // This definition is not as accurate as it could be, {pid, uid, status} is
+    // actually a giant union. Currently we're only interested in these fields,
+    // however.
+    #[repr(C)]
+    pub struct siginfo {
+        si_signo: libc::c_int,
+        si_code: libc::c_int,
+        si_errno: libc::c_int,
+        pub pid: libc::pid_t,
+        pub uid: libc::uid_t,
+        pub status: libc::c_int,
+    }
+
+    #[repr(C)]
+    pub struct sigaction {
+        pub sa_flags: libc::c_uint,
+        pub sa_handler: extern fn(libc::c_int),
+        pub sa_mask: sigset_t,
+        sa_restorer: *mut libc::c_void,
+        sa_resv: [libc::c_int, ..1],
+    }
+
+    #[repr(C)]
+    pub struct sigset_t {
+        __val: [libc::c_ulong, ..32],
+    }
+}
+
+#[cfg(any(target_os = "macos",
+          target_os = "ios",
+          target_os = "freebsd",
+          target_os = "dragonfly"))]
+mod signal {
+    use libc;
+
+    pub const SA_ONSTACK: libc::c_int = 0x0001;
+    pub const SA_RESTART: libc::c_int = 0x0002;
+    pub const SA_RESETHAND: libc::c_int = 0x0004;
+    pub const SA_NOCLDSTOP: libc::c_int = 0x0008;
+    pub const SA_NODEFER: libc::c_int = 0x0010;
+    pub const SA_NOCLDWAIT: libc::c_int = 0x0020;
+    pub const SA_SIGINFO: libc::c_int = 0x0040;
+    pub const SIGCHLD: libc::c_int = 20;
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub type sigset_t = u32;
+    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+    #[repr(C)]
+    pub struct sigset_t {
+        bits: [u32, ..4],
+    }
+
+    // This structure has more fields, but we're not all that interested in
+    // them.
+    #[repr(C)]
+    pub struct siginfo {
+        pub si_signo: libc::c_int,
+        pub si_errno: libc::c_int,
+        pub si_code: libc::c_int,
+        pub pid: libc::pid_t,
+        pub uid: libc::uid_t,
+        pub status: libc::c_int,
+    }
+
+    #[repr(C)]
+    pub struct sigaction {
+        pub sa_handler: extern fn(libc::c_int),
+        pub sa_flags: libc::c_int,
+        pub sa_mask: sigset_t,
+    }
+}
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
new file mode 100644
index 00000000000..2d02c34e958
--- /dev/null
+++ b/src/libstd/sys/unix/fs.rs
@@ -0,0 +1,392 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Blocking posix-based file I/O
+
+use libc::{mod, c_int, c_void};
+use c_str::CString;
+use mem;
+use io;
+
+use prelude::*;
+
+use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
+use io::{IoResult, FileStat, SeekStyle, Reader};
+use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
+use result::{Ok, Err};
+use sys::retry;
+use sys_common::{keep_going, eof, mkerr_libc};
+
+pub use path::PosixPath as Path;
+
+pub type fd_t = libc::c_int;
+
+pub struct FileDesc {
+    /// The underlying C file descriptor.
+    fd: fd_t,
+
+    /// Whether to close the file descriptor on drop.
+    close_on_drop: bool,
+}
+
+impl FileDesc {
+    pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
+        FileDesc { fd: fd, close_on_drop: close_on_drop }
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> IoResult<uint> {
+        let ret = retry(|| unsafe {
+            libc::read(self.fd(),
+                       buf.as_mut_ptr() as *mut libc::c_void,
+                       buf.len() as libc::size_t)
+        });
+        if ret == 0 {
+            Err(eof())
+        } else if ret < 0 {
+            Err(super::last_error())
+        } else {
+            Ok(ret as uint)
+        }
+    }
+    pub fn write(&self, buf: &[u8]) -> IoResult<()> {
+        let ret = keep_going(buf, |buf, len| {
+            unsafe {
+                libc::write(self.fd(), buf as *const libc::c_void,
+                            len as libc::size_t) as i64
+            }
+        });
+        if ret < 0 {
+            Err(super::last_error())
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn fd(&self) -> fd_t { self.fd }
+
+    pub fn seek(&self, pos: i64, whence: SeekStyle) -> IoResult<u64> {
+        let whence = match whence {
+            SeekSet => libc::SEEK_SET,
+            SeekEnd => libc::SEEK_END,
+            SeekCur => libc::SEEK_CUR,
+        };
+        let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) };
+        if n < 0 {
+            Err(super::last_error())
+        } else {
+            Ok(n as u64)
+        }
+    }
+
+    pub fn tell(&self) -> IoResult<u64> {
+        let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) };
+        if n < 0 {
+            Err(super::last_error())
+        } else {
+            Ok(n as u64)
+        }
+    }
+
+    pub fn fsync(&self) -> IoResult<()> {
+        mkerr_libc(retry(|| unsafe { libc::fsync(self.fd()) }))
+    }
+
+    pub fn datasync(&self) -> IoResult<()> {
+        return mkerr_libc(os_datasync(self.fd()));
+
+        #[cfg(any(target_os = "macos", target_os = "ios"))]
+        fn os_datasync(fd: c_int) -> c_int {
+            unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) }
+        }
+        #[cfg(target_os = "linux")]
+        fn os_datasync(fd: c_int) -> c_int {
+            retry(|| unsafe { libc::fdatasync(fd) })
+        }
+        #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
+        fn os_datasync(fd: c_int) -> c_int {
+            retry(|| unsafe { libc::fsync(fd) })
+        }
+    }
+
+    pub fn truncate(&self, offset: i64) -> IoResult<()> {
+        mkerr_libc(retry(|| unsafe {
+            libc::ftruncate(self.fd(), offset as libc::off_t)
+        }))
+    }
+
+    pub fn fstat(&self) -> IoResult<FileStat> {
+        let mut stat: libc::stat = unsafe { mem::zeroed() };
+        match unsafe { libc::fstat(self.fd(), &mut stat) } {
+            0 => Ok(mkstat(&stat)),
+            _ => Err(super::last_error()),
+        }
+    }
+
+    /// Extract the actual filedescriptor without closing it.
+    pub fn unwrap(self) -> fd_t {
+        let fd = self.fd;
+        unsafe { mem::forget(self) };
+        fd
+    }
+}
+
+impl Drop for FileDesc {
+    fn drop(&mut self) {
+        // closing stdio file handles makes no sense, so never do it. Also, note
+        // that errors are ignored when closing a file descriptor. The reason
+        // for this is that if an error occurs we don't actually know if the
+        // file descriptor was closed or not, and if we retried (for something
+        // like EINTR), we might close another valid file descriptor (opened
+        // after we closed ours.
+        if self.close_on_drop && self.fd > libc::STDERR_FILENO {
+            let n = unsafe { libc::close(self.fd) };
+            if n != 0 {
+                println!("error {} when closing file descriptor {}", n, self.fd);
+            }
+        }
+    }
+}
+
+pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
+    let flags = match fm {
+        Open => 0,
+        Append => libc::O_APPEND,
+        Truncate => libc::O_TRUNC,
+    };
+    // Opening with a write permission must silently create the file.
+    let (flags, mode) = match fa {
+        Read => (flags | libc::O_RDONLY, 0),
+        Write => (flags | libc::O_WRONLY | libc::O_CREAT,
+                        libc::S_IRUSR | libc::S_IWUSR),
+        ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT,
+                            libc::S_IRUSR | libc::S_IWUSR),
+    };
+
+    let path = path.to_c_str();
+    match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) {
+        -1 => Err(super::last_error()),
+        fd => Ok(FileDesc::new(fd, true)),
+    }
+}
+
+pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> {
+    let p = p.to_c_str();
+    mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) })
+}
+
+pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
+    use libc::{dirent_t};
+    use libc::{opendir, readdir_r, closedir};
+
+    fn prune(root: &CString, dirs: Vec<Path>) -> Vec<Path> {
+        let root = unsafe { CString::new(root.as_ptr(), false) };
+        let root = Path::new(root);
+
+        dirs.into_iter().filter(|path| {
+            path.as_vec() != b"." && path.as_vec() != b".."
+        }).map(|path| root.join(path)).collect()
+    }
+
+    extern {
+        fn rust_dirent_t_size() -> libc::c_int;
+        fn rust_list_dir_val(ptr: *mut dirent_t) -> *const libc::c_char;
+    }
+
+    let size = unsafe { rust_dirent_t_size() };
+    let mut buf = Vec::<u8>::with_capacity(size as uint);
+    let ptr = buf.as_mut_slice().as_mut_ptr() as *mut dirent_t;
+
+    let p = p.to_c_str();
+    let dir_ptr = unsafe {opendir(p.as_ptr())};
+
+    if dir_ptr as uint != 0 {
+        let mut paths = vec!();
+        let mut entry_ptr = 0 as *mut dirent_t;
+        while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } {
+            if entry_ptr.is_null() { break }
+            let cstr = unsafe {
+                CString::new(rust_list_dir_val(entry_ptr), false)
+            };
+            paths.push(Path::new(cstr));
+        }
+        assert_eq!(unsafe { closedir(dir_ptr) }, 0);
+        Ok(prune(&p, paths))
+    } else {
+        Err(super::last_error())
+    }
+}
+
+pub fn unlink(p: &Path) -> IoResult<()> {
+    let p = p.to_c_str();
+    mkerr_libc(unsafe { libc::unlink(p.as_ptr()) })
+}
+
+pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
+    let old = old.to_c_str();
+    let new = new.to_c_str();
+    mkerr_libc(unsafe {
+        libc::rename(old.as_ptr(), new.as_ptr())
+    })
+}
+
+pub fn chmod(p: &Path, mode: uint) -> IoResult<()> {
+    let p = p.to_c_str();
+    mkerr_libc(retry(|| unsafe {
+        libc::chmod(p.as_ptr(), mode as libc::mode_t)
+    }))
+}
+
+pub fn rmdir(p: &Path) -> IoResult<()> {
+    let p = p.to_c_str();
+    mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) })
+}
+
+pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> {
+    let p = p.to_c_str();
+    mkerr_libc(retry(|| unsafe {
+        libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t)
+    }))
+}
+
+pub fn readlink(p: &Path) -> IoResult<Path> {
+    let c_path = p.to_c_str();
+    let p = c_path.as_ptr();
+    let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) };
+    if len == -1 {
+        len = 1024; // FIXME: read PATH_MAX from C ffi?
+    }
+    let mut buf: Vec<u8> = Vec::with_capacity(len as uint);
+    match unsafe {
+        libc::readlink(p, buf.as_ptr() as *mut libc::c_char,
+                       len as libc::size_t) as libc::c_int
+    } {
+        -1 => Err(super::last_error()),
+        n => {
+            assert!(n > 0);
+            unsafe { buf.set_len(n as uint); }
+            Ok(Path::new(buf))
+        }
+    }
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
+    let src = src.to_c_str();
+    let dst = dst.to_c_str();
+    mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })
+}
+
+pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
+    let src = src.to_c_str();
+    let dst = dst.to_c_str();
+    mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })
+}
+
+fn mkstat(stat: &libc::stat) -> FileStat {
+    // FileStat times are in milliseconds
+    fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 }
+
+    #[cfg(not(any(target_os = "linux", target_os = "android")))]
+    fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 }
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    fn flags(_stat: &libc::stat) -> u64 { 0 }
+
+    #[cfg(not(any(target_os = "linux", target_os = "android")))]
+    fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 }
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    fn gen(_stat: &libc::stat) -> u64 { 0 }
+
+    FileStat {
+        size: stat.st_size as u64,
+        kind: match (stat.st_mode as libc::mode_t) & libc::S_IFMT {
+            libc::S_IFREG => io::TypeFile,
+            libc::S_IFDIR => io::TypeDirectory,
+            libc::S_IFIFO => io::TypeNamedPipe,
+            libc::S_IFBLK => io::TypeBlockSpecial,
+            libc::S_IFLNK => io::TypeSymlink,
+            _ => io::TypeUnknown,
+        },
+        perm: FilePermission::from_bits_truncate(stat.st_mode as u32),
+        created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64),
+        modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64),
+        accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64),
+        unstable: UnstableFileStat {
+            device: stat.st_dev as u64,
+            inode: stat.st_ino as u64,
+            rdev: stat.st_rdev as u64,
+            nlink: stat.st_nlink as u64,
+            uid: stat.st_uid as u64,
+            gid: stat.st_gid as u64,
+            blksize: stat.st_blksize as u64,
+            blocks: stat.st_blocks as u64,
+            flags: flags(stat),
+            gen: gen(stat),
+        },
+    }
+}
+
+pub fn stat(p: &Path) -> IoResult<FileStat> {
+    let p = p.to_c_str();
+    let mut stat: libc::stat = unsafe { mem::zeroed() };
+    match unsafe { libc::stat(p.as_ptr(), &mut stat) } {
+        0 => Ok(mkstat(&stat)),
+        _ => Err(super::last_error()),
+    }
+}
+
+pub fn lstat(p: &Path) -> IoResult<FileStat> {
+    let p = p.to_c_str();
+    let mut stat: libc::stat = unsafe { mem::zeroed() };
+    match unsafe { libc::lstat(p.as_ptr(), &mut stat) } {
+        0 => Ok(mkstat(&stat)),
+        _ => Err(super::last_error()),
+    }
+}
+
+pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
+    let p = p.to_c_str();
+    let buf = libc::utimbuf {
+        actime: (atime / 1000) as libc::time_t,
+        modtime: (mtime / 1000) as libc::time_t,
+    };
+    mkerr_libc(unsafe { libc::utime(p.as_ptr(), &buf) })
+}
+
+#[cfg(test)]
+mod tests {
+    use super::FileDesc;
+    use libc;
+    use os;
+    use prelude::*;
+
+    #[cfg_attr(target_os = "freebsd", ignore)] // hmm, maybe pipes have a tiny buffer
+    #[test]
+    fn test_file_desc() {
+        // Run this test with some pipes so we don't have to mess around with
+        // opening or closing files.
+        let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
+        let mut reader = FileDesc::new(reader, true);
+        let mut writer = FileDesc::new(writer, true);
+
+        writer.write(b"test").ok().unwrap();
+        let mut buf = [0u8, ..4];
+        match reader.read(buf) {
+            Ok(4) => {
+                assert_eq!(buf[0], 't' as u8);
+                assert_eq!(buf[1], 'e' as u8);
+                assert_eq!(buf[2], 's' as u8);
+                assert_eq!(buf[3], 't' as u8);
+            }
+            r => panic!("invalid read: {}", r),
+        }
+
+        assert!(writer.read(buf).is_err());
+        assert!(reader.write(buf).is_err());
+    }
+}
diff --git a/src/libstd/sys/unix/helper_signal.rs b/src/libstd/sys/unix/helper_signal.rs
new file mode 100644
index 00000000000..a806bea2568
--- /dev/null
+++ b/src/libstd/sys/unix/helper_signal.rs
@@ -0,0 +1,29 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use libc;
+use os;
+
+use sys::fs::FileDesc;
+
+pub type signal = libc::c_int;
+
+pub fn new() -> (signal, signal) {
+    let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
+    (reader, writer)
+}
+
+pub fn signal(fd: libc::c_int) {
+    FileDesc::new(fd, false).write([0]).ok().unwrap();
+}
+
+pub fn close(fd: libc::c_int) {
+    let _fd = FileDesc::new(fd, true);
+}
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
new file mode 100644
index 00000000000..d3f55d59534
--- /dev/null
+++ b/src/libstd/sys/unix/mod.rs
@@ -0,0 +1,146 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(missing_doc)]
+#![allow(non_camel_case_types)]
+#![allow(unused_imports)]
+#![allow(dead_code)]
+#![allow(unused_unsafe)]
+#![allow(unused_mut)]
+
+extern crate libc;
+
+use num;
+use prelude::*;
+use io::{mod, IoResult, IoError};
+use sys_common::mkerr_libc;
+
+macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
+    static $name: Helper<$m> = Helper {
+        lock: ::rt::mutex::NATIVE_MUTEX_INIT,
+        chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
+        signal: ::cell::UnsafeCell { value: 0 },
+        initialized: ::cell::UnsafeCell { value: false },
+    };
+) )
+
+pub mod c;
+pub mod fs;
+pub mod os;
+pub mod tcp;
+pub mod udp;
+pub mod pipe;
+pub mod helper_signal;
+pub mod process;
+pub mod timer;
+pub mod tty;
+
+pub mod addrinfo {
+    pub use sys_common::net::get_host_addresses;
+}
+
+// FIXME: move these to c module
+pub type sock_t = self::fs::fd_t;
+pub type wrlen = libc::size_t;
+pub type msglen_t = libc::size_t;
+pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); }
+
+pub fn last_error() -> IoError {
+    decode_error_detailed(os::errno() as i32)
+}
+
+pub fn last_net_error() -> IoError {
+    last_error()
+}
+
+extern "system" {
+    fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
+}
+
+pub fn last_gai_error(s: libc::c_int) -> IoError {
+    use c_str::CString;
+
+    let mut err = decode_error(s);
+    err.detail = Some(unsafe {
+        CString::new(gai_strerror(s), false).as_str().unwrap().to_string()
+    });
+    err
+}
+
+/// Convert an `errno` value into a high-level error variant and description.
+pub fn decode_error(errno: i32) -> IoError {
+    // FIXME: this should probably be a bit more descriptive...
+    let (kind, desc) = match errno {
+        libc::EOF => (io::EndOfFile, "end of file"),
+        libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"),
+        libc::ECONNRESET => (io::ConnectionReset, "connection reset"),
+        libc::EPERM | libc::EACCES =>
+            (io::PermissionDenied, "permission denied"),
+        libc::EPIPE => (io::BrokenPipe, "broken pipe"),
+        libc::ENOTCONN => (io::NotConnected, "not connected"),
+        libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"),
+        libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
+        libc::EADDRINUSE => (io::ConnectionRefused, "address in use"),
+        libc::ENOENT => (io::FileNotFound, "no such file or directory"),
+        libc::EISDIR => (io::InvalidInput, "illegal operation on a directory"),
+        libc::ENOSYS => (io::IoUnavailable, "function not implemented"),
+        libc::EINVAL => (io::InvalidInput, "invalid argument"),
+        libc::ENOTTY =>
+            (io::MismatchedFileTypeForOperation,
+             "file descriptor is not a TTY"),
+        libc::ETIMEDOUT => (io::TimedOut, "operation timed out"),
+        libc::ECANCELED => (io::TimedOut, "operation aborted"),
+
+        // These two constants can have the same value on some systems,
+        // but different values on others, so we can't use a match
+        // clause
+        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+            (io::ResourceUnavailable, "resource temporarily unavailable"),
+
+        _ => (io::OtherIoError, "unknown error")
+    };
+    IoError { kind: kind, desc: desc, detail: None }
+}
+
+pub fn decode_error_detailed(errno: i32) -> IoError {
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+#[inline]
+pub fn retry<I: PartialEq + num::One + Neg<I>> (f: || -> I) -> I {
+    let minus_one = -num::one::<I>();
+    loop {
+        let n = f();
+        if n == minus_one && os::errno() == libc::EINTR as int { }
+        else { return n }
+    }
+}
+
+pub fn ms_to_timeval(ms: u64) -> libc::timeval {
+    libc::timeval {
+        tv_sec: (ms / 1000) as libc::time_t,
+        tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
+    }
+}
+
+pub fn wouldblock() -> bool {
+    let err = os::errno();
+    err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
+}
+
+pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
+    let set = nb as libc::c_int;
+    mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
+}
+
+// nothing needed on unix platforms
+pub fn init_net() {}
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
new file mode 100644
index 00000000000..4e495f043bc
--- /dev/null
+++ b/src/libstd/sys/unix/os.rs
@@ -0,0 +1,112 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use libc;
+use libc::{c_int, c_char};
+use prelude::*;
+use io::IoResult;
+use sys::fs::FileDesc;
+
+use os::TMPBUF_SZ;
+
+/// Returns the platform-specific value of errno
+pub fn errno() -> int {
+    #[cfg(any(target_os = "macos",
+              target_os = "ios",
+              target_os = "freebsd"))]
+    fn errno_location() -> *const c_int {
+        extern {
+            fn __error() -> *const c_int;
+        }
+        unsafe {
+            __error()
+        }
+    }
+
+    #[cfg(target_os = "dragonfly")]
+    fn errno_location() -> *const c_int {
+        extern {
+            fn __dfly_error() -> *const c_int;
+        }
+        unsafe {
+            __dfly_error()
+        }
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    fn errno_location() -> *const c_int {
+        extern {
+            fn __errno_location() -> *const c_int;
+        }
+        unsafe {
+            __errno_location()
+        }
+    }
+
+    unsafe {
+        (*errno_location()) as int
+    }
+}
+
+/// Get a detailed string description for the given error number
+pub fn error_string(errno: i32) -> String {
+    #[cfg(any(target_os = "macos",
+              target_os = "ios",
+              target_os = "android",
+              target_os = "freebsd",
+              target_os = "dragonfly"))]
+    fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
+                  -> c_int {
+        extern {
+            fn strerror_r(errnum: c_int, buf: *mut c_char,
+                          buflen: libc::size_t) -> c_int;
+        }
+        unsafe {
+            strerror_r(errnum, buf, buflen)
+        }
+    }
+
+    // GNU libc provides a non-compliant version of strerror_r by default
+    // and requires macros to instead use the POSIX compliant variant.
+    // So we just use __xpg_strerror_r which is always POSIX compliant
+    #[cfg(target_os = "linux")]
+    fn strerror_r(errnum: c_int, buf: *mut c_char,
+                  buflen: libc::size_t) -> c_int {
+        extern {
+            fn __xpg_strerror_r(errnum: c_int,
+                                buf: *mut c_char,
+                                buflen: libc::size_t)
+                                -> c_int;
+        }
+        unsafe {
+            __xpg_strerror_r(errnum, buf, buflen)
+        }
+    }
+
+    let mut buf = [0 as c_char, ..TMPBUF_SZ];
+
+    let p = buf.as_mut_ptr();
+    unsafe {
+        if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 {
+            panic!("strerror_r failure");
+        }
+
+        ::string::raw::from_buf(p as *const u8)
+    }
+}
+
+pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
+    let mut fds = [0, ..2];
+    if libc::pipe(fds.as_mut_ptr()) == 0 {
+        Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
+    } else {
+        Err(super::last_error())
+    }
+}
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
new file mode 100644
index 00000000000..67384848a94
--- /dev/null
+++ b/src/libstd/sys/unix/pipe.rs
@@ -0,0 +1,321 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use alloc::arc::Arc;
+use libc;
+use c_str::CString;
+use mem;
+use rt::mutex;
+use sync::atomic;
+use io::{mod, IoResult, IoError};
+use prelude::*;
+
+use sys::{mod, timer, retry, c, set_nonblocking, wouldblock};
+use sys::fs::{fd_t, FileDesc};
+use sys_common::net::*;
+use sys_common::{eof, mkerr_libc};
+
+fn unix_socket(ty: libc::c_int) -> IoResult<fd_t> {
+    match unsafe { libc::socket(libc::AF_UNIX, ty, 0) } {
+        -1 => Err(super::last_error()),
+        fd => Ok(fd)
+    }
+}
+
+fn addr_to_sockaddr_un(addr: &CString,
+                       storage: &mut libc::sockaddr_storage)
+                       -> IoResult<libc::socklen_t> {
+    // the sun_path length is limited to SUN_LEN (with null)
+    assert!(mem::size_of::<libc::sockaddr_storage>() >=
+            mem::size_of::<libc::sockaddr_un>());
+    let s = unsafe { &mut *(storage as *mut _ as *mut libc::sockaddr_un) };
+
+    let len = addr.len();
+    if len > s.sun_path.len() - 1 {
+        return Err(IoError {
+            kind: io::InvalidInput,
+            desc: "invalid argument: path must be smaller than SUN_LEN",
+            detail: None,
+        })
+    }
+    s.sun_family = libc::AF_UNIX as libc::sa_family_t;
+    for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) {
+        *slot = value;
+    }
+
+    // count the null terminator
+    let len = mem::size_of::<libc::sa_family_t>() + len + 1;
+    return Ok(len as libc::socklen_t);
+}
+
+struct Inner {
+    fd: fd_t,
+
+    // Unused on Linux, where this lock is not necessary.
+    #[allow(dead_code)]
+    lock: mutex::NativeMutex
+}
+
+impl Inner {
+    fn new(fd: fd_t) -> Inner {
+        Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } }
+    }
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) { unsafe { let _ = libc::close(self.fd); } }
+}
+
+fn connect(addr: &CString, ty: libc::c_int,
+           timeout: Option<u64>) -> IoResult<Inner> {
+    let mut storage = unsafe { mem::zeroed() };
+    let len = try!(addr_to_sockaddr_un(addr, &mut storage));
+    let inner = Inner::new(try!(unix_socket(ty)));
+    let addrp = &storage as *const _ as *const libc::sockaddr;
+
+    match timeout {
+        None => {
+            match retry(|| unsafe { libc::connect(inner.fd, addrp, len) }) {
+                -1 => Err(super::last_error()),
+                _  => Ok(inner)
+            }
+        }
+        Some(timeout_ms) => {
+            try!(connect_timeout(inner.fd, addrp, len, timeout_ms));
+            Ok(inner)
+        }
+    }
+}
+
+fn bind(addr: &CString, ty: libc::c_int) -> IoResult<Inner> {
+    let mut storage = unsafe { mem::zeroed() };
+    let len = try!(addr_to_sockaddr_un(addr, &mut storage));
+    let inner = Inner::new(try!(unix_socket(ty)));
+    let addrp = &storage as *const _ as *const libc::sockaddr;
+    match unsafe {
+        libc::bind(inner.fd, addrp, len)
+    } {
+        -1 => Err(super::last_error()),
+        _  => Ok(inner)
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixStream {
+    inner: Arc<Inner>,
+    read_deadline: u64,
+    write_deadline: u64,
+}
+
+impl UnixStream {
+    pub fn connect(addr: &CString,
+                   timeout: Option<u64>) -> IoResult<UnixStream> {
+        connect(addr, libc::SOCK_STREAM, timeout).map(|inner| {
+            UnixStream::new(Arc::new(inner))
+        })
+    }
+
+    fn new(inner: Arc<Inner>) -> UnixStream {
+        UnixStream {
+            inner: inner,
+            read_deadline: 0,
+            write_deadline: 0,
+        }
+    }
+
+    fn fd(&self) -> fd_t { self.inner.fd }
+
+    #[cfg(target_os = "linux")]
+    fn lock_nonblocking(&self) {}
+
+    #[cfg(not(target_os = "linux"))]
+    fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
+        let ret = Guard {
+            fd: self.fd(),
+            guard: unsafe { self.inner.lock.lock() },
+        };
+        assert!(set_nonblocking(self.fd(), true).is_ok());
+        ret
+    }
+
+    pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        let fd = self.fd();
+        let dolock = || self.lock_nonblocking();
+        let doread = |nb| unsafe {
+            let flags = if nb {c::MSG_DONTWAIT} else {0};
+            libc::recv(fd,
+                       buf.as_mut_ptr() as *mut libc::c_void,
+                       buf.len() as libc::size_t,
+                       flags) as libc::c_int
+        };
+        read(fd, self.read_deadline, dolock, doread)
+    }
+
+    pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        let fd = self.fd();
+        let dolock = || self.lock_nonblocking();
+        let dowrite = |nb: bool, buf: *const u8, len: uint| unsafe {
+            let flags = if nb {c::MSG_DONTWAIT} else {0};
+            libc::send(fd,
+                       buf as *const _,
+                       len as libc::size_t,
+                       flags) as i64
+        };
+        match write(fd, self.write_deadline, buf, true, dolock, dowrite) {
+            Ok(_) => Ok(()),
+            Err(e) => Err(e)
+        }
+    }
+
+    pub fn close_write(&mut self) -> IoResult<()> {
+        mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
+    }
+
+    pub fn close_read(&mut self) -> IoResult<()> {
+        mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+        self.read_deadline = deadline;
+        self.write_deadline = deadline;
+    }
+
+    pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
+        self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+
+    pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
+        self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+}
+
+impl Clone for UnixStream {
+    fn clone(&self) -> UnixStream {
+        UnixStream::new(self.inner.clone())
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Listener
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixListener {
+    inner: Inner,
+    path: CString,
+}
+
+impl UnixListener {
+    pub fn bind(addr: &CString) -> IoResult<UnixListener> {
+        bind(addr, libc::SOCK_STREAM).map(|fd| {
+            UnixListener { inner: fd, path: addr.clone() }
+        })
+    }
+
+    fn fd(&self) -> fd_t { self.inner.fd }
+
+    pub fn listen(self) -> IoResult<UnixAcceptor> {
+        match unsafe { libc::listen(self.fd(), 128) } {
+            -1 => Err(super::last_error()),
+
+            _ => {
+                let (reader, writer) = try!(unsafe { sys::os::pipe() });
+                try!(set_nonblocking(reader.fd(), true));
+                try!(set_nonblocking(writer.fd(), true));
+                try!(set_nonblocking(self.fd(), true));
+                Ok(UnixAcceptor {
+                    inner: Arc::new(AcceptorInner {
+                        listener: self,
+                        reader: reader,
+                        writer: writer,
+                        closed: atomic::AtomicBool::new(false),
+                    }),
+                    deadline: 0,
+                })
+            }
+        }
+    }
+}
+
+pub struct UnixAcceptor {
+    inner: Arc<AcceptorInner>,
+    deadline: u64,
+}
+
+struct AcceptorInner {
+    listener: UnixListener,
+    reader: FileDesc,
+    writer: FileDesc,
+    closed: atomic::AtomicBool,
+}
+
+impl UnixAcceptor {
+    fn fd(&self) -> fd_t { self.inner.listener.fd() }
+
+    pub fn accept(&mut self) -> IoResult<UnixStream> {
+        let deadline = if self.deadline == 0 {None} else {Some(self.deadline)};
+
+        while !self.inner.closed.load(atomic::SeqCst) {
+            unsafe {
+                let mut storage: libc::sockaddr_storage = mem::zeroed();
+                let storagep = &mut storage as *mut libc::sockaddr_storage;
+                let size = mem::size_of::<libc::sockaddr_storage>();
+                let mut size = size as libc::socklen_t;
+                match retry(|| {
+                    libc::accept(self.fd(),
+                                 storagep as *mut libc::sockaddr,
+                                 &mut size as *mut libc::socklen_t) as libc::c_int
+                }) {
+                    -1 if wouldblock() => {}
+                    -1 => return Err(super::last_error()),
+                    fd => return Ok(UnixStream::new(Arc::new(Inner::new(fd)))),
+                }
+            }
+            try!(await([self.fd(), self.inner.reader.fd()],
+                             deadline, Readable));
+        }
+
+        Err(eof())
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+
+    pub fn close_accept(&mut self) -> IoResult<()> {
+        self.inner.closed.store(true, atomic::SeqCst);
+        let fd = FileDesc::new(self.inner.writer.fd(), false);
+        match fd.write([0]) {
+            Ok(..) => Ok(()),
+            Err(..) if wouldblock() => Ok(()),
+            Err(e) => Err(e),
+        }
+    }
+}
+
+impl Clone for UnixAcceptor {
+    fn clone(&self) -> UnixAcceptor {
+        UnixAcceptor { inner: self.inner.clone(), deadline: 0 }
+    }
+}
+
+impl Drop for UnixListener {
+    fn drop(&mut self) {
+        // Unlink the path to the socket to ensure that it doesn't linger. We're
+        // careful to unlink the path before we close the file descriptor to
+        // prevent races where we unlink someone else's path.
+        unsafe {
+            let _ = libc::unlink(self.path.as_ptr());
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs
new file mode 100644
index 00000000000..0965d98d9b0
--- /dev/null
+++ b/src/libstd/sys/unix/process.rs
@@ -0,0 +1,587 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use libc::{mod, pid_t, c_void, c_int};
+use c_str::CString;
+use io::{mod, IoResult, IoError};
+use mem;
+use os;
+use ptr;
+use prelude::*;
+use io::process::{ProcessExit, ExitStatus, ExitSignal};
+use collections;
+use path::BytesContainer;
+use hash::Hash;
+
+use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval};
+use sys::fs::FileDesc;
+use sys_common::helper_thread::Helper;
+use sys_common::{AsFileDesc, mkerr_libc, timeout};
+
+pub use sys_common::ProcessConfig;
+
+helper_init!(static HELPER: Helper<Req>)
+
+/// The unique id of the process (this should never be negative).
+pub struct Process {
+    pub pid: pid_t
+}
+
+enum Req {
+    NewChild(libc::pid_t, Sender<ProcessExit>, u64),
+}
+
+impl Process {
+    pub fn id(&self) -> pid_t {
+        self.pid
+    }
+
+    pub unsafe fn kill(&self, signal: int) -> IoResult<()> {
+        Process::killpid(self.pid, signal)
+    }
+
+    pub unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> {
+        let r = libc::funcs::posix88::signal::kill(pid, signal as c_int);
+        mkerr_libc(r)
+    }
+
+    pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
+                              out_fd: Option<P>, err_fd: Option<P>)
+                              -> IoResult<Process>
+        where C: ProcessConfig<K, V>, P: AsFileDesc,
+              K: BytesContainer + Eq + Hash, V: BytesContainer
+    {
+        use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
+        use libc::funcs::bsd44::getdtablesize;
+
+        mod rustrt {
+            extern {
+                pub fn rust_unset_sigprocmask();
+            }
+        }
+
+        #[cfg(target_os = "macos")]
+        unsafe fn set_environ(envp: *const c_void) {
+            extern { fn _NSGetEnviron() -> *mut *const c_void; }
+
+            *_NSGetEnviron() = envp;
+        }
+        #[cfg(not(target_os = "macos"))]
+        unsafe fn set_environ(envp: *const c_void) {
+            extern { static mut environ: *const c_void; }
+            environ = envp;
+        }
+
+        unsafe fn set_cloexec(fd: c_int) {
+            let ret = c::ioctl(fd, c::FIOCLEX);
+            assert_eq!(ret, 0);
+        }
+
+        let dirp = cfg.cwd().map(|c| c.as_ptr()).unwrap_or(ptr::null());
+
+        // temporary until unboxed closures land
+        let cfg = unsafe {
+            mem::transmute::<&ProcessConfig<K,V>,&'static ProcessConfig<K,V>>(cfg)
+        };
+
+        with_envp(cfg.env(), proc(envp) {
+            with_argv(cfg.program(), cfg.args(), proc(argv) unsafe {
+                let (input, mut output) = try!(sys::os::pipe());
+
+                // We may use this in the child, so perform allocations before the
+                // fork
+                let devnull = "/dev/null".to_c_str();
+
+                set_cloexec(output.fd());
+
+                let pid = fork();
+                if pid < 0 {
+                    return Err(super::last_error())
+                } else if pid > 0 {
+                    drop(output);
+                    let mut bytes = [0, ..4];
+                    return match input.read(bytes) {
+                        Ok(4) => {
+                            let errno = (bytes[0] as i32 << 24) |
+                                        (bytes[1] as i32 << 16) |
+                                        (bytes[2] as i32 <<  8) |
+                                        (bytes[3] as i32 <<  0);
+                            Err(super::decode_error(errno))
+                        }
+                        Err(..) => Ok(Process { pid: pid }),
+                        Ok(..) => panic!("short read on the cloexec pipe"),
+                    };
+                }
+
+                // And at this point we've reached a special time in the life of the
+                // child. The child must now be considered hamstrung and unable to
+                // do anything other than syscalls really. Consider the following
+                // scenario:
+                //
+                //      1. Thread A of process 1 grabs the malloc() mutex
+                //      2. Thread B of process 1 forks(), creating thread C
+                //      3. Thread C of process 2 then attempts to malloc()
+                //      4. The memory of process 2 is the same as the memory of
+                //         process 1, so the mutex is locked.
+                //
+                // This situation looks a lot like deadlock, right? It turns out
+                // that this is what pthread_atfork() takes care of, which is
+                // presumably implemented across platforms. The first thing that
+                // threads to *before* forking is to do things like grab the malloc
+                // mutex, and then after the fork they unlock it.
+                //
+                // Despite this information, libnative's spawn has been witnessed to
+                // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but
+                // all collected backtraces point at malloc/free traffic in the
+                // child spawned process.
+                //
+                // For this reason, the block of code below should contain 0
+                // invocations of either malloc of free (or their related friends).
+                //
+                // As an example of not having malloc/free traffic, we don't close
+                // this file descriptor by dropping the FileDesc (which contains an
+                // allocation). Instead we just close it manually. This will never
+                // have the drop glue anyway because this code never returns (the
+                // child will either exec() or invoke libc::exit)
+                let _ = libc::close(input.fd());
+
+                fn fail(output: &mut FileDesc) -> ! {
+                    let errno = sys::os::errno();
+                    let bytes = [
+                        (errno >> 24) as u8,
+                        (errno >> 16) as u8,
+                        (errno >>  8) as u8,
+                        (errno >>  0) as u8,
+                    ];
+                    assert!(output.write(bytes).is_ok());
+                    unsafe { libc::_exit(1) }
+                }
+
+                rustrt::rust_unset_sigprocmask();
+
+                // If a stdio file descriptor is set to be ignored (via a -1 file
+                // descriptor), then we don't actually close it, but rather open
+                // up /dev/null into that file descriptor. Otherwise, the first file
+                // descriptor opened up in the child would be numbered as one of the
+                // stdio file descriptors, which is likely to wreak havoc.
+                let setup = |src: Option<P>, dst: c_int| {
+                    let src = match src {
+                        None => {
+                            let flags = if dst == libc::STDIN_FILENO {
+                                libc::O_RDONLY
+                            } else {
+                                libc::O_RDWR
+                            };
+                            libc::open(devnull.as_ptr(), flags, 0)
+                        }
+                        Some(obj) => {
+                            let fd = obj.as_fd().fd();
+                            // Leak the memory and the file descriptor. We're in the
+                            // child now an all our resources are going to be
+                            // cleaned up very soon
+                            mem::forget(obj);
+                            fd
+                        }
+                    };
+                    src != -1 && retry(|| dup2(src, dst)) != -1
+                };
+
+                if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) }
+                if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) }
+                if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) }
+
+                // close all other fds
+                for fd in range(3, getdtablesize()).rev() {
+                    if fd != output.fd() {
+                        let _ = close(fd as c_int);
+                    }
+                }
+
+                match cfg.gid() {
+                    Some(u) => {
+                        if libc::setgid(u as libc::gid_t) != 0 {
+                            fail(&mut output);
+                        }
+                    }
+                    None => {}
+                }
+                match cfg.uid() {
+                    Some(u) => {
+                        // When dropping privileges from root, the `setgroups` call
+                        // will remove any extraneous groups. If we don't call this,
+                        // then even though our uid has dropped, we may still have
+                        // groups that enable us to do super-user things. This will
+                        // fail if we aren't root, so don't bother checking the
+                        // return value, this is just done as an optimistic
+                        // privilege dropping function.
+                        extern {
+                            fn setgroups(ngroups: libc::c_int,
+                                         ptr: *const libc::c_void) -> libc::c_int;
+                        }
+                        let _ = setgroups(0, 0 as *const libc::c_void);
+
+                        if libc::setuid(u as libc::uid_t) != 0 {
+                            fail(&mut output);
+                        }
+                    }
+                    None => {}
+                }
+                if cfg.detach() {
+                    // Don't check the error of setsid because it fails if we're the
+                    // process leader already. We just forked so it shouldn't return
+                    // error, but ignore it anyway.
+                    let _ = libc::setsid();
+                }
+                if !dirp.is_null() && chdir(dirp) == -1 {
+                    fail(&mut output);
+                }
+                if !envp.is_null() {
+                    set_environ(envp);
+                }
+                let _ = execvp(*argv, argv as *mut _);
+                fail(&mut output);
+            })
+        })
+    }
+
+    pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> {
+        use std::cmp;
+        use std::comm;
+
+        static mut WRITE_FD: libc::c_int = 0;
+
+        let mut status = 0 as c_int;
+        if deadline == 0 {
+            return match retry(|| unsafe { c::waitpid(self.pid, &mut status, 0) }) {
+                -1 => panic!("unknown waitpid error: {}", super::last_error()),
+                _ => Ok(translate_status(status)),
+            }
+        }
+
+        // On unix, wait() and its friends have no timeout parameters, so there is
+        // no way to time out a thread in wait(). From some googling and some
+        // thinking, it appears that there are a few ways to handle timeouts in
+        // wait(), but the only real reasonable one for a multi-threaded program is
+        // to listen for SIGCHLD.
+        //
+        // With this in mind, the waiting mechanism with a timeout barely uses
+        // waitpid() at all. There are a few times that waitpid() is invoked with
+        // WNOHANG, but otherwise all the necessary blocking is done by waiting for
+        // a SIGCHLD to arrive (and that blocking has a timeout). Note, however,
+        // that waitpid() is still used to actually reap the child.
+        //
+        // Signal handling is super tricky in general, and this is no exception. Due
+        // to the async nature of SIGCHLD, we use the self-pipe trick to transmit
+        // data out of the signal handler to the rest of the application. The first
+        // idea would be to have each thread waiting with a timeout to read this
+        // output file descriptor, but a write() is akin to a signal(), not a
+        // broadcast(), so it would only wake up one thread, and possibly the wrong
+        // thread. Hence a helper thread is used.
+        //
+        // The helper thread here is responsible for farming requests for a
+        // waitpid() with a timeout, and then processing all of the wait requests.
+        // By guaranteeing that only this helper thread is reading half of the
+        // self-pipe, we're sure that we'll never lose a SIGCHLD. This helper thread
+        // is also responsible for select() to wait for incoming messages or
+        // incoming SIGCHLD messages, along with passing an appropriate timeout to
+        // select() to wake things up as necessary.
+        //
+        // The ordering of the following statements is also very purposeful. First,
+        // we must be guaranteed that the helper thread is booted and available to
+        // receive SIGCHLD signals, and then we must also ensure that we do a
+        // nonblocking waitpid() at least once before we go ask the sigchld helper.
+        // This prevents the race where the child exits, we boot the helper, and
+        // then we ask for the child's exit status (never seeing a sigchld).
+        //
+        // The actual communication between the helper thread and this thread is
+        // quite simple, just a channel moving data around.
+
+        unsafe { HELPER.boot(register_sigchld, waitpid_helper) }
+
+        match self.try_wait() {
+            Some(ret) => return Ok(ret),
+            None => {}
+        }
+
+        let (tx, rx) = channel();
+        unsafe { HELPER.send(NewChild(self.pid, tx, deadline)); }
+        return match rx.recv_opt() {
+            Ok(e) => Ok(e),
+            Err(()) => Err(timeout("wait timed out")),
+        };
+
+        // Register a new SIGCHLD handler, returning the reading half of the
+        // self-pipe plus the old handler registered (return value of sigaction).
+        //
+        // Be sure to set up the self-pipe first because as soon as we register a
+        // handler we're going to start receiving signals.
+        fn register_sigchld() -> (libc::c_int, c::sigaction) {
+            unsafe {
+                let mut pipes = [0, ..2];
+                assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0);
+                set_nonblocking(pipes[0], true).ok().unwrap();
+                set_nonblocking(pipes[1], true).ok().unwrap();
+                WRITE_FD = pipes[1];
+
+                let mut old: c::sigaction = mem::zeroed();
+                let mut new: c::sigaction = mem::zeroed();
+                new.sa_handler = sigchld_handler;
+                new.sa_flags = c::SA_NOCLDSTOP;
+                assert_eq!(c::sigaction(c::SIGCHLD, &new, &mut old), 0);
+                (pipes[0], old)
+            }
+        }
+
+        // Helper thread for processing SIGCHLD messages
+        fn waitpid_helper(input: libc::c_int,
+                          messages: Receiver<Req>,
+                          (read_fd, old): (libc::c_int, c::sigaction)) {
+            set_nonblocking(input, true).ok().unwrap();
+            let mut set: c::fd_set = unsafe { mem::zeroed() };
+            let mut tv: libc::timeval;
+            let mut active = Vec::<(libc::pid_t, Sender<ProcessExit>, u64)>::new();
+            let max = cmp::max(input, read_fd) + 1;
+
+            'outer: loop {
+                // Figure out the timeout of our syscall-to-happen. If we're waiting
+                // for some processes, then they'll have a timeout, otherwise we
+                // wait indefinitely for a message to arrive.
+                //
+                // FIXME: sure would be nice to not have to scan the entire array
+                let min = active.iter().map(|a| *a.ref2()).enumerate().min_by(|p| {
+                    p.val1()
+                });
+                let (p, idx) = match min {
+                    Some((idx, deadline)) => {
+                        let now = sys::timer::now();
+                        let ms = if now < deadline {deadline - now} else {0};
+                        tv = ms_to_timeval(ms);
+                        (&mut tv as *mut _, idx)
+                    }
+                    None => (ptr::null_mut(), -1),
+                };
+
+                // Wait for something to happen
+                c::fd_set(&mut set, input);
+                c::fd_set(&mut set, read_fd);
+                match unsafe { c::select(max, &mut set, ptr::null_mut(),
+                                         ptr::null_mut(), p) } {
+                    // interrupted, retry
+                    -1 if os::errno() == libc::EINTR as uint => continue,
+
+                    // We read something, break out and process
+                    1 | 2 => {}
+
+                    // Timeout, the pending request is removed
+                    0 => {
+                        drop(active.remove(idx));
+                        continue
+                    }
+
+                    n => panic!("error in select {} ({})", os::errno(), n),
+                }
+
+                // Process any pending messages
+                if drain(input) {
+                    loop {
+                        match messages.try_recv() {
+                            Ok(NewChild(pid, tx, deadline)) => {
+                                active.push((pid, tx, deadline));
+                            }
+                            Err(comm::Disconnected) => {
+                                assert!(active.len() == 0);
+                                break 'outer;
+                            }
+                            Err(comm::Empty) => break,
+                        }
+                    }
+                }
+
+                // If a child exited (somehow received SIGCHLD), then poll all
+                // children to see if any of them exited.
+                //
+                // We also attempt to be responsible netizens when dealing with
+                // SIGCHLD by invoking any previous SIGCHLD handler instead of just
+                // ignoring any previous SIGCHLD handler. Note that we don't provide
+                // a 1:1 mapping of our handler invocations to the previous handler
+                // invocations because we drain the `read_fd` entirely. This is
+                // probably OK because the kernel is already allowed to coalesce
+                // simultaneous signals, we're just doing some extra coalescing.
+                //
+                // Another point of note is that this likely runs the signal handler
+                // on a different thread than the one that received the signal. I
+                // *think* this is ok at this time.
+                //
+                // The main reason for doing this is to allow stdtest to run native
+                // tests as well. Both libgreen and libnative are running around
+                // with process timeouts, but libgreen should get there first
+                // (currently libuv doesn't handle old signal handlers).
+                if drain(read_fd) {
+                    let i: uint = unsafe { mem::transmute(old.sa_handler) };
+                    if i != 0 {
+                        assert!(old.sa_flags & c::SA_SIGINFO == 0);
+                        (old.sa_handler)(c::SIGCHLD);
+                    }
+
+                    // FIXME: sure would be nice to not have to scan the entire
+                    //        array...
+                    active.retain(|&(pid, ref tx, _)| {
+                        let pr = Process { pid: pid };
+                        match pr.try_wait() {
+                            Some(msg) => { tx.send(msg); false }
+                            None => true,
+                        }
+                    });
+                }
+            }
+
+            // Once this helper thread is done, we re-register the old sigchld
+            // handler and close our intermediate file descriptors.
+            unsafe {
+                assert_eq!(c::sigaction(c::SIGCHLD, &old, ptr::null_mut()), 0);
+                let _ = libc::close(read_fd);
+                let _ = libc::close(WRITE_FD);
+                WRITE_FD = -1;
+            }
+        }
+
+        // Drain all pending data from the file descriptor, returning if any data
+        // could be drained. This requires that the file descriptor is in
+        // nonblocking mode.
+        fn drain(fd: libc::c_int) -> bool {
+            let mut ret = false;
+            loop {
+                let mut buf = [0u8, ..1];
+                match unsafe {
+                    libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void,
+                               buf.len() as libc::size_t)
+                } {
+                    n if n > 0 => { ret = true; }
+                    0 => return true,
+                    -1 if wouldblock() => return ret,
+                    n => panic!("bad read {} ({})", os::last_os_error(), n),
+                }
+            }
+        }
+
+        // Signal handler for SIGCHLD signals, must be async-signal-safe!
+        //
+        // This function will write to the writing half of the "self pipe" to wake
+        // up the helper thread if it's waiting. Note that this write must be
+        // nonblocking because if it blocks and the reader is the thread we
+        // interrupted, then we'll deadlock.
+        //
+        // When writing, if the write returns EWOULDBLOCK then we choose to ignore
+        // it. At that point we're guaranteed that there's something in the pipe
+        // which will wake up the other end at some point, so we just allow this
+        // signal to be coalesced with the pending signals on the pipe.
+        extern fn sigchld_handler(_signum: libc::c_int) {
+            let msg = 1i;
+            match unsafe {
+                libc::write(WRITE_FD, &msg as *const _ as *const libc::c_void, 1)
+            } {
+                1 => {}
+                -1 if wouldblock() => {} // see above comments
+                n => panic!("bad error on write fd: {} {}", n, os::errno()),
+            }
+        }
+    }
+
+    pub fn try_wait(&self) -> Option<ProcessExit> {
+        let mut status = 0 as c_int;
+        match retry(|| unsafe {
+            c::waitpid(self.pid, &mut status, c::WNOHANG)
+        }) {
+            n if n == self.pid => Some(translate_status(status)),
+            0 => None,
+            n => panic!("unknown waitpid error `{}`: {}", n,
+                       super::last_error()),
+        }
+    }
+}
+
+fn with_argv<T>(prog: &CString, args: &[CString],
+                cb: proc(*const *const libc::c_char) -> T) -> T {
+    let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1);
+
+    // Convert the CStrings into an array of pointers. Note: the
+    // lifetime of the various CStrings involved is guaranteed to be
+    // larger than the lifetime of our invocation of cb, but this is
+    // technically unsafe as the callback could leak these pointers
+    // out of our scope.
+    ptrs.push(prog.as_ptr());
+    ptrs.extend(args.iter().map(|tmp| tmp.as_ptr()));
+
+    // Add a terminating null pointer (required by libc).
+    ptrs.push(ptr::null());
+
+    cb(ptrs.as_ptr())
+}
+
+fn with_envp<K, V, T>(env: Option<&collections::HashMap<K, V>>,
+                      cb: proc(*const c_void) -> T) -> T
+    where K: BytesContainer + Eq + Hash, V: BytesContainer
+{
+    // On posixy systems we can pass a char** for envp, which is a
+    // null-terminated array of "k=v\0" strings. Since we must create
+    // these strings locally, yet expose a raw pointer to them, we
+    // create a temporary vector to own the CStrings that outlives the
+    // call to cb.
+    match env {
+        Some(env) => {
+            let mut tmps = Vec::with_capacity(env.len());
+
+            for pair in env.iter() {
+                let mut kv = Vec::new();
+                kv.push_all(pair.ref0().container_as_bytes());
+                kv.push('=' as u8);
+                kv.push_all(pair.ref1().container_as_bytes());
+                kv.push(0); // terminating null
+                tmps.push(kv);
+            }
+
+            // As with `with_argv`, this is unsafe, since cb could leak the pointers.
+            let mut ptrs: Vec<*const libc::c_char> =
+                tmps.iter()
+                    .map(|tmp| tmp.as_ptr() as *const libc::c_char)
+                    .collect();
+            ptrs.push(ptr::null());
+
+            cb(ptrs.as_ptr() as *const c_void)
+        }
+        _ => cb(ptr::null())
+    }
+}
+
+fn translate_status(status: c_int) -> ProcessExit {
+    #![allow(non_snake_case)]
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    mod imp {
+        pub fn WIFEXITED(status: i32) -> bool { (status & 0xff) == 0 }
+        pub fn WEXITSTATUS(status: i32) -> i32 { (status >> 8) & 0xff }
+        pub fn WTERMSIG(status: i32) -> i32 { status & 0x7f }
+    }
+
+    #[cfg(any(target_os = "macos",
+              target_os = "ios",
+              target_os = "freebsd",
+              target_os = "dragonfly"))]
+    mod imp {
+        pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
+        pub fn WEXITSTATUS(status: i32) -> i32 { status >> 8 }
+        pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 }
+    }
+
+    if imp::WIFEXITED(status) {
+        ExitStatus(imp::WEXITSTATUS(status) as int)
+    } else {
+        ExitSignal(imp::WTERMSIG(status) as int)
+    }
+}
diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs
new file mode 100644
index 00000000000..962475e4177
--- /dev/null
+++ b/src/libstd/sys/unix/tcp.rs
@@ -0,0 +1,157 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io::net::ip;
+use io::IoResult;
+use libc;
+use mem;
+use ptr;
+use prelude::*;
+use super::{last_error, last_net_error, retry, sock_t};
+use sync::{Arc, atomic};
+use sys::fs::FileDesc;
+use sys::{set_nonblocking, wouldblock};
+use sys;
+use sys_common;
+use sys_common::net::*;
+
+pub use sys_common::net::TcpStream;
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP listeners
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpListener {
+    pub inner: FileDesc,
+}
+
+impl TcpListener {
+    pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
+        let fd = try!(socket(addr, libc::SOCK_STREAM));
+        let ret = TcpListener { inner: FileDesc::new(fd, true) };
+
+        let mut storage = unsafe { mem::zeroed() };
+        let len = addr_to_sockaddr(addr, &mut storage);
+        let addrp = &storage as *const _ as *const libc::sockaddr;
+
+        // On platforms with Berkeley-derived sockets, this allows
+        // to quickly rebind a socket, without needing to wait for
+        // the OS to clean up the previous one.
+        try!(setsockopt(fd, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1 as libc::c_int));
+
+
+        match unsafe { libc::bind(fd, addrp, len) } {
+            -1 => Err(last_error()),
+            _ => Ok(ret),
+        }
+    }
+
+    pub fn fd(&self) -> sock_t { self.inner.fd() }
+
+    pub fn listen(self, backlog: int) -> IoResult<TcpAcceptor> {
+        match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
+            -1 => Err(last_net_error()),
+            _ => {
+                let (reader, writer) = try!(unsafe { sys::os::pipe() });
+                try!(set_nonblocking(reader.fd(), true));
+                try!(set_nonblocking(writer.fd(), true));
+                try!(set_nonblocking(self.fd(), true));
+                Ok(TcpAcceptor {
+                    inner: Arc::new(AcceptorInner {
+                        listener: self,
+                        reader: reader,
+                        writer: writer,
+                        closed: atomic::AtomicBool::new(false),
+                    }),
+                    deadline: 0,
+                })
+            }
+        }
+    }
+
+    pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
+        sockname(self.fd(), libc::getsockname)
+    }
+}
+
+pub struct TcpAcceptor {
+    inner: Arc<AcceptorInner>,
+    deadline: u64,
+}
+
+struct AcceptorInner {
+    listener: TcpListener,
+    reader: FileDesc,
+    writer: FileDesc,
+    closed: atomic::AtomicBool,
+}
+
+impl TcpAcceptor {
+    pub fn fd(&self) -> sock_t { self.inner.listener.fd() }
+
+    pub fn accept(&mut self) -> IoResult<TcpStream> {
+        // In implementing accept, the two main concerns are dealing with
+        // close_accept() and timeouts. The unix implementation is based on a
+        // nonblocking accept plus a call to select(). Windows ends up having
+        // an entirely separate implementation than unix, which is explained
+        // below.
+        //
+        // To implement timeouts, all blocking is done via select() instead of
+        // accept() by putting the socket in non-blocking mode. Because
+        // select() takes a timeout argument, we just pass through the timeout
+        // to select().
+        //
+        // To implement close_accept(), we have a self-pipe to ourselves which
+        // is passed to select() along with the socket being accepted on. The
+        // self-pipe is never written to unless close_accept() is called.
+        let deadline = if self.deadline == 0 {None} else {Some(self.deadline)};
+
+        while !self.inner.closed.load(atomic::SeqCst) {
+            match retry(|| unsafe {
+                libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut())
+            }) {
+                -1 if wouldblock() => {}
+                -1 => return Err(last_net_error()),
+                fd => return Ok(TcpStream::new(fd as sock_t)),
+            }
+            try!(await([self.fd(), self.inner.reader.fd()],
+                             deadline, Readable));
+        }
+
+        Err(sys_common::eof())
+    }
+
+    pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
+        sockname(self.fd(), libc::getsockname)
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        self.deadline = timeout.map(|a| sys::timer::now() + a).unwrap_or(0);
+    }
+
+    pub fn close_accept(&mut self) -> IoResult<()> {
+        self.inner.closed.store(true, atomic::SeqCst);
+        let fd = FileDesc::new(self.inner.writer.fd(), false);
+        match fd.write([0]) {
+            Ok(..) => Ok(()),
+            Err(..) if wouldblock() => Ok(()),
+            Err(e) => Err(e),
+        }
+    }
+}
+
+impl Clone for TcpAcceptor {
+    fn clone(&self) -> TcpAcceptor {
+        TcpAcceptor {
+            inner: self.inner.clone(),
+            deadline: 0,
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs
new file mode 100644
index 00000000000..a1e6ac3db7e
--- /dev/null
+++ b/src/libstd/sys/unix/timer.rs
@@ -0,0 +1,282 @@
+// 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.
+
+//! Timers for non-Linux/non-Windows OSes
+//!
+//! This module implements timers with a worker thread, select(), and a lot of
+//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate
+//! part is that I'm at a loss of what else to do one these OSes. This is also
+//! why Linux has a specialized timerfd implementation and windows has its own
+//! implementation (they're more accurate than this one).
+//!
+//! The basic idea is that there is a worker thread that's communicated to via a
+//! channel and a pipe, the pipe is used by the worker thread in a select()
+//! syscall with a timeout. The timeout is the "next timer timeout" while the
+//! channel is used to send data over to the worker thread.
+//!
+//! Whenever the call to select() times out, then a channel receives a message.
+//! Whenever the call returns that the file descriptor has information, then the
+//! channel from timers is drained, enqueuing all incoming requests.
+//!
+//! The actual implementation of the helper thread is a sorted array of
+//! timers in terms of target firing date. The target is the absolute time at
+//! which the timer should fire. Timers are then re-enqueued after a firing if
+//! the repeat boolean is set.
+//!
+//! Naturally, all this logic of adding times and keeping track of
+//! relative/absolute time is a little lossy and not quite exact. I've done the
+//! best I could to reduce the amount of calls to 'now()', but there's likely
+//! still inaccuracies trickling in here and there.
+//!
+//! One of the tricky parts of this implementation is that whenever a timer is
+//! acted upon, it must cancel whatever the previous action was (if one is
+//! active) in order to act like the other implementations of this timer. In
+//! order to do this, the timer's inner pointer is transferred to the worker
+//! thread. Whenever the timer is modified, it first takes ownership back from
+//! the worker thread in order to modify the same data structure. This has the
+//! side effect of "cancelling" the previous requests while allowing a
+//! re-enqueuing later on.
+//!
+//! Note that all time units in this file are in *milliseconds*.
+
+use libc;
+use mem;
+use os;
+use ptr;
+use sync::atomic;
+use comm;
+use sys::c;
+use sys::fs::FileDesc;
+use sys_common::helper_thread::Helper;
+use prelude::*;
+use io::IoResult;
+
+helper_init!(static HELPER: Helper<Req>)
+
+pub trait Callback {
+    fn call(&mut self);
+}
+
+pub struct Timer {
+    id: uint,
+    inner: Option<Box<Inner>>,
+}
+
+pub struct Inner {
+    cb: Option<Box<Callback + Send>>,
+    interval: u64,
+    repeat: bool,
+    target: u64,
+    id: uint,
+}
+
+pub enum Req {
+    // Add a new timer to the helper thread.
+    NewTimer(Box<Inner>),
+
+    // Remove a timer based on its id and then send it back on the channel
+    // provided
+    RemoveTimer(uint, Sender<Box<Inner>>),
+}
+
+// returns the current time (in milliseconds)
+pub fn now() -> u64 {
+    unsafe {
+        let mut now: libc::timeval = mem::zeroed();
+        assert_eq!(c::gettimeofday(&mut now, ptr::null_mut()), 0);
+        return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000;
+    }
+}
+
+fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
+    let mut set: c::fd_set = unsafe { mem::zeroed() };
+
+    let mut fd = FileDesc::new(input, true);
+    let mut timeout: libc::timeval = unsafe { mem::zeroed() };
+
+    // active timers are those which are able to be selected upon (and it's a
+    // sorted list, and dead timers are those which have expired, but ownership
+    // hasn't yet been transferred back to the timer itself.
+    let mut active: Vec<Box<Inner>> = vec![];
+    let mut dead = vec![];
+
+    // inserts a timer into an array of timers (sorted by firing time)
+    fn insert(t: Box<Inner>, active: &mut Vec<Box<Inner>>) {
+        match active.iter().position(|tm| tm.target > t.target) {
+            Some(pos) => { active.insert(pos, t); }
+            None => { active.push(t); }
+        }
+    }
+
+    // signals the first requests in the queue, possible re-enqueueing it.
+    fn signal(active: &mut Vec<Box<Inner>>,
+              dead: &mut Vec<(uint, Box<Inner>)>) {
+        let mut timer = match active.remove(0) {
+            Some(timer) => timer, None => return
+        };
+        let mut cb = timer.cb.take().unwrap();
+        cb.call();
+        if timer.repeat {
+            timer.cb = Some(cb);
+            timer.target += timer.interval;
+            insert(timer, active);
+        } else {
+            dead.push((timer.id, timer));
+        }
+    }
+
+    'outer: loop {
+        let timeout = if active.len() == 0 {
+            // Empty array? no timeout (wait forever for the next request)
+            ptr::null_mut()
+        } else {
+            let now = now();
+            // If this request has already expired, then signal it and go
+            // through another iteration
+            if active[0].target <= now {
+                signal(&mut active, &mut dead);
+                continue;
+            }
+
+            // The actual timeout listed in the requests array is an
+            // absolute date, so here we translate the absolute time to a
+            // relative time.
+            let tm = active[0].target - now;
+            timeout.tv_sec = (tm / 1000) as libc::time_t;
+            timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t;
+            &mut timeout as *mut libc::timeval
+        };
+
+        c::fd_set(&mut set, input);
+        match unsafe {
+            c::select(input + 1, &mut set, ptr::null_mut(),
+                      ptr::null_mut(), timeout)
+        } {
+            // timed out
+            0 => signal(&mut active, &mut dead),
+
+            // file descriptor write woke us up, we've got some new requests
+            1 => {
+                loop {
+                    match messages.try_recv() {
+                        Err(comm::Disconnected) => {
+                            assert!(active.len() == 0);
+                            break 'outer;
+                        }
+
+                        Ok(NewTimer(timer)) => insert(timer, &mut active),
+
+                        Ok(RemoveTimer(id, ack)) => {
+                            match dead.iter().position(|&(i, _)| id == i) {
+                                Some(i) => {
+                                    let (_, i) = dead.remove(i).unwrap();
+                                    ack.send(i);
+                                    continue
+                                }
+                                None => {}
+                            }
+                            let i = active.iter().position(|i| i.id == id);
+                            let i = i.expect("no timer found");
+                            let t = active.remove(i).unwrap();
+                            ack.send(t);
+                        }
+                        Err(..) => break
+                    }
+                }
+
+                // drain the file descriptor
+                let mut buf = [0];
+                assert_eq!(fd.read(buf).ok().unwrap(), 1);
+            }
+
+            -1 if os::errno() == libc::EINTR as uint => {}
+            n => panic!("helper thread failed in select() with error: {} ({})",
+                       n, os::last_os_error())
+        }
+    }
+}
+
+impl Timer {
+    pub fn new() -> IoResult<Timer> {
+        // See notes above regarding using int return value
+        // instead of ()
+        HELPER.boot(|| {}, helper);
+
+        static ID: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;
+        let id = ID.fetch_add(1, atomic::Relaxed);
+        Ok(Timer {
+            id: id,
+            inner: Some(box Inner {
+                cb: None,
+                interval: 0,
+                target: 0,
+                repeat: false,
+                id: id,
+            })
+        })
+    }
+
+    pub fn sleep(&mut self, ms: u64) {
+        let mut inner = self.inner();
+        inner.cb = None; // cancel any previous request
+        self.inner = Some(inner);
+
+        let mut to_sleep = libc::timespec {
+            tv_sec: (ms / 1000) as libc::time_t,
+            tv_nsec: ((ms % 1000) * 1000000) as libc::c_long,
+        };
+        while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 {
+            if os::errno() as int != libc::EINTR as int {
+                panic!("failed to sleep, but not because of EINTR?");
+            }
+        }
+    }
+
+    pub fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
+        let now = now();
+        let mut inner = self.inner();
+
+        inner.repeat = false;
+        inner.cb = Some(cb);
+        inner.interval = msecs;
+        inner.target = now + msecs;
+
+        HELPER.send(NewTimer(inner));
+    }
+
+    pub fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
+        let now = now();
+        let mut inner = self.inner();
+
+        inner.repeat = true;
+        inner.cb = Some(cb);
+        inner.interval = msecs;
+        inner.target = now + msecs;
+
+        HELPER.send(NewTimer(inner));
+    }
+
+    fn inner(&mut self) -> Box<Inner> {
+        match self.inner.take() {
+            Some(i) => i,
+            None => {
+                let (tx, rx) = channel();
+                HELPER.send(RemoveTimer(self.id, tx));
+                rx.recv()
+            }
+        }
+    }
+}
+
+impl Drop for Timer {
+    fn drop(&mut self) {
+        self.inner = Some(self.inner());
+    }
+}
diff --git a/src/libstd/sys/unix/tty.rs b/src/libstd/sys/unix/tty.rs
new file mode 100644
index 00000000000..28c17fd4966
--- /dev/null
+++ b/src/libstd/sys/unix/tty.rs
@@ -0,0 +1,47 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use sys::fs::FileDesc;
+use prelude::*;
+use libc::{mod, c_int};
+use io::{mod, IoResult, IoError};
+use sys_common;
+
+pub struct TTY {
+    pub fd: FileDesc,
+}
+
+impl TTY {
+    pub fn new(fd: c_int) -> IoResult<TTY> {
+        if unsafe { libc::isatty(fd) } != 0 {
+            Ok(TTY { fd: FileDesc::new(fd, true) })
+        } else {
+            Err(IoError {
+                kind: io::MismatchedFileTypeForOperation,
+                desc: "file descriptor is not a TTY",
+                detail: None,
+            })
+        }
+    }
+
+    pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        self.fd.read(buf)
+    }
+    pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.fd.write(buf)
+    }
+    pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
+        Err(sys_common::unimpl())
+    }
+    pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
+        Err(sys_common::unimpl())
+    }
+    pub fn isatty(&self) -> bool { false }
+}
diff --git a/src/libstd/sys/unix/udp.rs b/src/libstd/sys/unix/udp.rs
new file mode 100644
index 00000000000..50f8fb828ad
--- /dev/null
+++ b/src/libstd/sys/unix/udp.rs
@@ -0,0 +1,11 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use sys_common::net::UdpSocket;
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
new file mode 100644
index 00000000000..b8e9b1dca3a
--- /dev/null
+++ b/src/libstd/sys/windows/c.rs
@@ -0,0 +1,250 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! C definitions used by libnative that don't belong in liblibc
+
+#![allow(overflowing_literals)]
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+use libc;
+use prelude::*;
+
+pub const WSADESCRIPTION_LEN: uint = 256;
+pub const WSASYS_STATUS_LEN: uint = 128;
+pub const FIONBIO: libc::c_long = 0x8004667e;
+pub const FD_SETSIZE: uint = 64;
+pub const MSG_DONTWAIT: libc::c_int = 0;
+pub const ERROR_ILLEGAL_CHARACTER: libc::c_int = 582;
+pub const ENABLE_ECHO_INPUT: libc::DWORD = 0x4;
+pub const ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80;
+pub const ENABLE_INSERT_MODE: libc::DWORD = 0x20;
+pub const ENABLE_LINE_INPUT: libc::DWORD = 0x2;
+pub const ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1;
+pub const ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40;
+pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT;
+
+pub const FD_ACCEPT: libc::c_long = 0x08;
+pub const FD_MAX_EVENTS: uint = 10;
+pub const WSA_INFINITE: libc::DWORD = libc::INFINITE;
+pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT;
+pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0;
+pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED;
+
+#[repr(C)]
+#[cfg(target_arch = "x86")]
+pub struct WSADATA {
+    pub wVersion: libc::WORD,
+    pub wHighVersion: libc::WORD,
+    pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1],
+    pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1],
+    pub iMaxSockets: u16,
+    pub iMaxUdpDg: u16,
+    pub lpVendorInfo: *mut u8,
+}
+#[repr(C)]
+#[cfg(target_arch = "x86_64")]
+pub struct WSADATA {
+    pub wVersion: libc::WORD,
+    pub wHighVersion: libc::WORD,
+    pub iMaxSockets: u16,
+    pub iMaxUdpDg: u16,
+    pub lpVendorInfo: *mut u8,
+    pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1],
+    pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1],
+}
+
+pub type LPWSADATA = *mut WSADATA;
+
+#[repr(C)]
+pub struct WSANETWORKEVENTS {
+    pub lNetworkEvents: libc::c_long,
+    pub iErrorCode: [libc::c_int, ..FD_MAX_EVENTS],
+}
+
+pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS;
+
+pub type WSAEVENT = libc::HANDLE;
+
+#[repr(C)]
+pub struct fd_set {
+    fd_count: libc::c_uint,
+    fd_array: [libc::SOCKET, ..FD_SETSIZE],
+}
+
+pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) {
+    set.fd_array[set.fd_count as uint] = s;
+    set.fd_count += 1;
+}
+
+#[link(name = "ws2_32")]
+extern "system" {
+    pub fn WSAStartup(wVersionRequested: libc::WORD,
+                      lpWSAData: LPWSADATA) -> libc::c_int;
+    pub fn WSAGetLastError() -> libc::c_int;
+    pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL;
+    pub fn WSACreateEvent() -> WSAEVENT;
+    pub fn WSAEventSelect(s: libc::SOCKET,
+                          hEventObject: WSAEVENT,
+                          lNetworkEvents: libc::c_long) -> libc::c_int;
+    pub fn WSASetEvent(hEvent: WSAEVENT) -> libc::BOOL;
+    pub fn WSAWaitForMultipleEvents(cEvents: libc::DWORD,
+                                    lphEvents: *const WSAEVENT,
+                                    fWaitAll: libc::BOOL,
+                                    dwTimeout: libc::DWORD,
+                                    fAltertable: libc::BOOL) -> libc::DWORD;
+    pub fn WSAEnumNetworkEvents(s: libc::SOCKET,
+                                hEventObject: WSAEVENT,
+                                lpNetworkEvents: LPWSANETWORKEVENTS)
+                                -> libc::c_int;
+
+    pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long,
+                       argp: *mut libc::c_ulong) -> libc::c_int;
+    pub fn select(nfds: libc::c_int,
+                  readfds: *mut fd_set,
+                  writefds: *mut fd_set,
+                  exceptfds: *mut fd_set,
+                  timeout: *mut libc::timeval) -> libc::c_int;
+    pub fn getsockopt(sockfd: libc::SOCKET,
+                      level: libc::c_int,
+                      optname: libc::c_int,
+                      optval: *mut libc::c_char,
+                      optlen: *mut libc::c_int) -> libc::c_int;
+
+    pub fn SetEvent(hEvent: libc::HANDLE) -> libc::BOOL;
+    pub fn WaitForMultipleObjects(nCount: libc::DWORD,
+                                  lpHandles: *const libc::HANDLE,
+                                  bWaitAll: libc::BOOL,
+                                  dwMilliseconds: libc::DWORD) -> libc::DWORD;
+
+    pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL;
+    pub fn CancelIoEx(hFile: libc::HANDLE,
+                      lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
+}
+
+pub mod compat {
+    use intrinsics::{atomic_store_relaxed, transmute};
+    use iter::Iterator;
+    use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
+    use prelude::*;
+
+    extern "system" {
+        fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
+        fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID;
+    }
+
+    // store_func() is idempotent, so using relaxed ordering for the atomics
+    // should be enough.  This way, calling a function in this compatibility
+    // layer (after it's loaded) shouldn't be any slower than a regular DLL
+    // call.
+    unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) {
+        let mut module: Vec<u16> = module.utf16_units().collect();
+        module.push(0);
+        symbol.with_c_str(|symbol| {
+            let handle = GetModuleHandleW(module.as_ptr());
+            let func: uint = transmute(GetProcAddress(handle, symbol));
+            atomic_store_relaxed(ptr, if func == 0 {
+                fallback
+            } else {
+                func
+            })
+        })
+    }
+
+    /// Macro for creating a compatibility fallback for a Windows function
+    ///
+    /// # Example
+    /// ```
+    /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) {
+    ///     // Fallback implementation
+    /// })
+    /// ```
+    ///
+    /// Note that arguments unused by the fallback implementation should not be called `_` as
+    /// they are used to be passed to the real function if available.
+    macro_rules! compat_fn(
+        ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*)
+                                      -> $rettype:ty $fallback:block) => (
+            #[inline(always)]
+            pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
+                static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk;
+
+                extern "system" fn thunk($($argname: $argtype),*) -> $rettype {
+                    unsafe {
+                        ::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
+                                                    stringify!($module),
+                                                    stringify!($symbol),
+                                                    fallback as uint);
+                        ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+                    }
+                }
+
+                extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback
+
+                ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+            }
+        );
+
+        ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => (
+            compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback)
+        )
+    )
+
+    /// Compatibility layer for functions in `kernel32.dll`
+    ///
+    /// Latest versions of Windows this is needed for:
+    ///
+    /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003
+    /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003
+    pub mod kernel32 {
+        use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE};
+        use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
+
+        extern "system" {
+            fn SetLastError(dwErrCode: DWORD);
+        }
+
+        compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
+                                                 _lpTargetFileName: LPCWSTR,
+                                                 _dwFlags: DWORD) -> BOOLEAN {
+            unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
+            0
+        })
+
+        compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE,
+                                                       _lpszFilePath: LPCWSTR,
+                                                       _cchFilePath: DWORD,
+                                                       _dwFlags: DWORD) -> DWORD {
+            unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
+            0
+        })
+    }
+}
+
+extern "system" {
+    // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
+    pub fn ReadConsoleW(hConsoleInput: libc::HANDLE,
+                        lpBuffer: libc::LPVOID,
+                        nNumberOfCharsToRead: libc::DWORD,
+                        lpNumberOfCharsRead: libc::LPDWORD,
+                        pInputControl: libc::LPVOID) -> libc::BOOL;
+
+    pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE,
+                         lpBuffer: libc::types::os::arch::extra::LPCVOID,
+                         nNumberOfCharsToWrite: libc::DWORD,
+                         lpNumberOfCharsWritten: libc::LPDWORD,
+                         lpReserved: libc::LPVOID) -> libc::BOOL;
+
+    pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE,
+                          lpMode: libc::LPDWORD) -> libc::BOOL;
+
+    pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE,
+                          lpMode: libc::DWORD) -> libc::BOOL;
+}
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
new file mode 100644
index 00000000000..a07688b2fed
--- /dev/null
+++ b/src/libstd/sys/windows/fs.rs
@@ -0,0 +1,460 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Blocking Windows-based file I/O
+
+use alloc::arc::Arc;
+use libc::{mod, c_int};
+
+use c_str::CString;
+use mem;
+use os::windows::fill_utf16_buf_and_decode;
+use path;
+use ptr;
+use str;
+use io;
+
+use prelude::*;
+use sys;
+use sys_common::{keep_going, eof, mkerr_libc};
+
+use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
+use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader};
+use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append};
+
+pub use path::WindowsPath as Path;
+pub type fd_t = libc::c_int;
+
+pub struct FileDesc {
+    /// The underlying C file descriptor.
+    pub fd: fd_t,
+
+    /// Whether to close the file descriptor on drop.
+    close_on_drop: bool,
+}
+
+impl FileDesc {
+    pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
+        FileDesc { fd: fd, close_on_drop: close_on_drop }
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> IoResult<uint> {
+        let mut read = 0;
+        let ret = unsafe {
+            libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
+                           buf.len() as libc::DWORD, &mut read,
+                           ptr::null_mut())
+        };
+        if ret != 0 {
+            Ok(read as uint)
+        } else {
+            Err(super::last_error())
+        }
+    }
+
+    pub fn write(&self, buf: &[u8]) -> IoResult<()> {
+        let mut cur = buf.as_ptr();
+        let mut remaining = buf.len();
+        while remaining > 0 {
+            let mut amt = 0;
+            let ret = unsafe {
+                libc::WriteFile(self.handle(), cur as libc::LPVOID,
+                                remaining as libc::DWORD, &mut amt,
+                                ptr::null_mut())
+            };
+            if ret != 0 {
+                remaining -= amt as uint;
+                cur = unsafe { cur.offset(amt as int) };
+            } else {
+                return Err(super::last_error())
+            }
+        }
+        Ok(())
+    }
+
+    pub fn fd(&self) -> fd_t { self.fd }
+
+    pub fn handle(&self) -> libc::HANDLE {
+        unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE }
+    }
+
+    // A version of seek that takes &self so that tell can call it
+    //   - the private seek should of course take &mut self.
+    fn seek_common(&self, pos: i64, style: SeekStyle) -> IoResult<u64> {
+        let whence = match style {
+            SeekSet => libc::FILE_BEGIN,
+            SeekEnd => libc::FILE_END,
+            SeekCur => libc::FILE_CURRENT,
+        };
+        unsafe {
+            let mut newpos = 0;
+            match libc::SetFilePointerEx(self.handle(), pos, &mut newpos, whence) {
+                0 => Err(super::last_error()),
+                _ => Ok(newpos as u64),
+            }
+        }
+    }
+
+    pub fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<u64> {
+        self.seek_common(pos, style)
+    }
+
+    pub fn tell(&self) -> IoResult<u64> {
+        self.seek_common(0, SeekCur)
+    }
+
+    pub fn fsync(&mut self) -> IoResult<()> {
+        super::mkerr_winbool(unsafe {
+            libc::FlushFileBuffers(self.handle())
+        })
+    }
+
+    pub fn datasync(&mut self) -> IoResult<()> { return self.fsync(); }
+
+    pub fn truncate(&mut self, offset: i64) -> IoResult<()> {
+        let orig_pos = try!(self.tell());
+        let _ = try!(self.seek(offset, SeekSet));
+        let ret = unsafe {
+            match libc::SetEndOfFile(self.handle()) {
+                0 => Err(super::last_error()),
+                _ => Ok(())
+            }
+        };
+        let _ = self.seek(orig_pos as i64, SeekSet);
+        return ret;
+    }
+
+    pub fn fstat(&mut self) -> IoResult<io::FileStat> {
+        let mut stat: libc::stat = unsafe { mem::zeroed() };
+        match unsafe { libc::fstat(self.fd(), &mut stat) } {
+            0 => Ok(mkstat(&stat)),
+            _ => Err(super::last_error()),
+        }
+    }
+
+    /// Extract the actual filedescriptor without closing it.
+    pub fn unwrap(self) -> fd_t {
+        let fd = self.fd;
+        unsafe { mem::forget(self) };
+        fd
+    }
+}
+
+impl Drop for FileDesc {
+    fn drop(&mut self) {
+        // closing stdio file handles makes no sense, so never do it. Also, note
+        // that errors are ignored when closing a file descriptor. The reason
+        // for this is that if an error occurs we don't actually know if the
+        // file descriptor was closed or not, and if we retried (for something
+        // like EINTR), we might close another valid file descriptor (opened
+        // after we closed ours.
+        if self.close_on_drop && self.fd > libc::STDERR_FILENO {
+            let n = unsafe { libc::close(self.fd) };
+            if n != 0 {
+                println!("error {} when closing file descriptor {}", n, self.fd);
+            }
+        }
+    }
+}
+
+pub fn to_utf16(s: &Path) -> IoResult<Vec<u16>> {
+    sys::to_utf16(s.as_str())
+}
+
+pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> {
+    // Flags passed to open_osfhandle
+    let flags = match fm {
+        Open => 0,
+        Append => libc::O_APPEND,
+        Truncate => libc::O_TRUNC,
+    };
+    let flags = match fa {
+        Read => flags | libc::O_RDONLY,
+        Write => flags | libc::O_WRONLY | libc::O_CREAT,
+        ReadWrite => flags | libc::O_RDWR | libc::O_CREAT,
+    };
+    let mut dwDesiredAccess = match fa {
+        Read => libc::FILE_GENERIC_READ,
+        Write => libc::FILE_GENERIC_WRITE,
+        ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE
+    };
+
+    // libuv has a good comment about this, but the basic idea is what we try to
+    // emulate unix semantics by enabling all sharing by allowing things such as
+    // deleting a file while it's still open.
+    let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE |
+                      libc::FILE_SHARE_DELETE;
+
+    let dwCreationDisposition = match (fm, fa) {
+        (Truncate, Read) => libc::TRUNCATE_EXISTING,
+        (Truncate, _) => libc::CREATE_ALWAYS,
+        (Open, Read) => libc::OPEN_EXISTING,
+        (Open, _) => libc::OPEN_ALWAYS,
+        (Append, Read) => {
+            dwDesiredAccess |= libc::FILE_APPEND_DATA;
+            libc::OPEN_EXISTING
+        }
+        (Append, _) => {
+            dwDesiredAccess &= !libc::FILE_WRITE_DATA;
+            dwDesiredAccess |= libc::FILE_APPEND_DATA;
+            libc::OPEN_ALWAYS
+        }
+    };
+
+    let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL;
+    // Compat with unix, this allows opening directories (see libuv)
+    dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS;
+
+    let path = try!(to_utf16(path));
+    let handle = unsafe {
+        libc::CreateFileW(path.as_ptr(),
+                          dwDesiredAccess,
+                          dwShareMode,
+                          ptr::null_mut(),
+                          dwCreationDisposition,
+                          dwFlagsAndAttributes,
+                          ptr::null_mut())
+    };
+    if handle == libc::INVALID_HANDLE_VALUE {
+        Err(super::last_error())
+    } else {
+        let fd = unsafe {
+            libc::open_osfhandle(handle as libc::intptr_t, flags)
+        };
+        if fd < 0 {
+            let _ = unsafe { libc::CloseHandle(handle) };
+            Err(super::last_error())
+        } else {
+            Ok(FileDesc::new(fd, true))
+        }
+    }
+}
+
+pub fn mkdir(p: &Path, _mode: uint) -> IoResult<()> {
+    let p = try!(to_utf16(p));
+    super::mkerr_winbool(unsafe {
+        // FIXME: turn mode into something useful? #2623
+        libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut())
+    })
+}
+
+pub fn readdir(p: &Path) -> IoResult<Vec<Path>> {
+    fn prune(root: &Path, dirs: Vec<Path>) -> Vec<Path> {
+        dirs.into_iter().filter(|path| {
+            path.as_vec() != b"." && path.as_vec() != b".."
+        }).map(|path| root.join(path)).collect()
+    }
+
+    let star = p.join("*");
+    let path = try!(to_utf16(&star));
+
+    unsafe {
+        let mut wfd = mem::zeroed();
+        let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd);
+        if find_handle != libc::INVALID_HANDLE_VALUE {
+            let mut paths = vec![];
+            let mut more_files = 1 as libc::BOOL;
+            while more_files != 0 {
+                {
+                    let filename = str::truncate_utf16_at_nul(wfd.cFileName);
+                    match String::from_utf16(filename) {
+                        Some(filename) => paths.push(Path::new(filename)),
+                        None => {
+                            assert!(libc::FindClose(find_handle) != 0);
+                            return Err(IoError {
+                                kind: io::InvalidInput,
+                                desc: "path was not valid UTF-16",
+                                detail: Some(format!("path was not valid UTF-16: {}", filename)),
+                            })
+                        }, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring
+                    }
+                }
+                more_files = libc::FindNextFileW(find_handle, &mut wfd);
+            }
+            assert!(libc::FindClose(find_handle) != 0);
+            Ok(prune(p, paths))
+        } else {
+            Err(super::last_error())
+        }
+    }
+}
+
+pub fn unlink(p: &Path) -> IoResult<()> {
+    fn do_unlink(p_utf16: &Vec<u16>) -> IoResult<()> {
+        super::mkerr_winbool(unsafe { libc::DeleteFileW(p_utf16.as_ptr()) })
+    }
+
+    let p_utf16 = try!(to_utf16(p));
+    let res = do_unlink(&p_utf16);
+    match res {
+        Ok(()) => Ok(()),
+        Err(e) => {
+            // FIXME: change the code below to use more direct calls
+            // than `stat` and `chmod`, to avoid re-conversion to
+            // utf16 etc.
+
+            // On unix, a readonly file can be successfully removed. On windows,
+            // however, it cannot. To keep the two platforms in line with
+            // respect to their behavior, catch this case on windows, attempt to
+            // change it to read-write, and then remove the file.
+            if e.kind == io::PermissionDenied {
+                let stat = match stat(p) {
+                    Ok(stat) => stat,
+                    Err(..) => return Err(e),
+                };
+                if stat.perm.intersects(io::USER_WRITE) { return Err(e) }
+
+                match chmod(p, (stat.perm | io::USER_WRITE).bits() as uint) {
+                    Ok(()) => do_unlink(&p_utf16),
+                    Err(..) => {
+                        // Try to put it back as we found it
+                        let _ = chmod(p, stat.perm.bits() as uint);
+                        Err(e)
+                    }
+                }
+            } else {
+                Err(e)
+            }
+        }
+    }
+}
+
+pub fn rename(old: &Path, new: &Path) -> IoResult<()> {
+    let old = try!(to_utf16(old));
+    let new = try!(to_utf16(new));
+    super::mkerr_winbool(unsafe {
+        libc::MoveFileExW(old.as_ptr(), new.as_ptr(), libc::MOVEFILE_REPLACE_EXISTING)
+    })
+}
+
+pub fn chmod(p: &Path, mode: uint) -> IoResult<()> {
+    let p = try!(to_utf16(p));
+    mkerr_libc(unsafe {
+        libc::wchmod(p.as_ptr(), mode as libc::c_int)
+    })
+}
+
+pub fn rmdir(p: &Path) -> IoResult<()> {
+    let p = try!(to_utf16(p));
+    mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) })
+}
+
+pub fn chown(_p: &Path, _uid: int, _gid: int) -> IoResult<()> {
+    // libuv has this as a no-op, so seems like this should as well?
+    Ok(())
+}
+
+pub fn readlink(p: &Path) -> IoResult<Path> {
+    // FIXME: I have a feeling that this reads intermediate symlinks as well.
+    use sys::c::compat::kernel32::GetFinalPathNameByHandleW;
+    let p = try!(to_utf16(p));
+    let handle = unsafe {
+        libc::CreateFileW(p.as_ptr(),
+                          libc::GENERIC_READ,
+                          libc::FILE_SHARE_READ,
+                          ptr::null_mut(),
+                          libc::OPEN_EXISTING,
+                          libc::FILE_ATTRIBUTE_NORMAL,
+                          ptr::null_mut())
+    };
+    if handle == libc::INVALID_HANDLE_VALUE {
+        return Err(super::last_error())
+    }
+    // Specify (sz - 1) because the documentation states that it's the size
+    // without the null pointer
+    let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe {
+        GetFinalPathNameByHandleW(handle,
+                                  buf as *const u16,
+                                  sz - 1,
+                                  libc::VOLUME_NAME_DOS)
+    });
+    let ret = match ret {
+        Some(ref s) if s.as_slice().starts_with(r"\\?\") => { // "
+            Ok(Path::new(s.as_slice().slice_from(4)))
+        }
+        Some(s) => Ok(Path::new(s)),
+        None => Err(super::last_error()),
+    };
+    assert!(unsafe { libc::CloseHandle(handle) } != 0);
+    return ret;
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
+    use sys::c::compat::kernel32::CreateSymbolicLinkW;
+    let src = try!(to_utf16(src));
+    let dst = try!(to_utf16(dst));
+    super::mkerr_winbool(unsafe {
+        CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL
+    })
+}
+
+pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
+    let src = try!(to_utf16(src));
+    let dst = try!(to_utf16(dst));
+    super::mkerr_winbool(unsafe {
+        libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut())
+    })
+}
+
+fn mkstat(stat: &libc::stat) -> FileStat {
+    FileStat {
+        size: stat.st_size as u64,
+        kind: match (stat.st_mode as libc::c_int) & libc::S_IFMT {
+            libc::S_IFREG => io::TypeFile,
+            libc::S_IFDIR => io::TypeDirectory,
+            libc::S_IFIFO => io::TypeNamedPipe,
+            libc::S_IFBLK => io::TypeBlockSpecial,
+            libc::S_IFLNK => io::TypeSymlink,
+            _ => io::TypeUnknown,
+        },
+        perm: FilePermission::from_bits_truncate(stat.st_mode as u32),
+        created: stat.st_ctime as u64,
+        modified: stat.st_mtime as u64,
+        accessed: stat.st_atime as u64,
+        unstable: UnstableFileStat {
+            device: stat.st_dev as u64,
+            inode: stat.st_ino as u64,
+            rdev: stat.st_rdev as u64,
+            nlink: stat.st_nlink as u64,
+            uid: stat.st_uid as u64,
+            gid: stat.st_gid as u64,
+            blksize:0,
+            blocks: 0,
+            flags: 0,
+            gen: 0,
+        },
+    }
+}
+
+pub fn stat(p: &Path) -> IoResult<FileStat> {
+    let mut stat: libc::stat = unsafe { mem::zeroed() };
+    let p = try!(to_utf16(p));
+    match unsafe { libc::wstat(p.as_ptr(), &mut stat) } {
+        0 => Ok(mkstat(&stat)),
+        _ => Err(super::last_error()),
+    }
+}
+
+// FIXME: move this to platform-specific modules (for now)?
+pub fn lstat(_p: &Path) -> IoResult<FileStat> {
+    // FIXME: implementation is missing
+    Err(super::unimpl())
+}
+
+pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
+    let mut buf = libc::utimbuf {
+        actime: atime as libc::time64_t,
+        modtime: mtime as libc::time64_t,
+    };
+    let p = try!(to_utf16(p));
+    mkerr_libc(unsafe {
+        libc::wutime(p.as_ptr(), &mut buf)
+    })
+}
diff --git a/src/libstd/sys/windows/helper_signal.rs b/src/libstd/sys/windows/helper_signal.rs
new file mode 100644
index 00000000000..c547c79e83a
--- /dev/null
+++ b/src/libstd/sys/windows/helper_signal.rs
@@ -0,0 +1,38 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use libc::{mod, BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
+use ptr;
+
+pub type signal = HANDLE;
+
+pub fn new() -> (HANDLE, HANDLE) {
+    unsafe {
+        let handle = CreateEventA(ptr::null_mut(), libc::FALSE, libc::FALSE,
+                                  ptr::null());
+        (handle, handle)
+    }
+}
+
+pub fn signal(handle: HANDLE) {
+    assert!(unsafe { SetEvent(handle) != 0 });
+}
+
+pub fn close(handle: HANDLE) {
+    assert!(unsafe { CloseHandle(handle) != 0 });
+}
+
+extern "system" {
+    fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+                    bManualReset: BOOL,
+                    bInitialState: BOOL,
+                    lpName: LPCSTR) -> HANDLE;
+    fn SetEvent(hEvent: HANDLE) -> BOOL;
+}
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
new file mode 100644
index 00000000000..98da4d4e763
--- /dev/null
+++ b/src/libstd/sys/windows/mod.rs
@@ -0,0 +1,190 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(missing_doc)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(unused_imports)]
+#![allow(dead_code)]
+#![allow(unused_unsafe)]
+#![allow(unused_mut)]
+
+extern crate libc;
+
+use num;
+use mem;
+use prelude::*;
+use io::{mod, IoResult, IoError};
+use sync::{Once, ONCE_INIT};
+
+macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
+    static $name: Helper<$m> = Helper {
+        lock: ::rt::mutex::NATIVE_MUTEX_INIT,
+        chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
+        signal: ::cell::UnsafeCell { value: 0 },
+        initialized: ::cell::UnsafeCell { value: false },
+    };
+) )
+
+pub mod c;
+pub mod fs;
+pub mod os;
+pub mod tcp;
+pub mod udp;
+pub mod pipe;
+pub mod helper_signal;
+pub mod process;
+pub mod timer;
+pub mod tty;
+
+pub mod addrinfo {
+    pub use sys_common::net::get_host_addresses;
+}
+
+// FIXME: move these to c module
+pub type sock_t = libc::SOCKET;
+pub type wrlen = libc::c_int;
+pub type msglen_t = libc::c_int;
+pub unsafe fn close_sock(sock: sock_t) { let _ = libc::closesocket(sock); }
+
+// windows has zero values as errors
+fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
+    if ret == 0 {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
+pub fn last_error() -> IoError {
+    let errno = os::errno() as i32;
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+pub fn last_net_error() -> IoError {
+    let errno = unsafe { c::WSAGetLastError() as i32 };
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+pub fn last_gai_error(_errno: i32) -> IoError {
+    last_net_error()
+}
+
+/// Convert an `errno` value into a high-level error variant and description.
+pub fn decode_error(errno: i32) -> IoError {
+    let (kind, desc) = match errno {
+        libc::EOF => (io::EndOfFile, "end of file"),
+        libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"),
+        libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"),
+        libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"),
+        libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"),
+        libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"),
+        libc::ERROR_ACCESS_DENIED | libc::WSAEACCES =>
+            (io::PermissionDenied, "permission denied"),
+        libc::WSAEWOULDBLOCK => {
+            (io::ResourceUnavailable, "resource temporarily unavailable")
+        }
+        libc::WSAENOTCONN => (io::NotConnected, "not connected"),
+        libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"),
+        libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
+        libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"),
+        libc::ERROR_BROKEN_PIPE => (io::EndOfFile, "the pipe has ended"),
+        libc::ERROR_OPERATION_ABORTED =>
+            (io::TimedOut, "operation timed out"),
+        libc::WSAEINVAL => (io::InvalidInput, "invalid argument"),
+        libc::ERROR_CALL_NOT_IMPLEMENTED =>
+            (io::IoUnavailable, "function not implemented"),
+        libc::ERROR_INVALID_HANDLE =>
+            (io::MismatchedFileTypeForOperation,
+             "invalid handle provided to function"),
+        libc::ERROR_NOTHING_TO_TERMINATE =>
+            (io::InvalidInput, "no process to kill"),
+
+        // libuv maps this error code to EISDIR. we do too. if it is found
+        // to be incorrect, we can add in some more machinery to only
+        // return this message when ERROR_INVALID_FUNCTION after certain
+        // Windows calls.
+        libc::ERROR_INVALID_FUNCTION => (io::InvalidInput,
+                                         "illegal operation on a directory"),
+
+        _ => (io::OtherIoError, "unknown error")
+    };
+    IoError { kind: kind, desc: desc, detail: None }
+}
+
+pub fn decode_error_detailed(errno: i32) -> IoError {
+    let mut err = decode_error(errno);
+    err.detail = Some(os::error_string(errno));
+    err
+}
+
+#[inline]
+pub fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020
+
+pub fn ms_to_timeval(ms: u64) -> libc::timeval {
+    libc::timeval {
+        tv_sec: (ms / 1000) as libc::c_long,
+        tv_usec: ((ms % 1000) * 1000) as libc::c_long,
+    }
+}
+
+pub fn wouldblock() -> bool {
+    let err = os::errno();
+    err == libc::WSAEWOULDBLOCK as uint
+}
+
+pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
+    let mut set = nb as libc::c_ulong;
+    if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
+        Err(last_error())
+    } else {
+        Ok(())
+    }
+}
+
+pub fn init_net() {
+    unsafe {
+        static START: Once = ONCE_INIT;
+
+        START.doit(|| {
+            let mut data: c::WSADATA = mem::zeroed();
+            let ret = c::WSAStartup(0x202, // version 2.2
+                                    &mut data);
+            assert_eq!(ret, 0);
+        });
+    }
+}
+
+pub fn unimpl() -> IoError {
+    IoError {
+        kind: io::IoUnavailable,
+        desc: "operation is not implemented",
+        detail: None,
+    }
+}
+
+pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
+    match s {
+        Some(s) => Ok({
+            let mut s = s.utf16_units().collect::<Vec<u16>>();
+            s.push(0);
+            s
+        }),
+        None => Err(IoError {
+            kind: io::InvalidInput,
+            desc: "valid unicode input required",
+            detail: None
+        })
+    }
+}
diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs
new file mode 100644
index 00000000000..aaa1aaf6327
--- /dev/null
+++ b/src/libstd/sys/windows/os.rs
@@ -0,0 +1,103 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// FIXME: move various extern bindings from here into liblibc or
+// something similar
+
+use libc;
+use libc::{c_int, c_char, c_void};
+use prelude::*;
+use io::{IoResult, IoError};
+use sys::fs::FileDesc;
+use ptr;
+
+use os::TMPBUF_SZ;
+
+pub fn errno() -> uint {
+    use libc::types::os::arch::extra::DWORD;
+
+    #[link_name = "kernel32"]
+    extern "system" {
+        fn GetLastError() -> DWORD;
+    }
+
+    unsafe {
+        GetLastError() as uint
+    }
+}
+
+/// Get a detailed string description for the given error number
+pub fn error_string(errnum: i32) -> String {
+    use libc::types::os::arch::extra::DWORD;
+    use libc::types::os::arch::extra::LPWSTR;
+    use libc::types::os::arch::extra::LPVOID;
+    use libc::types::os::arch::extra::WCHAR;
+
+    #[link_name = "kernel32"]
+    extern "system" {
+        fn FormatMessageW(flags: DWORD,
+                          lpSrc: LPVOID,
+                          msgId: DWORD,
+                          langId: DWORD,
+                          buf: LPWSTR,
+                          nsize: DWORD,
+                          args: *const c_void)
+                          -> DWORD;
+    }
+
+    static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
+    static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
+
+    // This value is calculated from the macro
+    // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
+    let langId = 0x0800 as DWORD;
+
+    let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
+
+    unsafe {
+        let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
+                                 FORMAT_MESSAGE_IGNORE_INSERTS,
+                                 ptr::null_mut(),
+                                 errnum as DWORD,
+                                 langId,
+                                 buf.as_mut_ptr(),
+                                 buf.len() as DWORD,
+                                 ptr::null());
+        if res == 0 {
+            // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
+            let fm_err = errno();
+            return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
+        }
+
+        let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf));
+        match msg {
+            Some(msg) => format!("OS Error {}: {}", errnum, msg),
+            None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
+        }
+    }
+}
+
+pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
+    // Windows pipes work subtly differently than unix pipes, and their
+    // inheritance has to be handled in a different way that I do not
+    // fully understand. Here we explicitly make the pipe non-inheritable,
+    // which means to pass it to a subprocess they need to be duplicated
+    // first, as in std::run.
+    let mut fds = [0, ..2];
+    match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
+                     (libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
+        0 => {
+            assert!(fds[0] != -1 && fds[0] != 0);
+            assert!(fds[1] != -1 && fds[1] != 0);
+            Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
+        }
+        _ => Err(IoError::last_error()),
+    }
+}
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
new file mode 100644
index 00000000000..f2f7994a005
--- /dev/null
+++ b/src/libstd/sys/windows/pipe.rs
@@ -0,0 +1,751 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Named pipes implementation for windows
+//!
+//! If are unfortunate enough to be reading this code, I would like to first
+//! apologize. This was my first encounter with windows named pipes, and it
+//! didn't exactly turn out very cleanly. If you, too, are new to named pipes,
+//! read on as I'll try to explain some fun things that I ran into.
+//!
+//! # Unix pipes vs Named pipes
+//!
+//! As with everything else, named pipes on windows are pretty different from
+//! unix pipes on unix. On unix, you use one "server pipe" to accept new client
+//! pipes. So long as this server pipe is active, new children pipes can
+//! connect. On windows, you instead have a number of "server pipes", and each
+//! of these server pipes can throughout their lifetime be attached to a client
+//! or not. Once attached to a client, a server pipe may then disconnect at a
+//! later date.
+//!
+//! # Accepting clients
+//!
+//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces
+//! are built around the unix flavors. This means that we have one "server
+//! pipe" to which many clients can connect. In order to make this compatible
+//! with the windows model, each connected client consumes ownership of a server
+//! pipe, and then a new server pipe is created for the next client.
+//!
+//! Note that the server pipes attached to clients are never given back to the
+//! listener for recycling. This could possibly be implemented with a channel so
+//! the listener half can re-use server pipes, but for now I err'd on the simple
+//! side of things. Each stream accepted by a listener will destroy the server
+//! pipe after the stream is dropped.
+//!
+//! This model ends up having a small race or two, and you can find more details
+//! on the `native_accept` method.
+//!
+//! # Simultaneous reads and writes
+//!
+//! In testing, I found that two simultaneous writes and two simultaneous reads
+//! on a pipe ended up working out just fine, but problems were encountered when
+//! a read was executed simultaneously with a write. After some googling around,
+//! it sounded like named pipes just weren't built for this kind of interaction,
+//! and the suggested solution was to use overlapped I/O.
+//!
+//! I don't really know what overlapped I/O is, but my basic understanding after
+//! reading about it is that you have an external Event which is used to signal
+//! I/O completion, passed around in some OVERLAPPED structures. As to what this
+//! is, I'm not exactly sure.
+//!
+//! This problem implies that all named pipes are created with the
+//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is
+//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and
+//! inside of this structure is a HANDLE from CreateEvent. After the I/O is
+//! determined to be pending (may complete in the future), the
+//! GetOverlappedResult function is used to block on the event, waiting for the
+//! I/O to finish.
+//!
+//! This scheme ended up working well enough. There were two snags that I ran
+//! into, however:
+//!
+//! * Each UnixStream instance needs its own read/write events to wait on. These
+//!   can't be shared among clones of the same stream because the documentation
+//!   states that it unsets the event when the I/O is started (would possibly
+//!   corrupt other events simultaneously waiting). For convenience's sake,
+//!   these events are lazily initialized.
+//!
+//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition
+//!   to all pipes created through `connect`. Notably this means that the
+//!   ConnectNamedPipe function is nonblocking, implying that the Listener needs
+//!   to have yet another event to do the actual blocking.
+//!
+//! # Conclusion
+//!
+//! The conclusion here is that I probably don't know the best way to work with
+//! windows named pipes, but the solution here seems to work well enough to get
+//! the test suite passing (the suite is in libstd), and that's good enough for
+//! me!
+
+use alloc::arc::Arc;
+use libc;
+use c_str::CString;
+use mem;
+use ptr;
+use sync::atomic;
+use rt::mutex;
+use io::{mod, IoError, IoResult};
+use prelude::*;
+
+use sys_common::{mod, eof};
+
+use super::{c, os, timer, to_utf16, decode_error_detailed};
+
+struct Event(libc::HANDLE);
+
+impl Event {
+    fn new(manual_reset: bool, initial_state: bool) -> IoResult<Event> {
+        let event = unsafe {
+            libc::CreateEventW(ptr::null_mut(),
+                               manual_reset as libc::BOOL,
+                               initial_state as libc::BOOL,
+                               ptr::null())
+        };
+        if event as uint == 0 {
+            Err(super::last_error())
+        } else {
+            Ok(Event(event))
+        }
+    }
+
+    fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle }
+}
+
+impl Drop for Event {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.handle()); }
+    }
+}
+
+struct Inner {
+    handle: libc::HANDLE,
+    lock: mutex::NativeMutex,
+    read_closed: atomic::AtomicBool,
+    write_closed: atomic::AtomicBool,
+}
+
+impl Inner {
+    fn new(handle: libc::HANDLE) -> Inner {
+        Inner {
+            handle: handle,
+            lock: unsafe { mutex::NativeMutex::new() },
+            read_closed: atomic::AtomicBool::new(false),
+            write_closed: atomic::AtomicBool::new(false),
+        }
+    }
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) {
+        unsafe {
+            let _ = libc::FlushFileBuffers(self.handle);
+            let _ = libc::CloseHandle(self.handle);
+        }
+    }
+}
+
+unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE {
+    libc::CreateNamedPipeW(
+        name,
+        libc::PIPE_ACCESS_DUPLEX |
+            if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} |
+            libc::FILE_FLAG_OVERLAPPED,
+        libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE |
+            libc::PIPE_WAIT,
+        libc::PIPE_UNLIMITED_INSTANCES,
+        65536,
+        65536,
+        0,
+        ptr::null_mut()
+    )
+}
+
+pub fn await(handle: libc::HANDLE, deadline: u64,
+             events: &[libc::HANDLE]) -> IoResult<uint> {
+    use libc::consts::os::extra::{WAIT_FAILED, WAIT_TIMEOUT, WAIT_OBJECT_0};
+
+    // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo
+    // to figure out if we should indeed get the result.
+    let ms = if deadline == 0 {
+        libc::INFINITE as u64
+    } else {
+        let now = timer::now();
+        if deadline < now {0} else {deadline - now}
+    };
+    let ret = unsafe {
+        c::WaitForMultipleObjects(events.len() as libc::DWORD,
+                                  events.as_ptr(),
+                                  libc::FALSE,
+                                  ms as libc::DWORD)
+    };
+    match ret {
+        WAIT_FAILED => Err(super::last_error()),
+        WAIT_TIMEOUT => unsafe {
+            let _ = c::CancelIo(handle);
+            Err(sys_common::timeout("operation timed out"))
+        },
+        n => Ok((n - WAIT_OBJECT_0) as uint)
+    }
+}
+
+fn epipe() -> IoError {
+    IoError {
+        kind: io::EndOfFile,
+        desc: "the pipe has ended",
+        detail: None,
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixStream {
+    inner: Arc<Inner>,
+    write: Option<Event>,
+    read: Option<Event>,
+    read_deadline: u64,
+    write_deadline: u64,
+}
+
+impl UnixStream {
+    fn try_connect(p: *const u16) -> Option<libc::HANDLE> {
+        // Note that most of this is lifted from the libuv implementation.
+        // The idea is that if we fail to open a pipe in read/write mode
+        // that we try afterwards in just read or just write
+        let mut result = unsafe {
+            libc::CreateFileW(p,
+                libc::GENERIC_READ | libc::GENERIC_WRITE,
+                0,
+                ptr::null_mut(),
+                libc::OPEN_EXISTING,
+                libc::FILE_FLAG_OVERLAPPED,
+                ptr::null_mut())
+        };
+        if result != libc::INVALID_HANDLE_VALUE {
+            return Some(result)
+        }
+
+        let err = unsafe { libc::GetLastError() };
+        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+            result = unsafe {
+                libc::CreateFileW(p,
+                    libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES,
+                    0,
+                    ptr::null_mut(),
+                    libc::OPEN_EXISTING,
+                    libc::FILE_FLAG_OVERLAPPED,
+                    ptr::null_mut())
+            };
+            if result != libc::INVALID_HANDLE_VALUE {
+                return Some(result)
+            }
+        }
+        let err = unsafe { libc::GetLastError() };
+        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+            result = unsafe {
+                libc::CreateFileW(p,
+                    libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES,
+                    0,
+                    ptr::null_mut(),
+                    libc::OPEN_EXISTING,
+                    libc::FILE_FLAG_OVERLAPPED,
+                    ptr::null_mut())
+            };
+            if result != libc::INVALID_HANDLE_VALUE {
+                return Some(result)
+            }
+        }
+        None
+    }
+
+    pub fn connect(addr: &CString, timeout: Option<u64>) -> IoResult<UnixStream> {
+        let addr = try!(to_utf16(addr.as_str()));
+        let start = timer::now();
+        loop {
+            match UnixStream::try_connect(addr.as_ptr()) {
+                Some(handle) => {
+                    let inner = Inner::new(handle);
+                    let mut mode = libc::PIPE_TYPE_BYTE |
+                                   libc::PIPE_READMODE_BYTE |
+                                   libc::PIPE_WAIT;
+                    let ret = unsafe {
+                        libc::SetNamedPipeHandleState(inner.handle,
+                                                      &mut mode,
+                                                      ptr::null_mut(),
+                                                      ptr::null_mut())
+                    };
+                    return if ret == 0 {
+                        Err(super::last_error())
+                    } else {
+                        Ok(UnixStream {
+                            inner: Arc::new(inner),
+                            read: None,
+                            write: None,
+                            read_deadline: 0,
+                            write_deadline: 0,
+                        })
+                    }
+                }
+                None => {}
+            }
+
+            // On windows, if you fail to connect, you may need to call the
+            // `WaitNamedPipe` function, and this is indicated with an error
+            // code of ERROR_PIPE_BUSY.
+            let code = unsafe { libc::GetLastError() };
+            if code as int != libc::ERROR_PIPE_BUSY as int {
+                return Err(super::last_error())
+            }
+
+            match timeout {
+                Some(timeout) => {
+                    let now = timer::now();
+                    let timed_out = (now - start) >= timeout || unsafe {
+                        let ms = (timeout - (now - start)) as libc::DWORD;
+                        libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0
+                    };
+                    if timed_out {
+                        return Err(sys_common::timeout("connect timed out"))
+                    }
+                }
+
+                // An example I found on Microsoft's website used 20
+                // seconds, libuv uses 30 seconds, hence we make the
+                // obvious choice of waiting for 25 seconds.
+                None => {
+                    if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 {
+                        return Err(super::last_error())
+                    }
+                }
+            }
+        }
+    }
+
+    fn handle(&self) -> libc::HANDLE { self.inner.handle }
+
+    fn read_closed(&self) -> bool {
+        self.inner.read_closed.load(atomic::SeqCst)
+    }
+
+    fn write_closed(&self) -> bool {
+        self.inner.write_closed.load(atomic::SeqCst)
+    }
+
+    fn cancel_io(&self) -> IoResult<()> {
+        match unsafe { c::CancelIoEx(self.handle(), ptr::null_mut()) } {
+            0 if os::errno() == libc::ERROR_NOT_FOUND as uint => {
+                Ok(())
+            }
+            0 => Err(super::last_error()),
+            _ => Ok(())
+        }
+    }
+
+    pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        if self.read.is_none() {
+            self.read = Some(try!(Event::new(true, false)));
+        }
+
+        let mut bytes_read = 0;
+        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        overlapped.hEvent = self.read.as_ref().unwrap().handle();
+
+        // Pre-flight check to see if the reading half has been closed. This
+        // must be done before issuing the ReadFile request, but after we
+        // acquire the lock.
+        //
+        // See comments in close_read() about why this lock is necessary.
+        let guard = unsafe { self.inner.lock.lock() };
+        if self.read_closed() {
+            return Err(eof())
+        }
+
+        // Issue a nonblocking requests, succeeding quickly if it happened to
+        // succeed.
+        let ret = unsafe {
+            libc::ReadFile(self.handle(),
+                           buf.as_ptr() as libc::LPVOID,
+                           buf.len() as libc::DWORD,
+                           &mut bytes_read,
+                           &mut overlapped)
+        };
+        if ret != 0 { return Ok(bytes_read as uint) }
+
+        // If our errno doesn't say that the I/O is pending, then we hit some
+        // legitimate error and return immediately.
+        if os::errno() != libc::ERROR_IO_PENDING as uint {
+            return Err(super::last_error())
+        }
+
+        // Now that we've issued a successful nonblocking request, we need to
+        // wait for it to finish. This can all be done outside the lock because
+        // we'll see any invocation of CancelIoEx. We also call this in a loop
+        // because we're woken up if the writing half is closed, we just need to
+        // realize that the reading half wasn't closed and we go right back to
+        // sleep.
+        drop(guard);
+        loop {
+            // Process a timeout if one is pending
+            let wait_succeeded = await(self.handle(), self.read_deadline,
+                                       [overlapped.hEvent]);
+
+            let ret = unsafe {
+                libc::GetOverlappedResult(self.handle(),
+                                          &mut overlapped,
+                                          &mut bytes_read,
+                                          libc::TRUE)
+            };
+            // If we succeeded, or we failed for some reason other than
+            // CancelIoEx, return immediately
+            if ret != 0 { return Ok(bytes_read as uint) }
+            if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
+                return Err(super::last_error())
+            }
+
+            // If the reading half is now closed, then we're done. If we woke up
+            // because the writing half was closed, keep trying.
+            if wait_succeeded.is_err() {
+                return Err(sys_common::timeout("read timed out"))
+            }
+            if self.read_closed() {
+                return Err(eof())
+            }
+        }
+    }
+
+    pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        if self.write.is_none() {
+            self.write = Some(try!(Event::new(true, false)));
+        }
+
+        let mut offset = 0;
+        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        overlapped.hEvent = self.write.as_ref().unwrap().handle();
+
+        while offset < buf.len() {
+            let mut bytes_written = 0;
+
+            // This sequence below is quite similar to the one found in read().
+            // Some careful looping is done to ensure that if close_write() is
+            // invoked we bail out early, and if close_read() is invoked we keep
+            // going after we woke up.
+            //
+            // See comments in close_read() about why this lock is necessary.
+            let guard = unsafe { self.inner.lock.lock() };
+            if self.write_closed() {
+                return Err(epipe())
+            }
+            let ret = unsafe {
+                libc::WriteFile(self.handle(),
+                                buf[offset..].as_ptr() as libc::LPVOID,
+                                (buf.len() - offset) as libc::DWORD,
+                                &mut bytes_written,
+                                &mut overlapped)
+            };
+            let err = os::errno();
+            drop(guard);
+
+            if ret == 0 {
+                if err != libc::ERROR_IO_PENDING as uint {
+                    return Err(decode_error_detailed(err as i32))
+                }
+                // Process a timeout if one is pending
+                let wait_succeeded = await(self.handle(), self.write_deadline,
+                                           [overlapped.hEvent]);
+                let ret = unsafe {
+                    libc::GetOverlappedResult(self.handle(),
+                                              &mut overlapped,
+                                              &mut bytes_written,
+                                              libc::TRUE)
+                };
+                // If we weren't aborted, this was a legit error, if we were
+                // aborted, then check to see if the write half was actually
+                // closed or whether we woke up from the read half closing.
+                if ret == 0 {
+                    if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
+                        return Err(super::last_error())
+                    }
+                    if !wait_succeeded.is_ok() {
+                        let amt = offset + bytes_written as uint;
+                        return if amt > 0 {
+                            Err(IoError {
+                                kind: io::ShortWrite(amt),
+                                desc: "short write during write",
+                                detail: None,
+                            })
+                        } else {
+                            Err(sys_common::timeout("write timed out"))
+                        }
+                    }
+                    if self.write_closed() {
+                        return Err(epipe())
+                    }
+                    continue // retry
+                }
+            }
+            offset += bytes_written as uint;
+        }
+        Ok(())
+    }
+
+    pub fn close_read(&mut self) -> IoResult<()> {
+        // On windows, there's no actual shutdown() method for pipes, so we're
+        // forced to emulate the behavior manually at the application level. To
+        // do this, we need to both cancel any pending requests, as well as
+        // prevent all future requests from succeeding. These two operations are
+        // not atomic with respect to one another, so we must use a lock to do
+        // so.
+        //
+        // The read() code looks like:
+        //
+        //      1. Make sure the pipe is still open
+        //      2. Submit a read request
+        //      3. Wait for the read request to finish
+        //
+        // The race this lock is preventing is if another thread invokes
+        // close_read() between steps 1 and 2. By atomically executing steps 1
+        // and 2 with a lock with respect to close_read(), we're guaranteed that
+        // no thread will erroneously sit in a read forever.
+        let _guard = unsafe { self.inner.lock.lock() };
+        self.inner.read_closed.store(true, atomic::SeqCst);
+        self.cancel_io()
+    }
+
+    pub fn close_write(&mut self) -> IoResult<()> {
+        // see comments in close_read() for why this lock is necessary
+        let _guard = unsafe { self.inner.lock.lock() };
+        self.inner.write_closed.store(true, atomic::SeqCst);
+        self.cancel_io()
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+        self.read_deadline = deadline;
+        self.write_deadline = deadline;
+    }
+    pub fn set_read_timeout(&mut self, timeout: Option<u64>) {
+        self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+    pub fn set_write_timeout(&mut self, timeout: Option<u64>) {
+        self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+}
+
+impl Clone for UnixStream {
+    fn clone(&self) -> UnixStream {
+        UnixStream {
+            inner: self.inner.clone(),
+            read: None,
+            write: None,
+            read_deadline: 0,
+            write_deadline: 0,
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Listener
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixListener {
+    handle: libc::HANDLE,
+    name: CString,
+}
+
+impl UnixListener {
+    pub fn bind(addr: &CString) -> IoResult<UnixListener> {
+        // Although we technically don't need the pipe until much later, we
+        // create the initial handle up front to test the validity of the name
+        // and such.
+        let addr_v = try!(to_utf16(addr.as_str()));
+        let ret = unsafe { pipe(addr_v.as_ptr(), true) };
+        if ret == libc::INVALID_HANDLE_VALUE {
+            Err(super::last_error())
+        } else {
+            Ok(UnixListener { handle: ret, name: addr.clone() })
+        }
+    }
+
+    pub fn listen(self) -> IoResult<UnixAcceptor> {
+        Ok(UnixAcceptor {
+            listener: self,
+            event: try!(Event::new(true, false)),
+            deadline: 0,
+            inner: Arc::new(AcceptorState {
+                abort: try!(Event::new(true, false)),
+                closed: atomic::AtomicBool::new(false),
+            }),
+        })
+    }
+}
+
+impl Drop for UnixListener {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.handle); }
+    }
+}
+
+pub struct UnixAcceptor {
+    inner: Arc<AcceptorState>,
+    listener: UnixListener,
+    event: Event,
+    deadline: u64,
+}
+
+struct AcceptorState {
+    abort: Event,
+    closed: atomic::AtomicBool,
+}
+
+impl UnixAcceptor {
+    pub fn accept(&mut self) -> IoResult<UnixStream> {
+        // This function has some funky implementation details when working with
+        // unix pipes. On windows, each server named pipe handle can be
+        // connected to a one or zero clients. To the best of my knowledge, a
+        // named server is considered active and present if there exists at
+        // least one server named pipe for it.
+        //
+        // The model of this function is to take the current known server
+        // handle, connect a client to it, and then transfer ownership to the
+        // UnixStream instance. The next time accept() is invoked, it'll need a
+        // different server handle to connect a client to.
+        //
+        // Note that there is a possible race here. Once our server pipe is
+        // handed off to a `UnixStream` object, the stream could be closed,
+        // meaning that there would be no active server pipes, hence even though
+        // we have a valid `UnixAcceptor`, no one can connect to it. For this
+        // reason, we generate the next accept call's server pipe at the end of
+        // this function call.
+        //
+        // This provides us an invariant that we always have at least one server
+        // connection open at a time, meaning that all connects to this acceptor
+        // should succeed while this is active.
+        //
+        // The actual implementation of doing this is a little tricky. Once a
+        // server pipe is created, a client can connect to it at any time. I
+        // assume that which server a client connects to is nondeterministic, so
+        // we also need to guarantee that the only server able to be connected
+        // to is the one that we're calling ConnectNamedPipe on. This means that
+        // we have to create the second server pipe *after* we've already
+        // accepted a connection. In order to at least somewhat gracefully
+        // handle errors, this means that if the second server pipe creation
+        // fails that we disconnect the connected client and then just keep
+        // using the original server pipe.
+        let handle = self.listener.handle;
+
+        // If we've had an artificial call to close_accept, be sure to never
+        // proceed in accepting new clients in the future
+        if self.inner.closed.load(atomic::SeqCst) { return Err(eof()) }
+
+        let name = try!(to_utf16(self.listener.name.as_str()));
+
+        // Once we've got a "server handle", we need to wait for a client to
+        // connect. The ConnectNamedPipe function will block this thread until
+        // someone on the other end connects. This function can "fail" if a
+        // client connects after we created the pipe but before we got down
+        // here. Thanks windows.
+        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        overlapped.hEvent = self.event.handle();
+        if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } {
+            let mut err = unsafe { libc::GetLastError() };
+
+            if err == libc::ERROR_IO_PENDING as libc::DWORD {
+                // Process a timeout if one is pending
+                let wait_succeeded = await(handle, self.deadline,
+                                           [self.inner.abort.handle(),
+                                            overlapped.hEvent]);
+
+                // This will block until the overlapped I/O is completed. The
+                // timeout was previously handled, so this will either block in
+                // the normal case or succeed very quickly in the timeout case.
+                let ret = unsafe {
+                    let mut transfer = 0;
+                    libc::GetOverlappedResult(handle,
+                                              &mut overlapped,
+                                              &mut transfer,
+                                              libc::TRUE)
+                };
+                if ret == 0 {
+                    if wait_succeeded.is_ok() {
+                        err = unsafe { libc::GetLastError() };
+                    } else {
+                        return Err(sys_common::timeout("accept timed out"))
+                    }
+                } else {
+                    // we succeeded, bypass the check below
+                    err = libc::ERROR_PIPE_CONNECTED as libc::DWORD;
+                }
+            }
+            if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD {
+                return Err(super::last_error())
+            }
+        }
+
+        // Now that we've got a connected client to our handle, we need to
+        // create a second server pipe. If this fails, we disconnect the
+        // connected client and return an error (see comments above).
+        let new_handle = unsafe { pipe(name.as_ptr(), false) };
+        if new_handle == libc::INVALID_HANDLE_VALUE {
+            let ret = Err(super::last_error());
+            // If our disconnection fails, then there's not really a whole lot
+            // that we can do, so panic
+            let err = unsafe { libc::DisconnectNamedPipe(handle) };
+            assert!(err != 0);
+            return ret;
+        } else {
+            self.listener.handle = new_handle;
+        }
+
+        // Transfer ownership of our handle into this stream
+        Ok(UnixStream {
+            inner: Arc::new(Inner::new(handle)),
+            read: None,
+            write: None,
+            read_deadline: 0,
+            write_deadline: 0,
+        })
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        self.deadline = timeout.map(|i| i + timer::now()).unwrap_or(0);
+    }
+
+    pub fn close_accept(&mut self) -> IoResult<()> {
+        self.inner.closed.store(true, atomic::SeqCst);
+        let ret = unsafe {
+            c::SetEvent(self.inner.abort.handle())
+        };
+        if ret == 0 {
+            Err(super::last_error())
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl Clone for UnixAcceptor {
+    fn clone(&self) -> UnixAcceptor {
+        let name = to_utf16(self.listener.name.as_str()).ok().unwrap();
+        UnixAcceptor {
+            inner: self.inner.clone(),
+            event: Event::new(true, false).ok().unwrap(),
+            deadline: 0,
+            listener: UnixListener {
+                name: self.listener.name.clone(),
+                handle: unsafe {
+                    let p = pipe(name.as_ptr(), false) ;
+                    assert!(p != libc::INVALID_HANDLE_VALUE as libc::HANDLE);
+                    p
+                },
+            },
+        }
+    }
+}
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
new file mode 100644
index 00000000000..67e87841ed2
--- /dev/null
+++ b/src/libstd/sys/windows/process.rs
@@ -0,0 +1,511 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use libc::{pid_t, c_void, c_int};
+use libc;
+use c_str::CString;
+use io;
+use mem;
+use os;
+use ptr;
+use prelude::*;
+use io::process::{ProcessExit, ExitStatus, ExitSignal};
+use collections;
+use path::BytesContainer;
+use hash::Hash;
+use io::{IoResult, IoError};
+
+use sys::fs;
+use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer};
+use sys::fs::FileDesc;
+use sys_common::helper_thread::Helper;
+use sys_common::{AsFileDesc, mkerr_libc, timeout};
+
+use io::fs::PathExtensions;
+use string::String;
+
+pub use sys_common::ProcessConfig;
+
+/**
+ * A value representing a child process.
+ *
+ * The lifetime of this value is linked to the lifetime of the actual
+ * process - the Process destructor calls self.finish() which waits
+ * for the process to terminate.
+ */
+pub struct Process {
+    /// The unique id of the process (this should never be negative).
+    pid: pid_t,
+
+    /// A HANDLE to the process, which will prevent the pid being
+    /// re-used until the handle is closed.
+    handle: *mut (),
+}
+
+impl Drop for Process {
+    fn drop(&mut self) {
+        free_handle(self.handle);
+    }
+}
+
+impl Process {
+    pub fn id(&self) -> pid_t {
+        self.pid
+    }
+
+    pub unsafe fn kill(&self, signal: int) -> IoResult<()> {
+        Process::killpid(self.pid, signal)
+    }
+
+    pub unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> {
+        let handle = libc::OpenProcess(libc::PROCESS_TERMINATE |
+                                       libc::PROCESS_QUERY_INFORMATION,
+                                       libc::FALSE, pid as libc::DWORD);
+        if handle.is_null() {
+            return Err(super::last_error())
+        }
+        let ret = match signal {
+            // test for existence on signal 0
+            0 => {
+                let mut status = 0;
+                let ret = libc::GetExitCodeProcess(handle, &mut status);
+                if ret == 0 {
+                    Err(super::last_error())
+                } else if status != libc::STILL_ACTIVE {
+                    Err(IoError {
+                        kind: io::InvalidInput,
+                        desc: "no process to kill",
+                        detail: None,
+                    })
+                } else {
+                    Ok(())
+                }
+            }
+            15 | 9 => { // sigterm or sigkill
+                let ret = libc::TerminateProcess(handle, 1);
+                super::mkerr_winbool(ret)
+            }
+            _ => Err(IoError {
+                kind: io::IoUnavailable,
+                desc: "unsupported signal on windows",
+                detail: None,
+            })
+        };
+        let _ = libc::CloseHandle(handle);
+        return ret;
+    }
+
+    pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
+                              out_fd: Option<P>, err_fd: Option<P>)
+                              -> IoResult<Process>
+        where C: ProcessConfig<K, V>, P: AsFileDesc,
+              K: BytesContainer + Eq + Hash, V: BytesContainer
+    {
+        use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
+        use libc::consts::os::extra::{
+            TRUE, FALSE,
+            STARTF_USESTDHANDLES,
+            INVALID_HANDLE_VALUE,
+            DUPLICATE_SAME_ACCESS
+        };
+        use libc::funcs::extra::kernel32::{
+            GetCurrentProcess,
+            DuplicateHandle,
+            CloseHandle,
+            CreateProcessW
+        };
+        use libc::funcs::extra::msvcrt::get_osfhandle;
+
+        use mem;
+        use iter::Iterator;
+        use str::StrPrelude;
+
+        if cfg.gid().is_some() || cfg.uid().is_some() {
+            return Err(IoError {
+                kind: io::IoUnavailable,
+                desc: "unsupported gid/uid requested on windows",
+                detail: None,
+            })
+        }
+
+        // To have the spawning semantics of unix/windows stay the same, we need to
+        // read the *child's* PATH if one is provided. See #15149 for more details.
+        let program = cfg.env().and_then(|env| {
+            for (key, v) in env.iter() {
+                if b"PATH" != key.container_as_bytes() { continue }
+
+                // Split the value and test each path to see if the
+                // program exists.
+                for path in os::split_paths(v.container_as_bytes()).into_iter() {
+                    let path = path.join(cfg.program().as_bytes_no_nul())
+                                   .with_extension(os::consts::EXE_EXTENSION);
+                    if path.exists() {
+                        return Some(path.to_c_str())
+                    }
+                }
+                break
+            }
+            None
+        });
+
+        unsafe {
+            let mut si = zeroed_startupinfo();
+            si.cb = mem::size_of::<STARTUPINFO>() as DWORD;
+            si.dwFlags = STARTF_USESTDHANDLES;
+
+            let cur_proc = GetCurrentProcess();
+
+            // Similarly to unix, we don't actually leave holes for the stdio file
+            // descriptors, but rather open up /dev/null equivalents. These
+            // equivalents are drawn from libuv's windows process spawning.
+            let set_fd = |fd: &Option<P>, slot: &mut HANDLE,
+                          is_stdin: bool| {
+                match *fd {
+                    None => {
+                        let access = if is_stdin {
+                            libc::FILE_GENERIC_READ
+                        } else {
+                            libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES
+                        };
+                        let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>();
+                        let mut sa = libc::SECURITY_ATTRIBUTES {
+                            nLength: size as libc::DWORD,
+                            lpSecurityDescriptor: ptr::null_mut(),
+                            bInheritHandle: 1,
+                        };
+                        let mut filename: Vec<u16> = "NUL".utf16_units().collect();
+                        filename.push(0);
+                        *slot = libc::CreateFileW(filename.as_ptr(),
+                                                  access,
+                                                  libc::FILE_SHARE_READ |
+                                                      libc::FILE_SHARE_WRITE,
+                                                  &mut sa,
+                                                  libc::OPEN_EXISTING,
+                                                  0,
+                                                  ptr::null_mut());
+                        if *slot == INVALID_HANDLE_VALUE {
+                            return Err(super::last_error())
+                        }
+                    }
+                    Some(ref fd) => {
+                        let orig = get_osfhandle(fd.as_fd().fd()) as HANDLE;
+                        if orig == INVALID_HANDLE_VALUE {
+                            return Err(super::last_error())
+                        }
+                        if DuplicateHandle(cur_proc, orig, cur_proc, slot,
+                                           0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+                            return Err(super::last_error())
+                        }
+                    }
+                }
+                Ok(())
+            };
+
+            try!(set_fd(&in_fd, &mut si.hStdInput, true));
+            try!(set_fd(&out_fd, &mut si.hStdOutput, false));
+            try!(set_fd(&err_fd, &mut si.hStdError, false));
+
+            let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program()),
+                                            cfg.args());
+            let mut pi = zeroed_process_information();
+            let mut create_err = None;
+
+            // stolen from the libuv code.
+            let mut flags = libc::CREATE_UNICODE_ENVIRONMENT;
+            if cfg.detach() {
+                flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP;
+            }
+
+            with_envp(cfg.env(), |envp| {
+                with_dirp(cfg.cwd(), |dirp| {
+                    let mut cmd_str: Vec<u16> = cmd_str.as_slice().utf16_units().collect();
+                    cmd_str.push(0);
+                    let created = CreateProcessW(ptr::null(),
+                                                 cmd_str.as_mut_ptr(),
+                                                 ptr::null_mut(),
+                                                 ptr::null_mut(),
+                                                 TRUE,
+                                                 flags, envp, dirp,
+                                                 &mut si, &mut pi);
+                    if created == FALSE {
+                        create_err = Some(super::last_error());
+                    }
+                })
+            });
+
+            assert!(CloseHandle(si.hStdInput) != 0);
+            assert!(CloseHandle(si.hStdOutput) != 0);
+            assert!(CloseHandle(si.hStdError) != 0);
+
+            match create_err {
+                Some(err) => return Err(err),
+                None => {}
+            }
+
+            // We close the thread handle because we don't care about keeping the
+            // thread id valid, and we aren't keeping the thread handle around to be
+            // able to close it later. We don't close the process handle however
+            // because std::we want the process id to stay valid at least until the
+            // calling code closes the process handle.
+            assert!(CloseHandle(pi.hThread) != 0);
+
+            Ok(Process {
+                pid: pi.dwProcessId as pid_t,
+                handle: pi.hProcess as *mut ()
+            })
+        }
+    }
+
+    /**
+     * Waits for a process to exit and returns the exit code, failing
+     * if there is no process with the specified id.
+     *
+     * Note that this is private to avoid race conditions on unix where if
+     * a user calls waitpid(some_process.get_id()) then some_process.finish()
+     * and some_process.destroy() and some_process.finalize() will then either
+     * operate on a none-existent process or, even worse, on a newer process
+     * with the same id.
+     */
+    pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> {
+        use libc::types::os::arch::extra::DWORD;
+        use libc::consts::os::extra::{
+            SYNCHRONIZE,
+            PROCESS_QUERY_INFORMATION,
+            FALSE,
+            STILL_ACTIVE,
+            INFINITE,
+            WAIT_TIMEOUT,
+            WAIT_OBJECT_0,
+        };
+        use libc::funcs::extra::kernel32::{
+            OpenProcess,
+            GetExitCodeProcess,
+            CloseHandle,
+            WaitForSingleObject,
+        };
+
+        unsafe {
+            let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
+                                      FALSE,
+                                      self.pid as DWORD);
+            if process.is_null() {
+                return Err(super::last_error())
+            }
+
+            loop {
+                let mut status = 0;
+                if GetExitCodeProcess(process, &mut status) == FALSE {
+                    let err = Err(super::last_error());
+                    assert!(CloseHandle(process) != 0);
+                    return err;
+                }
+                if status != STILL_ACTIVE {
+                    assert!(CloseHandle(process) != 0);
+                    return Ok(ExitStatus(status as int));
+                }
+                let interval = if deadline == 0 {
+                    INFINITE
+                } else {
+                    let now = timer::now();
+                    if deadline < now {0} else {(deadline - now) as u32}
+                };
+                match WaitForSingleObject(process, interval) {
+                    WAIT_OBJECT_0 => {}
+                    WAIT_TIMEOUT => {
+                        assert!(CloseHandle(process) != 0);
+                        return Err(timeout("process wait timed out"))
+                    }
+                    _ => {
+                        let err = Err(super::last_error());
+                        assert!(CloseHandle(process) != 0);
+                        return err
+                    }
+                }
+            }
+        }
+    }
+}
+
+fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
+    libc::types::os::arch::extra::STARTUPINFO {
+        cb: 0,
+        lpReserved: ptr::null_mut(),
+        lpDesktop: ptr::null_mut(),
+        lpTitle: ptr::null_mut(),
+        dwX: 0,
+        dwY: 0,
+        dwXSize: 0,
+        dwYSize: 0,
+        dwXCountChars: 0,
+        dwYCountCharts: 0,
+        dwFillAttribute: 0,
+        dwFlags: 0,
+        wShowWindow: 0,
+        cbReserved2: 0,
+        lpReserved2: ptr::null_mut(),
+        hStdInput: libc::INVALID_HANDLE_VALUE,
+        hStdOutput: libc::INVALID_HANDLE_VALUE,
+        hStdError: libc::INVALID_HANDLE_VALUE,
+    }
+}
+
+fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
+    libc::types::os::arch::extra::PROCESS_INFORMATION {
+        hProcess: ptr::null_mut(),
+        hThread: ptr::null_mut(),
+        dwProcessId: 0,
+        dwThreadId: 0
+    }
+}
+
+fn make_command_line(prog: &CString, args: &[CString]) -> String {
+    let mut cmd = String::new();
+    append_arg(&mut cmd, prog.as_str()
+                             .expect("expected program name to be utf-8 encoded"));
+    for arg in args.iter() {
+        cmd.push(' ');
+        append_arg(&mut cmd, arg.as_str()
+                                .expect("expected argument to be utf-8 encoded"));
+    }
+    return cmd;
+
+    fn append_arg(cmd: &mut String, arg: &str) {
+        // If an argument has 0 characters then we need to quote it to ensure
+        // that it actually gets passed through on the command line or otherwise
+        // it will be dropped entirely when parsed on the other end.
+        let quote = arg.chars().any(|c| c == ' ' || c == '\t') || arg.len() == 0;
+        if quote {
+            cmd.push('"');
+        }
+        let argvec: Vec<char> = arg.chars().collect();
+        for i in range(0u, argvec.len()) {
+            append_char_at(cmd, argvec.as_slice(), i);
+        }
+        if quote {
+            cmd.push('"');
+        }
+    }
+
+    fn append_char_at(cmd: &mut String, arg: &[char], i: uint) {
+        match arg[i] {
+            '"' => {
+                // Escape quotes.
+                cmd.push_str("\\\"");
+            }
+            '\\' => {
+                if backslash_run_ends_in_quote(arg, i) {
+                    // Double all backslashes that are in runs before quotes.
+                    cmd.push_str("\\\\");
+                } else {
+                    // Pass other backslashes through unescaped.
+                    cmd.push('\\');
+                }
+            }
+            c => {
+                cmd.push(c);
+            }
+        }
+    }
+
+    fn backslash_run_ends_in_quote(s: &[char], mut i: uint) -> bool {
+        while i < s.len() && s[i] == '\\' {
+            i += 1;
+        }
+        return i < s.len() && s[i] == '"';
+    }
+}
+
+fn with_envp<K, V, T>(env: Option<&collections::HashMap<K, V>>,
+                      cb: |*mut c_void| -> T) -> T
+    where K: BytesContainer + Eq + Hash, V: BytesContainer
+{
+    // On Windows we pass an "environment block" which is not a char**, but
+    // rather a concatenation of null-terminated k=v\0 sequences, with a final
+    // \0 to terminate.
+    match env {
+        Some(env) => {
+            let mut blk = Vec::new();
+
+            for pair in env.iter() {
+                let kv = format!("{}={}",
+                                 pair.ref0().container_as_str().unwrap(),
+                                 pair.ref1().container_as_str().unwrap());
+                blk.extend(kv.as_slice().utf16_units());
+                blk.push(0);
+            }
+
+            blk.push(0);
+
+            cb(blk.as_mut_ptr() as *mut c_void)
+        }
+        _ => cb(ptr::null_mut())
+    }
+}
+
+fn with_dirp<T>(d: Option<&CString>, cb: |*const u16| -> T) -> T {
+    match d {
+      Some(dir) => {
+          let dir_str = dir.as_str()
+                           .expect("expected workingdirectory to be utf-8 encoded");
+          let mut dir_str: Vec<u16> = dir_str.utf16_units().collect();
+          dir_str.push(0);
+          cb(dir_str.as_ptr())
+      },
+      None => cb(ptr::null())
+    }
+}
+
+fn free_handle(handle: *mut ()) {
+    assert!(unsafe {
+        libc::CloseHandle(mem::transmute(handle)) != 0
+    })
+}
+
+#[cfg(test)]
+mod tests {
+
+    #[test]
+    fn test_make_command_line() {
+        use prelude::*;
+        use str;
+        use c_str::CString;
+        use super::make_command_line;
+
+        fn test_wrapper(prog: &str, args: &[&str]) -> String {
+            make_command_line(&prog.to_c_str(),
+                              args.iter()
+                                  .map(|a| a.to_c_str())
+                                  .collect::<Vec<CString>>()
+                                  .as_slice())
+        }
+
+        assert_eq!(
+            test_wrapper("prog", ["aaa", "bbb", "ccc"]),
+            "prog aaa bbb ccc".to_string()
+        );
+
+        assert_eq!(
+            test_wrapper("C:\\Program Files\\blah\\blah.exe", ["aaa"]),
+            "\"C:\\Program Files\\blah\\blah.exe\" aaa".to_string()
+        );
+        assert_eq!(
+            test_wrapper("C:\\Program Files\\test", ["aa\"bb"]),
+            "\"C:\\Program Files\\test\" aa\\\"bb".to_string()
+        );
+        assert_eq!(
+            test_wrapper("echo", ["a b c"]),
+            "echo \"a b c\"".to_string()
+        );
+        assert_eq!(
+            test_wrapper("\u03c0\u042f\u97f3\u00e6\u221e", []),
+            "\u03c0\u042f\u97f3\u00e6\u221e".to_string()
+        );
+    }
+}
diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs
new file mode 100644
index 00000000000..3baf2be08d2
--- /dev/null
+++ b/src/libstd/sys/windows/tcp.rs
@@ -0,0 +1,219 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io::net::ip;
+use io::IoResult;
+use libc;
+use mem;
+use ptr;
+use prelude::*;
+use super::{last_error, last_net_error, retry, sock_t};
+use sync::{Arc, atomic};
+use sys::fs::FileDesc;
+use sys::{mod, c, set_nonblocking, wouldblock, timer};
+use sys_common::{mod, timeout, eof};
+use sys_common::net::*;
+
+pub use sys_common::net::TcpStream;
+
+pub struct Event(c::WSAEVENT);
+
+impl Event {
+    pub fn new() -> IoResult<Event> {
+        let event = unsafe { c::WSACreateEvent() };
+        if event == c::WSA_INVALID_EVENT {
+            Err(super::last_error())
+        } else {
+            Ok(Event(event))
+        }
+    }
+
+    pub fn handle(&self) -> c::WSAEVENT { let Event(handle) = *self; handle }
+}
+
+impl Drop for Event {
+    fn drop(&mut self) {
+        unsafe { let _ = c::WSACloseEvent(self.handle()); }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP listeners
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpListener {
+    inner: FileDesc,
+}
+
+impl TcpListener {
+    pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
+        sys::init_net();
+
+        let fd = try!(socket(addr, libc::SOCK_STREAM));
+        let ret = TcpListener { inner: FileDesc::new(fd as libc::c_int, true) };
+
+        let mut storage = unsafe { mem::zeroed() };
+        let len = addr_to_sockaddr(addr, &mut storage);
+        let addrp = &storage as *const _ as *const libc::sockaddr;
+
+        match unsafe { libc::bind(fd, addrp, len) } {
+            -1 => Err(last_net_error()),
+            _ => Ok(ret),
+        }
+    }
+
+    pub fn fd(&self) -> sock_t { self.inner.fd as sock_t }
+
+    pub fn listen(self, backlog: int) -> IoResult<TcpAcceptor> {
+        match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
+            -1 => Err(last_net_error()),
+
+            _ => {
+                let accept = try!(Event::new());
+                let ret = unsafe {
+                    c::WSAEventSelect(self.fd(), accept.handle(), c::FD_ACCEPT)
+                };
+                if ret != 0 {
+                    return Err(last_net_error())
+                }
+                Ok(TcpAcceptor {
+                    inner: Arc::new(AcceptorInner {
+                        listener: self,
+                        abort: try!(Event::new()),
+                        accept: accept,
+                        closed: atomic::AtomicBool::new(false),
+                    }),
+                    deadline: 0,
+                })
+            }
+        }
+    }
+
+    pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
+        sockname(self.fd(), libc::getsockname)
+    }
+}
+
+pub struct TcpAcceptor {
+    inner: Arc<AcceptorInner>,
+    deadline: u64,
+}
+
+struct AcceptorInner {
+    listener: TcpListener,
+    abort: Event,
+    accept: Event,
+    closed: atomic::AtomicBool,
+}
+
+impl TcpAcceptor {
+    pub fn fd(&self) -> sock_t { self.inner.listener.fd() }
+
+    pub fn accept(&mut self) -> IoResult<TcpStream> {
+        // Unlink unix, windows cannot invoke `select` on arbitrary file
+        // descriptors like pipes, only sockets. Consequently, windows cannot
+        // use the same implementation as unix for accept() when close_accept()
+        // is considered.
+        //
+        // In order to implement close_accept() and timeouts, windows uses
+        // event handles. An acceptor-specific abort event is created which
+        // will only get set in close_accept(), and it will never be un-set.
+        // Additionally, another acceptor-specific event is associated with the
+        // FD_ACCEPT network event.
+        //
+        // These two events are then passed to WaitForMultipleEvents to see
+        // which one triggers first, and the timeout passed to this function is
+        // the local timeout for the acceptor.
+        //
+        // If the wait times out, then the accept timed out. If the wait
+        // succeeds with the abort event, then we were closed, and if the wait
+        // succeeds otherwise, then we do a nonblocking poll via `accept` to
+        // see if we can accept a connection. The connection is candidate to be
+        // stolen, so we do all of this in a loop as well.
+        let events = [self.inner.abort.handle(), self.inner.accept.handle()];
+
+        while !self.inner.closed.load(atomic::SeqCst) {
+            let ms = if self.deadline == 0 {
+                c::WSA_INFINITE as u64
+            } else {
+                let now = timer::now();
+                if self.deadline < now {0} else {self.deadline - now}
+            };
+            let ret = unsafe {
+                c::WSAWaitForMultipleEvents(2, events.as_ptr(), libc::FALSE,
+                                            ms as libc::DWORD, libc::FALSE)
+            };
+            match ret {
+                c::WSA_WAIT_TIMEOUT => {
+                    return Err(timeout("accept timed out"))
+                }
+                c::WSA_WAIT_FAILED => return Err(last_net_error()),
+                c::WSA_WAIT_EVENT_0 => break,
+                n => assert_eq!(n, c::WSA_WAIT_EVENT_0 + 1),
+            }
+
+            let mut wsaevents: c::WSANETWORKEVENTS = unsafe { mem::zeroed() };
+            let ret = unsafe {
+                c::WSAEnumNetworkEvents(self.fd(), events[1], &mut wsaevents)
+            };
+            if ret != 0 { return Err(last_net_error()) }
+
+            if wsaevents.lNetworkEvents & c::FD_ACCEPT == 0 { continue }
+            match unsafe {
+                libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut())
+            } {
+                -1 if wouldblock() => {}
+                -1 => return Err(last_net_error()),
+
+                // Accepted sockets inherit the same properties as the caller,
+                // so we need to deregister our event and switch the socket back
+                // to blocking mode
+                fd => {
+                    let stream = TcpStream::new(fd);
+                    let ret = unsafe {
+                        c::WSAEventSelect(fd, events[1], 0)
+                    };
+                    if ret != 0 { return Err(last_net_error()) }
+                    try!(set_nonblocking(fd, false));
+                    return Ok(stream)
+                }
+            }
+        }
+
+        Err(eof())
+    }
+
+    pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
+        sockname(self.fd(), libc::getsockname)
+    }
+
+    pub fn set_timeout(&mut self, timeout: Option<u64>) {
+        self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
+    }
+
+    pub fn close_accept(&mut self) -> IoResult<()> {
+        self.inner.closed.store(true, atomic::SeqCst);
+        let ret = unsafe { c::WSASetEvent(self.inner.abort.handle()) };
+        if ret == libc::TRUE {
+            Ok(())
+        } else {
+            Err(last_net_error())
+        }
+    }
+}
+
+impl Clone for TcpAcceptor {
+    fn clone(&self) -> TcpAcceptor {
+        TcpAcceptor {
+            inner: self.inner.clone(),
+            deadline: 0,
+        }
+    }
+}
diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs
new file mode 100644
index 00000000000..f507be2a985
--- /dev/null
+++ b/src/libstd/sys/windows/timer.rs
@@ -0,0 +1,208 @@
+// 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.
+
+//! Timers based on Windows WaitableTimers
+//!
+//! This implementation is meant to be used solely on windows. As with other
+//! implementations, there is a worker thread which is doing all the waiting on
+//! a large number of timers for all active timers in the system. This worker
+//! thread uses the select() equivalent, WaitForMultipleObjects. One of the
+//! objects being waited on is a signal into the worker thread to notify that
+//! the incoming channel should be looked at.
+//!
+//! Other than that, the implementation is pretty straightforward in terms of
+//! the other two implementations of timers with nothing *that* new showing up.
+
+use libc;
+use ptr;
+use comm;
+
+use sys::c;
+use sys::fs::FileDesc;
+use sys_common::helper_thread::Helper;
+use prelude::*;
+use io::IoResult;
+
+helper_init!(static HELPER: Helper<Req>)
+
+pub trait Callback {
+    fn call(&mut self);
+}
+
+pub struct Timer {
+    obj: libc::HANDLE,
+    on_worker: bool,
+}
+
+pub enum Req {
+    NewTimer(libc::HANDLE, Box<Callback + Send>, bool),
+    RemoveTimer(libc::HANDLE, Sender<()>),
+}
+
+fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
+    let mut objs = vec![input];
+    let mut chans = vec![];
+
+    'outer: loop {
+        let idx = unsafe {
+            imp::WaitForMultipleObjects(objs.len() as libc::DWORD,
+                                        objs.as_ptr(),
+                                        0 as libc::BOOL,
+                                        libc::INFINITE)
+        };
+
+        if idx == 0 {
+            loop {
+                match messages.try_recv() {
+                    Ok(NewTimer(obj, c, one)) => {
+                        objs.push(obj);
+                        chans.push((c, one));
+                    }
+                    Ok(RemoveTimer(obj, c)) => {
+                        c.send(());
+                        match objs.iter().position(|&o| o == obj) {
+                            Some(i) => {
+                                drop(objs.remove(i));
+                                drop(chans.remove(i - 1));
+                            }
+                            None => {}
+                        }
+                    }
+                    Err(comm::Disconnected) => {
+                        assert_eq!(objs.len(), 1);
+                        assert_eq!(chans.len(), 0);
+                        break 'outer;
+                    }
+                    Err(..) => break
+                }
+            }
+        } else {
+            let remove = {
+                match &mut chans[idx as uint - 1] {
+                    &(ref mut c, oneshot) => { c.call(); oneshot }
+                }
+            };
+            if remove {
+                drop(objs.remove(idx as uint));
+                drop(chans.remove(idx as uint - 1));
+            }
+        }
+    }
+}
+
+// returns the current time (in milliseconds)
+pub fn now() -> u64 {
+    let mut ticks_per_s = 0;
+    assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1);
+    let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
+    let mut ticks = 0;
+    assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1);
+
+    return (ticks as u64 * 1000) / (ticks_per_s as u64);
+}
+
+impl Timer {
+    pub fn new() -> IoResult<Timer> {
+        HELPER.boot(|| {}, helper);
+
+        let obj = unsafe {
+            imp::CreateWaitableTimerA(ptr::null_mut(), 0, ptr::null())
+        };
+        if obj.is_null() {
+            Err(super::last_error())
+        } else {
+            Ok(Timer { obj: obj, on_worker: false, })
+        }
+    }
+
+    fn remove(&mut self) {
+        if !self.on_worker { return }
+
+        let (tx, rx) = channel();
+        HELPER.send(RemoveTimer(self.obj, tx));
+        rx.recv();
+
+        self.on_worker = false;
+    }
+
+    pub fn sleep(&mut self, msecs: u64) {
+        self.remove();
+
+        // there are 10^6 nanoseconds in a millisecond, and the parameter is in
+        // 100ns intervals, so we multiply by 10^4.
+        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(),
+                                  ptr::null_mut(), 0)
+        }, 1);
+
+        let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) };
+    }
+
+    pub fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
+        self.remove();
+
+        // see above for the calculation
+        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(),
+                                  ptr::null_mut(), 0)
+        }, 1);
+
+        HELPER.send(NewTimer(self.obj, cb, true));
+        self.on_worker = true;
+    }
+
+    pub fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
+        self.remove();
+
+        // see above for the calculation
+        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG,
+                                  ptr::null_mut(), ptr::null_mut(), 0)
+        }, 1);
+
+        HELPER.send(NewTimer(self.obj, cb, false));
+        self.on_worker = true;
+    }
+}
+
+impl Drop for Timer {
+    fn drop(&mut self) {
+        self.remove();
+        assert!(unsafe { libc::CloseHandle(self.obj) != 0 });
+    }
+}
+
+mod imp {
+    use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER,
+                    LONG, LPVOID, DWORD, c_void};
+
+    pub type PTIMERAPCROUTINE = *mut c_void;
+
+    extern "system" {
+        pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES,
+                                    bManualReset: BOOL,
+                                    lpTimerName: LPCSTR) -> HANDLE;
+        pub fn SetWaitableTimer(hTimer: HANDLE,
+                                pDueTime: *const LARGE_INTEGER,
+                                lPeriod: LONG,
+                                pfnCompletionRoutine: PTIMERAPCROUTINE,
+                                lpArgToCompletionRoutine: LPVOID,
+                                fResume: BOOL) -> BOOL;
+        pub fn WaitForMultipleObjects(nCount: DWORD,
+                                      lpHandles: *const HANDLE,
+                                      bWaitAll: BOOL,
+                                      dwMilliseconds: DWORD) -> DWORD;
+        pub fn WaitForSingleObject(hHandle: HANDLE,
+                                   dwMilliseconds: DWORD) -> DWORD;
+    }
+}
diff --git a/src/libstd/sys/windows/tty.rs b/src/libstd/sys/windows/tty.rs
new file mode 100644
index 00000000000..7d001e6394c
--- /dev/null
+++ b/src/libstd/sys/windows/tty.rs
@@ -0,0 +1,166 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-lexer-test FIXME #15877
+
+//! Windows specific console TTY implementation
+//!
+//! This module contains the implementation of a Windows specific console TTY.
+//! Also converts between UTF-16 and UTF-8. Windows has very poor support for
+//! UTF-8 and some functions will fail. In particular ReadFile and ReadConsole
+//! will fail when the codepage is set to UTF-8 and a Unicode character is
+//! entered.
+//!
+//! FIXME
+//! This implementation does not account for codepoints that are split across
+//! multiple reads and writes. Also, this implementation does not expose a way
+//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer
+//! wrapper that performs encoding/decoding, this implementation should switch
+//! to working in raw UTF-16, with such a wrapper around it.
+
+use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
+use super::c::{ERROR_ILLEGAL_CHARACTER};
+use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
+use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
+use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
+use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
+use libc::{get_osfhandle, CloseHandle};
+use libc::types::os::arch::extra::LPCVOID;
+use io::{mod, IoError, IoResult, MemReader};
+use prelude::*;
+use ptr;
+use str::from_utf8;
+
+fn invalid_encoding() -> IoError {
+    IoError {
+        kind: io::InvalidInput,
+        desc: "text was not valid unicode",
+        detail: None,
+    }
+}
+
+pub fn is_tty(fd: c_int) -> bool {
+    let mut out: DWORD = 0;
+    // If this function doesn't fail then fd is a TTY
+    match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE,
+                                  &mut out as LPDWORD) } {
+        0 => false,
+        _ => true,
+    }
+}
+
+pub struct TTY {
+    closeme: bool,
+    handle: HANDLE,
+    utf8: MemReader,
+}
+
+impl TTY {
+    pub fn new(fd: c_int) -> IoResult<TTY> {
+        if is_tty(fd) {
+            // If the file descriptor is one of stdin, stderr, or stdout
+            // then it should not be closed by us
+            let closeme = match fd {
+                0...2 => false,
+                _ => true,
+            };
+            let handle = unsafe { get_osfhandle(fd) as HANDLE };
+            Ok(TTY {
+                handle: handle,
+                utf8: MemReader::new(Vec::new()),
+                closeme: closeme,
+            })
+        } else {
+            Err(IoError {
+                kind: io::MismatchedFileTypeForOperation,
+                desc: "invalid handle provided to function",
+                detail: None,
+            })
+        }
+    }
+
+    pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        // Read more if the buffer is empty
+        if self.utf8.eof() {
+            let mut utf16 = Vec::from_elem(0x1000, 0u16);
+            let mut num: DWORD = 0;
+            match unsafe { ReadConsoleW(self.handle,
+                                         utf16.as_mut_ptr() as LPVOID,
+                                         utf16.len() as u32,
+                                         &mut num as LPDWORD,
+                                         ptr::null_mut()) } {
+                0 => return Err(super::last_error()),
+                _ => (),
+            };
+            utf16.truncate(num as uint);
+            let utf8 = match String::from_utf16(utf16.as_slice()) {
+                Some(utf8) => utf8.into_bytes(),
+                None => return Err(invalid_encoding()),
+            };
+            self.utf8 = MemReader::new(utf8);
+        }
+        // MemReader shouldn't error here since we just filled it
+        Ok(self.utf8.read(buf).unwrap())
+    }
+
+    pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        let utf16 = match from_utf8(buf) {
+            Some(utf8) => {
+                utf8.as_slice().utf16_units().collect::<Vec<u16>>()
+            }
+            None => return Err(invalid_encoding()),
+        };
+        let mut num: DWORD = 0;
+        match unsafe { WriteConsoleW(self.handle,
+                                     utf16.as_ptr() as LPCVOID,
+                                     utf16.len() as u32,
+                                     &mut num as LPDWORD,
+                                     ptr::null_mut()) } {
+            0 => Err(super::last_error()),
+            _ => Ok(()),
+        }
+    }
+
+    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
+        // FIXME
+        // Somebody needs to decide on which of these flags we want
+        match unsafe { SetConsoleMode(self.handle,
+            match raw {
+                true => 0,
+                false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS |
+                         ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
+                         ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE,
+            }) } {
+            0 => Err(super::last_error()),
+            _ => Ok(()),
+        }
+    }
+
+    pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
+        // FIXME
+        // Get console buffer via CreateFile with CONOUT$
+        // Make a CONSOLE_SCREEN_BUFFER_INFO
+        // Call GetConsoleScreenBufferInfo
+        // Maybe call GetLargestConsoleWindowSize instead?
+        Err(super::unimpl())
+    }
+
+    // Let us magically declare this as a TTY
+    pub fn isatty(&self) -> bool { true }
+}
+
+impl Drop for TTY {
+    fn drop(&mut self) {
+        if self.closeme {
+            // Nobody cares about the return value
+            let _ = unsafe { CloseHandle(self.handle) };
+        }
+    }
+}
diff --git a/src/libstd/sys/windows/udp.rs b/src/libstd/sys/windows/udp.rs
new file mode 100644
index 00000000000..50f8fb828ad
--- /dev/null
+++ b/src/libstd/sys/windows/udp.rs
@@ -0,0 +1,11 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use sys_common::net::UdpSocket;