diff options
| author | bors <bors@rust-lang.org> | 2014-03-12 22:36:40 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-03-12 22:36:40 -0700 |
| commit | 792da8424f4f422c2750607dcc243315fdff9fc3 (patch) | |
| tree | 379b00baf982ea5b67c998f7f94f61e7af21eaf2 /src | |
| parent | e86e1d88b2842671123d0a072d00c94bd3f39264 (diff) | |
| parent | 65cca4bd3fa0abe1000662014b3e3ea1420728f5 (diff) | |
| download | rust-792da8424f4f422c2750607dcc243315fdff9fc3.tar.gz rust-792da8424f4f422c2750607dcc243315fdff9fc3.zip | |
auto merge of #12823 : alexcrichton/rust/issue-12666, r=pcwalton
If a TTY fails to get initialized, it still needs to have uv_close invoked on it. This fixes the problem by constructing the TtyWatcher struct before the call to uv_tty_init. The struct has a destructor on it which will close the handle properly. Closes #12666
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustuv/tty.rs | 31 | ||||
| -rw-r--r-- | src/test/run-pass/tcp-stress.rs | 74 |
2 files changed, 93 insertions, 12 deletions
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::<TtyWatcher>, 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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) } +} |
