Skip to content

Commit 9e0f995

Browse files
committed
---
yaml --- r: 109438 b: refs/heads/dist-snap c: 42e1003 h: refs/heads/master v: v3
1 parent b077661 commit 9e0f995

File tree

5 files changed

+117
-46
lines changed

5 files changed

+117
-46
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ refs/heads/try: f64fdf524a434f0e5cd0bc91d09c144723f3c90d
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c
9-
refs/heads/dist-snap: 68c2706780031e3aac6cccea0f7b867ad5eff13a
9+
refs/heads/dist-snap: 42e1003e4a2dd4d3a7e800c2f5b99bf77a4b635e
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503
1212
refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0

branches/dist-snap/src/libnative/io/process.rs

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ impl rtio::RtioProcess for Process {
134134
}
135135

136136
fn kill(&mut self, signum: int) -> Result<(), io::IoError> {
137+
// On linux (and possibly other unices), a process that has exited will
138+
// continue to accept signals because it is "defunct". The delivery of
139+
// signals will only fail once the child has been reaped. For this
140+
// reason, if the process hasn't exited yet, then we attempt to collect
141+
// their status with WNOHANG.
142+
if self.exit_code.is_none() {
143+
match waitpid_nowait(self.pid) {
144+
Some(code) => { self.exit_code = Some(code); }
145+
None => {}
146+
}
147+
}
148+
137149
// if the process has finished, and therefore had waitpid called,
138150
// and we kill it, then on unix we might ending up killing a
139151
// newer process that happens to have the same (re-used) id
@@ -662,6 +674,31 @@ fn free_handle(_handle: *()) {
662674
// unix has no process handle object, just a pid
663675
}
664676

677+
#[cfg(unix)]
678+
fn translate_status(status: c_int) -> p::ProcessExit {
679+
#[cfg(target_os = "linux")]
680+
#[cfg(target_os = "android")]
681+
mod imp {
682+
pub fn WIFEXITED(status: i32) -> bool { (status & 0xff) == 0 }
683+
pub fn WEXITSTATUS(status: i32) -> i32 { (status >> 8) & 0xff }
684+
pub fn WTERMSIG(status: i32) -> i32 { status & 0x7f }
685+
}
686+
687+
#[cfg(target_os = "macos")]
688+
#[cfg(target_os = "freebsd")]
689+
mod imp {
690+
pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
691+
pub fn WEXITSTATUS(status: i32) -> i32 { status >> 8 }
692+
pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 }
693+
}
694+
695+
if imp::WIFEXITED(status) {
696+
p::ExitStatus(imp::WEXITSTATUS(status) as int)
697+
} else {
698+
p::ExitSignal(imp::WTERMSIG(status) as int)
699+
}
700+
}
701+
665702
/**
666703
* Waits for a process to exit and returns the exit code, failing
667704
* if there is no process with the specified id.
@@ -723,33 +760,31 @@ fn waitpid(pid: pid_t) -> p::ProcessExit {
723760
#[cfg(unix)]
724761
fn waitpid_os(pid: pid_t) -> p::ProcessExit {
725762
use std::libc::funcs::posix01::wait;
726-
727-
#[cfg(target_os = "linux")]
728-
#[cfg(target_os = "android")]
729-
mod imp {
730-
pub fn WIFEXITED(status: i32) -> bool { (status & 0xff) == 0 }
731-
pub fn WEXITSTATUS(status: i32) -> i32 { (status >> 8) & 0xff }
732-
pub fn WTERMSIG(status: i32) -> i32 { status & 0x7f }
763+
let mut status = 0 as c_int;
764+
match retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) {
765+
-1 => fail!("unknown waitpid error: {}", super::last_error()),
766+
_ => translate_status(status),
733767
}
768+
}
769+
}
734770

735-
#[cfg(target_os = "macos")]
736-
#[cfg(target_os = "freebsd")]
737-
mod imp {
738-
pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
739-
pub fn WEXITSTATUS(status: i32) -> i32 { status >> 8 }
740-
pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 }
741-
}
771+
fn waitpid_nowait(pid: pid_t) -> Option<p::ProcessExit> {
772+
return waitpid_os(pid);
742773

774+
// This code path isn't necessary on windows
775+
#[cfg(windows)]
776+
fn waitpid_os(_pid: pid_t) -> Option<p::ProcessExit> { None }
777+
778+
#[cfg(unix)]
779+
fn waitpid_os(pid: pid_t) -> Option<p::ProcessExit> {
780+
use std::libc::funcs::posix01::wait;
743781
let mut status = 0 as c_int;
744-
match retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) {
745-
-1 => fail!("unknown waitpid error: {}", super::last_error()),
746-
_ => {
747-
if imp::WIFEXITED(status) {
748-
p::ExitStatus(imp::WEXITSTATUS(status) as int)
749-
} else {
750-
p::ExitSignal(imp::WTERMSIG(status) as int)
751-
}
752-
}
782+
match retry(|| unsafe {
783+
wait::waitpid(pid, &mut status, libc::WNOHANG)
784+
}) {
785+
n if n == pid => Some(translate_status(status)),
786+
0 => None,
787+
n => fail!("unknown waitpid error `{}`: {}", n, super::last_error()),
753788
}
754789
}
755790
}

branches/dist-snap/src/libstd/io/process.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,9 @@ impl Process {
331331
/// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`.
332332
///
333333
/// Additionally, a signal number of 0 can check for existence of the target
334-
/// process.
334+
/// process. Note, though, that on some platforms signals will continue to
335+
/// be successfully delivered if the child has exited, but not yet been
336+
/// reaped.
335337
pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> {
336338
LocalIo::maybe_raise(|io| io.kill(id, signal))
337339
}
@@ -342,8 +344,16 @@ impl Process {
342344
/// Sends the specified signal to the child process, returning whether the
343345
/// signal could be delivered or not.
344346
///
345-
/// Note that this is purely a wrapper around libuv's `uv_process_kill`
346-
/// function.
347+
/// Note that signal 0 is interpreted as a poll to check whether the child
348+
/// process is still alive or not. If an error is returned, then the child
349+
/// process has exited.
350+
///
351+
/// On some unix platforms signals will continue to be received after a
352+
/// child has exited but not yet been reaped. In order to report the status
353+
/// of signal delivery correctly, unix implementations may invoke
354+
/// `waitpid()` with `WNOHANG` in order to reap the child as necessary.
355+
///
356+
/// # Errors
347357
///
348358
/// If the signal delivery fails, the corresponding error is returned.
349359
pub fn signal(&mut self, signal: int) -> IoResult<()> {
@@ -833,4 +843,17 @@ mod tests {
833843
p.signal_kill().unwrap();
834844
assert!(!p.wait().success());
835845
})
846+
847+
iotest!(fn test_zero() {
848+
let mut p = sleeper();
849+
p.signal_kill().unwrap();
850+
for _ in range(0, 20) {
851+
if p.signal(0).is_err() {
852+
assert!(!p.wait().success());
853+
return
854+
}
855+
timer::sleep(100);
856+
}
857+
fail!("never saw the child go away");
858+
})
836859
}

branches/dist-snap/src/libstd/libc.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,8 @@ pub mod consts {
23642364

23652365
pub static CLOCK_REALTIME: c_int = 0;
23662366
pub static CLOCK_MONOTONIC: c_int = 1;
2367+
2368+
pub static WNOHANG: c_int = 1;
23672369
}
23682370
pub mod posix08 {
23692371
}
@@ -2812,6 +2814,8 @@ pub mod consts {
28122814

28132815
pub static CLOCK_REALTIME: c_int = 0;
28142816
pub static CLOCK_MONOTONIC: c_int = 4;
2817+
2818+
pub static WNOHANG: c_int = 1;
28152819
}
28162820
pub mod posix08 {
28172821
}
@@ -3199,6 +3203,8 @@ pub mod consts {
31993203
pub static PTHREAD_CREATE_JOINABLE: c_int = 1;
32003204
pub static PTHREAD_CREATE_DETACHED: c_int = 2;
32013205
pub static PTHREAD_STACK_MIN: size_t = 8192;
3206+
3207+
pub static WNOHANG: c_int = 1;
32023208
}
32033209
pub mod posix08 {
32043210
}

branches/dist-snap/src/test/run-pass/core-run-destroy.rs

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ extern crate native;
2222
extern crate green;
2323
extern crate rustuv;
2424

25+
use std::io::Process;
26+
27+
macro_rules! succeed( ($e:expr) => (
28+
match $e { Ok(..) => {}, Err(e) => fail!("failure: {}", e) }
29+
) )
30+
2531
macro_rules! iotest (
2632
{ fn $name:ident() $b:block $($a:attr)* } => (
2733
mod $name {
@@ -53,28 +59,29 @@ fn start(argc: int, argv: **u8) -> int {
5359
}
5460

5561
iotest!(fn test_destroy_once() {
56-
#[cfg(not(target_os="android"))]
57-
static mut PROG: &'static str = "echo";
58-
59-
#[cfg(target_os="android")]
60-
static mut PROG: &'static str = "ls"; // android don't have echo binary
61-
62-
let mut p = unsafe {Process::new(PROG, []).unwrap()};
63-
p.signal_exit().unwrap(); // this shouldn't crash (and nor should the destructor)
62+
let mut p = sleeper();
63+
match p.signal_exit() {
64+
Ok(()) => {}
65+
Err(e) => fail!("error: {}", e),
66+
}
6467
})
6568

69+
#[cfg(unix)]
70+
pub fn sleeper() -> Process {
71+
Process::new("sleep", [~"1000"]).unwrap()
72+
}
73+
#[cfg(windows)]
74+
pub fn sleeper() -> Process {
75+
// There's a `timeout` command on windows, but it doesn't like having
76+
// its output piped, so instead just ping ourselves a few times with
77+
// gaps inbetweeen so we're sure this process is alive for awhile
78+
Process::new("ping", [~"127.0.0.1", ~"-n", ~"1000"]).unwrap()
79+
}
80+
6681
iotest!(fn test_destroy_twice() {
67-
#[cfg(not(target_os="android"))]
68-
static mut PROG: &'static str = "echo";
69-
#[cfg(target_os="android")]
70-
static mut PROG: &'static str = "ls"; // android don't have echo binary
71-
72-
let mut p = match unsafe{Process::new(PROG, [])} {
73-
Ok(p) => p,
74-
Err(e) => fail!("wut: {}", e),
75-
};
76-
p.signal_exit().unwrap(); // this shouldnt crash...
77-
p.signal_exit().unwrap(); // ...and nor should this (and nor should the destructor)
82+
let mut p = sleeper();
83+
succeed!(p.signal_exit()); // this shouldnt crash...
84+
let _ = p.signal_exit(); // ...and nor should this (and nor should the destructor)
7885
})
7986

8087
pub fn test_destroy_actually_kills(force: bool) {

0 commit comments

Comments
 (0)