1
Fork 0

Change the behaviour of core::run::Program.destroy to

forcibly terminate the program (as suggested in issue #5632)
This commit is contained in:
gareth 2013-04-06 20:49:52 +01:00
parent 622bb6300f
commit 483e95a35c
2 changed files with 75 additions and 7 deletions

View file

@ -863,6 +863,7 @@ pub mod consts {
pub static F_TEST : int = 3; pub static F_TEST : int = 3;
pub static F_TLOCK : int = 2; pub static F_TLOCK : int = 2;
pub static F_ULOCK : int = 0; pub static F_ULOCK : int = 0;
pub static SIGKILL : int = 9;
} }
pub mod posix01 { pub mod posix01 {
} }
@ -930,6 +931,7 @@ pub mod consts {
pub static F_TEST : int = 3; pub static F_TEST : int = 3;
pub static F_TLOCK : int = 2; pub static F_TLOCK : int = 2;
pub static F_ULOCK : int = 0; pub static F_ULOCK : int = 0;
pub static SIGKILL : int = 9;
} }
pub mod posix01 { pub mod posix01 {
} }
@ -998,6 +1000,7 @@ pub mod consts {
pub static F_TEST : int = 3; pub static F_TEST : int = 3;
pub static F_TLOCK : int = 2; pub static F_TLOCK : int = 2;
pub static F_ULOCK : int = 0; pub static F_ULOCK : int = 0;
pub static SIGKILL : int = 9;
} }
pub mod posix01 { pub mod posix01 {
} }
@ -1482,6 +1485,17 @@ pub mod funcs {
-> ssize_t; -> ssize_t;
} }
} }
#[nolink]
#[abi = "cdecl"]
pub mod signal {
use libc::types::os::arch::c95::{c_int};
use libc::types::os::arch::posix88::{pid_t};
pub extern {
unsafe fn kill(pid: pid_t, sig: c_int) -> c_int;
}
}
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
@ -1623,6 +1637,7 @@ pub mod funcs {
pub mod extra { pub mod extra {
pub mod kernel32 { pub mod kernel32 {
use libc::types::os::arch::c95::{c_uint};
use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE}; use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH}; use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH};
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES}; use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
@ -1663,6 +1678,7 @@ pub mod funcs {
findFileData: HANDLE) findFileData: HANDLE)
-> BOOL; -> BOOL;
unsafe fn FindClose(findFile: HANDLE) -> BOOL; unsafe fn FindClose(findFile: HANDLE) -> BOOL;
unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
} }
} }

View file

@ -62,7 +62,10 @@ pub trait Program {
*/ */
fn finish(&mut self) -> int; fn finish(&mut self) -> int;
/// Closes open handles /**
* Forcibly terminate the program. On Posix OSs SIGKILL will be sent
* to the process. On Win32 TerminateProcess(..) will be called.
*/
fn destroy(&mut self); fn destroy(&mut self);
} }
@ -248,19 +251,43 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
r.in_fd = invalid_fd; r.in_fd = invalid_fd;
} }
} }
fn close_repr_outputs(r: &mut ProgRepr) {
unsafe {
fclose_and_null(&mut r.out_file);
fclose_and_null(&mut r.err_file);
}
}
fn finish_repr(r: &mut ProgRepr) -> int { fn finish_repr(r: &mut ProgRepr) -> int {
if r.finished { return 0; } if r.finished { return 0; }
r.finished = true; r.finished = true;
close_repr_input(&mut *r); close_repr_input(&mut *r);
return waitpid(r.pid); return waitpid(r.pid);
} }
fn destroy_repr(r: &mut ProgRepr) { fn destroy_repr(r: &mut ProgRepr) {
unsafe { killpid(r.pid);
finish_repr(&mut *r); finish_repr(&mut *r);
fclose_and_null(&mut r.out_file); close_repr_outputs(&mut *r);
fclose_and_null(&mut r.err_file);
#[cfg(windows)]
fn killpid(pid: pid_t) {
unsafe {
libc::funcs::extra::kernel32::TerminateProcess(
cast::transmute(pid), 1);
}
}
#[cfg(unix)]
fn killpid(pid: pid_t) {
unsafe {
libc::funcs::posix88::signal::kill(
pid, libc::consts::os::posix88::SIGKILL as c_int);
}
} }
} }
struct ProgRes { struct ProgRes {
r: ProgRepr, r: ProgRepr,
} }
@ -268,8 +295,9 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
impl Drop for ProgRes { impl Drop for ProgRes {
fn finalize(&self) { fn finalize(&self) {
unsafe { unsafe {
// FIXME #4943: This is bad. // FIXME #4943: transmute is bad.
destroy_repr(cast::transmute(&self.r)); finish_repr(cast::transmute(&self.r));
close_repr_outputs(cast::transmute(&self.r));
} }
} }
} }
@ -295,6 +323,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
fn finish(&mut self) -> int { finish_repr(&mut self.r) } fn finish(&mut self) -> int { finish_repr(&mut self.r) }
fn destroy(&mut self) { destroy_repr(&mut self.r); } fn destroy(&mut self) { destroy_repr(&mut self.r); }
} }
let mut repr = ProgRepr { let mut repr = ProgRepr {
pid: pid, pid: pid,
in_fd: pipe_input.out, in_fd: pipe_input.out,
@ -466,8 +495,10 @@ pub fn waitpid(pid: pid_t) -> int {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use libc;
use option::None; use option::None;
use os; use os;
use path::Path;
use run::{readclose, writeclose}; use run::{readclose, writeclose};
use run; use run;
@ -528,6 +559,27 @@ mod tests {
p.destroy(); // ...and nor should this (and nor should the destructor) p.destroy(); // ...and nor should this (and nor should the destructor)
} }
#[test]
#[cfg(unix)] // there is no way to sleep on windows from inside libcore...
pub fn test_destroy_actually_kills() {
let path = Path("test/core-run-test-destroy-actually-kills.tmp");
os::remove_file(&path);
let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str());
let mut p = run::start_program("sh", [~"-c", cmd]);
p.destroy(); // destroy the program before it has a chance to echo its message
unsafe {
// wait to ensure the program is really destroyed and not just waiting itself
libc::sleep(10);
}
// the program should not have had chance to echo its message
assert!(!path.exists());
}
} }
// Local Variables: // Local Variables: