| author | |
| committer | |
| log | dafefe9c9d3ffd484915ead0474c7e772f1dfcfb |
| tree | fc8d6b6144f52645b7d3bf0f4796ae6326ab9327 |
| parent | 0a8fe34b11f7a44fd7f744bf4332353a5e7bfcdf |
3 files changed, 19 insertions(+), 33 deletions(-)
lib/std/os.zig+2-32| ... | @@ -7057,42 +7057,12 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec { | ... | @@ -7057,42 +7057,12 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec { |
| 7057 | }; | 7057 | }; |
| 7058 | } | 7058 | } |
| 7059 | 7059 | ||
| 7060 | /// Whether or not the current target support SIGPIPE | 7060 | pub const have_sigpipe_support = @hasDecl(@This(), "SIG") and @hasDecl(SIG, "PIPE"); |
| 7061 | pub const have_sigpipe_support = switch (builtin.os.tag) { | ||
| 7062 | .linux, | ||
| 7063 | .macos, | ||
| 7064 | .netbsd, | ||
| 7065 | .solaris, | ||
| 7066 | .freebsd, | ||
| 7067 | .openbsd, | ||
| 7068 | => true, | ||
| 7069 | else => false, | ||
| 7070 | }; | ||
| 7071 | |||
| 7072 | pub const keep_sigpipe: bool = if (@hasDecl(root, "keep_sigpipe")) | ||
| 7073 | root.keep_sigpipe | ||
| 7074 | else | ||
| 7075 | false; | ||
| 7076 | 7061 | ||
| 7077 | fn noopSigHandler(_: c_int) callconv(.C) void {} | 7062 | fn noopSigHandler(_: c_int) callconv(.C) void {} |
| 7078 | 7063 | ||
| 7079 | /// This function will tell the kernel to ignore SIGPIPE rather than terminate | ||
| 7080 | /// the process. This function is automatically called in `start.zig` before | ||
| 7081 | /// `main`. This behavior can be disabled by adding this to your root module: | ||
| 7082 | /// | ||
| 7083 | /// pub const keep_sigpipe = true; | ||
| 7084 | /// | ||
| 7085 | /// SIGPIPE is triggered when a process attempts to write to a broken pipe. | ||
| 7086 | /// By default, SIGPIPE will terminate the process without giving the program | ||
| 7087 | /// an opportunity to handle the situation. Unlike a segfault, it doesn't | ||
| 7088 | /// trigger the panic handler so all the developer sees is that the program | ||
| 7089 | /// terminated with no indication as to why. | ||
| 7090 | /// | ||
| 7091 | /// By telling the kernel to instead ignore SIGPIPE, writes to broken pipes | ||
| 7092 | /// will return the EPIPE error (error.BrokenPipe) and the program can handle | ||
| 7093 | /// it like any other error. | ||
| 7094 | pub fn maybeIgnoreSigpipe() void { | 7064 | pub fn maybeIgnoreSigpipe() void { |
| 7095 | if (have_sigpipe_support and !keep_sigpipe) { | 7065 | if (have_sigpipe_support and !std.options.keep_sigpipe) { |
| 7096 | const act = Sigaction{ | 7066 | const act = Sigaction{ |
| 7097 | // We set handler to a noop function instead of SIG.IGN so we don't leak our | 7067 | // We set handler to a noop function instead of SIG.IGN so we don't leak our |
| 7098 | // signal disposition to a child process | 7068 | // signal disposition to a child process |
lib/std/std.zig+16| ... | @@ -167,6 +167,22 @@ pub const options = struct { | ... | @@ -167,6 +167,22 @@ pub const options = struct { |
| 167 | options_override.crypto_always_getrandom | 167 | options_override.crypto_always_getrandom |
| 168 | else | 168 | else |
| 169 | false; | 169 | false; |
| 170 | |||
| 171 | /// By default Zig disables SIGPIPE by setting a "no-op" handler for it. Set this option | ||
| 172 | /// to `true` to prevent that. | ||
| 173 | /// | ||
| 174 | /// Note that we use a "no-op" handler instead of SIG_IGN because it will not be inherited by | ||
| 175 | /// any child process. | ||
| 176 | /// | ||
| 177 | /// SIGPIPE is triggered when a process attempts to write to a broken pipe. By default, SIGPIPE | ||
| 178 | /// will terminate the process instead of exiting. It doesn't trigger the panic handler so in many | ||
| 179 | /// cases it's unclear why the process was terminated. By capturing SIGPIPE instead, functions that | ||
| 180 | /// write to broken pipes will return the EPIPE error (error.BrokenPipe) and the program can handle | ||
| 181 | /// it like any other error. | ||
| 182 | pub const keep_sigpipe: bool = if (@hasDecl(options_override, "keep_sigpipe")) | ||
| 183 | options_override.keep_sigpipe | ||
| 184 | else | ||
| 185 | false; | ||
| 170 | }; | 186 | }; |
| 171 | 187 | ||
| 172 | // This forces the start.zig file to be imported, and the comptime logic inside that | 188 | // This forces the start.zig file to be imported, and the comptime logic inside that |
test/standalone/sigpipe/breakpipe.zig+1-1| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const build_options = @import("build_options"); | 2 | const build_options = @import("build_options"); |
| 3 | 3 | ||
| 4 | pub usingnamespace if (build_options.keep_sigpipe) struct { | 4 | pub const std_options = if (build_options.keep_sigpipe) struct { |
| 5 | pub const keep_sigpipe = true; | 5 | pub const keep_sigpipe = true; |
| 6 | } else struct { | 6 | } else struct { |
| 7 | // intentionally not setting keep_sigpipe to ensure the default behavior is equivalent to false | 7 | // intentionally not setting keep_sigpipe to ensure the default behavior is equivalent to false |