@@ -62,7 +62,10 @@ pub trait Program {
62
62
*/
63
63
fn finish ( & mut self ) -> int ;
64
64
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
+ */
66
69
fn destroy ( & mut self ) ;
67
70
}
68
71
@@ -248,28 +251,53 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
248
251
r. in_fd = invalid_fd;
249
252
}
250
253
}
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
+
251
262
fn finish_repr ( r : & mut ProgRepr ) -> int {
252
263
if r. finished { return 0 ; }
253
264
r. finished = true ;
254
265
close_repr_input ( & mut * r) ;
255
266
return waitpid ( r. pid ) ;
256
267
}
268
+
257
269
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
+ }
262
288
}
263
289
}
290
+
264
291
struct ProgRes {
265
292
r : ProgRepr ,
266
293
}
267
294
268
295
impl Drop for ProgRes {
269
296
fn finalize ( & self ) {
270
297
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 ) ) ;
273
301
}
274
302
}
275
303
}
@@ -295,6 +323,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
295
323
fn finish ( & mut self ) -> int { finish_repr ( & mut self . r ) }
296
324
fn destroy ( & mut self ) { destroy_repr ( & mut self . r ) ; }
297
325
}
326
+
298
327
let mut repr = ProgRepr {
299
328
pid : pid,
300
329
in_fd : pipe_input. out ,
@@ -466,8 +495,10 @@ pub fn waitpid(pid: pid_t) -> int {
466
495
467
496
#[ cfg( test) ]
468
497
mod tests {
498
+ use libc;
469
499
use option:: None ;
470
500
use os;
501
+ use path:: Path ;
471
502
use run:: { readclose, writeclose} ;
472
503
use run;
473
504
@@ -528,6 +559,27 @@ mod tests {
528
559
p. destroy ( ) ; // ...and nor should this (and nor should the destructor)
529
560
}
530
561
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
+
531
583
}
532
584
533
585
// Local Variables:
0 commit comments