authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-28 18:45:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:52-07:00
log05b28409e7204f78e3edb32ea9c46b10e4e97cef
tree4db0f476cbb8718941df6c07a375ee384f1b0d00
parentb863f2548b95cdc8b2e2818ac3a26e553be155dc

std.Io.Threaded: install and cleanup signal handlers

rather than in start code. delete std.options.keep_sig_io and std.options.keep_sig_pipe

4 files changed, 38 insertions(+), 37 deletions(-)

lib/std/Io/Threaded.zig+37-1
...@@ -26,8 +26,13 @@ threads: std.ArrayListUnmanaged(std.Thread),...@@ -26,8 +26,13 @@ threads: std.ArrayListUnmanaged(std.Thread),
26stack_size: usize,26stack_size: usize,
27cpu_count: std.Thread.CpuCountError!usize,27cpu_count: std.Thread.CpuCountError!usize,
28concurrent_count: usize,28concurrent_count: usize,
29
29wsa: if (is_windows) Wsa else struct {} = .{},30wsa: if (is_windows) Wsa else struct {} = .{},
3031
32have_signal_handler: bool,
33old_sig_io: if (have_sig_io) posix.Sigaction else void,
34old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void,
35
31threadlocal var current_closure: ?*Closure = null;36threadlocal var current_closure: ?*Closure = null;
3237
33const max_iovecs_len = 8;38const max_iovecs_len = 8;
...@@ -104,23 +109,46 @@ pub fn init(...@@ -104,23 +109,46 @@ pub fn init(
104 .stack_size = std.Thread.SpawnConfig.default_stack_size,109 .stack_size = std.Thread.SpawnConfig.default_stack_size,
105 .cpu_count = std.Thread.getCpuCount(),110 .cpu_count = std.Thread.getCpuCount(),
106 .concurrent_count = 0,111 .concurrent_count = 0,
112 .old_sig_io = undefined,
113 .old_sig_pipe = undefined,
114 .have_signal_handler = false,
107 };115 };
116
108 if (t.cpu_count) |n| {117 if (t.cpu_count) |n| {
109 t.threads.ensureTotalCapacityPrecise(gpa, n - 1) catch {};118 t.threads.ensureTotalCapacityPrecise(gpa, n - 1) catch {};
110 } else |_| {}119 } else |_| {}
120
121 if (posix.Sigaction != void) {
122 // This causes sending `posix.SIG.IO` to thread to interrupt blocking
123 // syscalls, returning `posix.E.INTR`.
124 const act: posix.Sigaction = .{
125 .handler = .{ .handler = doNothingSignalHandler },
126 .mask = posix.sigemptyset(),
127 .flags = 0,
128 };
129 if (have_sig_io) posix.sigaction(.IO, &act, &t.old_sig_io);
130 if (have_sig_pipe) posix.sigaction(.PIPE, &act, &t.old_sig_pipe);
131 t.have_signal_handler = true;
132 }
133
111 return t;134 return t;
112}135}
113136
114/// Statically initialize such that calls to `Io.VTable.concurrent` will fail137/// Statically initialize such that calls to `Io.VTable.concurrent` will fail
115/// with `error.ConcurrencyUnavailable`.138/// with `error.ConcurrencyUnavailable`.
116///139///
117/// When initialized this way, `deinit` is safe, but unnecessary to call.140/// When initialized this way:
141/// * cancel requests have no effect.
142/// * `deinit` is safe, but unnecessary to call.
118pub const init_single_threaded: Threaded = .{143pub const init_single_threaded: Threaded = .{
119 .allocator = .failing,144 .allocator = .failing,
120 .threads = .empty,145 .threads = .empty,
121 .stack_size = std.Thread.SpawnConfig.default_stack_size,146 .stack_size = std.Thread.SpawnConfig.default_stack_size,
122 .cpu_count = 1,147 .cpu_count = 1,
123 .concurrent_count = 0,148 .concurrent_count = 0,
149 .old_sig_io = undefined,
150 .old_sig_pipe = undefined,
151 .have_signal_handler = false,
124};152};
125153
126pub fn deinit(t: *Threaded) void {154pub fn deinit(t: *Threaded) void {
...@@ -130,6 +158,10 @@ pub fn deinit(t: *Threaded) void {...@@ -130,6 +158,10 @@ pub fn deinit(t: *Threaded) void {
130 if (is_windows and t.wsa.status == .initialized) {158 if (is_windows and t.wsa.status == .initialized) {
131 if (ws2_32.WSACleanup() != 0) recoverableOsBugDetected();159 if (ws2_32.WSACleanup() != 0) recoverableOsBugDetected();
132 }160 }
161 if (posix.Sigaction != void and t.have_signal_handler) {
162 if (have_sig_io) posix.sigaction(.IO, &t.old_sig_io, null);
163 if (have_sig_pipe) posix.sigaction(.PIPE, &t.old_sig_pipe, null);
164 }
133 t.* = undefined;165 t.* = undefined;
134}166}
135167
...@@ -338,6 +370,8 @@ const have_preadv = switch (native_os) {...@@ -338,6 +370,8 @@ const have_preadv = switch (native_os) {
338 .windows, .haiku, .serenity => false, // 💩💩💩370 .windows, .haiku, .serenity => false, // 💩💩💩
339 else => true,371 else => true,
340};372};
373const have_sig_io = posix.SIG != void and @hasField(posix.SIG, "IO");
374const have_sig_pipe = posix.SIG != void and @hasField(posix.SIG, "PIPE");
341375
342const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat;376const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat;
343const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat;377const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat;
...@@ -6115,6 +6149,8 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {...@@ -6115,6 +6149,8 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
6115 return error.NetworkDown;6149 return error.NetworkDown;
6116}6150}
61176151
6152fn doNothingSignalHandler(_: posix.SIG) callconv(.c) void {}
6153
6118test {6154test {
6119 _ = @import("Threaded/test.zig");6155 _ = @import("Threaded/test.zig");
6120}6156}
lib/std/posix.zig+1
...@@ -55,6 +55,7 @@ else switch (native_os) {...@@ -55,6 +55,7 @@ else switch (native_os) {
55 pub const mode_t = u0;55 pub const mode_t = u0;
56 pub const ino_t = void;56 pub const ino_t = void;
57 pub const IFNAMESIZE = {};57 pub const IFNAMESIZE = {};
58 pub const SIG = void;
58 },59 },
59};60};
6061
lib/std/start.zig-21
...@@ -651,7 +651,6 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {...@@ -651,7 +651,6 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
651 std.os.argv = argv[0..argc];651 std.os.argv = argv[0..argc];
652 std.os.environ = envp;652 std.os.environ = envp;
653653
654 maybeIgnoreSignals();
655 std.debug.maybeEnableSegfaultHandler();654 std.debug.maybeEnableSegfaultHandler();
656655
657 return callMain();656 return callMain();
...@@ -756,23 +755,3 @@ pub fn call_wWinMain() std.os.windows.INT {...@@ -756,23 +755,3 @@ pub fn call_wWinMain() std.os.windows.INT {
756 // second parameter hPrevInstance, MSDN: "This parameter is always NULL"755 // second parameter hPrevInstance, MSDN: "This parameter is always NULL"
757 return root.wWinMain(hInstance, null, lpCmdLine, nCmdShow);756 return root.wWinMain(hInstance, null, lpCmdLine, nCmdShow);
758}757}
759
760fn maybeIgnoreSignals() void {
761 const posix = std.posix;
762 if (posix.Sigaction == void) return;
763 const act: posix.Sigaction = .{
764 // Set handler to a noop function instead of `IGN` to prevent
765 // leaking signal disposition to a child process.
766 .handler = .{ .handler = noopSigHandler },
767 .mask = posix.sigemptyset(),
768 .flags = 0,
769 };
770
771 if (@hasField(posix.SIG, "IO") and !std.options.keep_sig_io)
772 posix.sigaction(.IO, &act, null);
773
774 if (@hasField(posix.SIG, "PIPE") and !std.options.keep_sig_pipe)
775 posix.sigaction(.PIPE, &act, null);
776}
777
778fn noopSigHandler(_: std.posix.SIG) callconv(.c) void {}
lib/std/std.zig-15
...@@ -144,21 +144,6 @@ pub const Options = struct {...@@ -144,21 +144,6 @@ pub const Options = struct {
144144
145 crypto_fork_safety: bool = true,145 crypto_fork_safety: bool = true,
146146
147 keep_sig_io: bool = false,
148
149 /// By default Zig disables SIGPIPE by setting a "no-op" handler for it. Set this option
150 /// to `true` to prevent that.
151 ///
152 /// Note that we use a "no-op" handler instead of SIG_IGN because it will not be inherited by
153 /// any child process.
154 ///
155 /// SIGPIPE is triggered when a process attempts to write to a broken pipe. By default, SIGPIPE
156 /// will terminate the process instead of exiting. It doesn't trigger the panic handler so in many
157 /// cases it's unclear why the process was terminated. By capturing SIGPIPE instead, functions that
158 /// write to broken pipes will return the EPIPE error (error.BrokenPipe) and the program can handle
159 /// it like any other error.
160 keep_sig_pipe: bool = false,
161
162 /// By default, std.http.Client will support HTTPS connections. Set this option to `true` to147 /// By default, std.http.Client will support HTTPS connections. Set this option to `true` to
163 /// disable TLS support.148 /// disable TLS support.
164 ///149 ///