1 //! Tests for ctrl-C handling.
4 use std
::io
::{self, Read}
;
5 use std
::net
::TcpListener
;
6 use std
::process
::{Child, Stdio}
;
9 use cargo_test_support
::{project, slow_cpu_multiplier}
;
12 fn ctrl_c_kills_everyone() {
13 let listener
= TcpListener
::bind("127.0.0.1:0").unwrap();
14 let addr
= listener
.local_addr().unwrap();
27 .file("src/lib.rs", "")
32 use std::net::TcpStream;
36 let mut socket = TcpStream::connect("{}").unwrap();
37 let _ = socket.read(&mut [0; 10]);
38 panic!("that read should never return");
46 let mut cargo
= p
.cargo("check").build_command();
48 .stdin(Stdio
::piped())
49 .stdout(Stdio
::piped())
50 .stderr(Stdio
::piped())
51 .env("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE", "1");
52 let mut child
= cargo
.spawn().unwrap();
54 let mut sock
= listener
.accept().unwrap().0;
57 assert
!(!child
.wait().unwrap().success());
58 match sock
.read(&mut [0; 10]) {
59 Ok(n
) => assert_eq
!(n
, 0),
60 Err(e
) => assert_eq
!(e
.kind(), io
::ErrorKind
::ConnectionReset
),
63 // Ok so what we just did was spawn cargo that spawned a build script, then
64 // we killed cargo in hopes of it killing the build script as well. If all
65 // went well the build script is now dead. On Windows, however, this is
66 // enforced with job objects which means that it may actually be in the
67 // *process* of being torn down at this point.
69 // Now on Windows we can't completely remove a file until all handles to it
70 // have been closed. Including those that represent running processes. So if
71 // we were to return here then there may still be an open reference to some
72 // file in the build directory. What we want to actually do is wait for the
73 // build script to *complete* exit. Take care of that by blowing away the
74 // build directory here, and panicking if we eventually spin too long
75 // without being able to.
77 match fs
::remove_dir_all(&p
.root().join("target")) {
79 Err(e
) => println
!("attempt {}: {}", i
, e
),
81 thread
::sleep(slow_cpu_multiplier(100));
85 "couldn't remove build directory after a few tries, seems like \
91 pub fn ctrl_c(child
: &mut Child
) {
92 let r
= unsafe { libc::kill(-(child.id() as i32), libc::SIGINT) }
;
94 panic
!("failed to kill: {}", io
::Error
::last_os_error());
99 pub fn ctrl_c(child
: &mut Child
) {
100 child
.kill().unwrap();