about summary refs log tree commit diff
path: root/src/libstd/rt/uv
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/uv
parent4ce71eaca34526d0e3ee1ebf0658d2a20d388ef2 (diff)
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/uv')
-rw-r--r--src/libstd/rt/uv/mod.rs11
-rw-r--r--src/libstd/rt/uv/uvio.rs86
-rw-r--r--src/libstd/rt/uv/uvll.rs5
3 files changed, 58 insertions, 44 deletions
diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs
index a03264af7e1..18c99157707 100644
--- a/src/libstd/rt/uv/mod.rs
+++ b/src/libstd/rt/uv/mod.rs
@@ -170,6 +170,7 @@ pub trait WatcherInterop {
     fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData;
     fn drop_watcher_data(&mut self);
     fn close(self, cb: NullCallback);
+    fn close_async(self);
 }
 
 impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
@@ -235,6 +236,16 @@ impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
             unsafe { uvll::free_handle(handle as *c_void) }
         }
     }
+
+    fn close_async(self) {
+        unsafe { uvll::close(self.native_handle(), close_cb); }
+
+        extern fn close_cb(handle: *uvll::uv_handle_t) {
+            let mut h: Handle = NativeHandle::from_native_handle(handle);
+            h.drop_watcher_data();
+            unsafe { uvll::free_handle(handle as *c_void) }
+        }
+    }
 }
 
 // XXX: Need to define the error constants like EOF so they can be
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index 322588973ae..915c7d0da52 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -868,13 +868,13 @@ impl IoFactory for UvIoFactory {
         return ret;
     }
 
-    fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool)
+    fn tty_open(&mut self, fd: c_int, readable: bool)
             -> Result<~RtioTTY, IoError> {
         match tty::TTY::new(self.uv_loop(), fd, readable) {
             Ok(tty) => Ok(~UvTTY {
                 home: get_handle_to_current_scheduler!(),
                 tty: tty,
-                close_on_drop: close_on_drop,
+                fd: fd,
             } as ~RtioTTY),
             Err(e) => Err(uv_error_to_io_error(e))
         }
@@ -1748,7 +1748,7 @@ impl RtioUnixListener for UvUnixListener {
 pub struct UvTTY {
     tty: tty::TTY,
     home: SchedHandle,
-    close_on_drop: bool,
+    fd: c_int,
 }
 
 impl HomingIO for UvTTY {
@@ -1757,20 +1757,48 @@ impl HomingIO for UvTTY {
 
 impl Drop for UvTTY {
     fn drop(&mut self) {
-        if self.close_on_drop {
-            let scheduler: ~Scheduler = Local::take();
-            do scheduler.deschedule_running_task_and_then |_, task| {
-                let task = Cell::new(task);
-                do self.tty.close {
-                    let scheduler: ~Scheduler = Local::take();
-                    scheduler.resume_blocked_task_immediately(task.take());
-                }
+        // TTY handles are used for the logger in a task, so this destructor is
+        // run when a task is destroyed. When a task is being destroyed, a local
+        // scheduler isn't available, so we can't do the normal "take the
+        // scheduler and resume once close is done". Instead close operations on
+        // a TTY are asynchronous.
+
+        self.tty.close_async();
+    }
+}
+
+impl RtioTTY for UvTTY {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
+        do self.home_for_io_with_sched |self_, scheduler| {
+            read_stream(self_.tty.as_stream(), scheduler, buf)
+        }
+    }
+
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+        do self.home_for_io_with_sched |self_, scheduler| {
+            write_stream(self_.tty.as_stream(), scheduler, buf)
+        }
+    }
+
+    fn set_raw(&mut self, raw: bool) -> Result<(), IoError> {
+        do self.home_for_io |self_| {
+            match self_.tty.set_mode(raw) {
+                Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
             }
-        } else {
-            self.tty.drop_watcher_data();
-            unsafe { uvll::free_handle(self.tty.native_handle()) }
         }
     }
+
+    fn get_winsize(&mut self) -> Result<(int, int), IoError> {
+        do self.home_for_io |self_| {
+            match self_.tty.get_winsize() {
+                Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
+            }
+        }
+    }
+
+    fn isatty(&self) -> bool {
+        unsafe { uvll::guess_handle(self.fd) == uvll::UV_TTY }
+    }
 }
 
 pub struct UvUnixAcceptor {
@@ -1808,36 +1836,6 @@ impl RtioUnixAcceptor for UvUnixAcceptor {
     }
 }
 
-impl RtioTTY for UvTTY {
-    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
-        do self.home_for_io_with_sched |self_, scheduler| {
-            read_stream(self_.tty.as_stream(), scheduler, buf)
-        }
-    }
-
-    fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
-        do self.home_for_io_with_sched |self_, scheduler| {
-            write_stream(self_.tty.as_stream(), scheduler, buf)
-        }
-    }
-
-    fn set_raw(&mut self, raw: bool) -> Result<(), IoError> {
-        do self.home_for_io |self_| {
-            match self_.tty.set_mode(raw) {
-                Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
-            }
-        }
-    }
-
-    fn get_winsize(&mut self) -> Result<(int, int), IoError> {
-        do self.home_for_io |self_| {
-            match self_.tty.get_winsize() {
-                Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
-            }
-        }
-    }
-}
-
 // this function is full of lies
 unsafe fn local_io() -> &'static mut IoFactory {
     do Local::borrow |sched: &mut Scheduler| {
diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs
index e78b2579779..8f8aea9d121 100644
--- a/src/libstd/rt/uv/uvll.rs
+++ b/src/libstd/rt/uv/uvll.rs
@@ -986,6 +986,10 @@ pub unsafe fn tty_get_winsize(tty: *uv_tty_t, width: *c_int,
     #[fixed_stack_segment]; #[inline(never)];
     rust_uv_tty_get_winsize(tty, width, height)
 }
+pub unsafe fn guess_handle(fd: c_int) -> uv_handle_type {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_uv_guess_handle(fd)
+}
 
 pub struct uv_err_data {
     priv err_name: ~str,
@@ -1140,6 +1144,7 @@ extern {
     fn rust_uv_tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int;
     fn rust_uv_tty_get_winsize(tty: *uv_tty_t, width: *c_int,
                                height: *c_int) -> c_int;
+    fn rust_uv_guess_handle(fd: c_int) -> uv_handle_type;
 
     // These should all really be constants...
     #[rust_stack] pub fn rust_SOCK_STREAM() -> c_int;