diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs index 34e85a9819a..59b3437ad9a 100644 --- a/src/libnative/lib.rs +++ b/src/libnative/lib.rs @@ -97,6 +97,24 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int { // frames above our current position. let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE; + // When using libgreen, one of the first things that we do is to turn off + // the SIGPIPE signal (set it to ignore). By default, some platforms will + // send a *signal* when a EPIPE error would otherwise be delivered. This + // runtime doesn't install a SIGPIPE handler, causing it to kill the + // program, which isn't exactly what we want! + // + // Hence, we set SIGPIPE to ignore when the program starts up in order to + // prevent this problem. + #[cfg(windows)] fn ignore_sigpipe() {} + #[cfg(unix)] fn ignore_sigpipe() { + use std::libc; + use std::libc::funcs::posix01::signal::signal; + unsafe { + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1); + } + } + ignore_sigpipe(); + rt::init(argc, argv); let mut exit_code = None; let mut main = Some(main); diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 972002fe34e..83a95952e02 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -266,6 +266,8 @@ pub mod types { } pub enum timezone {} + + pub type sighandler_t = size_t; } pub mod bsd44 { use libc::types::os::arch::c95::{c_char, c_int, c_uint}; @@ -637,6 +639,8 @@ pub mod types { } pub enum timezone {} + + pub type sighandler_t = size_t; } pub mod bsd44 { use libc::types::os::arch::c95::{c_char, c_int, c_uint}; @@ -1206,6 +1210,8 @@ pub mod types { } pub enum timezone {} + + pub type sighandler_t = size_t; } pub mod bsd44 { @@ -2292,6 +2298,8 @@ pub mod consts { use libc::types::os::arch::c95::{c_int, size_t}; pub static SIGTRAP : c_int = 5; + pub static SIGPIPE: c_int = 13; + pub static SIG_IGN: size_t = 1; pub static GLOB_ERR : c_int = 1 << 0; pub static GLOB_MARK : c_int = 1 << 1; @@ -2743,6 +2751,8 @@ pub mod consts { use libc::types::os::arch::c95::{c_int, size_t}; pub static SIGTRAP : c_int = 5; + pub static SIGPIPE: c_int = 13; + pub static SIG_IGN: size_t = 1; pub static GLOB_APPEND : c_int = 0x0001; pub static GLOB_DOOFFS : c_int = 0x0002; @@ -3140,6 +3150,8 @@ pub mod consts { use libc::types::os::arch::c95::{c_int, size_t}; pub static SIGTRAP : c_int = 5; + pub static SIGPIPE: c_int = 13; + pub static SIG_IGN: size_t = 1; pub static GLOB_APPEND : c_int = 0x0001; pub static GLOB_DOOFFS : c_int = 0x0002; @@ -3844,6 +3856,24 @@ pub mod funcs { } } + pub mod signal { + use libc::types::os::arch::c95::c_int; + use libc::types::os::common::posix01::sighandler_t; + + #[cfg(not(target_os = "android"))] + extern { + pub fn signal(signum: c_int, + handler: sighandler_t) -> sighandler_t; + } + + #[cfg(target_os = "android")] + extern { + #[link_name = "bsd_signal"] + pub fn signal(signum: c_int, + handler: sighandler_t) -> sighandler_t; + } + } + pub mod wait { use libc::types::os::arch::c95::{c_int}; use libc::types::os::arch::posix88::{pid_t}; diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs new file mode 100644 index 00000000000..5c62ea2ad21 --- /dev/null +++ b/src/test/run-pass/sigpipe-should-be-ignored.rs @@ -0,0 +1,36 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-fast + +// Be sure that when a SIGPIPE would have been received that the entire process +// doesn't die in a ball of fire, but rather it's gracefully handled. + +use std::os; +use std::io::{PipeStream, Process}; + +fn test() { + let os::Pipe { input, out } = os::pipe(); + let input = PipeStream::open(input); + let mut out = PipeStream::open(out); + drop(input); + + let _ = out.write([1]); +} + +fn main() { + let args = os::args(); + if args.len() > 1 && args[1].as_slice() == "test" { + return test(); + } + + let mut p = Process::new(args[0], [~"test"]).unwrap(); + assert!(p.wait().success()); +}