From e38a89d0b0fcc3b2f5cad600d7b3a16faeb94248 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Sat, 9 Nov 2013 11:02:16 -0800
Subject: [PATCH] Fix usage of libuv for windows

---
 .gitmodules               |  2 +-
 src/librustuv/net.rs      |  1 +
 src/librustuv/pipe.rs     |  6 ++++++
 src/librustuv/process.rs  |  2 +-
 src/librustuv/signal.rs   | 29 ++++++++++++-----------------
 src/librustuv/timer.rs    | 33 ++++++++++++++++++++++++++++++---
 src/librustuv/tty.rs      |  2 +-
 src/librustuv/uvll.rs     | 34 +++++++++++++++++++++++-----------
 src/libstd/rt/io/stdio.rs | 12 +++++++++++-
 src/libstd/rt/io/timer.rs |  8 ++------
 src/libuv                 |  2 +-
 11 files changed, 89 insertions(+), 42 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index a861cf79978..7e997334cec 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,7 +4,7 @@
 	branch = master
 [submodule "src/libuv"]
 	path = src/libuv
-	url = https://github.com/joyent/libuv.git
+	url = https://github.com/alexcrichton/libuv.git
 	branch = master
 [submodule "src/gyp"]
 	path = src/gyp
diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs
index 0fc87e4e4fa..32c9b6c3d17 100644
--- a/src/librustuv/net.rs
+++ b/src/librustuv/net.rs
@@ -883,6 +883,7 @@ mod test {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#10102) server never sees second packet
     fn test_udp_twice() {
         let server_addr = next_test_ip4();
         let client_addr = next_test_ip4();
diff --git a/src/librustuv/pipe.rs b/src/librustuv/pipe.rs
index 1b0f352dc4d..c123f916ef2 100644
--- a/src/librustuv/pipe.rs
+++ b/src/librustuv/pipe.rs
@@ -251,6 +251,7 @@ mod tests {
     use super::super::local_loop;
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
     fn connect_err() {
         match PipeWatcher::connect(local_loop(), &"path/to/nowhere".to_c_str()) {
             Ok(*) => fail!(),
@@ -259,6 +260,7 @@ mod tests {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
     fn bind_err() {
         match PipeListener::bind(local_loop(), &"path/to/nowhere".to_c_str()) {
             Ok(*) => fail!(),
@@ -267,6 +269,7 @@ mod tests {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
     fn bind() {
         let p = next_test_unix().to_c_str();
         match PipeListener::bind(local_loop(), &p) {
@@ -276,6 +279,7 @@ mod tests {
     }
 
     #[test] #[should_fail]
+    #[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
     fn bind_fail() {
         let p = next_test_unix().to_c_str();
         let _w = PipeListener::bind(local_loop(), &p).unwrap();
@@ -283,6 +287,7 @@ mod tests {
     }
 
     #[test]
+    #[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
     fn connect() {
         let path = next_test_unix();
         let path2 = path.clone();
@@ -308,6 +313,7 @@ mod tests {
     }
 
     #[test] #[should_fail]
+    #[ignore(cfg(windows))] // FIXME(#10386): how windows pipes work
     fn connect_fail() {
         let path = next_test_unix();
         let path2 = path.clone();
diff --git a/src/librustuv/process.rs b/src/librustuv/process.rs
index 840ae814f35..7e75515972c 100644
--- a/src/librustuv/process.rs
+++ b/src/librustuv/process.rs
@@ -232,6 +232,6 @@ impl Drop for Process {
     fn drop(&mut self) {
         let _m = self.fire_homing_missile();
         assert!(self.to_wake.is_none());
-        self.close_async_();
+        self.close();
     }
 }
diff --git a/src/librustuv/signal.rs b/src/librustuv/signal.rs
index 5486cdfc418..da2e1d8837c 100644
--- a/src/librustuv/signal.rs
+++ b/src/librustuv/signal.rs
@@ -30,26 +30,21 @@ pub struct SignalWatcher {
 impl SignalWatcher {
     pub fn new(loop_: &mut Loop, signum: Signum,
                channel: SharedChan<Signum>) -> Result<~SignalWatcher, UvError> {
-        let handle = UvHandle::alloc(None::<SignalWatcher>, uvll::UV_SIGNAL);
+        let s = ~SignalWatcher {
+            handle: UvHandle::alloc(None::<SignalWatcher>, uvll::UV_SIGNAL),
+            home: get_handle_to_current_scheduler!(),
+            channel: channel,
+            signal: signum,
+        };
         assert_eq!(unsafe {
-            uvll::uv_signal_init(loop_.handle, handle)
-
+            uvll::uv_signal_init(loop_.handle, s.handle)
         }, 0);
 
-        match unsafe { uvll::uv_signal_start(handle, signal_cb, signum as c_int) } {
-            0 => {
-                let s = ~SignalWatcher {
-                    handle: handle,
-                    home: get_handle_to_current_scheduler!(),
-                    channel: channel,
-                    signal: signum,
-                };
-                Ok(s.install())
-            }
-            n => {
-                unsafe { uvll::free_handle(handle) }
-                Err(UvError(n))
-            }
+        match unsafe {
+            uvll::uv_signal_start(s.handle, signal_cb, signum as c_int)
+        } {
+            0 => Ok(s.install()),
+            n => Err(UvError(n)),
         }
 
     }
diff --git a/src/librustuv/timer.rs b/src/librustuv/timer.rs
index 7cc41b2a882..01763990305 100644
--- a/src/librustuv/timer.rs
+++ b/src/librustuv/timer.rs
@@ -67,12 +67,27 @@ impl UvHandle<uvll::uv_timer_t> for TimerWatcher {
 
 impl RtioTimer for TimerWatcher {
     fn sleep(&mut self, msecs: u64) {
-        let (_m, sched) = self.fire_homing_missile_sched();
+        // As with all of the below functions, we must be extra careful when
+        // destroying the previous action. If the previous action was a channel,
+        // destroying it could invoke a context switch. For these situtations,
+        // we must temporarily un-home ourselves, then destroy the action, and
+        // then re-home again.
+        let missile = self.fire_homing_missile();
+        self.stop();
+        let _missile = match util::replace(&mut self.action, None) {
+            None => missile, // no need to do a homing dance
+            Some(action) => {
+                util::ignore(missile);      // un-home ourself
+                util::ignore(action);       // destroy the previous action
+                self.fire_homing_missile()  // re-home ourself
+            }
+        };
 
         // If the descheduling operation unwinds after the timer has been
         // started, then we need to call stop on the timer.
         let _f = ForbidUnwind::new("timer");
 
+        let sched: ~Scheduler = Local::take();
         do sched.deschedule_running_task_and_then |_sched, task| {
             self.action = Some(WakeTask(task));
             self.start(msecs, 0);
@@ -87,6 +102,7 @@ impl RtioTimer for TimerWatcher {
         // of the homing missile
         let _prev_action = {
             let _m = self.fire_homing_missile();
+            self.stop();
             self.start(msecs, 0);
             util::replace(&mut self.action, Some(SendOnce(chan)))
         };
@@ -97,12 +113,11 @@ impl RtioTimer for TimerWatcher {
     fn period(&mut self, msecs: u64) -> Port<()> {
         let (port, chan) = stream();
 
-        let _m = self.fire_homing_missile();
-
         // similarly to the destructor, we must drop the previous action outside
         // of the homing missile
         let _prev_action = {
             let _m = self.fire_homing_missile();
+            self.stop();
             self.start(msecs, msecs);
             util::replace(&mut self.action, Some(SendMany(chan)))
         };
@@ -236,6 +251,18 @@ mod test {
 
         timer.oneshot(1);
     }
+    #[test]
+    fn reset_doesnt_switch_tasks2() {
+        // similar test to the one above.
+        let mut timer = TimerWatcher::new(local_loop());
+        let timer_port = Cell::new(timer.period(1000));
+
+        do spawn {
+            timer_port.take().try_recv();
+        }
+
+        timer.sleep(1);
+    }
 
     #[test]
     fn sender_goes_away_oneshot() {
diff --git a/src/librustuv/tty.rs b/src/librustuv/tty.rs
index 4853973f1a3..d3f001f3931 100644
--- a/src/librustuv/tty.rs
+++ b/src/librustuv/tty.rs
@@ -113,6 +113,6 @@ impl HomingIO for TtyWatcher {
 impl Drop for TtyWatcher {
     fn drop(&mut self) {
         let _m = self.fire_homing_missile();
-        self.close();
+        self.close_async_();
     }
 }
diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs
index 5f68ac5e71d..c76d03bfe6c 100644
--- a/src/librustuv/uvll.rs
+++ b/src/librustuv/uvll.rs
@@ -47,14 +47,14 @@ pub static UNKNOWN: c_int = -4094;
 pub mod errors {
     use std::libc::c_int;
 
-    pub static EACCES: c_int = -4093;
-    pub static ECONNREFUSED: c_int = -4079;
-    pub static ECONNRESET: c_int = -4078;
-    pub static ENOTCONN: c_int = -4054;
-    pub static EPIPE: c_int = -4048;
-    pub static ECONNABORTED: c_int = -4080;
-    pub static ECANCELED: c_int = -4082;
-    pub static EBADF: c_int = -4084;
+    pub static EACCES: c_int = -4092;
+    pub static ECONNREFUSED: c_int = -4078;
+    pub static ECONNRESET: c_int = -4077;
+    pub static ENOTCONN: c_int = -4053;
+    pub static EPIPE: c_int = -4047;
+    pub static ECONNABORTED: c_int = -4079;
+    pub static ECANCELED: c_int = -4081;
+    pub static EBADF: c_int = -4083;
 }
 #[cfg(not(windows))]
 pub mod errors {
@@ -87,19 +87,19 @@ pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
 #[cfg(unix)]
 pub type uv_buf_len_t = libc::size_t;
 #[cfg(windows)]
-pub type uv_buf_len_t = u32;
+pub type uv_buf_len_t = libc::c_ulong;
 
 // see libuv/include/uv-unix.h
 #[cfg(unix)]
 pub struct uv_buf_t {
     base: *u8,
-    len: libc::size_t,
+    len: uv_buf_len_t,
 }
 
 // see libuv/include/uv-win.h
 #[cfg(windows)]
 pub struct uv_buf_t {
-    len: u32,
+    len: uv_buf_len_t,
     base: *u8,
 }
 
@@ -544,7 +544,19 @@ pub unsafe fn guess_handle(handle: c_int) -> c_int {
 
 
 // uv_support is the result of compiling rust_uv.cpp
+//
+// Note that this is in a cfg'd block so it doesn't get linked during testing.
+// There's a bit of a conundrum when testing in that we're actually assuming
+// that the tests are running in a uv loop, but they were created from the
+// statically linked uv to the original rustuv crate. When we create the test
+// executable, on some platforms if we re-link against uv, it actually creates
+// second copies of everything. We obviously don't want this, so instead of
+// dying horribly during testing, we allow all of the test rustuv's references
+// to get resolved to the original rustuv crate.
 #[link_args = "-luv_support -luv"]
+#[cfg(not(test))]
+extern {}
+
 extern {
     fn rust_uv_loop_new() -> *c_void;
 
diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs
index 674b34639bc..acc2e11f067 100644
--- a/src/libstd/rt/io/stdio.rs
+++ b/src/libstd/rt/io/stdio.rs
@@ -33,7 +33,8 @@ use result::{Ok, Err};
 use rt::io::buffered::LineBufferedWriter;
 use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
                CloseAsynchronously};
-use super::{Reader, Writer, io_error, IoError, OtherIoError};
+use super::{Reader, Writer, io_error, IoError, OtherIoError,
+            standard_error, EndOfFile};
 
 // And so begins the tale of acquiring a uv handle to a stdio stream on all
 // platforms in all situations. Our story begins by splitting the world into two
@@ -203,6 +204,15 @@ impl Reader for StdReader {
             File(ref mut file) => file.read(buf).map(|i| i as uint),
         };
         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
+            // return an actual EOF error, but apparently for stdin it's a
+            // little different. Hence, here we convert a 0 length read to an
+            // end-of-file indicator so the caller knows to stop reading.
+            Ok(0) => {
+                io_error::cond.raise(standard_error(EndOfFile));
+                None
+            }
             Ok(amt) => Some(amt as uint),
             Err(e) => {
                 io_error::cond.raise(e);
diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs
index fed6b9daa64..b0cf7dee10a 100644
--- a/src/libstd/rt/io/timer.rs
+++ b/src/libstd/rt/io/timer.rs
@@ -142,14 +142,10 @@ mod test {
     fn oneshot_twice() {
         do run_in_mt_newsched_task {
             let mut timer = Timer::new().unwrap();
-            let port1 = timer.oneshot(100000000000);
+            let port1 = timer.oneshot(10000);
             let port = timer.oneshot(1);
             port.recv();
-            let port1 = Cell::new(port1);
-            let ret = do task::try {
-                port1.take().recv();
-            };
-            assert!(ret.is_err());
+            assert_eq!(port1.try_recv(), None);
         }
     }
 
diff --git a/src/libuv b/src/libuv
index c6ecf97aafc..7ac7e0248b3 160000
--- a/src/libuv
+++ b/src/libuv
@@ -1 +1 @@
-Subproject commit c6ecf97aafc858c2ad1089fb78da6c586d61d8b6
+Subproject commit 7ac7e0248b34732e9963cdb8e31f7e612d23d14b