Commit dafefe9c9d

Jonathan Marler <johnnymarler@gmail.com>
2023-02-18 19:46:24
use std_options for keep_sigpipe and existence of SIG.PIPE to check for support
1 parent 0a8fe34
Changed files (3)
lib
test
standalone
lib/std/os.zig
@@ -7057,42 +7057,12 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {
     };
 }
 
-/// Whether or not the current target support SIGPIPE
-pub const have_sigpipe_support = switch (builtin.os.tag) {
-    .linux,
-    .macos,
-    .netbsd,
-    .solaris,
-    .freebsd,
-    .openbsd,
-    => true,
-    else => false,
-};
-
-pub const keep_sigpipe: bool = if (@hasDecl(root, "keep_sigpipe"))
-    root.keep_sigpipe
-else
-    false;
+pub const have_sigpipe_support = @hasDecl(@This(), "SIG") and @hasDecl(SIG, "PIPE");
 
 fn noopSigHandler(_: c_int) callconv(.C) void {}
 
-/// This function will tell the kernel to ignore SIGPIPE rather than terminate
-/// the process.  This function is automatically called in `start.zig` before
-/// `main`.  This behavior can be disabled by adding this to your root module:
-///
-///     pub const keep_sigpipe = true;
-///
-/// SIGPIPE is triggered when a process attempts to write to a broken pipe.
-/// By default, SIGPIPE will terminate the process without giving the program
-/// an opportunity to handle the situation.  Unlike a segfault, it doesn't
-/// trigger the panic handler so all the developer sees is that the program
-/// terminated with no indication as to why.
-///
-/// By telling the kernel to instead ignore SIGPIPE, writes to broken pipes
-/// will return the EPIPE error (error.BrokenPipe) and the program can handle
-/// it like any other error.
 pub fn maybeIgnoreSigpipe() void {
-    if (have_sigpipe_support and !keep_sigpipe) {
+    if (have_sigpipe_support and !std.options.keep_sigpipe) {
         const act = Sigaction{
             // We set handler to a noop function instead of SIG.IGN so we don't leak our
             // signal disposition to a child process
lib/std/std.zig
@@ -167,6 +167,22 @@ pub const options = struct {
         options_override.crypto_always_getrandom
     else
         false;
+
+    /// By default Zig disables SIGPIPE by setting a "no-op" handler for it.  Set this option
+    /// to `true` to prevent that.
+    ///
+    /// Note that we use a "no-op" handler instead of SIG_IGN because it will not be inherited by
+    /// any child process.
+    ///
+    /// SIGPIPE is triggered when a process attempts to write to a broken pipe. By default, SIGPIPE
+    /// will terminate the process instead of exiting.  It doesn't trigger the panic handler so in many
+    /// cases it's unclear why the process was terminated.  By capturing SIGPIPE instead, functions that
+    /// write to broken pipes will return the EPIPE error (error.BrokenPipe) and the program can handle
+    /// it like any other error.
+    pub const keep_sigpipe: bool = if (@hasDecl(options_override, "keep_sigpipe"))
+        options_override.keep_sigpipe
+    else
+        false;
 };
 
 // This forces the start.zig file to be imported, and the comptime logic inside that
test/standalone/sigpipe/breakpipe.zig
@@ -1,7 +1,7 @@
 const std = @import("std");
 const build_options = @import("build_options");
 
-pub usingnamespace if (build_options.keep_sigpipe) struct {
+pub const std_options = if (build_options.keep_sigpipe) struct {
     pub const keep_sigpipe = true;
 } else struct {
     // intentionally not setting keep_sigpipe to ensure the default behavior is equivalent to false