diff --git a/src/librustuv/tty.rs b/src/librustuv/tty.rs index 0e76ed9feb9..19c98c79b6a 100644 --- a/src/librustuv/tty.rs +++ b/src/librustuv/tty.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::libc; use std::io::IoError; +use std::libc; +use std::ptr; use std::rt::rtio::RtioTTY; use homing::{HomingIO, HomeHandle}; @@ -54,20 +55,24 @@ impl TtyWatcher { // If this file descriptor is indeed guessed to be a tty, then go ahead // with attempting to open it as a tty. let handle = UvHandle::alloc(None::, uvll::UV_TTY); + let mut watcher = TtyWatcher { + tty: handle, + stream: StreamWatcher::new(handle), + home: io.make_handle(), + fd: fd, + }; match unsafe { uvll::uv_tty_init(io.uv_loop(), handle, fd as libc::c_int, readable as libc::c_int) } { - 0 => { - Ok(TtyWatcher { - tty: handle, - stream: StreamWatcher::new(handle), - home: io.make_handle(), - fd: fd, - }) - } + 0 => Ok(watcher), n => { - unsafe { uvll::free_handle(handle) } + // On windows, libuv returns errors before initializing the + // handle, so our only cleanup is to free the handle itself + if cfg!(windows) { + unsafe { uvll::free_handle(handle); } + watcher.tty = ptr::null(); + } Err(UvError(n)) } } @@ -124,7 +129,9 @@ impl HomingIO for TtyWatcher { impl Drop for TtyWatcher { fn drop(&mut self) { - let _m = self.fire_homing_missile(); - self.close_async_(); + if !self.tty.is_null() { + let _m = self.fire_homing_missile(); + self.close_async_(); + } } } diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs new file mode 100644 index 00000000000..d1fc90cf007 --- /dev/null +++ b/src/test/run-pass/tcp-stress.rs @@ -0,0 +1,74 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-linux see joyent/libuv#1189 +// ignore-fast +// ignore-android needs extra network permissions +// exec-env:RUST_LOG=debug + +use std::libc; +use std::io::net::ip::{Ipv4Addr, SocketAddr}; +use std::io::net::tcp::{TcpListener, TcpStream}; +use std::io::{Acceptor, Listener}; + +fn main() { + // This test has a chance to time out, try to not let it time out + spawn(proc() { + use std::io::timer; + timer::sleep(30 * 1000); + println!("timed out!"); + unsafe { libc::exit(1) } + }); + + let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 0 }; + let (p, c) = Chan::new(); + spawn(proc() { + let mut listener = TcpListener::bind(addr).unwrap(); + c.send(listener.socket_name().unwrap()); + let mut acceptor = listener.listen(); + loop { + let mut stream = match acceptor.accept() { + Ok(stream) => stream, + Err(error) => { + debug!("accept failed: {:?}", error); + continue; + } + }; + stream.read_byte(); + stream.write([2]); + } + }); + let addr = p.recv(); + + let (p, c) = Chan::new(); + for _ in range(0, 1000) { + let c = c.clone(); + spawn(proc() { + match TcpStream::connect(addr) { + Ok(stream) => { + let mut stream = stream; + stream.write([1]); + let mut buf = [0]; + stream.read(buf); + }, + Err(e) => debug!("{:?}", e) + } + c.send(()); + }); + } + + // Wait for all clients to exit, but don't wait for the server to exit. The + // server just runs infinitely. + drop(c); + for _ in range(0, 1000) { + p.recv(); + } + unsafe { libc::exit(0) } +}