summary refs log tree commit diff
path: root/src/libstd/rt/io
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-17 17:04:51 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-24 14:21:57 -0700
commit4eb53360541baf3e6df36dc0f0766bc7c1c9f8be (patch)
tree0b78ce834f9df44297595d66b38883831811b99f /src/libstd/rt/io
parent4ce71eaca34526d0e3ee1ebf0658d2a20d388ef2 (diff)
downloadrust-4eb53360541baf3e6df36dc0f0766bc7c1c9f8be.tar.gz
rust-4eb53360541baf3e6df36dc0f0766bc7c1c9f8be.zip
Move as much I/O as possible off of native::io
When uv's TTY I/O is used for the stdio streams, the file descriptors are put
into a non-blocking mode. This means that other concurrent writes to the same
stream can fail with EAGAIN or EWOULDBLOCK. By all I/O to event-loop I/O, we
avoid this error.

There is one location which cannot move, which is the runtime's dumb_println
function. This was implemented to handle the EAGAIN and EWOULDBLOCK errors and
simply retry again and again.
Diffstat (limited to 'src/libstd/rt/io')
-rw-r--r--src/libstd/rt/io/mod.rs2
-rw-r--r--src/libstd/rt/io/native/file.rs6
-rw-r--r--src/libstd/rt/io/stdio.rs68
3 files changed, 52 insertions, 24 deletions
diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs
index 1a5c197fd52..240210880bf 100644
--- a/src/libstd/rt/io/mod.rs
+++ b/src/libstd/rt/io/mod.rs
@@ -370,6 +370,7 @@ pub enum IoErrorKind {
     PathAlreadyExists,
     PathDoesntExist,
     MismatchedFileTypeForOperation,
+    ResourceUnavailable,
     IoUnavailable,
 }
 
@@ -392,6 +393,7 @@ impl ToStr for IoErrorKind {
             PathDoesntExist => ~"PathDoesntExist",
             MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation",
             IoUnavailable => ~"IoUnavailable",
+            ResourceUnavailable => ~"ResourceUnavailable",
         }
     }
 }
diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs
index d6820981181..a2b2289679a 100644
--- a/src/libstd/rt/io/native/file.rs
+++ b/src/libstd/rt/io/native/file.rs
@@ -21,6 +21,12 @@ fn raise_error() {
     // XXX: this should probably be a bit more descriptive...
     let (kind, desc) = match os::errno() as i32 {
         libc::EOF => (EndOfFile, "end of file"),
+
+        // These two constants can have the same value on some systems, but
+        // different values on others, so we can't use a match clause
+        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+            (ResourceUnavailable, "resource temporarily unavailable"),
+
         _ => (OtherIoError, "unknown error"),
     };
 
diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs
index 52838425422..294df9a6442 100644
--- a/src/libstd/rt/io/stdio.rs
+++ b/src/libstd/rt/io/stdio.rs
@@ -8,6 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*!
+
+This modules provides bindings to the local event loop's TTY interface, using it
+to have synchronous, but non-blocking versions of stdio. These handles can be
+inspected for information about terminal dimensions or related information
+about the stream or terminal that it is attached to.
+
+# Example
+
+```rust
+use std::rt::io;
+
+let mut out = io::stdout();
+out.write(bytes!("Hello, world!"));
+```
+
+*/
+
 use fmt;
 use libc;
 use option::{Option, Some, None};
@@ -15,13 +33,14 @@ use result::{Ok, Err};
 use rt::rtio::{IoFactory, RtioTTY, with_local_io};
 use super::{Reader, Writer, io_error};
 
-/// Creates a new non-blocking handle to the stdin of the current process.
-///
-/// See `stdout()` for notes about this function.
-pub fn stdin() -> StdReader {
+#[fixed_stack_segment] #[inline(never)]
+fn tty<T>(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T {
     do with_local_io |io| {
-        match io.tty_open(libc::STDIN_FILENO, true, false) {
-            Ok(tty) => Some(StdReader { inner: tty }),
+        // Always pass in readable as true, otherwise libuv turns our writes
+        // into blocking writes. We also need to dup the file descriptor because
+        // the tty will be closed when it's dropped.
+        match io.tty_open(unsafe { libc::dup(fd) }, true) {
+            Ok(tty) => Some(f(tty)),
             Err(e) => {
                 io_error::cond.raise(e);
                 None
@@ -30,6 +49,13 @@ pub fn stdin() -> StdReader {
     }.unwrap()
 }
 
+/// Creates a new non-blocking handle to the stdin of the current process.
+///
+/// See `stdout()` for notes about this function.
+pub fn stdin() -> StdReader {
+    do tty(libc::STDIN_FILENO) |tty| { StdReader { inner: tty } }
+}
+
 /// Creates a new non-blocking handle to the stdout of the current process.
 ///
 /// Note that this is a fairly expensive operation in that at least one memory
@@ -37,30 +63,14 @@ pub fn stdin() -> StdReader {
 /// task context because the stream returned will be a non-blocking object using
 /// the local scheduler to perform the I/O.
 pub fn stdout() -> StdWriter {
-    do with_local_io |io| {
-        match io.tty_open(libc::STDOUT_FILENO, false, false) {
-            Ok(tty) => Some(StdWriter { inner: tty }),
-            Err(e) => {
-                io_error::cond.raise(e);
-                None
-            }
-        }
-    }.unwrap()
+    do tty(libc::STDOUT_FILENO) |tty| { StdWriter { inner: tty } }
 }
 
 /// Creates a new non-blocking handle to the stderr of the current process.
 ///
 /// See `stdout()` for notes about this function.
 pub fn stderr() -> StdWriter {
-    do with_local_io |io| {
-        match io.tty_open(libc::STDERR_FILENO, false, false) {
-            Ok(tty) => Some(StdWriter { inner: tty }),
-            Err(e) => {
-                io_error::cond.raise(e);
-                None
-            }
-        }
-    }.unwrap()
+    do tty(libc::STDERR_FILENO) |tty| { StdWriter { inner: tty } }
 }
 
 /// Prints a string to the stdout of the current process. No newline is emitted
@@ -115,6 +125,11 @@ impl StdReader {
             Err(e) => io_error::cond.raise(e),
         }
     }
+
+    /// Returns whether this tream is attached to a TTY instance or not.
+    ///
+    /// This is similar to libc's isatty() function
+    pub fn isatty(&self) -> bool { self.inner.isatty() }
 }
 
 impl Reader for StdReader {
@@ -170,6 +185,11 @@ impl StdWriter {
             Err(e) => io_error::cond.raise(e),
         }
     }
+
+    /// Returns whether this tream is attached to a TTY instance or not.
+    ///
+    /// This is similar to libc's isatty() function
+    pub fn isatty(&self) -> bool { self.inner.isatty() }
 }
 
 impl Writer for StdWriter {