authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-11-29 07:36:44-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-01 19:17:52-08:00
log39ac40209b57d105dff28988a954a594e2e9dd8f
tree12529825088f0ef1aaedf659d4118ef63a4b9c3a
parentd60760d61e19018aa354fbb2f241444db88ca51b

std.Io.Threaded: use musl's beautiful pthread_cancel semantics


3 files changed, 121 insertions(+), 83 deletions(-)

lib/std/Io/Threaded.zig+103-83
......@@ -3,6 +3,7 @@ const Threaded = @This();
33const builtin = @import("builtin");
44const native_os = builtin.os.tag;
55const is_windows = native_os == .windows;
6const is_musl = builtin.link_libc and builtin.abi.isMusl();
67const windows = std.os.windows;
78const ws2_32 = std.os.windows.ws2_32;
89const is_debug = builtin.mode == .Debug;
......@@ -111,7 +112,7 @@ const Thread = struct {
111112 @atomicStore(CancelStatus, &closure.cancel_status, .acknowledged, .release);
112113 return error.Canceled;
113114 },
114 .acknowledged => unreachable,
115 .acknowledged => return,
115116 _ => unreachable,
116117 }
117118 }
......@@ -128,6 +129,13 @@ const Thread = struct {
128129 );
129130 }
130131
132 fn endSyscallCanceled(thread: *Thread) Io.Cancelable {
133 if (thread.current_closure) |closure| {
134 @atomicStore(CancelStatus, &closure.cancel_status, .acknowledged, .release);
135 }
136 return error.Canceled;
137 }
138
131139 fn currentSignalId() SignalId {
132140 return if (std.Thread.use_pthreads) std.c.pthread_self() else std.Thread.getCurrentId();
133141 }
......@@ -197,6 +205,13 @@ const Closure = struct {
197205 .none, .acknowledged, .requested => return,
198206 .signal_id => |signal_id| signal_id,
199207 };
208 // Musl has an undocumented extension that makes pthread_cancel have the useful, desired
209 // behavior of causing the next syscall to return ECANCELED.
210 if (is_musl) {
211 _ = std.c.pthread_cancel(signal_id);
212 return;
213 }
214
200215 // The task will enter a blocking syscall before checking for cancellation again.
201216 // We can send a signal to interrupt the syscall, but if it arrives before
202217 // the syscall instruction, it will be missed. Therefore, this code tries
......@@ -218,8 +233,7 @@ const Closure = struct {
218233
219234 for (0..max_attempts) |attempt_index| {
220235 if (std.Thread.use_pthreads) {
221 const rc = std.c.pthread_kill(signal_id, .IO);
222 if (is_debug) assert(rc == 0);
236 if (std.c.pthread_kill(signal_id, .IO) != 0) return;
223237 } else if (native_os == .linux) {
224238 const pid: posix.pid_t = p: {
225239 const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
......@@ -228,7 +242,7 @@ const Closure = struct {
228242 @atomicStore(Pid, &t.pid, @enumFromInt(pid), .monotonic);
229243 break :p pid;
230244 };
231 _ = std.os.linux.tgkill(pid, @bitCast(signal_id), .IO);
245 if (std.os.linux.tgkill(pid, @bitCast(signal_id), .IO) != 0) return;
232246 } else {
233247 return;
234248 }
......@@ -354,6 +368,11 @@ fn worker(t: *Threaded) void {
354368 while (true) {
355369 while (t.run_queue.popFirst()) |closure_node| {
356370 t.mutex.unlock();
371
372 // Musl has an undocumented extension that makes pthread_cancel have the useful, desired
373 // behavior of causing the next syscall to return ECANCELED.
374 if (is_musl) assert(std.c.pthread_setcancelstate(.MASKED, null) == .SUCCESS);
375
357376 const closure: *Closure = @fieldParentPtr("node", closure_node);
358377 closure.start(closure, t);
359378 t.mutex.lock();
......@@ -1198,10 +1217,10 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode:
11981217 try current_thread.checkCancel();
11991218 continue;
12001219 },
1220 .CANCELED => return current_thread.endSyscallCanceled(),
12011221 else => |e| {
12021222 current_thread.endSyscall();
12031223 switch (e) {
1204 .CANCELED => return error.Canceled,
12051224 .ACCES => return error.AccessDenied,
12061225 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
12071226 .PERM => return error.PermissionDenied,
......@@ -1241,25 +1260,29 @@ fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: I
12411260 try current_thread.checkCancel();
12421261 continue;
12431262 },
1244 .CANCELED => return error.Canceled,
1245
1246 .ACCES => return error.AccessDenied,
1247 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1248 .PERM => return error.PermissionDenied,
1249 .DQUOT => return error.DiskQuota,
1250 .EXIST => return error.PathAlreadyExists,
1251 .FAULT => |err| return errnoBug(err),
1252 .LOOP => return error.SymLinkLoop,
1253 .MLINK => return error.LinkQuotaExceeded,
1254 .NAMETOOLONG => return error.NameTooLong,
1255 .NOENT => return error.FileNotFound,
1256 .NOMEM => return error.SystemResources,
1257 .NOSPC => return error.NoSpaceLeft,
1258 .NOTDIR => return error.NotDir,
1259 .ROFS => return error.ReadOnlyFileSystem,
1260 .NOTCAPABLE => return error.AccessDenied,
1261 .ILSEQ => return error.BadPathName,
1262 else => |err| return posix.unexpectedErrno(err),
1263 .CANCELED => return current_thread.endSyscallCanceled(),
1264 else => |e| {
1265 current_thread.endSyscall();
1266 switch (e) {
1267 .ACCES => return error.AccessDenied,
1268 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1269 .PERM => return error.PermissionDenied,
1270 .DQUOT => return error.DiskQuota,
1271 .EXIST => return error.PathAlreadyExists,
1272 .FAULT => |err| return errnoBug(err),
1273 .LOOP => return error.SymLinkLoop,
1274 .MLINK => return error.LinkQuotaExceeded,
1275 .NAMETOOLONG => return error.NameTooLong,
1276 .NOENT => return error.FileNotFound,
1277 .NOMEM => return error.SystemResources,
1278 .NOSPC => return error.NoSpaceLeft,
1279 .NOTDIR => return error.NotDir,
1280 .ROFS => return error.ReadOnlyFileSystem,
1281 .NOTCAPABLE => return error.AccessDenied,
1282 .ILSEQ => return error.BadPathName,
1283 else => |err| return posix.unexpectedErrno(err),
1284 }
1285 },
12631286 }
12641287 }
12651288}
......@@ -1503,10 +1526,10 @@ fn dirStatPathLinux(
15031526 try current_thread.checkCancel();
15041527 continue;
15051528 },
1529 .CANCELED => return current_thread.endSyscallCanceled(),
15061530 else => |e| {
15071531 current_thread.endSyscall();
15081532 switch (e) {
1509 .CANCELED => return error.Canceled,
15101533 .ACCES => return error.AccessDenied,
15111534 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
15121535 .FAULT => |err| return errnoBug(err),
......@@ -1549,10 +1572,10 @@ fn dirStatPathPosix(
15491572 try current_thread.checkCancel();
15501573 continue;
15511574 },
1575 .CANCELED => return current_thread.endSyscallCanceled(),
15521576 else => |e| {
15531577 current_thread.endSyscall();
15541578 switch (e) {
1555 .CANCELED => return error.Canceled,
15561579 .INVAL => |err| return errnoBug(err),
15571580 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
15581581 .NOMEM => return error.SystemResources,
......@@ -1610,10 +1633,10 @@ fn dirStatPathWasi(
16101633 try current_thread.checkCancel();
16111634 continue;
16121635 },
1636 .CANCELED => return current_thread.endSyscallCanceled(),
16131637 else => |e| {
16141638 current_thread.endSyscall();
16151639 switch (e) {
1616 .CANCELED => return error.Canceled,
16171640 .INVAL => |err| return errnoBug(err),
16181641 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
16191642 .NOMEM => return error.SystemResources,
......@@ -1656,10 +1679,10 @@ fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
16561679 try current_thread.checkCancel();
16571680 continue;
16581681 },
1682 .CANCELED => return current_thread.endSyscallCanceled(),
16591683 else => |e| {
16601684 current_thread.endSyscall();
16611685 switch (e) {
1662 .CANCELED => return error.Canceled,
16631686 .INVAL => |err| return errnoBug(err),
16641687 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
16651688 .NOMEM => return error.SystemResources,
......@@ -1695,10 +1718,10 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
16951718 try current_thread.checkCancel();
16961719 continue;
16971720 },
1721 .CANCELED => return current_thread.endSyscallCanceled(),
16981722 else => |e| {
16991723 current_thread.endSyscall();
17001724 switch (e) {
1701 .CANCELED => return error.Canceled,
17021725 .ACCES => |err| return errnoBug(err),
17031726 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
17041727 .FAULT => |err| return errnoBug(err),
......@@ -1781,10 +1804,10 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.
17811804 try current_thread.checkCancel();
17821805 continue;
17831806 },
1807 .CANCELED => return current_thread.endSyscallCanceled(),
17841808 else => |e| {
17851809 current_thread.endSyscall();
17861810 switch (e) {
1787 .CANCELED => return error.Canceled,
17881811 .INVAL => |err| return errnoBug(err),
17891812 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
17901813 .NOMEM => return error.SystemResources,
......@@ -1833,10 +1856,10 @@ fn dirAccessPosix(
18331856 try current_thread.checkCancel();
18341857 continue;
18351858 },
1859 .CANCELED => return current_thread.endSyscallCanceled(),
18361860 else => |e| {
18371861 current_thread.endSyscall();
18381862 switch (e) {
1839 .CANCELED => return error.Canceled,
18401863 .ACCES => return error.AccessDenied,
18411864 .PERM => return error.PermissionDenied,
18421865 .ROFS => return error.ReadOnlyFileSystem,
......@@ -1883,10 +1906,10 @@ fn dirAccessWasi(
18831906 try current_thread.checkCancel();
18841907 continue;
18851908 },
1909 .CANCELED => return current_thread.endSyscallCanceled(),
18861910 else => |e| {
18871911 current_thread.endSyscall();
18881912 switch (e) {
1889 .CANCELED => return error.Canceled,
18901913 .INVAL => |err| return errnoBug(err),
18911914 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
18921915 .NOMEM => return error.SystemResources,
......@@ -2030,10 +2053,10 @@ fn dirCreateFilePosix(
20302053 try current_thread.checkCancel();
20312054 continue;
20322055 },
2056 .CANCELED => return current_thread.endSyscallCanceled(),
20332057 else => |e| {
20342058 current_thread.endSyscall();
20352059 switch (e) {
2036 .CANCELED => return error.Canceled,
20372060 .FAULT => |err| return errnoBug(err),
20382061 .INVAL => return error.BadPathName,
20392062 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -2085,10 +2108,10 @@ fn dirCreateFilePosix(
20852108 try current_thread.checkCancel();
20862109 continue;
20872110 },
2111 .CANCELED => return current_thread.endSyscallCanceled(),
20882112 else => |e| {
20892113 current_thread.endSyscall();
20902114 switch (e) {
2091 .CANCELED => return error.Canceled,
20922115 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
20932116 .INVAL => |err| return errnoBug(err), // invalid parameters
20942117 .NOLCK => return error.SystemResources,
......@@ -2240,10 +2263,10 @@ fn dirCreateFileWasi(
22402263 try current_thread.checkCancel();
22412264 continue;
22422265 },
2266 .CANCELED => return current_thread.endSyscallCanceled(),
22432267 else => |e| {
22442268 current_thread.endSyscall();
22452269 switch (e) {
2246 .CANCELED => return error.Canceled,
22472270 .FAULT => |err| return errnoBug(err),
22482271 .INVAL => return error.BadPathName,
22492272 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -2334,10 +2357,10 @@ fn dirOpenFilePosix(
23342357 try current_thread.checkCancel();
23352358 continue;
23362359 },
2360 .CANCELED => return current_thread.endSyscallCanceled(),
23372361 else => |e| {
23382362 current_thread.endSyscall();
23392363 switch (e) {
2340 .CANCELED => return error.Canceled,
23412364 .FAULT => |err| return errnoBug(err),
23422365 .INVAL => return error.BadPathName,
23432366 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -2388,10 +2411,10 @@ fn dirOpenFilePosix(
23882411 try current_thread.checkCancel();
23892412 continue;
23902413 },
2414 .CANCELED => return current_thread.endSyscallCanceled(),
23912415 else => |e| {
23922416 current_thread.endSyscall();
23932417 switch (e) {
2394 .CANCELED => return error.Canceled,
23952418 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
23962419 .INVAL => |err| return errnoBug(err), // invalid parameters
23972420 .NOLCK => return error.SystemResources,
......@@ -2417,6 +2440,7 @@ fn dirOpenFilePosix(
24172440 try current_thread.checkCancel();
24182441 continue;
24192442 },
2443 .CANCELED => return current_thread.endSyscallCanceled(),
24202444 else => |err| {
24212445 current_thread.endSyscall();
24222446 return posix.unexpectedErrno(err);
......@@ -2437,6 +2461,7 @@ fn dirOpenFilePosix(
24372461 try current_thread.checkCancel();
24382462 continue;
24392463 },
2464 .CANCELED => return current_thread.endSyscallCanceled(),
24402465 else => |err| {
24412466 current_thread.endSyscall();
24422467 return posix.unexpectedErrno(err);
......@@ -2635,10 +2660,10 @@ fn dirOpenFileWasi(
26352660 try current_thread.checkCancel();
26362661 continue;
26372662 },
2663 .CANCELED => return current_thread.endSyscallCanceled(),
26382664 else => |e| {
26392665 current_thread.endSyscall();
26402666 switch (e) {
2641 .CANCELED => return error.Canceled,
26422667 .FAULT => |err| return errnoBug(err),
26432668 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
26442669 .ACCES => return error.AccessDenied,
......@@ -2719,10 +2744,10 @@ fn dirOpenDirPosix(
27192744 try current_thread.checkCancel();
27202745 continue;
27212746 },
2747 .CANCELED => return current_thread.endSyscallCanceled(),
27222748 else => |e| {
27232749 current_thread.endSyscall();
27242750 switch (e) {
2725 .CANCELED => return error.Canceled,
27262751 .FAULT => |err| return errnoBug(err),
27272752 .INVAL => return error.BadPathName,
27282753 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -2772,10 +2797,10 @@ fn dirOpenDirHaiku(
27722797 try current_thread.checkCancel();
27732798 continue;
27742799 },
2800 .CANCELED => return current_thread.endSyscallCanceled(),
27752801 else => |e| {
27762802 current_thread.endSyscall();
27772803 switch (e) {
2778 .CANCELED => return error.Canceled,
27792804 .FAULT => |err| return errnoBug(err),
27802805 .INVAL => |err| return errnoBug(err),
27812806 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -2917,10 +2942,10 @@ fn dirOpenDirWasi(
29172942 try current_thread.checkCancel();
29182943 continue;
29192944 },
2945 .CANCELED => return current_thread.endSyscallCanceled(),
29202946 else => |e| {
29212947 current_thread.endSyscall();
29222948 switch (e) {
2923 .CANCELED => return error.Canceled,
29242949 .FAULT => |err| return errnoBug(err),
29252950 .INVAL => return error.BadPathName,
29262951 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -2984,10 +3009,10 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io
29843009 try current_thread.checkCancel();
29853010 continue;
29863011 },
3012 .CANCELED => return current_thread.endSyscallCanceled(),
29873013 else => |e| {
29883014 current_thread.endSyscall();
29893015 switch (e) {
2990 .CANCELED => return error.Canceled,
29913016 .INVAL => |err| return errnoBug(err),
29923017 .FAULT => |err| return errnoBug(err),
29933018 .BADF => return error.NotOpenForReading, // File operation on directory.
......@@ -3018,10 +3043,10 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io
30183043 try current_thread.checkCancel();
30193044 continue;
30203045 },
3046 .CANCELED => return current_thread.endSyscallCanceled(),
30213047 else => |e| {
30223048 current_thread.endSyscall();
30233049 switch (e) {
3024 .CANCELED => return error.Canceled,
30253050 .INVAL => |err| return errnoBug(err),
30263051 .FAULT => |err| return errnoBug(err),
30273052 .SRCH => return error.ProcessNotFound,
......@@ -3104,10 +3129,10 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o
31043129 try current_thread.checkCancel();
31053130 continue;
31063131 },
3132 .CANCELED => return current_thread.endSyscallCanceled(),
31073133 else => |e| {
31083134 current_thread.endSyscall();
31093135 switch (e) {
3110 .CANCELED => return error.Canceled,
31113136 .INVAL => |err| return errnoBug(err),
31123137 .FAULT => |err| return errnoBug(err),
31133138 .AGAIN => |err| return errnoBug(err),
......@@ -3142,10 +3167,10 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o
31423167 try current_thread.checkCancel();
31433168 continue;
31443169 },
3170 .CANCELED => return current_thread.endSyscallCanceled(),
31453171 else => |e| {
31463172 current_thread.endSyscall();
31473173 switch (e) {
3148 .CANCELED => return error.Canceled,
31493174 .INVAL => |err| return errnoBug(err),
31503175 .FAULT => |err| return errnoBug(err),
31513176 .SRCH => return error.ProcessNotFound,
......@@ -3244,10 +3269,10 @@ fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekErr
32443269 try current_thread.checkCancel();
32453270 continue;
32463271 },
3272 .CANCELED => return current_thread.endSyscallCanceled(),
32473273 else => |e| {
32483274 current_thread.endSyscall();
32493275 switch (e) {
3250 .CANCELED => return error.Canceled,
32513276 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
32523277 .INVAL => return error.Unseekable,
32533278 .OVERFLOW => return error.Unseekable,
......@@ -3277,10 +3302,10 @@ fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekErr
32773302 try current_thread.checkCancel();
32783303 continue;
32793304 },
3305 .CANCELED => return current_thread.endSyscallCanceled(),
32803306 else => |e| {
32813307 current_thread.endSyscall();
32823308 switch (e) {
3283 .CANCELED => return error.Canceled,
32843309 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
32853310 .INVAL => return error.Unseekable,
32863311 .OVERFLOW => return error.Unseekable,
......@@ -3306,10 +3331,10 @@ fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekErr
33063331 try current_thread.checkCancel();
33073332 continue;
33083333 },
3334 .CANCELED => return current_thread.endSyscallCanceled(),
33093335 else => |e| {
33103336 current_thread.endSyscall();
33113337 switch (e) {
3312 .CANCELED => return error.Canceled,
33133338 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
33143339 .INVAL => return error.Unseekable,
33153340 .OVERFLOW => return error.Unseekable,
......@@ -3430,7 +3455,8 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
34303455const sleep = switch (native_os) {
34313456 .windows => sleepWindows,
34323457 .wasi => sleepWasi,
3433 .linux => sleepLinux,
3458 // Since we use musl's pthread_cancel, it's important that all the syscalls go through libc.
3459 .linux => if (is_musl) sleepPosix else sleepLinux,
34343460 else => sleepPosix,
34353461};
34363462
......@@ -3462,10 +3488,10 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
34623488 try current_thread.checkCancel();
34633489 continue;
34643490 },
3491 .CANCELED => return current_thread.endSyscallCanceled(),
34653492 else => |e| {
34663493 current_thread.endSyscall();
34673494 switch (e) {
3468 .CANCELED => return error.Canceled,
34693495 .INVAL => return error.UnsupportedClock,
34703496 else => |err| return posix.unexpectedErrno(err),
34713497 }
......@@ -3540,11 +3566,9 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
35403566 try current_thread.checkCancel();
35413567 continue;
35423568 },
3543 else => {
3544 // This prong handles success as well as unexpected errors.
3545 current_thread.endSyscall();
3546 return;
3547 },
3569 .CANCELED => return current_thread.endSyscallCanceled(),
3570 // This prong handles success as well as unexpected errors.
3571 else => return current_thread.endSyscall(),
35483572 }
35493573 }
35503574}
......@@ -3616,10 +3640,10 @@ fn netListenIpPosix(
36163640 try current_thread.checkCancel();
36173641 continue;
36183642 },
3643 .CANCELED => return current_thread.endSyscallCanceled(),
36193644 else => |e| {
36203645 current_thread.endSyscall();
36213646 switch (e) {
3622 .CANCELED => return error.Canceled,
36233647 .ADDRINUSE => return error.AddressInUse,
36243648 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
36253649 else => |err| return posix.unexpectedErrno(err),
......@@ -3777,10 +3801,10 @@ fn netListenUnixPosix(
37773801 try current_thread.checkCancel();
37783802 continue;
37793803 },
3804 .CANCELED => return current_thread.endSyscallCanceled(),
37803805 else => |e| {
37813806 current_thread.endSyscall();
37823807 switch (e) {
3783 .CANCELED => return error.Canceled,
37843808 .ADDRINUSE => return error.AddressInUse,
37853809 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
37863810 else => |err| return posix.unexpectedErrno(err),
......@@ -3901,10 +3925,10 @@ fn posixBindUnix(
39013925 try current_thread.checkCancel();
39023926 continue;
39033927 },
3928 .CANCELED => return current_thread.endSyscallCanceled(),
39043929 else => |e| {
39053930 current_thread.endSyscall();
39063931 switch (e) {
3907 .CANCELED => return error.Canceled,
39083932 .ACCES => return error.AccessDenied,
39093933 .ADDRINUSE => return error.AddressInUse,
39103934 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
......@@ -3946,10 +3970,10 @@ fn posixBind(
39463970 try current_thread.checkCancel();
39473971 continue;
39483972 },
3973 .CANCELED => return current_thread.endSyscallCanceled(),
39493974 else => |e| {
39503975 current_thread.endSyscall();
39513976 switch (e) {
3952 .CANCELED => return error.Canceled,
39533977 .ADDRINUSE => return error.AddressInUse,
39543978 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
39553979 .INVAL => |err| return errnoBug(err), // invalid parameters
......@@ -3982,10 +4006,10 @@ fn posixConnect(
39824006 try current_thread.checkCancel();
39834007 continue;
39844008 },
4009 .CANCELED => return current_thread.endSyscallCanceled(),
39854010 else => |e| {
39864011 current_thread.endSyscall();
39874012 switch (e) {
3988 .CANCELED => return error.Canceled,
39894013 .ADDRNOTAVAIL => return error.AddressUnavailable,
39904014 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
39914015 .AGAIN, .INPROGRESS => return error.WouldBlock,
......@@ -4029,10 +4053,10 @@ fn posixConnectUnix(
40294053 try current_thread.checkCancel();
40304054 continue;
40314055 },
4056 .CANCELED => return current_thread.endSyscallCanceled(),
40324057 else => |e| {
40334058 current_thread.endSyscall();
40344059 switch (e) {
4035 .CANCELED => return error.Canceled,
40364060 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
40374061 .AGAIN => return error.WouldBlock,
40384062 .INPROGRESS => return error.WouldBlock,
......@@ -4074,10 +4098,10 @@ fn posixGetSockName(
40744098 try current_thread.checkCancel();
40754099 continue;
40764100 },
4101 .CANCELED => return current_thread.endSyscallCanceled(),
40774102 else => |e| {
40784103 current_thread.endSyscall();
40794104 switch (e) {
4080 .CANCELED => return error.Canceled,
40814105 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
40824106 .FAULT => |err| return errnoBug(err),
40834107 .INVAL => |err| return errnoBug(err), // invalid parameters
......@@ -4142,10 +4166,10 @@ fn setSocketOption(current_thread: *Thread, fd: posix.fd_t, level: i32, opt_name
41424166 try current_thread.checkCancel();
41434167 continue;
41444168 },
4169 .CANCELED => return current_thread.endSyscallCanceled(),
41454170 else => |e| {
41464171 current_thread.endSyscall();
41474172 switch (e) {
4148 .CANCELED => return error.Canceled,
41494173 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
41504174 .NOTSOCK => |err| return errnoBug(err),
41514175 .INVAL => |err| return errnoBug(err),
......@@ -4472,12 +4496,10 @@ fn openSocketPosix(
44724496 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
44734497 .SUCCESS => break,
44744498 .INTR => continue,
4475 else => |e| {
4499 .CANCELED => return current_thread.endSyscallCanceled(),
4500 else => |err| {
44764501 current_thread.endSyscall();
4477 switch (e) {
4478 .CANCELED => return error.Canceled,
4479 else => |err| return posix.unexpectedErrno(err),
4480 }
4502 return posix.unexpectedErrno(err);
44814503 },
44824504 }
44834505 };
......@@ -4488,10 +4510,10 @@ fn openSocketPosix(
44884510 try current_thread.checkCancel();
44894511 continue;
44904512 },
4513 .CANCELED => return current_thread.endSyscallCanceled(),
44914514 else => |e| {
44924515 current_thread.endSyscall();
44934516 switch (e) {
4494 .CANCELED => return error.Canceled,
44954517 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
44964518 .INVAL => return error.ProtocolUnsupportedBySystem,
44974519 .MFILE => return error.ProcessFdQuotaExceeded,
......@@ -4590,10 +4612,10 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
45904612 try current_thread.checkCancel();
45914613 continue;
45924614 },
4615 .CANCELED => return current_thread.endSyscallCanceled(),
45934616 else => |e| {
45944617 current_thread.endSyscall();
45954618 switch (e) {
4596 .CANCELED => return error.Canceled,
45974619 .AGAIN => |err| return errnoBug(err),
45984620 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
45994621 .CONNABORTED => return error.ConnectionAborted,
......@@ -4699,10 +4721,10 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
46994721 try current_thread.checkCancel();
47004722 continue;
47014723 },
4724 .CANCELED => return current_thread.endSyscallCanceled(),
47024725 else => |e| {
47034726 current_thread.endSyscall();
47044727 switch (e) {
4705 .CANCELED => return error.Canceled,
47064728 .INVAL => |err| return errnoBug(err),
47074729 .FAULT => |err| return errnoBug(err),
47084730 .AGAIN => |err| return errnoBug(err),
......@@ -4732,10 +4754,10 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
47324754 try current_thread.checkCancel();
47334755 continue;
47344756 },
4757 .CANCELED => return current_thread.endSyscallCanceled(),
47354758 else => |e| {
47364759 current_thread.endSyscall();
47374760 switch (e) {
4738 .CANCELED => return error.Canceled,
47394761 .INVAL => |err| return errnoBug(err),
47404762 .FAULT => |err| return errnoBug(err),
47414763 .AGAIN => |err| return errnoBug(err),
......@@ -4968,10 +4990,10 @@ fn netSendOne(
49684990 try current_thread.checkCancel();
49694991 continue;
49704992 },
4993 .CANCELED => return current_thread.endSyscallCanceled(),
49714994 else => |e| {
49724995 current_thread.endSyscall();
49734996 switch (e) {
4974 .CANCELED => return error.Canceled,
49754997 .ACCES => return error.AccessDenied,
49764998 .ALREADY => return error.FastOpenAlreadyInProgress,
49774999 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -5045,10 +5067,10 @@ fn netSendMany(
50455067 try current_thread.checkCancel();
50465068 continue;
50475069 },
5070 .CANCELED => return current_thread.endSyscallCanceled(),
50485071 else => |e| {
50495072 current_thread.endSyscall();
50505073 switch (e) {
5051 .CANCELED => return error.Canceled,
50525074 .AGAIN => |err| return errnoBug(err),
50535075 .ALREADY => return error.FastOpenAlreadyInProgress,
50545076 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
......@@ -5178,7 +5200,7 @@ fn netReceivePosix(
51785200 continue :recv;
51795201 },
51805202 .INTR => continue,
5181 .CANCELED => return .{ error.Canceled, message_i },
5203 .CANCELED => return .{ current_thread.endSyscallCanceled(), message_i },
51825204
51835205 .FAULT => |err| return .{ errnoBug(err), message_i },
51845206 .INVAL => |err| return .{ errnoBug(err), message_i },
......@@ -5187,7 +5209,7 @@ fn netReceivePosix(
51875209 }
51885210 },
51895211 .INTR => continue,
5190 .CANCELED => return .{ error.Canceled, message_i },
5212 .CANCELED => return .{ current_thread.endSyscallCanceled(), message_i },
51915213
51925214 .BADF => |err| return .{ errnoBug(err), message_i },
51935215 .NFILE => return .{ error.SystemFdQuotaExceeded, message_i },
......@@ -5306,10 +5328,10 @@ fn netWritePosix(
53065328 try current_thread.checkCancel();
53075329 continue;
53085330 },
5331 .CANCELED => return current_thread.endSyscallCanceled(),
53095332 else => |e| {
53105333 current_thread.endSyscall();
53115334 switch (e) {
5312 .CANCELED => return error.Canceled,
53135335 .ACCES => |err| return errnoBug(err),
53145336 .AGAIN => |err| return errnoBug(err),
53155337 .ALREADY => return error.FastOpenAlreadyInProgress,
......@@ -5405,7 +5427,7 @@ fn netWriteWindows(
54055427 };
54065428 switch (wsa_error) {
54075429 .EINTR => continue,
5408 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
5430 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return current_thread.endSyscallCanceled(),
54095431 .NOTINITIALISED => {
54105432 try initializeWsa(t);
54115433 continue;
......@@ -5517,10 +5539,10 @@ fn netInterfaceNameResolve(
55175539 try current_thread.checkCancel();
55185540 continue;
55195541 },
5542 .CANCELED => return current_thread.endSyscallCanceled(),
55205543 else => |e| {
55215544 current_thread.endSyscall();
55225545 switch (e) {
5523 .CANCELED => return error.Canceled,
55245546 .INVAL => |err| return errnoBug(err), // Bad parameters.
55255547 .NOTTY => |err| return errnoBug(err),
55265548 .NXIO => |err| return errnoBug(err),
......@@ -5818,12 +5840,10 @@ fn netLookupFallible(
58185840 try current_thread.checkCancel();
58195841 continue;
58205842 },
5843 .CANCELED => return current_thread.endSyscallCanceled(),
58215844 else => |e| {
58225845 current_thread.endSyscall();
5823 switch (e) {
5824 .CANCELED => return error.Canceled,
5825 else => |inner| return posix.unexpectedErrno(inner),
5826 }
5846 return posix.unexpectedErrno(e);
58275847 },
58285848 },
58295849 else => |e| {
lib/std/c.zig+17
......@@ -10881,6 +10881,23 @@ pub extern "c" fn pthread_create(
1088110881 start_routine: *const fn (?*anyopaque) callconv(.c) ?*anyopaque,
1088210882 noalias arg: ?*anyopaque,
1088310883) E;
10884pub const pthread_cancelstate = switch (native_os) {
10885 .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => enum(c_int) {
10886 ENABLE = 1,
10887 DISABLE = 0,
10888 },
10889 .linux => if (native_abi.isMusl()) enum(c_int) {
10890 ENABLE = 0,
10891 DISABLE = 1,
10892 MASKED = 2,
10893 } else if (native_abi.isGnu()) enum(c_int) {
10894 ENABLE = 0,
10895 DISABLE = 1,
10896 },
10897 else => void,
10898};
10899pub extern "c" fn pthread_setcancelstate(pthread_cancelstate, ?*pthread_cancelstate) E;
10900pub extern "c" fn pthread_cancel(pthread_t) E;
1088410901pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) E;
1088510902pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *anyopaque, stacksize: usize) E;
1088610903pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) E;
lib/std/posix.zig+1
......@@ -1360,6 +1360,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
13601360 .PIPE => return error.BrokenPipe,
13611361 .CONNRESET => return error.ConnectionResetByPeer,
13621362 .BUSY => return error.DeviceBusy,
1363 .CANCELED => return error.Canceled,
13631364 else => |err| return unexpectedErrno(err),
13641365 }
13651366 }