| ... | ... | @@ -26,8 +26,13 @@ threads: std.ArrayListUnmanaged(std.Thread), |
| 26 | 26 | stack_size: usize, |
| 27 | 27 | cpu_count: std.Thread.CpuCountError!usize, |
| 28 | 28 | concurrent_count: usize, |
| 29 | |
| 29 | 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 | 36 | threadlocal var current_closure: ?*Closure = null; |
| 32 | 37 | |
| 33 | 38 | const max_iovecs_len = 8; |
| ... | ... | @@ -104,23 +109,46 @@ pub fn init( |
| 104 | 109 | .stack_size = std.Thread.SpawnConfig.default_stack_size, |
| 105 | 110 | .cpu_count = std.Thread.getCpuCount(), |
| 106 | 111 | .concurrent_count = 0, |
| 112 | .old_sig_io = undefined, |
| 113 | .old_sig_pipe = undefined, |
| 114 | .have_signal_handler = false, |
| 107 | 115 | }; |
| 116 | |
| 108 | 117 | if (t.cpu_count) |n| { |
| 109 | 118 | t.threads.ensureTotalCapacityPrecise(gpa, n - 1) catch {}; |
| 110 | 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 | 134 | return t; |
| 112 | 135 | } |
| 113 | 136 | |
| 114 | 137 | /// Statically initialize such that calls to `Io.VTable.concurrent` will fail |
| 115 | 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 | 143 | pub const init_single_threaded: Threaded = .{ |
| 119 | 144 | .allocator = .failing, |
| 120 | 145 | .threads = .empty, |
| 121 | 146 | .stack_size = std.Thread.SpawnConfig.default_stack_size, |
| 122 | 147 | .cpu_count = 1, |
| 123 | 148 | .concurrent_count = 0, |
| 149 | .old_sig_io = undefined, |
| 150 | .old_sig_pipe = undefined, |
| 151 | .have_signal_handler = false, |
| 124 | 152 | }; |
| 125 | 153 | |
| 126 | 154 | pub fn deinit(t: *Threaded) void { |
| ... | ... | @@ -130,6 +158,10 @@ pub fn deinit(t: *Threaded) void { |
| 130 | 158 | if (is_windows and t.wsa.status == .initialized) { |
| 131 | 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 | 165 | t.* = undefined; |
| 134 | 166 | } |
| 135 | 167 | |
| ... | ... | @@ -338,6 +370,8 @@ const have_preadv = switch (native_os) { |
| 338 | 370 | .windows, .haiku, .serenity => false, // 💩💩💩 |
| 339 | 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 | 376 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; |
| 343 | 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 | 6149 | return error.NetworkDown; |
| 6116 | 6150 | } |
| 6117 | 6151 | |
| 6152 | fn doNothingSignalHandler(_: posix.SIG) callconv(.c) void {} |
| 6153 | |
| 6118 | 6154 | test { |
| 6119 | 6155 | _ = @import("Threaded/test.zig"); |
| 6120 | 6156 | } |