@@ -24,8 +24,9 @@ use task;
2424use vec;
2525
2626pub mod rustrt {
27- use libc:: { c_int, c_void, pid_t } ;
27+ use libc:: { c_int, c_void} ;
2828 use libc;
29+ use run;
2930
3031 #[ abi = "cdecl" ]
3132 pub extern {
@@ -34,11 +35,18 @@ pub mod rustrt {
3435 dir : * libc:: c_char ,
3536 in_fd : c_int ,
3637 out_fd : c_int ,
37- err_fd : c_int )
38- -> pid_t ;
38+ err_fd : c_int ) -> run:: RunProgramResult ;
3939 }
4040}
4141
42+ pub struct RunProgramResult {
43+ // the process id of the program, or -1 if in case of errors
44+ pid : pid_t ,
45+ // a handle to the process - on unix this will always be NULL, but on windows it will be a
46+ // HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
47+ handle : * ( ) ,
48+ }
49+
4250/// A value representing a child process
4351pub trait Program {
4452 /// Returns the process id of the program
@@ -100,16 +108,24 @@ pub trait Program {
100108 * The process id of the spawned process
101109 */
102110pub fn spawn_process ( prog : & str , args : & [ ~str ] ,
103- env : & Option < ~[ ( ~str , ~str ) ] > ,
104- dir : & Option < ~str > ,
105- in_fd : c_int , out_fd : c_int , err_fd : c_int )
106- -> pid_t {
111+ env : & Option < ~[ ( ~str , ~str ) ] > ,
112+ dir : & Option < ~str > ,
113+ in_fd : c_int , out_fd : c_int , err_fd : c_int ) -> pid_t {
114+
115+ let res = spawn_process_internal ( prog, args, env, dir, in_fd, out_fd, err_fd) ;
116+ free_handle ( res. handle ) ;
117+ return res. pid ;
118+ }
119+
120+ fn spawn_process_internal ( prog : & str , args : & [ ~str ] ,
121+ env : & Option < ~[ ( ~str , ~str ) ] > ,
122+ dir : & Option < ~str > ,
123+ in_fd : c_int , out_fd : c_int , err_fd : c_int ) -> RunProgramResult {
107124 unsafe {
108125 do with_argv ( prog, args) |argv| {
109126 do with_envp ( env) |envp| {
110127 do with_dirp ( dir) |dirp| {
111- rustrt:: rust_run_program ( argv, envp, dirp,
112- in_fd, out_fd, err_fd)
128+ rustrt:: rust_run_program ( argv, envp, dirp, in_fd, out_fd, err_fd)
113129 }
114130 }
115131 }
@@ -195,6 +211,18 @@ priv unsafe fn fclose_and_null(f: &mut *libc::FILE) {
195211 }
196212}
197213
214+ #[ cfg( windows) ]
215+ priv fn free_handle ( handle : * ( ) ) {
216+ unsafe {
217+ libc:: funcs:: extra:: kernel32:: CloseHandle ( cast:: transmute ( handle) ) ;
218+ }
219+ }
220+
221+ #[ cfg( unix) ]
222+ priv fn free_handle ( _handle : * ( ) ) {
223+ // unix has no process handle object, just a pid
224+ }
225+
198226/**
199227 * Spawns a process and waits for it to terminate
200228 *
@@ -208,10 +236,13 @@ priv unsafe fn fclose_and_null(f: &mut *libc::FILE) {
208236 * The process's exit code
209237 */
210238pub fn run_program ( prog : & str , args : & [ ~str ] ) -> int {
211- let pid = spawn_process ( prog, args, & None , & None ,
212- 0i32 , 0i32 , 0i32 ) ;
213- if pid == -1 as pid_t { fail ! ( ) ; }
214- return waitpid ( pid) ;
239+ let res = spawn_process_internal ( prog, args, & None , & None ,
240+ 0i32 , 0i32 , 0i32 ) ;
241+ if res. pid == -1 as pid_t { fail ! ( ) ; }
242+
243+ let code = waitpid ( res. pid ) ;
244+ free_handle ( res. handle ) ;
245+ return code;
215246}
216247
217248/**
@@ -234,20 +265,21 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
234265 let pipe_input = os:: pipe ( ) ;
235266 let pipe_output = os:: pipe ( ) ;
236267 let pipe_err = os:: pipe ( ) ;
237- let pid =
238- spawn_process ( prog, args, & None , & None ,
239- pipe_input. in , pipe_output. out ,
240- pipe_err. out ) ;
268+ let res =
269+ spawn_process_internal ( prog, args, & None , & None ,
270+ pipe_input. in , pipe_output. out ,
271+ pipe_err. out ) ;
241272
242273 unsafe {
243- if pid == -1 as pid_t { fail ! ( ) ; }
274+ if res . pid == -1 as pid_t { fail ! ( ) ; }
244275 libc:: close ( pipe_input. in ) ;
245276 libc:: close ( pipe_output. out ) ;
246277 libc:: close ( pipe_err. out ) ;
247278 }
248279
249280 struct ProgRepr {
250281 pid : pid_t ,
282+ handle : * ( ) ,
251283 in_fd : c_int ,
252284 out_file : * libc:: FILE ,
253285 err_file : * libc:: FILE ,
@@ -317,6 +349,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
317349 finish_repr ( cast:: transmute ( & self . r ) ) ;
318350 close_repr_outputs ( cast:: transmute ( & self . r ) ) ;
319351 }
352+ free_handle ( self . r . handle ) ;
320353 }
321354 }
322355
@@ -343,8 +376,9 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
343376 fn force_destroy ( & mut self ) { destroy_repr ( & mut self . r , true ) ; }
344377 }
345378
346- let repr = ProgRepr {
347- pid : pid,
379+ let mut repr = ProgRepr {
380+ pid : res. pid ,
381+ handle : res. handle ,
348382 in_fd : pipe_input. out ,
349383 out_file : os:: fdopen ( pipe_output. in ) ,
350384 err_file : os:: fdopen ( pipe_err. in ) ,
@@ -385,13 +419,13 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
385419 let pipe_in = os:: pipe ( ) ;
386420 let pipe_out = os:: pipe ( ) ;
387421 let pipe_err = os:: pipe ( ) ;
388- let pid = spawn_process ( prog, args, & None , & None ,
389- pipe_in. in , pipe_out. out , pipe_err. out ) ;
422+ let res = spawn_process_internal ( prog, args, & None , & None ,
423+ pipe_in. in , pipe_out. out , pipe_err. out ) ;
390424
391425 os:: close ( pipe_in. in ) ;
392426 os:: close ( pipe_out. out ) ;
393427 os:: close ( pipe_err. out ) ;
394- if pid == -1i32 {
428+ if res . pid == -1i32 {
395429 os:: close ( pipe_in. out ) ;
396430 os:: close ( pipe_out. in ) ;
397431 os:: close ( pipe_err. in ) ;
@@ -415,7 +449,10 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
415449 let output = readclose ( pipe_out. in ) ;
416450 ch_clone. send ( ( 1 , output) ) ;
417451 } ;
418- let status = run:: waitpid ( pid) ;
452+
453+ let status = waitpid ( res. pid ) ;
454+ free_handle ( res. handle ) ;
455+
419456 let mut errs = ~"";
420457 let mut outs = ~"";
421458 let mut count = 2 ;
@@ -563,6 +600,12 @@ mod tests {
563600 assert ! ( status == 1 ) ;
564601 }
565602
603+ #[ test]
604+ #[ should_fail]
605+ fn waitpid_non_existant_pid ( ) {
606+ run:: waitpid ( 123456789 ) ; // assume that this pid doesn't exist
607+ }
608+
566609 #[ test]
567610 fn test_destroy_once ( ) {
568611 let mut p = run:: start_program ( "echo" , [ ] ) ;
0 commit comments