Skip to content

Commit 792da84

Browse files
committed
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
2 parents e86e1d8 + 65cca4b commit 792da84

File tree

2 files changed

+93
-12
lines changed

2 files changed

+93
-12
lines changed

src/librustuv/tty.rs

+19-12
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::libc;
1211
use std::io::IoError;
12+
use std::libc;
13+
use std::ptr;
1314
use std::rt::rtio::RtioTTY;
1415

1516
use homing::{HomingIO, HomeHandle};
@@ -54,20 +55,24 @@ impl TtyWatcher {
5455
// If this file descriptor is indeed guessed to be a tty, then go ahead
5556
// with attempting to open it as a tty.
5657
let handle = UvHandle::alloc(None::<TtyWatcher>, uvll::UV_TTY);
58+
let mut watcher = TtyWatcher {
59+
tty: handle,
60+
stream: StreamWatcher::new(handle),
61+
home: io.make_handle(),
62+
fd: fd,
63+
};
5764
match unsafe {
5865
uvll::uv_tty_init(io.uv_loop(), handle, fd as libc::c_int,
5966
readable as libc::c_int)
6067
} {
61-
0 => {
62-
Ok(TtyWatcher {
63-
tty: handle,
64-
stream: StreamWatcher::new(handle),
65-
home: io.make_handle(),
66-
fd: fd,
67-
})
68-
}
68+
0 => Ok(watcher),
6969
n => {
70-
unsafe { uvll::free_handle(handle) }
70+
// On windows, libuv returns errors before initializing the
71+
// handle, so our only cleanup is to free the handle itself
72+
if cfg!(windows) {
73+
unsafe { uvll::free_handle(handle); }
74+
watcher.tty = ptr::null();
75+
}
7176
Err(UvError(n))
7277
}
7378
}
@@ -124,7 +129,9 @@ impl HomingIO for TtyWatcher {
124129

125130
impl Drop for TtyWatcher {
126131
fn drop(&mut self) {
127-
let _m = self.fire_homing_missile();
128-
self.close_async_();
132+
if !self.tty.is_null() {
133+
let _m = self.fire_homing_missile();
134+
self.close_async_();
135+
}
129136
}
130137
}

src/test/run-pass/tcp-stress.rs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-linux see joyent/libuv#1189
12+
// ignore-fast
13+
// ignore-android needs extra network permissions
14+
// exec-env:RUST_LOG=debug
15+
16+
use std::libc;
17+
use std::io::net::ip::{Ipv4Addr, SocketAddr};
18+
use std::io::net::tcp::{TcpListener, TcpStream};
19+
use std::io::{Acceptor, Listener};
20+
21+
fn main() {
22+
// This test has a chance to time out, try to not let it time out
23+
spawn(proc() {
24+
use std::io::timer;
25+
timer::sleep(30 * 1000);
26+
println!("timed out!");
27+
unsafe { libc::exit(1) }
28+
});
29+
30+
let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 0 };
31+
let (p, c) = Chan::new();
32+
spawn(proc() {
33+
let mut listener = TcpListener::bind(addr).unwrap();
34+
c.send(listener.socket_name().unwrap());
35+
let mut acceptor = listener.listen();
36+
loop {
37+
let mut stream = match acceptor.accept() {
38+
Ok(stream) => stream,
39+
Err(error) => {
40+
debug!("accept failed: {:?}", error);
41+
continue;
42+
}
43+
};
44+
stream.read_byte();
45+
stream.write([2]);
46+
}
47+
});
48+
let addr = p.recv();
49+
50+
let (p, c) = Chan::new();
51+
for _ in range(0, 1000) {
52+
let c = c.clone();
53+
spawn(proc() {
54+
match TcpStream::connect(addr) {
55+
Ok(stream) => {
56+
let mut stream = stream;
57+
stream.write([1]);
58+
let mut buf = [0];
59+
stream.read(buf);
60+
},
61+
Err(e) => debug!("{:?}", e)
62+
}
63+
c.send(());
64+
});
65+
}
66+
67+
// Wait for all clients to exit, but don't wait for the server to exit. The
68+
// server just runs infinitely.
69+
drop(c);
70+
for _ in range(0, 1000) {
71+
p.recv();
72+
}
73+
unsafe { libc::exit(0) }
74+
}

0 commit comments

Comments
 (0)