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) -> Result<~SignalWatcher, UvError> { - let handle = UvHandle::alloc(None::, uvll::UV_SIGNAL); + let s = ~SignalWatcher { + handle: UvHandle::alloc(None::, 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 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