diff --git a/src/libextra/url.rs b/src/libextra/url.rs index bfa3934700a..d268b106e5c 100644 --- a/src/libextra/url.rs +++ b/src/libextra/url.rs @@ -145,7 +145,7 @@ fn decode_inner(s: &str, full_url: bool) -> ~str { let mut bytes = [0, 0]; match rdr.read(bytes) { Some(2) => {} - _ => fail2!() // XXX: malformed url? + _ => fail!() // XXX: malformed url? } let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char; @@ -279,7 +279,7 @@ pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> { let mut bytes = [0, 0]; match rdr.read(bytes) { Some(2) => {} - _ => fail2!() // XXX: malformed? + _ => fail!() // XXX: malformed? } uint::parse_bytes(bytes, 16u).unwrap() as u8 as char } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 16e13f70092..ce5e81d4109 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -11,7 +11,10 @@ // rustpkg unit tests use context::{BuildContext, Context, RustcFlags}; -use std::{io, os, run, str, task}; +use std::{os, run, str, task}; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use extra::arc::Arc; use extra::arc::RWArc; use extra::tempfile::TempDir; @@ -81,8 +84,9 @@ fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { } fn writeFile(file_path: &Path, contents: &str) { - let out = io::file_writer(file_path, [io::Create, io::Truncate]).unwrap(); - out.write_line(contents); + let mut out = file_path.open_writer(io::CreateOrTruncate); + out.write(contents.as_bytes()); + out.write(['\n' as u8]); } fn mk_emptier_workspace(tag: &str) -> TempDir { @@ -550,10 +554,11 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) { debug!("Frobbed? {:?}", maybe_p); match maybe_p { Some(ref p) => { - let w = io::file_writer(p, &[io::Append]); - match w { - Err(s) => { let _ = cond.raise((p.clone(), format!("Bad path: {}", s))); } - Ok(w) => w.write_line("/* hi */") + do io::io_error::cond.trap(|e| { + cond.raise((p.clone(), format!("Bad path: {}", e.desc))); + }).inside { + let mut w = p.open_writer(io::Append); + w.write(bytes!("/* hi */\n")); } } None => fail!("frob_source_file failed to find a source file in {}", diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs index b667dc0a576..016635339a9 100644 --- a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs @@ -11,7 +11,7 @@ extern mod rustpkg; extern mod rustc; -use std::{io, os, task}; +use std::{os, task}; use rustpkg::api; use rustpkg::version::NoVersion; use rustpkg::workcache_support::digest_file_with_date; @@ -36,7 +36,7 @@ pub fn main() { } if args[2] != ~"install" { - io::println(format!("Warning: I don't know how to {}", args[2])); + println(format!("Warning: I don't know how to {}", args[2])); return; } diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index 0b838b3e0f9..f82c585b1d1 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -11,7 +11,10 @@ extern mod rustpkg; extern mod rustc; -use std::{io, os}; +use std::os; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use rustpkg::api; use rustpkg::version::NoVersion; @@ -42,9 +45,9 @@ pub fn main() { let out_path = os::self_exe_path().expect("Couldn't get self_exe path"); debug!("Writing file"); - let file = io::file_writer(&out_path.join("generated.rs"), [io::Create]).unwrap(); - file.write_str("pub fn wheeeee() { let xs = [1, 2, 3]; \ - for _ in xs.iter() { assert!(true); } }"); + let mut file = out_path.join("generated.rs").open_writer(io::Create); + file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \ + for _ in xs.iter() { assert!(true); } }".as_bytes()); let context = api::default_context(sysroot, api::default_workspace()); api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]); diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs index 07fe91f57a0..a13fc19d000 100644 --- a/src/libstd/rt/io/signal.rs +++ b/src/libstd/rt/io/signal.rs @@ -147,6 +147,7 @@ impl Listener { mod test { use libc; use rt::io::timer; + use rt::io; use super::*; // kill is only available on Unixes @@ -158,7 +159,7 @@ mod test { } } - #[test] + #[test] #[cfg(unix)] fn test_io_signal_smoketest() { let mut signal = Listener::new(); signal.register(Interrupt); @@ -166,11 +167,11 @@ mod test { timer::sleep(10); match signal.port.recv() { Interrupt => (), - s => fail2!("Expected Interrupt, got {:?}", s), + s => fail!("Expected Interrupt, got {:?}", s), } } - #[test] + #[test] #[cfg(unix)] fn test_io_signal_two_signal_one_signum() { let mut s1 = Listener::new(); let mut s2 = Listener::new(); @@ -180,15 +181,15 @@ mod test { timer::sleep(10); match s1.port.recv() { Interrupt => (), - s => fail2!("Expected Interrupt, got {:?}", s), + s => fail!("Expected Interrupt, got {:?}", s), } match s1.port.recv() { Interrupt => (), - s => fail2!("Expected Interrupt, got {:?}", s), + s => fail!("Expected Interrupt, got {:?}", s), } } - #[test] + #[test] #[cfg(unix)] fn test_io_signal_unregister() { let mut s1 = Listener::new(); let mut s2 = Listener::new(); @@ -198,7 +199,7 @@ mod test { sigint(); timer::sleep(10); if s2.port.peek() { - fail2!("Unexpected {:?}", s2.port.recv()); + fail!("Unexpected {:?}", s2.port.recv()); } } @@ -206,8 +207,14 @@ mod test { #[test] fn test_io_signal_invalid_signum() { let mut s = Listener::new(); - if s.register(User1) { - fail2!("Unexpected successful registry of signum {:?}", User1); + let mut called = false; + do io::io_error::cond.trap(|_| { + called = true; + }).inside { + if s.register(User1) { + fail!("Unexpected successful registry of signum {:?}", User1); + } } + assert!(called); } } diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index e601ece88bb..b922e6400cc 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -30,20 +30,57 @@ use fmt; use libc; use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::rtio::{IoFactory, RtioTTY, with_local_io, RtioPipe}; -use super::{Reader, Writer, io_error}; +use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io, + CloseAsynchronously}; +use super::{Reader, Writer, io_error, IoError, OtherIoError}; + +// 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 +// categories, windows and unix. Then one day the creators of unix said let +// there be redirection! And henceforth there was redirection away from the +// console for standard I/O streams. +// +// After this day, the world split into four factions: +// +// 1. Unix with stdout on a terminal. +// 2. Unix with stdout redirected. +// 3. Windows with stdout on a terminal. +// 4. Windows with stdout redirected. +// +// Many years passed, and then one day the nation of libuv decided to unify this +// world. After months of toiling, uv created three ideas: TTY, Pipe, File. +// These three ideas propagated throughout the lands and the four great factions +// decided to settle among them. +// +// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon +// doing so, they even enhanced themselves further then their Pipe/File +// brethren, becoming the dominant powers. +// +// The group of 4, however, decided to work independently. They abandoned the +// common TTY belief throughout, and even abandoned the fledgling Pipe belief. +// The members of the 4th faction decided to only align themselves with File. +// +// 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(~RtioTTY), + File(~RtioFileStream), +} #[fixed_stack_segment] #[inline(never)] -fn tty(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T { +fn src(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T { do with_local_io |io| { - // 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 + let fd = unsafe { libc::dup(fd) }; + match io.tty_open(fd, readable) { + Ok(tty) => Some(f(TTY(tty))), + Err(_) => { + // It's not really that desirable if these handles are closed + // synchronously, and because they're squirreled away in a task + // structure the destructors will be run when the task is + // attempted to get destroyed. This means that if we run a + // synchronous destructor we'll attempt to do some scheduling + // operations which will just result in sadness. + Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously)))) } } }.unwrap() @@ -54,15 +91,7 @@ fn tty(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T { /// See `stdout()` for notes about this function. #[fixed_stack_segment] #[inline(never)] pub fn stdin() -> StdReader { - do with_local_io |io| { - match io.pipe_open(unsafe { libc::dup(libc::STDIN_FILENO) }) { - Ok(stream) => Some(StdReader { inner: stream }), - Err(e) => { - io_error::cond.raise(e); - None - } - } - }.unwrap() + do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } } } /// Creates a new non-blocking handle to the stdout of the current process. @@ -72,14 +101,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 tty(libc::STDOUT_FILENO) |tty| { StdWriter { inner: tty } } + do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } } } /// 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 tty(libc::STDERR_FILENO) |tty| { StdWriter { inner: tty } } + do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } } } /// Prints a string to the stdout of the current process. No newline is emitted @@ -117,12 +146,16 @@ pub fn println_args(fmt: &fmt::Arguments) { /// Representation of a reader of a standard input stream pub struct StdReader { - priv inner: ~RtioPipe + priv inner: StdSource } impl Reader for StdReader { fn read(&mut self, buf: &mut [u8]) -> Option { - match self.inner.read(buf) { + let ret = match self.inner { + TTY(ref mut tty) => tty.read(buf), + File(ref mut file) => file.read(buf).map_move(|i| i as uint), + }; + match ret { Ok(amt) => Some(amt as uint), Err(e) => { io_error::cond.raise(e); @@ -136,7 +169,7 @@ impl Reader for StdReader { /// Representation of a writer to a standard output stream pub struct StdWriter { - priv inner: ~RtioTTY + priv inner: StdSource } impl StdWriter { @@ -151,10 +184,22 @@ impl StdWriter { /// This function will raise on the `io_error` condition if an error /// happens. pub fn winsize(&mut self) -> Option<(int, int)> { - match self.inner.get_winsize() { - Ok(p) => Some(p), - Err(e) => { - io_error::cond.raise(e); + match self.inner { + TTY(ref mut tty) => { + match tty.get_winsize() { + Ok(p) => Some(p), + Err(e) => { + io_error::cond.raise(e); + None + } + } + } + File(*) => { + io_error::cond.raise(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }); None } } @@ -168,21 +213,41 @@ impl StdWriter { /// This function will raise on the `io_error` condition if an error /// happens. pub fn set_raw(&mut self, raw: bool) { - match self.inner.set_raw(raw) { - Ok(()) => {}, - Err(e) => io_error::cond.raise(e), + match self.inner { + TTY(ref mut tty) => { + match tty.set_raw(raw) { + Ok(()) => {}, + Err(e) => io_error::cond.raise(e), + } + } + File(*) => { + io_error::cond.raise(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }); + } } } /// 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() } + pub fn isatty(&self) -> bool { + match self.inner { + TTY(ref tty) => tty.isatty(), + File(*) => false, + } + } } impl Writer for StdWriter { fn write(&mut self, buf: &[u8]) { - match self.inner.write(buf) { + let ret = match self.inner { + TTY(ref mut tty) => tty.write(buf), + File(ref mut file) => file.write(buf), + }; + match ret { Ok(()) => {} Err(e) => io_error::cond.raise(e) } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 528be59c54f..66a0676a2f4 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -58,6 +58,20 @@ pub struct FileOpenConfig { priv mode: int } +/// Description of what to do when a file handle is closed +pub enum CloseBehavior { + /// Do not close this handle when the object is destroyed + DontClose, + /// Synchronously close the handle, meaning that the task will block when + /// the handle is destroyed until it has been fully closed. + CloseSynchronously, + /// Asynchronously closes a handle, meaning that the task will *not* block + /// when the handle is destroyed, but the handle will still get deallocated + /// and cleaned up (but this will happen asynchronously on the local event + /// loop). + CloseAsynchronously, +} + pub fn with_local_io(f: &fn(&mut IoFactory) -> Option) -> Option { use rt::sched::Scheduler; use rt::local::Local; @@ -84,7 +98,7 @@ pub trait IoFactory { fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; + fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>; diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index b3c65ce4749..1ea68bb52d7 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -479,7 +479,6 @@ pub extern "C" fn rust_stack_exhausted() { use rt::in_green_task_context; use rt::task::Task; use rt::local::Local; - use rt::logging::Logger; use unstable::intrinsics; unsafe { @@ -529,8 +528,12 @@ pub extern "C" fn rust_stack_exhausted() { do Local::borrow |task: &mut Task| { let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or(""); - format_args!(|args| { task.logger.log(args) }, - "task '{}' has overflowed its stack", n); + // See the message below for why this is not emitted to the + // task's logger. This has the additional conundrum of the + // logger may not be initialized just yet, meaning that an FFI + // call would happen to initialized it (calling out to libuv), + // and the FFI call needs 2MB of stack when we just ran out. + rterrln!("task '{}' has overflowed its stack", n); } } else { rterrln!("stack overflow in non-task context"); diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 78b3a88f5f1..d2ca15959b0 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -43,10 +43,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), self.native_handle(), p, flags, mode, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn open_sync(self, loop_: &Loop, path: &CString, @@ -67,10 +68,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_unlink(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn unlink_sync(self, loop_: &Loop, path: &CString) @@ -91,10 +93,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_stat(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) { @@ -104,11 +107,12 @@ impl FsRequest { }; let base_ptr = buf.base as *c_void; let len = buf.len as uint; - unsafe { + let ret = unsafe { uvll::fs_write(loop_.native_handle(), self.native_handle(), fd, base_ptr, len, offset, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { @@ -133,11 +137,12 @@ impl FsRequest { }; let buf_ptr = buf.base as *c_void; let len = buf.len as uint; - unsafe { + let ret = unsafe { uvll::fs_read(loop_.native_handle(), self.native_handle(), fd, buf_ptr, len, offset, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { @@ -160,10 +165,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - unsafe { + let ret = unsafe { uvll::fs_close(loop_.native_handle(), self.native_handle(), fd, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result { let complete_cb_ptr = { @@ -182,10 +188,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_mkdir(loop_.native_handle(), - self.native_handle(), p, mode, complete_cb_ptr) + self.native_handle(), p, mode, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) { @@ -193,10 +200,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_rmdir(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) + self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn readdir(self, loop_: &Loop, path: &CString, @@ -205,10 +213,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_readdir(loop_.native_handle(), - self.native_handle(), p, flags, complete_cb_ptr) + self.native_handle(), p, flags, complete_cb_ptr) }); + assert_eq!(ret, 0); } // accessors/utility funcs diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs index 9d392583b9e..40f0750b2d0 100644 --- a/src/libstd/rt/uv/idle.rs +++ b/src/libstd/rt/uv/idle.rs @@ -20,9 +20,9 @@ impl Watcher for IdleWatcher { } impl IdleWatcher { pub fn new(loop_: &mut Loop) -> IdleWatcher { unsafe { - let handle = uvll::idle_new(); + let handle = uvll::malloc_handle(uvll::UV_IDLE); assert!(handle.is_not_null()); - assert!(0 == uvll::idle_init(loop_.native_handle(), handle)); + assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0); let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle); watcher.install_watcher_data(); return watcher @@ -36,29 +36,14 @@ impl IdleWatcher { } unsafe { - assert!(0 == uvll::idle_start(self.native_handle(), idle_cb)) - }; - - extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - let data = idle_watcher.get_watcher_data(); - let cb: &IdleCallback = data.idle_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(idle_watcher, status); + assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0) } } pub fn restart(&mut self) { unsafe { - assert!(0 == uvll::idle_start(self.native_handle(), idle_cb)) - }; - - extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - let data = idle_watcher.get_watcher_data(); - let cb: &IdleCallback = data.idle_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(idle_watcher, status); + assert!(self.get_watcher_data().idle_cb.is_some()); + assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0) } } @@ -68,7 +53,7 @@ impl IdleWatcher { // free unsafe { - assert!(0 == uvll::idle_stop(self.native_handle())); + assert_eq!(uvll::idle_stop(self.native_handle()), 0); } } } @@ -82,6 +67,14 @@ impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher { } } +extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { + let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); + let data = idle_watcher.get_watcher_data(); + let cb: &IdleCallback = data.idle_cb.get_ref(); + let status = status_to_maybe_uv_error(status); + (*cb)(idle_watcher, status); +} + #[cfg(test)] mod test { diff --git a/src/libstd/rt/uv/signal.rs b/src/libstd/rt/uv/signal.rs index e51b7d90d95..3252c89673d 100644 --- a/src/libstd/rt/uv/signal.rs +++ b/src/libstd/rt/uv/signal.rs @@ -51,7 +51,7 @@ impl SignalWatcher { let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); let data = watcher.get_watcher_data(); let cb = data.signal_cb.get_ref(); - (*cb)(watcher, unsafe { cast::transmute(signum as i64) }); + (*cb)(watcher, unsafe { cast::transmute(signum as int) }); } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 473eec32c67..29370c484eb 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -547,10 +547,10 @@ impl IoFactory for UvIoFactory { Ok(~UvTimer::new(watcher, home) as ~RtioTimer) } - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream { + fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream { let loop_ = Loop {handle: self.uv_loop().native_handle()}; let home = get_handle_to_current_scheduler!(); - ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream + ~UvFileStream::new(loop_, fd, close, home) as ~RtioFileStream } fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) @@ -590,7 +590,7 @@ impl IoFactory for UvIoFactory { let home = get_handle_to_current_scheduler!(); let fd = req.get_result() as c_int; let fs = ~UvFileStream::new( - loop_, fd, true, home) as ~RtioFileStream; + loop_, fd, CloseSynchronously, home) as ~RtioFileStream; let res = Ok(fs); unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); @@ -1482,8 +1482,8 @@ impl RtioTimer for UvTimer { pub struct UvFileStream { priv loop_: Loop, priv fd: c_int, - priv close_on_drop: bool, - priv home: SchedHandle + priv close: CloseBehavior, + priv home: SchedHandle, } impl HomingIO for UvFileStream { @@ -1491,13 +1491,13 @@ impl HomingIO for UvFileStream { } impl UvFileStream { - fn new(loop_: Loop, fd: c_int, close_on_drop: bool, + fn new(loop_: Loop, fd: c_int, close: CloseBehavior, home: SchedHandle) -> UvFileStream { UvFileStream { loop_: loop_, fd: fd, - close_on_drop: close_on_drop, - home: home + close: close, + home: home, } } fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result { @@ -1517,9 +1517,9 @@ impl UvFileStream { unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - }; + } + } + } result_cell.take() } fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { @@ -1539,9 +1539,9 @@ impl UvFileStream { unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - }; + } + } + } result_cell.take() } fn seek_common(&mut self, pos: i64, whence: c_int) -> @@ -1564,16 +1564,23 @@ impl UvFileStream { impl Drop for UvFileStream { fn drop(&mut self) { - if self.close_on_drop { - do self.home_for_io_with_sched |self_, scheduler| { - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - let close_req = file::FsRequest::new(); - do close_req.close(&self_.loop_, self_.fd) |_,_| { - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; + match self.close { + DontClose => {} + CloseAsynchronously => { + let close_req = file::FsRequest::new(); + do close_req.close(&self.loop_, self.fd) |_,_| {} + } + CloseSynchronously => { + do self.home_for_io_with_sched |self_, scheduler| { + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let close_req = file::FsRequest::new(); + do close_req.close(&self_.loop_, self_.fd) |_,_| { + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } } } } @@ -1750,7 +1757,6 @@ impl Drop for UvTTY { // 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(); } } @@ -2465,7 +2471,7 @@ fn uvio_naive_print(input: &str) { use libc::{STDOUT_FILENO}; let io = local_io(); { - let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, false); + let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, DontClose); let write_buf = input.as_bytes(); fd.write(write_buf); } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index fa4083657d5..75e6a0c6ca5 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -235,37 +235,37 @@ pub type socklen_t = c_int; #[cfg(target_os = "android")] #[cfg(target_os = "linux")] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: socklen_t, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, ai_addr: *sockaddr, - priv ai_canonname: *char, + ai_canonname: *char, ai_next: *addrinfo } #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: socklen_t, - priv ai_canonname: *char, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, + ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } #[cfg(windows)] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: size_t, - priv ai_canonname: *char, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } @@ -423,18 +423,6 @@ pub unsafe fn walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void) { rust_uv_walk(loop_handle, cb, arg); } -pub unsafe fn idle_new() -> *uv_idle_t { - #[fixed_stack_segment]; #[inline(never)]; - - rust_uv_idle_new() -} - -pub unsafe fn idle_delete(handle: *uv_idle_t) { - #[fixed_stack_segment]; #[inline(never)]; - - rust_uv_idle_delete(handle) -} - pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int { #[fixed_stack_segment]; #[inline(never)]; @@ -1028,8 +1016,6 @@ extern { fn rust_uv_close(handle: *c_void, cb: uv_close_cb); fn rust_uv_walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void); - fn rust_uv_idle_new() -> *uv_idle_t; - fn rust_uv_idle_delete(handle: *uv_idle_t); fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int; fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int; fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 650ef491a3b..615ba60e066 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -219,16 +219,27 @@ impl Process { let (p, ch) = stream(); let ch = SharedChan::new(ch); let ch_clone = ch.clone(); - do task::spawn_sched(task::SingleThreaded) { - match error.take() { - Some(ref mut e) => ch.send((2, e.read_to_end())), - None => ch.send((2, ~[])) + + // FIXME(#910, #8674): right now I/O is incredibly brittle when it comes + // to linked failure, so these tasks must be spawn so they're not + // affected by linked failure. If these are removed, then the + // runtime may never exit because linked failure will cause some + // SchedHandle structures to not get destroyed, meaning that + // there's always an async watcher available. + do task::spawn_unlinked { + do io::ignore_io_error { + match error.take() { + Some(ref mut e) => ch.send((2, e.read_to_end())), + None => ch.send((2, ~[])) + } } } - do task::spawn_sched(task::SingleThreaded) { - match output.take() { - Some(ref mut e) => ch_clone.send((1, e.read_to_end())), - None => ch_clone.send((1, ~[])) + do task::spawn_unlinked { + do io::ignore_io_error { + match output.take() { + Some(ref mut e) => ch_clone.send((1, e.read_to_end())), + None => ch_clone.send((1, ~[])) + } } } diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index c463cf039d3..0cbbb58d02c 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -466,16 +466,6 @@ rust_uv_addrinfo_as_sockaddr_in6(addrinfo* input) { return (sockaddr_in6*)input->ai_addr; } -extern "C" uv_idle_t* -rust_uv_idle_new() { - return new uv_idle_t; -} - -extern "C" void -rust_uv_idle_delete(uv_idle_t* handle) { - delete handle; -} - extern "C" int rust_uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) { return uv_idle_init(loop, idle); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 3c10e42f743..269da8e7882 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -98,8 +98,6 @@ rust_uv_get_base_from_buf rust_uv_get_len_from_buf rust_uv_getaddrinfo rust_uv_freeaddrinfo -rust_uv_idle_new -rust_uv_idle_delete rust_uv_idle_init rust_uv_idle_start rust_uv_idle_stop