about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libnative/lib.rs18
-rw-r--r--src/libstd/libc.rs30
-rw-r--r--src/test/run-pass/sigpipe-should-be-ignored.rs36
3 files changed, 84 insertions, 0 deletions
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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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());
+}