about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-03-12 22:36:40 -0700
committerbors <bors@rust-lang.org>2014-03-12 22:36:40 -0700
commit792da8424f4f422c2750607dcc243315fdff9fc3 (patch)
tree379b00baf982ea5b67c998f7f94f61e7af21eaf2 /src
parente86e1d88b2842671123d0a072d00c94bd3f39264 (diff)
parent65cca4bd3fa0abe1000662014b3e3ea1420728f5 (diff)
downloadrust-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.rs31
-rw-r--r--src/test/run-pass/tcp-stress.rs74
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) }
+}