@@ -24,8 +24,9 @@ use task;
24
24
use vec;
25
25
26
26
pub mod rustrt {
27
- use libc:: { c_int, c_void, pid_t } ;
27
+ use libc:: { c_int, c_void} ;
28
28
use libc;
29
+ use run;
29
30
30
31
#[ abi = "cdecl" ]
31
32
pub extern {
@@ -34,11 +35,18 @@ pub mod rustrt {
34
35
dir : * libc:: c_char ,
35
36
in_fd : c_int ,
36
37
out_fd : c_int ,
37
- err_fd : c_int )
38
- -> pid_t ;
38
+ err_fd : c_int ) -> run:: RunProgramResult ;
39
39
}
40
40
}
41
41
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
+
42
50
/// A value representing a child process
43
51
pub trait Program {
44
52
/// Returns the process id of the program
@@ -100,16 +108,24 @@ pub trait Program {
100
108
* The process id of the spawned process
101
109
*/
102
110
pub 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 {
107
124
unsafe {
108
125
do with_argv ( prog, args) |argv| {
109
126
do with_envp ( env) |envp| {
110
127
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)
113
129
}
114
130
}
115
131
}
@@ -195,6 +211,18 @@ priv unsafe fn fclose_and_null(f: &mut *libc::FILE) {
195
211
}
196
212
}
197
213
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
+
198
226
/**
199
227
* Spawns a process and waits for it to terminate
200
228
*
@@ -208,10 +236,13 @@ priv unsafe fn fclose_and_null(f: &mut *libc::FILE) {
208
236
* The process's exit code
209
237
*/
210
238
pub 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;
215
246
}
216
247
217
248
/**
@@ -234,20 +265,21 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
234
265
let pipe_input = os:: pipe ( ) ;
235
266
let pipe_output = os:: pipe ( ) ;
236
267
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 ) ;
241
272
242
273
unsafe {
243
- if pid == -1 as pid_t { fail ! ( ) ; }
274
+ if res . pid == -1 as pid_t { fail ! ( ) ; }
244
275
libc:: close ( pipe_input. in ) ;
245
276
libc:: close ( pipe_output. out ) ;
246
277
libc:: close ( pipe_err. out ) ;
247
278
}
248
279
249
280
struct ProgRepr {
250
281
pid : pid_t ,
282
+ handle : * ( ) ,
251
283
in_fd : c_int ,
252
284
out_file : * libc:: FILE ,
253
285
err_file : * libc:: FILE ,
@@ -317,6 +349,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
317
349
finish_repr ( cast:: transmute ( & self . r ) ) ;
318
350
close_repr_outputs ( cast:: transmute ( & self . r ) ) ;
319
351
}
352
+ free_handle ( self . r . handle ) ;
320
353
}
321
354
}
322
355
@@ -343,8 +376,9 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
343
376
fn force_destroy ( & mut self ) { destroy_repr ( & mut self . r , true ) ; }
344
377
}
345
378
346
- let repr = ProgRepr {
347
- pid : pid,
379
+ let mut repr = ProgRepr {
380
+ pid : res. pid ,
381
+ handle : res. handle ,
348
382
in_fd : pipe_input. out ,
349
383
out_file : os:: fdopen ( pipe_output. in ) ,
350
384
err_file : os:: fdopen ( pipe_err. in ) ,
@@ -385,13 +419,13 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
385
419
let pipe_in = os:: pipe ( ) ;
386
420
let pipe_out = os:: pipe ( ) ;
387
421
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 ) ;
390
424
391
425
os:: close ( pipe_in. in ) ;
392
426
os:: close ( pipe_out. out ) ;
393
427
os:: close ( pipe_err. out ) ;
394
- if pid == -1i32 {
428
+ if res . pid == -1i32 {
395
429
os:: close ( pipe_in. out ) ;
396
430
os:: close ( pipe_out. in ) ;
397
431
os:: close ( pipe_err. in ) ;
@@ -415,7 +449,10 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
415
449
let output = readclose ( pipe_out. in ) ;
416
450
ch_clone. send ( ( 1 , output) ) ;
417
451
} ;
418
- let status = run:: waitpid ( pid) ;
452
+
453
+ let status = waitpid ( res. pid ) ;
454
+ free_handle ( res. handle ) ;
455
+
419
456
let mut errs = ~"";
420
457
let mut outs = ~"";
421
458
let mut count = 2 ;
@@ -563,6 +600,12 @@ mod tests {
563
600
assert ! ( status == 1 ) ;
564
601
}
565
602
603
+ #[ test]
604
+ #[ should_fail]
605
+ fn waitpid_non_existant_pid ( ) {
606
+ run:: waitpid ( 123456789 ) ; // assume that this pid doesn't exist
607
+ }
608
+
566
609
#[ test]
567
610
fn test_destroy_once ( ) {
568
611
let mut p = run:: start_program ( "echo" , [ ] ) ;
0 commit comments