Skip to content

Commit 8708e0c

Browse files
committed
auto merge of #6010 : Dretch/rust/run-windows, r=brson
This fixes #5976. It also removes `os::waitpid` in favour of (the existing) `run::waitpid`. I included this change because I figured it is kind of related. r?
2 parents 0b90493 + 62befac commit 8708e0c

File tree

4 files changed

+133
-65
lines changed

4 files changed

+133
-65
lines changed

src/libcore/libc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,7 @@ pub mod funcs {
17251725
findFileData: HANDLE)
17261726
-> BOOL;
17271727
unsafe fn FindClose(findFile: HANDLE) -> BOOL;
1728+
unsafe fn CloseHandle(hObject: HANDLE) -> BOOL;
17281729
unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
17291730
}
17301731
}

src/libcore/os.rs

+1-23
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use cast;
3030
use io;
3131
use libc;
3232
use libc::{c_char, c_void, c_int, size_t};
33-
use libc::{mode_t, pid_t, FILE};
33+
use libc::{mode_t, FILE};
3434
use option;
3535
use option::{Some, None};
3636
use prelude::*;
@@ -60,7 +60,6 @@ pub mod rustrt {
6060
unsafe fn rust_get_argv() -> **c_char;
6161
unsafe fn rust_path_is_dir(path: *libc::c_char) -> c_int;
6262
unsafe fn rust_path_exists(path: *libc::c_char) -> c_int;
63-
unsafe fn rust_process_wait(handle: c_int) -> c_int;
6463
unsafe fn rust_set_exit_status(code: libc::intptr_t);
6564
}
6665
}
@@ -352,27 +351,6 @@ pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
352351
}
353352
}
354353

355-
356-
#[cfg(windows)]
357-
pub fn waitpid(pid: pid_t) -> c_int {
358-
unsafe {
359-
return rustrt::rust_process_wait(pid);
360-
}
361-
}
362-
363-
#[cfg(unix)]
364-
pub fn waitpid(pid: pid_t) -> c_int {
365-
unsafe {
366-
use libc::funcs::posix01::wait::*;
367-
let mut status = 0 as c_int;
368-
369-
assert!((waitpid(pid, &mut status, 0 as c_int) !=
370-
(-1 as c_int)));
371-
return status;
372-
}
373-
}
374-
375-
376354
pub struct Pipe { mut in: c_int, mut out: c_int }
377355

378356
#[cfg(unix)]

src/libcore/run.rs

+86-28
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ use option::{Some, None};
1818
use os;
1919
use prelude::*;
2020
use ptr;
21-
use run;
2221
use str;
2322
use task;
2423
use vec;
2524

2625
pub mod rustrt {
27-
use libc::{c_int, c_void, pid_t};
26+
use libc::{c_int, c_void};
2827
use libc;
28+
use run;
2929

3030
#[abi = "cdecl"]
3131
pub extern {
@@ -34,11 +34,19 @@ pub mod rustrt {
3434
dir: *libc::c_char,
3535
in_fd: c_int,
3636
out_fd: c_int,
37-
err_fd: c_int)
38-
-> pid_t;
37+
err_fd: c_int) -> run::RunProgramResult;
38+
unsafe fn rust_process_wait(pid: c_int) -> c_int;
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
4351
pub 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
*/
102110
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 {
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
*/
210238
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;
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

@@ -344,7 +377,8 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program {
344377
}
345378

346379
let repr = ProgRepr {
347-
pid: pid,
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;
@@ -466,17 +503,27 @@ pub fn readclose(fd: c_int) -> ~str {
466503
}
467504
}
468505

469-
/// Waits for a process to exit and returns the exit code
506+
/**
507+
* Waits for a process to exit and returns the exit code, failing
508+
* if there is no process with the specified id.
509+
*/
470510
pub fn waitpid(pid: pid_t) -> int {
471511
return waitpid_os(pid);
472512

473513
#[cfg(windows)]
474514
fn waitpid_os(pid: pid_t) -> int {
475-
os::waitpid(pid) as int
515+
let status = unsafe { rustrt::rust_process_wait(pid) };
516+
if status < 0 {
517+
fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error()));
518+
}
519+
return status as int;
476520
}
477521

478522
#[cfg(unix)]
479523
fn waitpid_os(pid: pid_t) -> int {
524+
525+
use libc::funcs::posix01::wait::*;
526+
480527
#[cfg(target_os = "linux")]
481528
#[cfg(target_os = "android")]
482529
fn WIFEXITED(status: i32) -> bool {
@@ -501,7 +548,11 @@ pub fn waitpid(pid: pid_t) -> int {
501548
status >> 8i32
502549
}
503550

504-
let status = os::waitpid(pid);
551+
let mut status = 0 as c_int;
552+
if unsafe { waitpid(pid, &mut status, 0) } == -1 {
553+
fail!(fmt!("failure in waitpid: %s", os::last_os_error()));
554+
}
555+
505556
return if WIFEXITED(status) {
506557
WEXITSTATUS(status) as int
507558
} else {
@@ -547,7 +598,7 @@ mod tests {
547598
writeclose(pipe_in.out, copy expected);
548599
let actual = readclose(pipe_out.in);
549600
readclose(pipe_err.in);
550-
os::waitpid(pid);
601+
run::waitpid(pid);
551602

552603
debug!(copy expected);
553604
debug!(copy actual);
@@ -563,6 +614,13 @@ mod tests {
563614
assert!(status == 1);
564615
}
565616

617+
#[test]
618+
#[should_fail]
619+
#[ignore(cfg(windows))]
620+
fn waitpid_non_existant_pid() {
621+
run::waitpid(123456789); // assume that this pid doesn't exist
622+
}
623+
566624
#[test]
567625
fn test_destroy_once() {
568626
let mut p = run::start_program("echo", []);

0 commit comments

Comments
 (0)