Skip to content

Commit a432d87

Browse files
committed
---
yaml --- r: 106359 b: refs/heads/auto c: cbfc0a5 h: refs/heads/master i: 106357: cf48910 106355: dde1d51 106351: cc90078 v: v3
1 parent 9bca6d0 commit a432d87

File tree

7 files changed

+201
-46
lines changed

7 files changed

+201
-46
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0
1313
refs/tags/release-0.3.1: 495bae036dfe5ec6ceafd3312b4dca48741e845b
1414
refs/tags/release-0.4: e828ea2080499553b97dfe33b3f4d472b4562ad7
1515
refs/tags/release-0.5: 7e3bcfbf21278251ee936ad53e92e9b719702d73
16-
refs/heads/auto: 2e6607a1dd44aab097d0a3f9d7b1a418f6698602
16+
refs/heads/auto: cbfc0a5e33eb3d97a2995d120536b8dadc0cc0a2
1717
refs/heads/servo: af82457af293e2a842ba6b7759b70288da276167
1818
refs/tags/release-0.6: b4ebcfa1812664df5e142f0134a5faea3918544c
1919
refs/tags/0.1: b19db808c2793fe2976759b85a355c3ad8c8b336

branches/auto/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/auto/src/libnative/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,24 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int {
9797
// frames above our current position.
9898
let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE;
9999

100+
// When using libgreen, one of the first things that we do is to turn off
101+
// the SIGPIPE signal (set it to ignore). By default, some platforms will
102+
// send a *signal* when a EPIPE error would otherwise be delivered. This
103+
// runtime doesn't install a SIGPIPE handler, causing it to kill the
104+
// program, which isn't exactly what we want!
105+
//
106+
// Hence, we set SIGPIPE to ignore when the program starts up in order to
107+
// prevent this problem.
108+
#[cfg(windows)] fn ignore_sigpipe() {}
109+
#[cfg(unix)] fn ignore_sigpipe() {
110+
use std::libc;
111+
use std::libc::funcs::posix01::signal::signal;
112+
unsafe {
113+
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1);
114+
}
115+
}
116+
ignore_sigpipe();
117+
100118
rt::init(argc, argv);
101119
let mut exit_code = None;
102120
let mut main = Some(main);

branches/auto/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/auto/src/libstd/libc.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ pub mod types {
266266
}
267267

268268
pub enum timezone {}
269+
270+
pub type sighandler_t = size_t;
269271
}
270272
pub mod bsd44 {
271273
use libc::types::os::arch::c95::{c_char, c_int, c_uint};
@@ -637,6 +639,8 @@ pub mod types {
637639
}
638640

639641
pub enum timezone {}
642+
643+
pub type sighandler_t = size_t;
640644
}
641645
pub mod bsd44 {
642646
use libc::types::os::arch::c95::{c_char, c_int, c_uint};
@@ -1206,6 +1210,8 @@ pub mod types {
12061210
}
12071211

12081212
pub enum timezone {}
1213+
1214+
pub type sighandler_t = size_t;
12091215
}
12101216

12111217
pub mod bsd44 {
@@ -2292,6 +2298,8 @@ pub mod consts {
22922298
use libc::types::os::arch::c95::{c_int, size_t};
22932299

22942300
pub static SIGTRAP : c_int = 5;
2301+
pub static SIGPIPE: c_int = 13;
2302+
pub static SIG_IGN: size_t = 1;
22952303

22962304
pub static GLOB_ERR : c_int = 1 << 0;
22972305
pub static GLOB_MARK : c_int = 1 << 1;
@@ -2356,6 +2364,8 @@ pub mod consts {
23562364

23572365
pub static CLOCK_REALTIME: c_int = 0;
23582366
pub static CLOCK_MONOTONIC: c_int = 1;
2367+
2368+
pub static WNOHANG: c_int = 1;
23592369
}
23602370
pub mod posix08 {
23612371
}
@@ -2741,6 +2751,8 @@ pub mod consts {
27412751
use libc::types::os::arch::c95::{c_int, size_t};
27422752

27432753
pub static SIGTRAP : c_int = 5;
2754+
pub static SIGPIPE: c_int = 13;
2755+
pub static SIG_IGN: size_t = 1;
27442756

27452757
pub static GLOB_APPEND : c_int = 0x0001;
27462758
pub static GLOB_DOOFFS : c_int = 0x0002;
@@ -2802,6 +2814,8 @@ pub mod consts {
28022814

28032815
pub static CLOCK_REALTIME: c_int = 0;
28042816
pub static CLOCK_MONOTONIC: c_int = 4;
2817+
2818+
pub static WNOHANG: c_int = 1;
28052819
}
28062820
pub mod posix08 {
28072821
}
@@ -3136,6 +3150,8 @@ pub mod consts {
31363150
use libc::types::os::arch::c95::{c_int, size_t};
31373151

31383152
pub static SIGTRAP : c_int = 5;
3153+
pub static SIGPIPE: c_int = 13;
3154+
pub static SIG_IGN: size_t = 1;
31393155

31403156
pub static GLOB_APPEND : c_int = 0x0001;
31413157
pub static GLOB_DOOFFS : c_int = 0x0002;
@@ -3187,6 +3203,8 @@ pub mod consts {
31873203
pub static PTHREAD_CREATE_JOINABLE: c_int = 1;
31883204
pub static PTHREAD_CREATE_DETACHED: c_int = 2;
31893205
pub static PTHREAD_STACK_MIN: size_t = 8192;
3206+
3207+
pub static WNOHANG: c_int = 1;
31903208
}
31913209
pub mod posix08 {
31923210
}
@@ -3838,6 +3856,24 @@ pub mod funcs {
38383856
}
38393857
}
38403858

3859+
pub mod signal {
3860+
use libc::types::os::arch::c95::c_int;
3861+
use libc::types::os::common::posix01::sighandler_t;
3862+
3863+
#[cfg(not(target_os = "android"))]
3864+
extern {
3865+
pub fn signal(signum: c_int,
3866+
handler: sighandler_t) -> sighandler_t;
3867+
}
3868+
3869+
#[cfg(target_os = "android")]
3870+
extern {
3871+
#[link_name = "bsd_signal"]
3872+
pub fn signal(signum: c_int,
3873+
handler: sighandler_t) -> sighandler_t;
3874+
}
3875+
}
3876+
38413877
pub mod wait {
38423878
use libc::types::os::arch::c95::{c_int};
38433879
use libc::types::os::arch::posix88::{pid_t};

branches/auto/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) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-fast
12+
13+
// Be sure that when a SIGPIPE would have been received that the entire process
14+
// doesn't die in a ball of fire, but rather it's gracefully handled.
15+
16+
use std::os;
17+
use std::io::{PipeStream, Process};
18+
19+
fn test() {
20+
let os::Pipe { input, out } = os::pipe();
21+
let input = PipeStream::open(input);
22+
let mut out = PipeStream::open(out);
23+
drop(input);
24+
25+
let _ = out.write([1]);
26+
}
27+
28+
fn main() {
29+
let args = os::args();
30+
if args.len() > 1 && args[1].as_slice() == "test" {
31+
return test();
32+
}
33+
34+
let mut p = Process::new(args[0], [~"test"]).unwrap();
35+
assert!(p.wait().success());
36+
}

0 commit comments

Comments
 (0)