Skip to content

Commit 483e95a

Browse files
garethgareth
gareth
authored and
gareth
committed
Change the behaviour of core::run::Program.destroy to
forcibly terminate the program (as suggested in issue #5632)
1 parent 622bb63 commit 483e95a

File tree

2 files changed

+75
-7
lines changed

2 files changed

+75
-7
lines changed

src/libcore/libc.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ pub mod consts {
863863
pub static F_TEST : int = 3;
864864
pub static F_TLOCK : int = 2;
865865
pub static F_ULOCK : int = 0;
866+
pub static SIGKILL : int = 9;
866867
}
867868
pub mod posix01 {
868869
}
@@ -930,6 +931,7 @@ pub mod consts {
930931
pub static F_TEST : int = 3;
931932
pub static F_TLOCK : int = 2;
932933
pub static F_ULOCK : int = 0;
934+
pub static SIGKILL : int = 9;
933935
}
934936
pub mod posix01 {
935937
}
@@ -998,6 +1000,7 @@ pub mod consts {
9981000
pub static F_TEST : int = 3;
9991001
pub static F_TLOCK : int = 2;
10001002
pub static F_ULOCK : int = 0;
1003+
pub static SIGKILL : int = 9;
10011004
}
10021005
pub mod posix01 {
10031006
}
@@ -1482,6 +1485,17 @@ pub mod funcs {
14821485
-> ssize_t;
14831486
}
14841487
}
1488+
1489+
#[nolink]
1490+
#[abi = "cdecl"]
1491+
pub mod signal {
1492+
use libc::types::os::arch::c95::{c_int};
1493+
use libc::types::os::arch::posix88::{pid_t};
1494+
1495+
pub extern {
1496+
unsafe fn kill(pid: pid_t, sig: c_int) -> c_int;
1497+
}
1498+
}
14851499
}
14861500

14871501
#[cfg(target_os = "linux")]
@@ -1623,6 +1637,7 @@ pub mod funcs {
16231637
pub mod extra {
16241638

16251639
pub mod kernel32 {
1640+
use libc::types::os::arch::c95::{c_uint};
16261641
use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
16271642
use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH};
16281643
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
@@ -1663,6 +1678,7 @@ pub mod funcs {
16631678
findFileData: HANDLE)
16641679
-> BOOL;
16651680
unsafe fn FindClose(findFile: HANDLE) -> BOOL;
1681+
unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
16661682
}
16671683
}
16681684

src/libcore/run.rs

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ pub trait Program {
6262
*/
6363
fn finish(&mut self) -> int;
6464

65-
/// Closes open handles
65+
/**
66+
* Forcibly terminate the program. On Posix OSs SIGKILL will be sent
67+
* to the process. On Win32 TerminateProcess(..) will be called.
68+
*/
6669
fn destroy(&mut self);
6770
}
6871

@@ -248,28 +251,53 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
248251
r.in_fd = invalid_fd;
249252
}
250253
}
254+
255+
fn close_repr_outputs(r: &mut ProgRepr) {
256+
unsafe {
257+
fclose_and_null(&mut r.out_file);
258+
fclose_and_null(&mut r.err_file);
259+
}
260+
}
261+
251262
fn finish_repr(r: &mut ProgRepr) -> int {
252263
if r.finished { return 0; }
253264
r.finished = true;
254265
close_repr_input(&mut *r);
255266
return waitpid(r.pid);
256267
}
268+
257269
fn destroy_repr(r: &mut ProgRepr) {
258-
unsafe {
259-
finish_repr(&mut *r);
260-
fclose_and_null(&mut r.out_file);
261-
fclose_and_null(&mut r.err_file);
270+
killpid(r.pid);
271+
finish_repr(&mut *r);
272+
close_repr_outputs(&mut *r);
273+
274+
#[cfg(windows)]
275+
fn killpid(pid: pid_t) {
276+
unsafe {
277+
libc::funcs::extra::kernel32::TerminateProcess(
278+
cast::transmute(pid), 1);
279+
}
280+
}
281+
282+
#[cfg(unix)]
283+
fn killpid(pid: pid_t) {
284+
unsafe {
285+
libc::funcs::posix88::signal::kill(
286+
pid, libc::consts::os::posix88::SIGKILL as c_int);
287+
}
262288
}
263289
}
290+
264291
struct ProgRes {
265292
r: ProgRepr,
266293
}
267294

268295
impl Drop for ProgRes {
269296
fn finalize(&self) {
270297
unsafe {
271-
// FIXME #4943: This is bad.
272-
destroy_repr(cast::transmute(&self.r));
298+
// FIXME #4943: transmute is bad.
299+
finish_repr(cast::transmute(&self.r));
300+
close_repr_outputs(cast::transmute(&self.r));
273301
}
274302
}
275303
}
@@ -295,6 +323,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
295323
fn finish(&mut self) -> int { finish_repr(&mut self.r) }
296324
fn destroy(&mut self) { destroy_repr(&mut self.r); }
297325
}
326+
298327
let mut repr = ProgRepr {
299328
pid: pid,
300329
in_fd: pipe_input.out,
@@ -466,8 +495,10 @@ pub fn waitpid(pid: pid_t) -> int {
466495

467496
#[cfg(test)]
468497
mod tests {
498+
use libc;
469499
use option::None;
470500
use os;
501+
use path::Path;
471502
use run::{readclose, writeclose};
472503
use run;
473504

@@ -528,6 +559,27 @@ mod tests {
528559
p.destroy(); // ...and nor should this (and nor should the destructor)
529560
}
530561

562+
#[test]
563+
#[cfg(unix)] // there is no way to sleep on windows from inside libcore...
564+
pub fn test_destroy_actually_kills() {
565+
let path = Path("test/core-run-test-destroy-actually-kills.tmp");
566+
567+
os::remove_file(&path);
568+
569+
let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str());
570+
let mut p = run::start_program("sh", [~"-c", cmd]);
571+
572+
p.destroy(); // destroy the program before it has a chance to echo its message
573+
574+
unsafe {
575+
// wait to ensure the program is really destroyed and not just waiting itself
576+
libc::sleep(10);
577+
}
578+
579+
// the program should not have had chance to echo its message
580+
assert!(!path.exists());
581+
}
582+
531583
}
532584

533585
// Local Variables:

0 commit comments

Comments
 (0)