| ... | @@ -26,8 +26,13 @@ threads: std.ArrayListUnmanaged(std.Thread), | ... | @@ -26,8 +26,13 @@ threads: std.ArrayListUnmanaged(std.Thread), |
| 26 | stack_size: usize, | 26 | stack_size: usize, |
| 27 | cpu_count: std.Thread.CpuCountError!usize, | 27 | cpu_count: std.Thread.CpuCountError!usize, |
| 28 | concurrent_count: usize, | 28 | concurrent_count: usize, |
| | 29 | |
| 29 | wsa: if (is_windows) Wsa else struct {} = .{}, | 30 | wsa: if (is_windows) Wsa else struct {} = .{}, |
| 30 | | 31 | |
| | 32 | have_signal_handler: bool, |
| | 33 | old_sig_io: if (have_sig_io) posix.Sigaction else void, |
| | 34 | old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void, |
| | 35 | |
| 31 | threadlocal var current_closure: ?*Closure = null; | 36 | threadlocal var current_closure: ?*Closure = null; |
| 32 | | 37 | |
| 33 | const max_iovecs_len = 8; | 38 | const 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 | } |
| 113 | | 136 | |
| 114 | /// Statically initialize such that calls to `Io.VTable.concurrent` will fail | 137 | /// 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. |
| 118 | pub const init_single_threaded: Threaded = .{ | 143 | pub 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 | }; |
| 125 | | 153 | |
| 126 | pub fn deinit(t: *Threaded) void { | 154 | pub 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 | } |
| 135 | | 167 | |
| ... | @@ -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 | }; |
| | 373 | const have_sig_io = posix.SIG != void and @hasField(posix.SIG, "IO"); |
| | 374 | const have_sig_pipe = posix.SIG != void and @hasField(posix.SIG, "PIPE"); |
| 341 | | 375 | |
| 342 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; | 376 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; |
| 343 | const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat; | 377 | const 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 | } |
| 6117 | | 6151 | |
| | 6152 | fn doNothingSignalHandler(_: posix.SIG) callconv(.c) void {} |
| | 6153 | |
| 6118 | test { | 6154 | test { |
| 6119 | _ = @import("Threaded/test.zig"); | 6155 | _ = @import("Threaded/test.zig"); |
| 6120 | } | 6156 | } |