authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-11-27 08:42:06-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-01 19:17:52-08:00
log29e418cbfb3d5e5800ac2ad267b21cf2b8942c2c
treefd28b3a438e564c13137d5e178248e3087c35328
parent95f93a0b281e32583edef36808231a5f61fb7de1

std.Io.Threaded: fix the cancellation race

Now, before a syscall is entered, beginSyscall is called, which may return error.Canceled. After syscall returns, whether error or success, endSyscall is called. If the syscall returns EINTR then checkCancel is called. `cancelRequested` is removed from the std.Io VTable for now, with plans to replace it with a more powerful API that allows protection against cancellation requests. closes #25751

2 files changed, 1910 insertions(+), 1114 deletions(-)

lib/std/Io.zig-5
......@@ -620,11 +620,6 @@ pub const VTable = struct {
620620 result: []u8,
621621 result_alignment: std.mem.Alignment,
622622 ) void,
623 /// Returns whether the current thread of execution is known to have
624 /// been requested to cancel.
625 ///
626 /// Thread-safe.
627 cancelRequested: *const fn (?*anyopaque) bool,
628623
629624 /// When this function returns, implementation guarantees that `start` has
630625 /// either already been called, or a unit of concurrency has been assigned
lib/std/Io/Threaded.zig+1910-1109
......@@ -50,6 +50,8 @@ cpu_count_error: ?std.Thread.CpuCountError,
5050/// available count, subtract this from either `async_limit` or
5151/// `concurrent_limit`.
5252busy_count: usize = 0,
53main_thread: Thread,
54pid: Pid = .unknown,
5355
5456wsa: if (is_windows) Wsa else struct {} = .{},
5557
......@@ -57,7 +59,79 @@ have_signal_handler: bool,
5759old_sig_io: if (have_sig_io) posix.Sigaction else void,
5860old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void,
5961
60threadlocal var current_closure: ?*Closure = null;
62pub const Pid = if (native_os == .linux) enum(posix.pid_t) {
63 unknown = 0,
64 _,
65} else enum(u0) { unknown = 0 };
66
67const Thread = struct {
68 /// The value that needs to be passed to pthread_kill or tgkill in order to
69 /// send a signal.
70 signal_id: SignalId,
71 current_closure: ?*Closure = null,
72
73 const SignalId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;
74
75 threadlocal var current: ?*Thread = null;
76
77 fn getCurrent(t: *Threaded) *Thread {
78 return current orelse return &t.main_thread;
79 }
80
81 fn checkCancel(thread: *Thread) error{Canceled}!void {
82 const closure = thread.current_closure orelse return;
83 switch (@cmpxchgStrong(
84 CancelStatus,
85 &closure.cancel_status,
86 .requested,
87 .acknowledged,
88 .acq_rel,
89 .acquire,
90 ) orelse return error.Canceled) {
91 .none => return,
92 .requested => unreachable,
93 .acknowledged => unreachable,
94 _ => return,
95 }
96 }
97
98 fn beginSyscall(thread: *Thread) error{Canceled}!void {
99 const closure = thread.current_closure orelse return;
100
101 switch (@cmpxchgStrong(
102 CancelStatus,
103 &closure.cancel_status,
104 .none,
105 .fromSignalId(thread.signal_id),
106 .acq_rel,
107 .acquire,
108 ) orelse return) {
109 .none => unreachable,
110 .requested => {
111 @atomicStore(CancelStatus, &closure.cancel_status, .acknowledged, .release);
112 return error.Canceled;
113 },
114 .acknowledged => unreachable,
115 _ => unreachable,
116 }
117 }
118
119 fn endSyscall(thread: *Thread) void {
120 const closure = thread.current_closure orelse return;
121 _ = @cmpxchgStrong(
122 CancelStatus,
123 &closure.cancel_status,
124 .fromSignalId(thread.signal_id),
125 .none,
126 .acq_rel,
127 .acquire,
128 );
129 }
130
131 fn currentSignalId() SignalId {
132 return if (std.Thread.use_pthreads) std.c.pthread_self() else std.Thread.getCurrentId();
133 }
134};
61135
62136const max_iovecs_len = 8;
63137const splat_buffer_size = 64;
......@@ -66,48 +140,93 @@ comptime {
66140 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
67141}
68142
69const CancelId = enum(usize) {
143const CancelStatus = enum(usize) {
144 /// Cancellation has neither been requested, nor checked. The async
145 /// operation will check status before entering a blocking syscall.
146 /// This is also the status used for uninteruptible tasks.
70147 none = 0,
71 canceling = std.math.maxInt(usize),
148 /// Cancellation has been requested and the status will be checked before
149 /// entering a blocking syscall.
150 requested = std.math.maxInt(usize) - 1,
151 /// Cancellation has been acknowledged and is in progress. Signals should
152 /// not be sent.
153 acknowledged = std.math.maxInt(usize),
154 /// Stores a `Thread.SignalId` and indicates that sending a signal to this thread
155 /// is needed in order to cancel. This state is set before going into
156 /// a blocking operation that needs to get unblocked via signal.
72157 _,
73158
74 const ThreadId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;
159 const Unpacked = union(enum) {
160 none,
161 requested,
162 acknowledged,
163 signal_id: Thread.SignalId,
164 };
75165
76 fn currentThread() CancelId {
77 if (std.Thread.use_pthreads) {
78 return @enumFromInt(@intFromPtr(std.c.pthread_self()));
79 } else {
80 return @enumFromInt(std.Thread.getCurrentId());
81 }
166 fn unpack(cs: CancelStatus) Unpacked {
167 return switch (cs) {
168 .none => .none,
169 .requested => .requested,
170 .acknowledged => .acknowledged,
171 _ => |signal_id| .{
172 .signal_id = if (std.Thread.use_pthreads)
173 @ptrFromInt(@intFromEnum(signal_id))
174 else
175 @truncate(@intFromEnum(signal_id)),
176 },
177 };
82178 }
83179
84 fn toThreadId(cancel_id: CancelId) ThreadId {
85 if (std.Thread.use_pthreads) {
86 return @ptrFromInt(@intFromEnum(cancel_id));
87 } else {
88 return @intCast(@intFromEnum(cancel_id));
89 }
180 fn fromSignalId(signal_id: Thread.SignalId) CancelStatus {
181 return if (std.Thread.use_pthreads)
182 @enumFromInt(@intFromPtr(signal_id))
183 else
184 @enumFromInt(signal_id);
90185 }
91186};
92187
93188const Closure = struct {
94189 start: Start,
95190 node: std.SinglyLinkedList.Node = .{},
96 cancel_tid: CancelId,
97
98 const Start = *const fn (*Closure) void;
99
100 fn requestCancel(closure: *Closure) void {
101 switch (@atomicRmw(CancelId, &closure.cancel_tid, .Xchg, .canceling, .acq_rel)) {
102 .none, .canceling => {},
103 else => |tid| {
104 if (std.Thread.use_pthreads) {
105 const rc = std.c.pthread_kill(tid.toThreadId(), .IO);
106 if (is_debug) assert(rc == 0);
107 } else if (native_os == .linux) {
108 _ = std.os.linux.tgkill(std.os.linux.getpid(), @bitCast(tid.toThreadId()), .IO);
109 }
110 },
191 cancel_status: CancelStatus,
192
193 const Start = *const fn (*Closure, *Threaded) void;
194
195 fn requestCancel(closure: *Closure, t: *Threaded) void {
196 var signal_id = switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
197 .none, .acknowledged, .requested => return,
198 .signal_id => |signal_id| signal_id,
199 };
200 // The task will enter a blocking syscall before checking for cancellation again.
201 // We can send a signal to interrupt the syscall, but if it arrives before
202 // the syscall instruction, it will be missed. Therefore, this code tries
203 // again until the cancellation request is acknowledged.
204 const max_attempts = 3;
205 for (0..max_attempts) |_| {
206 if (std.Thread.use_pthreads) {
207 const rc = std.c.pthread_kill(signal_id, .IO);
208 if (is_debug) assert(rc == 0);
209 } else if (native_os == .linux) {
210 const pid: posix.pid_t = p: {
211 const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
212 if (cached_pid != .unknown) break :p @intFromEnum(cached_pid);
213 const pid = std.os.linux.getpid();
214 @atomicStore(Pid, &t.pid, @enumFromInt(pid), .monotonic);
215 break :p pid;
216 };
217 _ = std.os.linux.tgkill(pid, @bitCast(signal_id), .IO);
218 } else {
219 return;
220 }
221
222 // TODO make this a nanosleep with 1 << attempt duration
223 std.Thread.yield() catch {};
224
225 switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
226 .requested => continue,
227 .none, .acknowledged => return,
228 .signal_id => |new_signal_id| signal_id = new_signal_id,
229 }
111230 }
112231 }
113232};
......@@ -136,6 +255,9 @@ pub fn init(
136255 .old_sig_io = undefined,
137256 .old_sig_pipe = undefined,
138257 .have_signal_handler = false,
258 .main_thread = .{
259 .signal_id = Thread.currentSignalId(),
260 },
139261 };
140262
141263 if (posix.Sigaction != void) {
......@@ -169,6 +291,7 @@ pub const init_single_threaded: Threaded = .{
169291 .old_sig_io = undefined,
170292 .old_sig_pipe = undefined,
171293 .have_signal_handler = false,
294 .main_thread = .{ .signal_id = undefined },
172295};
173296
174297pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {
......@@ -201,6 +324,11 @@ fn join(t: *Threaded) void {
201324}
202325
203326fn worker(t: *Threaded) void {
327 var thread: Thread = .{
328 .signal_id = Thread.currentSignalId(),
329 };
330 Thread.current = &thread;
331
204332 defer t.wait_group.finish();
205333
206334 t.mutex.lock();
......@@ -210,7 +338,7 @@ fn worker(t: *Threaded) void {
210338 while (t.run_queue.popFirst()) |closure_node| {
211339 t.mutex.unlock();
212340 const closure: *Closure = @fieldParentPtr("node", closure_node);
213 closure.start(closure);
341 closure.start(closure, t);
214342 t.mutex.lock();
215343 t.busy_count -= 1;
216344 }
......@@ -227,7 +355,6 @@ pub fn io(t: *Threaded) Io {
227355 .concurrent = concurrent,
228356 .await = await,
229357 .cancel = cancel,
230 .cancelRequested = cancelRequested,
231358 .select = select,
232359
233360 .groupAsync = groupAsync,
......@@ -324,7 +451,6 @@ pub fn ioBasic(t: *Threaded) Io {
324451 .concurrent = concurrent,
325452 .await = await,
326453 .cancel = cancel,
327 .cancelRequested = cancelRequested,
328454 .select = select,
329455
330456 .groupAsync = groupAsync,
......@@ -418,24 +544,12 @@ const AsyncClosure = struct {
418544
419545 const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent));
420546
421 fn start(closure: *Closure) void {
547 fn start(closure: *Closure, t: *Threaded) void {
422548 const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure));
423 const tid: CancelId = .currentThread();
424 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {
425 assert(cancel_tid == .canceling);
426 // Even though we already know the task is canceled, we must still
427 // run the closure in order to make the return value valid and in
428 // case there are side effects.
429 }
430 current_closure = closure;
549 const current_thread = Thread.getCurrent(t);
550 current_thread.current_closure = closure;
431551 ac.func(ac.contextPointer(), ac.resultPointer());
432 current_closure = null;
433
434 // In case a cancel happens after successful task completion, prevents
435 // signal from being delivered to the thread in `requestCancel`.
436 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, tid, .none, .acq_rel, .acquire)) |cancel_tid| {
437 assert(cancel_tid == .canceling);
438 }
552 current_thread.current_closure = null;
439553
440554 if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| {
441555 assert(select_reset != done_reset_event);
......@@ -476,7 +590,7 @@ const AsyncClosure = struct {
476590 const actual_result_offset = actual_result_addr - @intFromPtr(ac);
477591 ac.* = .{
478592 .closure = .{
479 .cancel_tid = .none,
593 .cancel_status = .none,
480594 .start = start,
481595 },
482596 .func = func,
......@@ -493,7 +607,7 @@ const AsyncClosure = struct {
493607 fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void {
494608 ac.reset_event.wait(t) catch |err| switch (err) {
495609 error.Canceled => {
496 ac.closure.requestCancel();
610 ac.closure.requestCancel(t);
497611 ac.reset_event.waitUncancelable();
498612 },
499613 };
......@@ -604,7 +718,6 @@ fn concurrent(
604718
605719const GroupClosure = struct {
606720 closure: Closure,
607 t: *Threaded,
608721 group: *Io.Group,
609722 /// Points to sibling `GroupClosure`. Used for walking the group to cancel all.
610723 node: std.SinglyLinkedList.Node,
......@@ -612,26 +725,15 @@ const GroupClosure = struct {
612725 context_alignment: Alignment,
613726 alloc_len: usize,
614727
615 fn start(closure: *Closure) void {
728 fn start(closure: *Closure, t: *Threaded) void {
616729 const gc: *GroupClosure = @alignCast(@fieldParentPtr("closure", closure));
617 const tid: CancelId = .currentThread();
730 const current_thread = Thread.getCurrent(t);
618731 const group = gc.group;
619732 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);
620733 const reset_event: *ResetEvent = @ptrCast(&group.context);
621 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {
622 assert(cancel_tid == .canceling);
623 // Even though we already know the task is canceled, we must still
624 // run the closure in case there are side effects.
625 }
626 current_closure = closure;
734 current_thread.current_closure = closure;
627735 gc.func(group, gc.contextPointer());
628 current_closure = null;
629
630 // In case a cancel happens after successful task completion, prevents
631 // signal from being delivered to the thread in `requestCancel`.
632 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, tid, .none, .acq_rel, .acquire)) |cancel_tid| {
633 assert(cancel_tid == .canceling);
634 }
736 current_thread.current_closure = null;
635737
636738 const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel);
637739 assert((prev_state / sync_one_pending) > 0);
......@@ -647,7 +749,6 @@ const GroupClosure = struct {
647749 /// Does not initialize the `node` field.
648750 fn init(
649751 gpa: Allocator,
650 t: *Threaded,
651752 group: *Io.Group,
652753 context: []const u8,
653754 context_alignment: Alignment,
......@@ -662,10 +763,9 @@ const GroupClosure = struct {
662763
663764 gc.* = .{
664765 .closure = .{
665 .cancel_tid = .none,
766 .cancel_status = .none,
666767 .start = start,
667768 },
668 .t = t,
669769 .group = group,
670770 .node = undefined,
671771 .func = func,
......@@ -696,7 +796,7 @@ fn groupAsync(
696796 if (builtin.single_threaded) return start(group, context.ptr);
697797
698798 const gpa = t.allocator;
699 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch
799 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
700800 return start(group, context.ptr);
701801
702802 t.mutex.lock();
......@@ -752,7 +852,7 @@ fn groupConcurrent(
752852 const t: *Threaded = @ptrCast(@alignCast(userdata));
753853
754854 const gpa = t.allocator;
755 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch
855 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
756856 return error.ConcurrencyUnavailable;
757857
758858 t.mutex.lock();
......@@ -806,7 +906,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
806906 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
807907 while (true) {
808908 const gc: *GroupClosure = @fieldParentPtr("node", node);
809 gc.closure.requestCancel();
909 gc.closure.requestCancel(t);
810910 node = node.next orelse break;
811911 }
812912 reset_event.waitUncancelable();
......@@ -832,7 +932,7 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void
832932 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
833933 while (true) {
834934 const gc: *GroupClosure = @fieldParentPtr("node", node);
835 gc.closure.requestCancel();
935 gc.closure.requestCancel(t);
836936 node = node.next orelse break;
837937 }
838938 }
......@@ -875,30 +975,20 @@ fn cancel(
875975 _ = result_alignment;
876976 const t: *Threaded = @ptrCast(@alignCast(userdata));
877977 const ac: *AsyncClosure = @ptrCast(@alignCast(any_future));
878 ac.closure.requestCancel();
978 ac.closure.requestCancel(t);
879979 ac.waitAndDeinit(t, result);
880980}
881981
882fn cancelRequested(userdata: ?*anyopaque) bool {
883 const t: *Threaded = @ptrCast(@alignCast(userdata));
884 _ = t;
885 const closure = current_closure orelse return false;
886 return @atomicLoad(CancelId, &closure.cancel_tid, .acquire) == .canceling;
887}
888
889fn checkCancel(t: *Threaded) error{Canceled}!void {
890 if (cancelRequested(t)) return error.Canceled;
891}
892
893982fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {
894983 if (builtin.single_threaded) unreachable; // Interface should have prevented this.
895984 if (native_os == .netbsd) @panic("TODO");
896985 const t: *Threaded = @ptrCast(@alignCast(userdata));
986 const current_thread = Thread.getCurrent(t);
897987 if (prev_state == .contended) {
898 try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
988 try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
899989 }
900990 while (@atomicRmw(Io.Mutex.State, &mutex.state, .Xchg, .contended, .acquire) != .unlocked) {
901 try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
991 try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
902992 }
903993}
904994
......@@ -960,6 +1050,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
9601050 if (builtin.single_threaded) unreachable; // Deadlock.
9611051 if (native_os == .netbsd) @panic("TODO");
9621052 const t: *Threaded = @ptrCast(@alignCast(userdata));
1053 const current_thread = Thread.getCurrent(t);
9631054 const t_io = ioBasic(t);
9641055 comptime assert(@TypeOf(cond.state) == u64);
9651056 const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state);
......@@ -988,7 +1079,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
9881079 defer mutex.lockUncancelable(t_io);
9891080
9901081 while (true) {
991 try futexWait(t, cond_epoch, epoch);
1082 try futexWait(current_thread, cond_epoch, epoch);
9921083
9931084 epoch = cond_epoch.load(.acquire);
9941085 state = cond_state.load(.monotonic);
......@@ -1074,35 +1165,46 @@ const dirMake = switch (native_os) {
10741165
10751166fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
10761167 const t: *Threaded = @ptrCast(@alignCast(userdata));
1168 const current_thread = Thread.getCurrent(t);
10771169
10781170 var path_buffer: [posix.PATH_MAX]u8 = undefined;
10791171 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
10801172
1173 try current_thread.beginSyscall();
10811174 while (true) {
1082 try t.checkCancel();
10831175 switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) {
1084 .SUCCESS => return,
1085 .INTR => continue,
1086 .CANCELED => return error.Canceled,
1087
1088 .ACCES => return error.AccessDenied,
1089 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1090 .PERM => return error.PermissionDenied,
1091 .DQUOT => return error.DiskQuota,
1092 .EXIST => return error.PathAlreadyExists,
1093 .FAULT => |err| return errnoBug(err),
1094 .LOOP => return error.SymLinkLoop,
1095 .MLINK => return error.LinkQuotaExceeded,
1096 .NAMETOOLONG => return error.NameTooLong,
1097 .NOENT => return error.FileNotFound,
1098 .NOMEM => return error.SystemResources,
1099 .NOSPC => return error.NoSpaceLeft,
1100 .NOTDIR => return error.NotDir,
1101 .ROFS => return error.ReadOnlyFileSystem,
1102 // dragonfly: when dir_fd is unlinked from filesystem
1103 .NOTCONN => return error.FileNotFound,
1104 .ILSEQ => return error.BadPathName,
1105 else => |err| return posix.unexpectedErrno(err),
1176 .SUCCESS => {
1177 current_thread.endSyscall();
1178 return;
1179 },
1180 .INTR => {
1181 try current_thread.checkCancel();
1182 continue;
1183 },
1184 else => |e| {
1185 current_thread.endSyscall();
1186 switch (e) {
1187 .CANCELED => return error.Canceled,
1188 .ACCES => return error.AccessDenied,
1189 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1190 .PERM => return error.PermissionDenied,
1191 .DQUOT => return error.DiskQuota,
1192 .EXIST => return error.PathAlreadyExists,
1193 .FAULT => |err| return errnoBug(err),
1194 .LOOP => return error.SymLinkLoop,
1195 .MLINK => return error.LinkQuotaExceeded,
1196 .NAMETOOLONG => return error.NameTooLong,
1197 .NOENT => return error.FileNotFound,
1198 .NOMEM => return error.SystemResources,
1199 .NOSPC => return error.NoSpaceLeft,
1200 .NOTDIR => return error.NotDir,
1201 .ROFS => return error.ReadOnlyFileSystem,
1202 // dragonfly: when dir_fd is unlinked from filesystem
1203 .NOTCONN => return error.FileNotFound,
1204 .ILSEQ => return error.BadPathName,
1205 else => |err| return posix.unexpectedErrno(err),
1206 }
1207 },
11061208 }
11071209 }
11081210}
......@@ -1110,11 +1212,18 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode:
11101212fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
11111213 if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode);
11121214 const t: *Threaded = @ptrCast(@alignCast(userdata));
1215 const current_thread = Thread.getCurrent(t);
1216 try current_thread.beginSyscall();
11131217 while (true) {
1114 try t.checkCancel();
11151218 switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) {
1116 .SUCCESS => return,
1117 .INTR => continue,
1219 .SUCCESS => {
1220 current_thread.endSyscall();
1221 return;
1222 },
1223 .INTR => {
1224 try current_thread.checkCancel();
1225 continue;
1226 },
11181227 .CANCELED => return error.Canceled,
11191228
11201229 .ACCES => return error.AccessDenied,
......@@ -1140,7 +1249,8 @@ fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: I
11401249
11411250fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
11421251 const t: *Threaded = @ptrCast(@alignCast(userdata));
1143 try t.checkCancel();
1252 const current_thread = Thread.getCurrent(t);
1253 try current_thread.checkCancel();
11441254
11451255 const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
11461256 _ = mode;
......@@ -1213,6 +1323,7 @@ fn dirMakeOpenPathWindows(
12131323 options: Io.Dir.OpenOptions,
12141324) Io.Dir.MakeOpenPathError!Io.Dir {
12151325 const t: *Threaded = @ptrCast(@alignCast(userdata));
1326 const current_thread = Thread.getCurrent(t);
12161327 const w = windows;
12171328 const access_mask = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
12181329 w.SYNCHRONIZE | w.FILE_TRAVERSE |
......@@ -1226,7 +1337,7 @@ fn dirMakeOpenPathWindows(
12261337 };
12271338
12281339 while (true) {
1229 try t.checkCancel();
1340 try current_thread.checkCancel();
12301341
12311342 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, component.path);
12321343 const sub_path_w = sub_path_w_array.span();
......@@ -1328,8 +1439,7 @@ fn dirMakeOpenPathWasi(
13281439
13291440fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
13301441 const t: *Threaded = @ptrCast(@alignCast(userdata));
1331 try t.checkCancel();
1332
1442 _ = t;
13331443 _ = dir;
13341444 @panic("TODO implement dirStat");
13351445}
......@@ -1348,6 +1458,7 @@ fn dirStatPathLinux(
13481458 options: Io.Dir.StatPathOptions,
13491459) Io.Dir.StatPathError!Io.File.Stat {
13501460 const t: *Threaded = @ptrCast(@alignCast(userdata));
1461 const current_thread = Thread.getCurrent(t);
13511462 const linux = std.os.linux;
13521463
13531464 var path_buffer: [posix.PATH_MAX]u8 = undefined;
......@@ -1356,8 +1467,8 @@ fn dirStatPathLinux(
13561467 const flags: u32 = linux.AT.NO_AUTOMOUNT |
13571468 @as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);
13581469
1470 try current_thread.beginSyscall();
13591471 while (true) {
1360 try t.checkCancel();
13611472 var statx = std.mem.zeroes(linux.Statx);
13621473 const rc = linux.statx(
13631474 dir.handle,
......@@ -1367,20 +1478,30 @@ fn dirStatPathLinux(
13671478 &statx,
13681479 );
13691480 switch (linux.errno(rc)) {
1370 .SUCCESS => return statFromLinux(&statx),
1371 .INTR => continue,
1372 .CANCELED => return error.Canceled,
1373
1374 .ACCES => return error.AccessDenied,
1375 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1376 .FAULT => |err| return errnoBug(err),
1377 .INVAL => |err| return errnoBug(err),
1378 .LOOP => return error.SymLinkLoop,
1379 .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.
1380 .NOENT => return error.FileNotFound,
1381 .NOTDIR => return error.NotDir,
1382 .NOMEM => return error.SystemResources,
1383 else => |err| return posix.unexpectedErrno(err),
1481 .SUCCESS => {
1482 current_thread.endSyscall();
1483 return statFromLinux(&statx);
1484 },
1485 .INTR => {
1486 try current_thread.checkCancel();
1487 continue;
1488 },
1489 else => |e| {
1490 current_thread.endSyscall();
1491 switch (e) {
1492 .CANCELED => return error.Canceled,
1493 .ACCES => return error.AccessDenied,
1494 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1495 .FAULT => |err| return errnoBug(err),
1496 .INVAL => |err| return errnoBug(err),
1497 .LOOP => return error.SymLinkLoop,
1498 .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.
1499 .NOENT => return error.FileNotFound,
1500 .NOTDIR => return error.NotDir,
1501 .NOMEM => return error.SystemResources,
1502 else => |err| return posix.unexpectedErrno(err),
1503 }
1504 },
13841505 }
13851506 }
13861507}
......@@ -1392,32 +1513,43 @@ fn dirStatPathPosix(
13921513 options: Io.Dir.StatPathOptions,
13931514) Io.Dir.StatPathError!Io.File.Stat {
13941515 const t: *Threaded = @ptrCast(@alignCast(userdata));
1516 const current_thread = Thread.getCurrent(t);
13951517
13961518 var path_buffer: [posix.PATH_MAX]u8 = undefined;
13971519 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
13981520
13991521 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
14001522
1523 try current_thread.beginSyscall();
14011524 while (true) {
1402 try t.checkCancel();
14031525 var stat = std.mem.zeroes(posix.Stat);
14041526 switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) {
1405 .SUCCESS => return statFromPosix(&stat),
1406 .INTR => continue,
1407 .CANCELED => return error.Canceled,
1408
1409 .INVAL => |err| return errnoBug(err),
1410 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1411 .NOMEM => return error.SystemResources,
1412 .ACCES => return error.AccessDenied,
1413 .PERM => return error.PermissionDenied,
1414 .FAULT => |err| return errnoBug(err),
1415 .NAMETOOLONG => return error.NameTooLong,
1416 .LOOP => return error.SymLinkLoop,
1417 .NOENT => return error.FileNotFound,
1418 .NOTDIR => return error.FileNotFound,
1419 .ILSEQ => return error.BadPathName,
1420 else => |err| return posix.unexpectedErrno(err),
1527 .SUCCESS => {
1528 current_thread.endSyscall();
1529 return statFromPosix(&stat);
1530 },
1531 .INTR => {
1532 try current_thread.checkCancel();
1533 continue;
1534 },
1535 else => |e| {
1536 current_thread.endSyscall();
1537 switch (e) {
1538 .CANCELED => return error.Canceled,
1539 .INVAL => |err| return errnoBug(err),
1540 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1541 .NOMEM => return error.SystemResources,
1542 .ACCES => return error.AccessDenied,
1543 .PERM => return error.PermissionDenied,
1544 .FAULT => |err| return errnoBug(err),
1545 .NAMETOOLONG => return error.NameTooLong,
1546 .LOOP => return error.SymLinkLoop,
1547 .NOENT => return error.FileNotFound,
1548 .NOTDIR => return error.FileNotFound,
1549 .ILSEQ => return error.BadPathName,
1550 else => |err| return posix.unexpectedErrno(err),
1551 }
1552 },
14211553 }
14221554 }
14231555}
......@@ -1444,29 +1576,40 @@ fn dirStatPathWasi(
14441576) Io.Dir.StatPathError!Io.File.Stat {
14451577 if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);
14461578 const t: *Threaded = @ptrCast(@alignCast(userdata));
1579 const current_thread = Thread.getCurrent(t);
14471580 const wasi = std.os.wasi;
14481581 const flags: wasi.lookupflags_t = .{
14491582 .SYMLINK_FOLLOW = options.follow_symlinks,
14501583 };
14511584 var stat: wasi.filestat_t = undefined;
1585 try current_thread.beginSyscall();
14521586 while (true) {
1453 try t.checkCancel();
14541587 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
1455 .SUCCESS => return statFromWasi(&stat),
1456 .INTR => continue,
1457 .CANCELED => return error.Canceled,
1458
1459 .INVAL => |err| return errnoBug(err),
1460 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1461 .NOMEM => return error.SystemResources,
1462 .ACCES => return error.AccessDenied,
1463 .FAULT => |err| return errnoBug(err),
1464 .NAMETOOLONG => return error.NameTooLong,
1465 .NOENT => return error.FileNotFound,
1466 .NOTDIR => return error.FileNotFound,
1467 .NOTCAPABLE => return error.AccessDenied,
1468 .ILSEQ => return error.BadPathName,
1469 else => |err| return posix.unexpectedErrno(err),
1588 .SUCCESS => {
1589 current_thread.endSyscall();
1590 return statFromWasi(&stat);
1591 },
1592 .INTR => {
1593 try current_thread.checkCancel();
1594 continue;
1595 },
1596 else => |e| {
1597 current_thread.endSyscall();
1598 switch (e) {
1599 .CANCELED => return error.Canceled,
1600 .INVAL => |err| return errnoBug(err),
1601 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1602 .NOMEM => return error.SystemResources,
1603 .ACCES => return error.AccessDenied,
1604 .FAULT => |err| return errnoBug(err),
1605 .NAMETOOLONG => return error.NameTooLong,
1606 .NOENT => return error.FileNotFound,
1607 .NOTDIR => return error.FileNotFound,
1608 .NOTCAPABLE => return error.AccessDenied,
1609 .ILSEQ => return error.BadPathName,
1610 else => |err| return posix.unexpectedErrno(err),
1611 }
1612 },
14701613 }
14711614 }
14721615}
......@@ -1480,31 +1623,44 @@ const fileStat = switch (native_os) {
14801623
14811624fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
14821625 const t: *Threaded = @ptrCast(@alignCast(userdata));
1626 const current_thread = Thread.getCurrent(t);
14831627
14841628 if (posix.Stat == void) return error.Streaming;
14851629
1630 try current_thread.beginSyscall();
14861631 while (true) {
1487 try t.checkCancel();
14881632 var stat = std.mem.zeroes(posix.Stat);
14891633 switch (posix.errno(fstat_sym(file.handle, &stat))) {
1490 .SUCCESS => return statFromPosix(&stat),
1491 .INTR => continue,
1492 .CANCELED => return error.Canceled,
1493
1494 .INVAL => |err| return errnoBug(err),
1495 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1496 .NOMEM => return error.SystemResources,
1497 .ACCES => return error.AccessDenied,
1498 else => |err| return posix.unexpectedErrno(err),
1634 .SUCCESS => {
1635 current_thread.endSyscall();
1636 return statFromPosix(&stat);
1637 },
1638 .INTR => {
1639 try current_thread.checkCancel();
1640 continue;
1641 },
1642 else => |e| {
1643 current_thread.endSyscall();
1644 switch (e) {
1645 .CANCELED => return error.Canceled,
1646 .INVAL => |err| return errnoBug(err),
1647 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1648 .NOMEM => return error.SystemResources,
1649 .ACCES => return error.AccessDenied,
1650 else => |err| return posix.unexpectedErrno(err),
1651 }
1652 },
14991653 }
15001654 }
15011655}
15021656
15031657fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
15041658 const t: *Threaded = @ptrCast(@alignCast(userdata));
1659 const current_thread = Thread.getCurrent(t);
15051660 const linux = std.os.linux;
1661
1662 try current_thread.beginSyscall();
15061663 while (true) {
1507 try t.checkCancel();
15081664 var statx = std.mem.zeroes(linux.Statx);
15091665 const rc = linux.statx(
15101666 file.handle,
......@@ -1514,27 +1670,38 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
15141670 &statx,
15151671 );
15161672 switch (linux.errno(rc)) {
1517 .SUCCESS => return statFromLinux(&statx),
1518 .INTR => continue,
1519 .CANCELED => return error.Canceled,
1520
1521 .ACCES => |err| return errnoBug(err),
1522 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1523 .FAULT => |err| return errnoBug(err),
1524 .INVAL => |err| return errnoBug(err),
1525 .LOOP => |err| return errnoBug(err),
1526 .NAMETOOLONG => |err| return errnoBug(err),
1527 .NOENT => |err| return errnoBug(err),
1528 .NOMEM => return error.SystemResources,
1529 .NOTDIR => |err| return errnoBug(err),
1530 else => |err| return posix.unexpectedErrno(err),
1673 .SUCCESS => {
1674 current_thread.endSyscall();
1675 return statFromLinux(&statx);
1676 },
1677 .INTR => {
1678 try current_thread.checkCancel();
1679 continue;
1680 },
1681 else => |e| {
1682 current_thread.endSyscall();
1683 switch (e) {
1684 .CANCELED => return error.Canceled,
1685 .ACCES => |err| return errnoBug(err),
1686 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1687 .FAULT => |err| return errnoBug(err),
1688 .INVAL => |err| return errnoBug(err),
1689 .LOOP => |err| return errnoBug(err),
1690 .NAMETOOLONG => |err| return errnoBug(err),
1691 .NOENT => |err| return errnoBug(err),
1692 .NOMEM => return error.SystemResources,
1693 .NOTDIR => |err| return errnoBug(err),
1694 else => |err| return posix.unexpectedErrno(err),
1695 }
1696 },
15311697 }
15321698 }
15331699}
15341700
15351701fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
15361702 const t: *Threaded = @ptrCast(@alignCast(userdata));
1537 try t.checkCancel();
1703 const current_thread = Thread.getCurrent(t);
1704 try current_thread.checkCancel();
15381705
15391706 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
15401707 var info: windows.FILE_ALL_INFORMATION = undefined;
......@@ -1581,21 +1748,34 @@ fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.Fi
15811748
15821749fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
15831750 if (builtin.link_libc) return fileStatPosix(userdata, file);
1751
15841752 const t: *Threaded = @ptrCast(@alignCast(userdata));
1753 const current_thread = Thread.getCurrent(t);
1754
1755 try current_thread.beginSyscall();
15851756 while (true) {
1586 try t.checkCancel();
15871757 var stat: std.os.wasi.filestat_t = undefined;
15881758 switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {
1589 .SUCCESS => return statFromWasi(&stat),
1590 .INTR => continue,
1591 .CANCELED => return error.Canceled,
1592
1593 .INVAL => |err| return errnoBug(err),
1594 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1595 .NOMEM => return error.SystemResources,
1596 .ACCES => return error.AccessDenied,
1597 .NOTCAPABLE => return error.AccessDenied,
1598 else => |err| return posix.unexpectedErrno(err),
1759 .SUCCESS => {
1760 current_thread.endSyscall();
1761 return statFromWasi(&stat);
1762 },
1763 .INTR => {
1764 try current_thread.checkCancel();
1765 continue;
1766 },
1767 else => |e| {
1768 current_thread.endSyscall();
1769 switch (e) {
1770 .CANCELED => return error.Canceled,
1771 .INVAL => |err| return errnoBug(err),
1772 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1773 .NOMEM => return error.SystemResources,
1774 .ACCES => return error.AccessDenied,
1775 .NOTCAPABLE => return error.AccessDenied,
1776 else => |err| return posix.unexpectedErrno(err),
1777 }
1778 },
15991779 }
16001780 }
16011781}
......@@ -1613,6 +1793,7 @@ fn dirAccessPosix(
16131793 options: Io.Dir.AccessOptions,
16141794) Io.Dir.AccessError!void {
16151795 const t: *Threaded = @ptrCast(@alignCast(userdata));
1796 const current_thread = Thread.getCurrent(t);
16161797
16171798 var path_buffer: [posix.PATH_MAX]u8 = undefined;
16181799 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
......@@ -1624,27 +1805,37 @@ fn dirAccessPosix(
16241805 @as(u32, if (options.write) posix.W_OK else 0) |
16251806 @as(u32, if (options.execute) posix.X_OK else 0);
16261807
1808 try current_thread.beginSyscall();
16271809 while (true) {
1628 try t.checkCancel();
16291810 switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, flags))) {
1630 .SUCCESS => return,
1631 .INTR => continue,
1632 .CANCELED => return error.Canceled,
1633
1634 .ACCES => return error.AccessDenied,
1635 .PERM => return error.PermissionDenied,
1636 .ROFS => return error.ReadOnlyFileSystem,
1637 .LOOP => return error.SymLinkLoop,
1638 .TXTBSY => return error.FileBusy,
1639 .NOTDIR => return error.FileNotFound,
1640 .NOENT => return error.FileNotFound,
1641 .NAMETOOLONG => return error.NameTooLong,
1642 .INVAL => |err| return errnoBug(err),
1643 .FAULT => |err| return errnoBug(err),
1644 .IO => return error.InputOutput,
1645 .NOMEM => return error.SystemResources,
1646 .ILSEQ => return error.BadPathName,
1647 else => |err| return posix.unexpectedErrno(err),
1811 .SUCCESS => {
1812 current_thread.endSyscall();
1813 return;
1814 },
1815 .INTR => {
1816 try current_thread.checkCancel();
1817 continue;
1818 },
1819 else => |e| {
1820 current_thread.endSyscall();
1821 switch (e) {
1822 .CANCELED => return error.Canceled,
1823 .ACCES => return error.AccessDenied,
1824 .PERM => return error.PermissionDenied,
1825 .ROFS => return error.ReadOnlyFileSystem,
1826 .LOOP => return error.SymLinkLoop,
1827 .TXTBSY => return error.FileBusy,
1828 .NOTDIR => return error.FileNotFound,
1829 .NOENT => return error.FileNotFound,
1830 .NAMETOOLONG => return error.NameTooLong,
1831 .INVAL => |err| return errnoBug(err),
1832 .FAULT => |err| return errnoBug(err),
1833 .IO => return error.InputOutput,
1834 .NOMEM => return error.SystemResources,
1835 .ILSEQ => return error.BadPathName,
1836 else => |err| return posix.unexpectedErrno(err),
1837 }
1838 },
16481839 }
16491840 }
16501841}
......@@ -1657,29 +1848,41 @@ fn dirAccessWasi(
16571848) Io.Dir.AccessError!void {
16581849 if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options);
16591850 const t: *Threaded = @ptrCast(@alignCast(userdata));
1851 const current_thread = Thread.getCurrent(t);
16601852 const wasi = std.os.wasi;
16611853 const flags: wasi.lookupflags_t = .{
16621854 .SYMLINK_FOLLOW = options.follow_symlinks,
16631855 };
16641856 var stat: wasi.filestat_t = undefined;
1857
1858 try current_thread.beginSyscall();
16651859 while (true) {
1666 try t.checkCancel();
16671860 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
1668 .SUCCESS => break,
1669 .INTR => continue,
1670 .CANCELED => return error.Canceled,
1671
1672 .INVAL => |err| return errnoBug(err),
1673 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1674 .NOMEM => return error.SystemResources,
1675 .ACCES => return error.AccessDenied,
1676 .FAULT => |err| return errnoBug(err),
1677 .NAMETOOLONG => return error.NameTooLong,
1678 .NOENT => return error.FileNotFound,
1679 .NOTDIR => return error.FileNotFound,
1680 .NOTCAPABLE => return error.AccessDenied,
1681 .ILSEQ => return error.BadPathName,
1682 else => |err| return posix.unexpectedErrno(err),
1861 .SUCCESS => {
1862 current_thread.endSyscall();
1863 break;
1864 },
1865 .INTR => {
1866 try current_thread.checkCancel();
1867 continue;
1868 },
1869 else => |e| {
1870 current_thread.endSyscall();
1871 switch (e) {
1872 .CANCELED => return error.Canceled,
1873 .INVAL => |err| return errnoBug(err),
1874 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1875 .NOMEM => return error.SystemResources,
1876 .ACCES => return error.AccessDenied,
1877 .FAULT => |err| return errnoBug(err),
1878 .NAMETOOLONG => return error.NameTooLong,
1879 .NOENT => return error.FileNotFound,
1880 .NOTDIR => return error.FileNotFound,
1881 .NOTCAPABLE => return error.AccessDenied,
1882 .ILSEQ => return error.BadPathName,
1883 else => |err| return posix.unexpectedErrno(err),
1884 }
1885 },
16831886 }
16841887 }
16851888
......@@ -1717,7 +1920,8 @@ fn dirAccessWindows(
17171920 options: Io.Dir.AccessOptions,
17181921) Io.Dir.AccessError!void {
17191922 const t: *Threaded = @ptrCast(@alignCast(userdata));
1720 try t.checkCancel();
1923 const current_thread = Thread.getCurrent(t);
1924 try current_thread.checkCancel();
17211925
17221926 _ = options; // TODO
17231927
......@@ -1768,6 +1972,7 @@ fn dirCreateFilePosix(
17681972 flags: Io.File.CreateFlags,
17691973) Io.File.OpenError!Io.File {
17701974 const t: *Threaded = @ptrCast(@alignCast(userdata));
1975 const current_thread = Thread.getCurrent(t);
17711976
17721977 var path_buffer: [posix.PATH_MAX]u8 = undefined;
17731978 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
......@@ -1796,40 +2001,50 @@ fn dirCreateFilePosix(
17962001 },
17972002 };
17982003
2004 try current_thread.beginSyscall();
17992005 const fd: posix.fd_t = while (true) {
1800 try t.checkCancel();
18012006 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
18022007 switch (posix.errno(rc)) {
1803 .SUCCESS => break @intCast(rc),
1804 .INTR => continue,
1805 .CANCELED => return error.Canceled,
1806
1807 .FAULT => |err| return errnoBug(err),
1808 .INVAL => return error.BadPathName,
1809 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1810 .ACCES => return error.AccessDenied,
1811 .FBIG => return error.FileTooBig,
1812 .OVERFLOW => return error.FileTooBig,
1813 .ISDIR => return error.IsDir,
1814 .LOOP => return error.SymLinkLoop,
1815 .MFILE => return error.ProcessFdQuotaExceeded,
1816 .NAMETOOLONG => return error.NameTooLong,
1817 .NFILE => return error.SystemFdQuotaExceeded,
1818 .NODEV => return error.NoDevice,
1819 .NOENT => return error.FileNotFound,
1820 .SRCH => return error.ProcessNotFound,
1821 .NOMEM => return error.SystemResources,
1822 .NOSPC => return error.NoSpaceLeft,
1823 .NOTDIR => return error.NotDir,
1824 .PERM => return error.PermissionDenied,
1825 .EXIST => return error.PathAlreadyExists,
1826 .BUSY => return error.DeviceBusy,
1827 .OPNOTSUPP => return error.FileLocksNotSupported,
1828 .AGAIN => return error.WouldBlock,
1829 .TXTBSY => return error.FileBusy,
1830 .NXIO => return error.NoDevice,
1831 .ILSEQ => return error.BadPathName,
1832 else => |err| return posix.unexpectedErrno(err),
2008 .SUCCESS => {
2009 current_thread.endSyscall();
2010 break @intCast(rc);
2011 },
2012 .INTR => {
2013 try current_thread.checkCancel();
2014 continue;
2015 },
2016 else => |e| {
2017 current_thread.endSyscall();
2018 switch (e) {
2019 .CANCELED => return error.Canceled,
2020 .FAULT => |err| return errnoBug(err),
2021 .INVAL => return error.BadPathName,
2022 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2023 .ACCES => return error.AccessDenied,
2024 .FBIG => return error.FileTooBig,
2025 .OVERFLOW => return error.FileTooBig,
2026 .ISDIR => return error.IsDir,
2027 .LOOP => return error.SymLinkLoop,
2028 .MFILE => return error.ProcessFdQuotaExceeded,
2029 .NAMETOOLONG => return error.NameTooLong,
2030 .NFILE => return error.SystemFdQuotaExceeded,
2031 .NODEV => return error.NoDevice,
2032 .NOENT => return error.FileNotFound,
2033 .SRCH => return error.ProcessNotFound,
2034 .NOMEM => return error.SystemResources,
2035 .NOSPC => return error.NoSpaceLeft,
2036 .NOTDIR => return error.NotDir,
2037 .PERM => return error.PermissionDenied,
2038 .EXIST => return error.PathAlreadyExists,
2039 .BUSY => return error.DeviceBusy,
2040 .OPNOTSUPP => return error.FileLocksNotSupported,
2041 .AGAIN => return error.WouldBlock,
2042 .TXTBSY => return error.FileBusy,
2043 .NXIO => return error.NoDevice,
2044 .ILSEQ => return error.BadPathName,
2045 else => |err| return posix.unexpectedErrno(err),
2046 }
2047 },
18332048 }
18342049 };
18352050 errdefer posix.close(fd);
......@@ -1841,42 +2056,71 @@ fn dirCreateFilePosix(
18412056 .shared => posix.LOCK.SH | lock_nonblocking,
18422057 .exclusive => posix.LOCK.EX | lock_nonblocking,
18432058 };
2059
2060 try current_thread.beginSyscall();
18442061 while (true) {
1845 try t.checkCancel();
18462062 switch (posix.errno(posix.system.flock(fd, lock_flags))) {
1847 .SUCCESS => break,
1848 .INTR => continue,
1849 .CANCELED => return error.Canceled,
1850
1851 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1852 .INVAL => |err| return errnoBug(err), // invalid parameters
1853 .NOLCK => return error.SystemResources,
1854 .AGAIN => return error.WouldBlock,
1855 .OPNOTSUPP => return error.FileLocksNotSupported,
1856 else => |err| return posix.unexpectedErrno(err),
1857 }
2063 .SUCCESS => {
2064 current_thread.endSyscall();
2065 break;
2066 },
2067 .INTR => {
2068 try current_thread.checkCancel();
2069 continue;
2070 },
2071 else => |e| {
2072 current_thread.endSyscall();
2073 switch (e) {
2074 .CANCELED => return error.Canceled,
2075 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2076 .INVAL => |err| return errnoBug(err), // invalid parameters
2077 .NOLCK => return error.SystemResources,
2078 .AGAIN => return error.WouldBlock,
2079 .OPNOTSUPP => return error.FileLocksNotSupported,
2080 else => |err| return posix.unexpectedErrno(err),
2081 }
2082 },
2083 }
18582084 }
18592085 }
18602086
18612087 if (have_flock_open_flags and flags.lock_nonblocking) {
2088 try current_thread.beginSyscall();
18622089 var fl_flags: usize = while (true) {
1863 try t.checkCancel();
18642090 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
18652091 switch (posix.errno(rc)) {
1866 .SUCCESS => break @intCast(rc),
1867 .INTR => continue,
1868 .CANCELED => return error.Canceled,
1869 else => |err| return posix.unexpectedErrno(err),
2092 .SUCCESS => {
2093 current_thread.endSyscall();
2094 break @intCast(rc);
2095 },
2096 .INTR => {
2097 try current_thread.checkCancel();
2098 continue;
2099 },
2100 else => |err| {
2101 current_thread.endSyscall();
2102 return posix.unexpectedErrno(err);
2103 },
18702104 }
18712105 };
2106
18722107 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2108
2109 try current_thread.beginSyscall();
18732110 while (true) {
1874 try t.checkCancel();
18752111 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
1876 .SUCCESS => break,
1877 .INTR => continue,
1878 .CANCELED => return error.Canceled,
1879 else => |err| return posix.unexpectedErrno(err),
2112 .SUCCESS => {
2113 current_thread.endSyscall();
2114 break;
2115 },
2116 .INTR => {
2117 try current_thread.checkCancel();
2118 continue;
2119 },
2120 else => |err| {
2121 current_thread.endSyscall();
2122 return posix.unexpectedErrno(err);
2123 },
18802124 }
18812125 }
18822126 }
......@@ -1892,7 +2136,8 @@ fn dirCreateFileWindows(
18922136) Io.File.OpenError!Io.File {
18932137 const w = windows;
18942138 const t: *Threaded = @ptrCast(@alignCast(userdata));
1895 try t.checkCancel();
2139 const current_thread = Thread.getCurrent(t);
2140 try current_thread.checkCancel();
18962141
18972142 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);
18982143 const sub_path_w = sub_path_w_array.span();
......@@ -1939,6 +2184,7 @@ fn dirCreateFileWasi(
19392184 flags: Io.File.CreateFlags,
19402185) Io.File.OpenError!Io.File {
19412186 const t: *Threaded = @ptrCast(@alignCast(userdata));
2187 const current_thread = Thread.getCurrent(t);
19422188 const wasi = std.os.wasi;
19432189 const lookup_flags: wasi.lookupflags_t = .{};
19442190 const oflags: wasi.oflags_t = .{
......@@ -1966,35 +2212,45 @@ fn dirCreateFileWasi(
19662212 };
19672213 const inheriting: wasi.rights_t = .{};
19682214 var fd: posix.fd_t = undefined;
2215 try current_thread.beginSyscall();
19692216 while (true) {
1970 try t.checkCancel();
19712217 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
1972 .SUCCESS => return .{ .handle = fd },
1973 .INTR => continue,
1974 .CANCELED => return error.Canceled,
1975
1976 .FAULT => |err| return errnoBug(err),
1977 .INVAL => return error.BadPathName,
1978 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1979 .ACCES => return error.AccessDenied,
1980 .FBIG => return error.FileTooBig,
1981 .OVERFLOW => return error.FileTooBig,
1982 .ISDIR => return error.IsDir,
1983 .LOOP => return error.SymLinkLoop,
1984 .MFILE => return error.ProcessFdQuotaExceeded,
1985 .NAMETOOLONG => return error.NameTooLong,
1986 .NFILE => return error.SystemFdQuotaExceeded,
1987 .NODEV => return error.NoDevice,
1988 .NOENT => return error.FileNotFound,
1989 .NOMEM => return error.SystemResources,
1990 .NOSPC => return error.NoSpaceLeft,
1991 .NOTDIR => return error.NotDir,
1992 .PERM => return error.PermissionDenied,
1993 .EXIST => return error.PathAlreadyExists,
1994 .BUSY => return error.DeviceBusy,
1995 .NOTCAPABLE => return error.AccessDenied,
1996 .ILSEQ => return error.BadPathName,
1997 else => |err| return posix.unexpectedErrno(err),
2218 .SUCCESS => {
2219 current_thread.endSyscall();
2220 return .{ .handle = fd };
2221 },
2222 .INTR => {
2223 try current_thread.checkCancel();
2224 continue;
2225 },
2226 else => |e| {
2227 current_thread.endSyscall();
2228 switch (e) {
2229 .CANCELED => return error.Canceled,
2230 .FAULT => |err| return errnoBug(err),
2231 .INVAL => return error.BadPathName,
2232 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2233 .ACCES => return error.AccessDenied,
2234 .FBIG => return error.FileTooBig,
2235 .OVERFLOW => return error.FileTooBig,
2236 .ISDIR => return error.IsDir,
2237 .LOOP => return error.SymLinkLoop,
2238 .MFILE => return error.ProcessFdQuotaExceeded,
2239 .NAMETOOLONG => return error.NameTooLong,
2240 .NFILE => return error.SystemFdQuotaExceeded,
2241 .NODEV => return error.NoDevice,
2242 .NOENT => return error.FileNotFound,
2243 .NOMEM => return error.SystemResources,
2244 .NOSPC => return error.NoSpaceLeft,
2245 .NOTDIR => return error.NotDir,
2246 .PERM => return error.PermissionDenied,
2247 .EXIST => return error.PathAlreadyExists,
2248 .BUSY => return error.DeviceBusy,
2249 .NOTCAPABLE => return error.AccessDenied,
2250 .ILSEQ => return error.BadPathName,
2251 else => |err| return posix.unexpectedErrno(err),
2252 }
2253 },
19982254 }
19992255 }
20002256}
......@@ -2012,6 +2268,7 @@ fn dirOpenFilePosix(
20122268 flags: Io.File.OpenFlags,
20132269) Io.File.OpenError!Io.File {
20142270 const t: *Threaded = @ptrCast(@alignCast(userdata));
2271 const current_thread = Thread.getCurrent(t);
20152272
20162273 var path_buffer: [posix.PATH_MAX]u8 = undefined;
20172274 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
......@@ -2048,40 +2305,50 @@ fn dirOpenFilePosix(
20482305 },
20492306 };
20502307
2308 try current_thread.beginSyscall();
20512309 const fd: posix.fd_t = while (true) {
2052 try t.checkCancel();
20532310 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, @as(posix.mode_t, 0));
20542311 switch (posix.errno(rc)) {
2055 .SUCCESS => break @intCast(rc),
2056 .INTR => continue,
2057 .CANCELED => return error.Canceled,
2058
2059 .FAULT => |err| return errnoBug(err),
2060 .INVAL => return error.BadPathName,
2061 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2062 .ACCES => return error.AccessDenied,
2063 .FBIG => return error.FileTooBig,
2064 .OVERFLOW => return error.FileTooBig,
2065 .ISDIR => return error.IsDir,
2066 .LOOP => return error.SymLinkLoop,
2067 .MFILE => return error.ProcessFdQuotaExceeded,
2068 .NAMETOOLONG => return error.NameTooLong,
2069 .NFILE => return error.SystemFdQuotaExceeded,
2070 .NODEV => return error.NoDevice,
2071 .NOENT => return error.FileNotFound,
2072 .SRCH => return error.ProcessNotFound,
2073 .NOMEM => return error.SystemResources,
2074 .NOSPC => return error.NoSpaceLeft,
2075 .NOTDIR => return error.NotDir,
2076 .PERM => return error.PermissionDenied,
2077 .EXIST => return error.PathAlreadyExists,
2078 .BUSY => return error.DeviceBusy,
2079 .OPNOTSUPP => return error.FileLocksNotSupported,
2080 .AGAIN => return error.WouldBlock,
2081 .TXTBSY => return error.FileBusy,
2082 .NXIO => return error.NoDevice,
2083 .ILSEQ => return error.BadPathName,
2084 else => |err| return posix.unexpectedErrno(err),
2312 .SUCCESS => {
2313 current_thread.endSyscall();
2314 break @intCast(rc);
2315 },
2316 .INTR => {
2317 try current_thread.checkCancel();
2318 continue;
2319 },
2320 else => |e| {
2321 current_thread.endSyscall();
2322 switch (e) {
2323 .CANCELED => return error.Canceled,
2324 .FAULT => |err| return errnoBug(err),
2325 .INVAL => return error.BadPathName,
2326 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2327 .ACCES => return error.AccessDenied,
2328 .FBIG => return error.FileTooBig,
2329 .OVERFLOW => return error.FileTooBig,
2330 .ISDIR => return error.IsDir,
2331 .LOOP => return error.SymLinkLoop,
2332 .MFILE => return error.ProcessFdQuotaExceeded,
2333 .NAMETOOLONG => return error.NameTooLong,
2334 .NFILE => return error.SystemFdQuotaExceeded,
2335 .NODEV => return error.NoDevice,
2336 .NOENT => return error.FileNotFound,
2337 .SRCH => return error.ProcessNotFound,
2338 .NOMEM => return error.SystemResources,
2339 .NOSPC => return error.NoSpaceLeft,
2340 .NOTDIR => return error.NotDir,
2341 .PERM => return error.PermissionDenied,
2342 .EXIST => return error.PathAlreadyExists,
2343 .BUSY => return error.DeviceBusy,
2344 .OPNOTSUPP => return error.FileLocksNotSupported,
2345 .AGAIN => return error.WouldBlock,
2346 .TXTBSY => return error.FileBusy,
2347 .NXIO => return error.NoDevice,
2348 .ILSEQ => return error.BadPathName,
2349 else => |err| return posix.unexpectedErrno(err),
2350 }
2351 },
20852352 }
20862353 };
20872354 errdefer posix.close(fd);
......@@ -2093,42 +2360,70 @@ fn dirOpenFilePosix(
20932360 .shared => posix.LOCK.SH | lock_nonblocking,
20942361 .exclusive => posix.LOCK.EX | lock_nonblocking,
20952362 };
2363 try current_thread.beginSyscall();
20962364 while (true) {
2097 try t.checkCancel();
20982365 switch (posix.errno(posix.system.flock(fd, lock_flags))) {
2099 .SUCCESS => break,
2100 .INTR => continue,
2101 .CANCELED => return error.Canceled,
2102
2103 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2104 .INVAL => |err| return errnoBug(err), // invalid parameters
2105 .NOLCK => return error.SystemResources,
2106 .AGAIN => return error.WouldBlock,
2107 .OPNOTSUPP => return error.FileLocksNotSupported,
2108 else => |err| return posix.unexpectedErrno(err),
2366 .SUCCESS => {
2367 current_thread.endSyscall();
2368 break;
2369 },
2370 .INTR => {
2371 try current_thread.checkCancel();
2372 continue;
2373 },
2374 else => |e| {
2375 current_thread.endSyscall();
2376 switch (e) {
2377 .CANCELED => return error.Canceled,
2378 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2379 .INVAL => |err| return errnoBug(err), // invalid parameters
2380 .NOLCK => return error.SystemResources,
2381 .AGAIN => return error.WouldBlock,
2382 .OPNOTSUPP => return error.FileLocksNotSupported,
2383 else => |err| return posix.unexpectedErrno(err),
2384 }
2385 },
21092386 }
21102387 }
21112388 }
21122389
21132390 if (have_flock_open_flags and flags.lock_nonblocking) {
2391 try current_thread.beginSyscall();
21142392 var fl_flags: usize = while (true) {
2115 try t.checkCancel();
21162393 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
21172394 switch (posix.errno(rc)) {
2118 .SUCCESS => break @intCast(rc),
2119 .INTR => continue,
2120 .CANCELED => return error.Canceled,
2121 else => |err| return posix.unexpectedErrno(err),
2395 .SUCCESS => {
2396 current_thread.endSyscall();
2397 break @intCast(rc);
2398 },
2399 .INTR => {
2400 try current_thread.checkCancel();
2401 continue;
2402 },
2403 else => |err| {
2404 current_thread.endSyscall();
2405 return posix.unexpectedErrno(err);
2406 },
21222407 }
21232408 };
2409
21242410 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2411
2412 try current_thread.beginSyscall();
21252413 while (true) {
2126 try t.checkCancel();
21272414 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
2128 .SUCCESS => break,
2129 .INTR => continue,
2130 .CANCELED => return error.Canceled,
2131 else => |err| return posix.unexpectedErrno(err),
2415 .SUCCESS => {
2416 current_thread.endSyscall();
2417 break;
2418 },
2419 .INTR => {
2420 try current_thread.checkCancel();
2421 continue;
2422 },
2423 else => |err| {
2424 current_thread.endSyscall();
2425 return posix.unexpectedErrno(err);
2426 },
21322427 }
21332428 }
21342429 }
......@@ -2158,7 +2453,7 @@ pub fn dirOpenFileWtf16(
21582453 if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
21592454 if (std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;
21602455 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
2161
2456 const current_thread = Thread.getCurrent(t);
21622457 const w = windows;
21632458
21642459 var nt_name: w.UNICODE_STRING = .{
......@@ -2187,7 +2482,7 @@ pub fn dirOpenFileWtf16(
21872482 var attempt: u5 = 0;
21882483
21892484 const handle = while (true) {
2190 try t.checkCancel();
2485 try current_thread.checkCancel();
21912486
21922487 var result: w.HANDLE = undefined;
21932488 const rc = w.ntdll.NtCreateFile(
......@@ -2281,6 +2576,7 @@ fn dirOpenFileWasi(
22812576) Io.File.OpenError!Io.File {
22822577 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);
22832578 const t: *Threaded = @ptrCast(@alignCast(userdata));
2579 const current_thread = Thread.getCurrent(t);
22842580 const wasi = std.os.wasi;
22852581 var base: std.os.wasi.rights_t = .{};
22862582 // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE
......@@ -2310,33 +2606,44 @@ fn dirOpenFileWasi(
23102606 const inheriting: wasi.rights_t = .{};
23112607 const fdflags: wasi.fdflags_t = .{};
23122608 var fd: posix.fd_t = undefined;
2609 try current_thread.beginSyscall();
23132610 while (true) {
2314 try t.checkCancel();
23152611 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
2316 .SUCCESS => return .{ .handle = fd },
2317 .INTR => continue,
2318 .CANCELED => return error.Canceled,
2319
2320 .FAULT => |err| return errnoBug(err),
2321 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2322 .ACCES => return error.AccessDenied,
2323 .FBIG => return error.FileTooBig,
2324 .OVERFLOW => return error.FileTooBig,
2325 .ISDIR => return error.IsDir,
2326 .LOOP => return error.SymLinkLoop,
2327 .MFILE => return error.ProcessFdQuotaExceeded,
2328 .NFILE => return error.SystemFdQuotaExceeded,
2329 .NODEV => return error.NoDevice,
2330 .NOENT => return error.FileNotFound,
2331 .NOMEM => return error.SystemResources,
2332 .NOTDIR => return error.NotDir,
2333 .PERM => return error.PermissionDenied,
2334 .BUSY => return error.DeviceBusy,
2335 .NOTCAPABLE => return error.AccessDenied,
2336 .NAMETOOLONG => return error.NameTooLong,
2337 .INVAL => return error.BadPathName,
2338 .ILSEQ => return error.BadPathName,
2339 else => |err| return posix.unexpectedErrno(err),
2612 .SUCCESS => {
2613 errdefer posix.close(fd);
2614 current_thread.endSyscall();
2615 return .{ .handle = fd };
2616 },
2617 .INTR => {
2618 try current_thread.checkCancel();
2619 continue;
2620 },
2621 else => |e| {
2622 current_thread.endSyscall();
2623 switch (e) {
2624 .CANCELED => return error.Canceled,
2625 .FAULT => |err| return errnoBug(err),
2626 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2627 .ACCES => return error.AccessDenied,
2628 .FBIG => return error.FileTooBig,
2629 .OVERFLOW => return error.FileTooBig,
2630 .ISDIR => return error.IsDir,
2631 .LOOP => return error.SymLinkLoop,
2632 .MFILE => return error.ProcessFdQuotaExceeded,
2633 .NFILE => return error.SystemFdQuotaExceeded,
2634 .NODEV => return error.NoDevice,
2635 .NOENT => return error.FileNotFound,
2636 .NOMEM => return error.SystemResources,
2637 .NOTDIR => return error.NotDir,
2638 .PERM => return error.PermissionDenied,
2639 .BUSY => return error.DeviceBusy,
2640 .NOTCAPABLE => return error.AccessDenied,
2641 .NAMETOOLONG => return error.NameTooLong,
2642 .INVAL => return error.BadPathName,
2643 .ILSEQ => return error.BadPathName,
2644 else => |err| return posix.unexpectedErrno(err),
2645 }
2646 },
23402647 }
23412648 }
23422649}
......@@ -2361,6 +2668,8 @@ fn dirOpenDirPosix(
23612668 return dirOpenDirWindows(t, dir, sub_path_w.span(), options);
23622669 }
23632670
2671 const current_thread = Thread.getCurrent(t);
2672
23642673 var path_buffer: [posix.PATH_MAX]u8 = undefined;
23652674 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
23662675
......@@ -2381,31 +2690,41 @@ fn dirOpenDirPosix(
23812690 if (@hasField(posix.O, "PATH") and !options.iterate)
23822691 flags.PATH = true;
23832692
2693 try current_thread.beginSyscall();
23842694 while (true) {
2385 try t.checkCancel();
23862695 const rc = openat_sym(dir.handle, sub_path_posix, flags, @as(usize, 0));
23872696 switch (posix.errno(rc)) {
2388 .SUCCESS => return .{ .handle = @intCast(rc) },
2389 .INTR => continue,
2390 .CANCELED => return error.Canceled,
2391
2392 .FAULT => |err| return errnoBug(err),
2393 .INVAL => return error.BadPathName,
2394 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2395 .ACCES => return error.AccessDenied,
2396 .LOOP => return error.SymLinkLoop,
2397 .MFILE => return error.ProcessFdQuotaExceeded,
2398 .NAMETOOLONG => return error.NameTooLong,
2399 .NFILE => return error.SystemFdQuotaExceeded,
2400 .NODEV => return error.NoDevice,
2401 .NOENT => return error.FileNotFound,
2402 .NOMEM => return error.SystemResources,
2403 .NOTDIR => return error.NotDir,
2404 .PERM => return error.PermissionDenied,
2405 .BUSY => return error.DeviceBusy,
2406 .NXIO => return error.NoDevice,
2407 .ILSEQ => return error.BadPathName,
2408 else => |err| return posix.unexpectedErrno(err),
2697 .SUCCESS => {
2698 current_thread.endSyscall();
2699 return .{ .handle = @intCast(rc) };
2700 },
2701 .INTR => {
2702 try current_thread.checkCancel();
2703 continue;
2704 },
2705 else => |e| {
2706 current_thread.endSyscall();
2707 switch (e) {
2708 .CANCELED => return error.Canceled,
2709 .FAULT => |err| return errnoBug(err),
2710 .INVAL => return error.BadPathName,
2711 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2712 .ACCES => return error.AccessDenied,
2713 .LOOP => return error.SymLinkLoop,
2714 .MFILE => return error.ProcessFdQuotaExceeded,
2715 .NAMETOOLONG => return error.NameTooLong,
2716 .NFILE => return error.SystemFdQuotaExceeded,
2717 .NODEV => return error.NoDevice,
2718 .NOENT => return error.FileNotFound,
2719 .NOMEM => return error.SystemResources,
2720 .NOTDIR => return error.NotDir,
2721 .PERM => return error.PermissionDenied,
2722 .BUSY => return error.DeviceBusy,
2723 .NXIO => return error.NoDevice,
2724 .ILSEQ => return error.BadPathName,
2725 else => |err| return posix.unexpectedErrno(err),
2726 }
2727 },
24092728 }
24102729 }
24112730}
......@@ -2417,34 +2736,46 @@ fn dirOpenDirHaiku(
24172736 options: Io.Dir.OpenOptions,
24182737) Io.Dir.OpenError!Io.Dir {
24192738 const t: *Threaded = @ptrCast(@alignCast(userdata));
2739 const current_thread = Thread.getCurrent(t);
24202740
24212741 var path_buffer: [posix.PATH_MAX]u8 = undefined;
24222742 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
24232743
24242744 _ = options;
24252745
2746 try current_thread.beginSyscall();
24262747 while (true) {
2427 try t.checkCancel();
24282748 const rc = posix.system._kern_open_dir(dir.handle, sub_path_posix);
2429 if (rc >= 0) return .{ .handle = rc };
2749 if (rc >= 0) {
2750 current_thread.endSyscall();
2751 return .{ .handle = rc };
2752 }
24302753 switch (@as(posix.E, @enumFromInt(rc))) {
2431 .INTR => continue,
2432 .CANCELED => return error.Canceled,
2433 .FAULT => |err| return errnoBug(err),
2434 .INVAL => |err| return errnoBug(err),
2435 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2436 .ACCES => return error.AccessDenied,
2437 .LOOP => return error.SymLinkLoop,
2438 .MFILE => return error.ProcessFdQuotaExceeded,
2439 .NAMETOOLONG => return error.NameTooLong,
2440 .NFILE => return error.SystemFdQuotaExceeded,
2441 .NODEV => return error.NoDevice,
2442 .NOENT => return error.FileNotFound,
2443 .NOMEM => return error.SystemResources,
2444 .NOTDIR => return error.NotDir,
2445 .PERM => return error.PermissionDenied,
2446 .BUSY => return error.DeviceBusy,
2447 else => |err| return posix.unexpectedErrno(err),
2754 .INTR => {
2755 try current_thread.checkCancel();
2756 continue;
2757 },
2758 else => |e| {
2759 current_thread.endSyscall();
2760 switch (e) {
2761 .CANCELED => return error.Canceled,
2762 .FAULT => |err| return errnoBug(err),
2763 .INVAL => |err| return errnoBug(err),
2764 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2765 .ACCES => return error.AccessDenied,
2766 .LOOP => return error.SymLinkLoop,
2767 .MFILE => return error.ProcessFdQuotaExceeded,
2768 .NAMETOOLONG => return error.NameTooLong,
2769 .NFILE => return error.SystemFdQuotaExceeded,
2770 .NODEV => return error.NoDevice,
2771 .NOENT => return error.FileNotFound,
2772 .NOMEM => return error.SystemResources,
2773 .NOTDIR => return error.NotDir,
2774 .PERM => return error.PermissionDenied,
2775 .BUSY => return error.DeviceBusy,
2776 else => |err| return posix.unexpectedErrno(err),
2777 }
2778 },
24482779 }
24492780 }
24502781}
......@@ -2455,6 +2786,7 @@ pub fn dirOpenDirWindows(
24552786 sub_path_w: [:0]const u16,
24562787 options: Io.Dir.OpenOptions,
24572788) Io.Dir.OpenError!Io.Dir {
2789 const current_thread = Thread.getCurrent(t);
24582790 const w = windows;
24592791 // TODO remove some of these flags if options.access_sub_paths is false
24602792 const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
......@@ -2478,7 +2810,7 @@ pub fn dirOpenDirWindows(
24782810 const open_reparse_point: w.DWORD = if (!options.follow_symlinks) w.FILE_OPEN_REPARSE_POINT else 0x0;
24792811 var io_status_block: w.IO_STATUS_BLOCK = undefined;
24802812 var result: Io.Dir = .{ .handle = undefined };
2481 try t.checkCancel();
2813 try current_thread.checkCancel();
24822814 const rc = w.ntdll.NtCreateFile(
24832815 &result.handle,
24842816 access_mask,
......@@ -2527,6 +2859,7 @@ fn dirOpenDirWasi(
25272859) Io.Dir.OpenError!Io.Dir {
25282860 if (builtin.link_libc) return dirOpenDirPosix(userdata, dir, sub_path, options);
25292861 const t: *Threaded = @ptrCast(@alignCast(userdata));
2862 const current_thread = Thread.getCurrent(t);
25302863 const wasi = std.os.wasi;
25312864
25322865 var base: std.os.wasi.rights_t = .{
......@@ -2556,31 +2889,40 @@ fn dirOpenDirWasi(
25562889 const oflags: wasi.oflags_t = .{ .DIRECTORY = true };
25572890 const fdflags: wasi.fdflags_t = .{};
25582891 var fd: posix.fd_t = undefined;
2559
2892 try current_thread.beginSyscall();
25602893 while (true) {
2561 try t.checkCancel();
25622894 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, base, fdflags, &fd)) {
2563 .SUCCESS => return .{ .handle = fd },
2564 .INTR => continue,
2565 .CANCELED => return error.Canceled,
2566
2567 .FAULT => |err| return errnoBug(err),
2568 .INVAL => return error.BadPathName,
2569 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2570 .ACCES => return error.AccessDenied,
2571 .LOOP => return error.SymLinkLoop,
2572 .MFILE => return error.ProcessFdQuotaExceeded,
2573 .NAMETOOLONG => return error.NameTooLong,
2574 .NFILE => return error.SystemFdQuotaExceeded,
2575 .NODEV => return error.NoDevice,
2576 .NOENT => return error.FileNotFound,
2577 .NOMEM => return error.SystemResources,
2578 .NOTDIR => return error.NotDir,
2579 .PERM => return error.PermissionDenied,
2580 .BUSY => return error.DeviceBusy,
2581 .NOTCAPABLE => return error.AccessDenied,
2582 .ILSEQ => return error.BadPathName,
2583 else => |err| return posix.unexpectedErrno(err),
2895 .SUCCESS => {
2896 current_thread.endSyscall();
2897 return .{ .handle = fd };
2898 },
2899 .INTR => {
2900 try current_thread.checkCancel();
2901 continue;
2902 },
2903 else => |e| {
2904 current_thread.endSyscall();
2905 switch (e) {
2906 .CANCELED => return error.Canceled,
2907 .FAULT => |err| return errnoBug(err),
2908 .INVAL => return error.BadPathName,
2909 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2910 .ACCES => return error.AccessDenied,
2911 .LOOP => return error.SymLinkLoop,
2912 .MFILE => return error.ProcessFdQuotaExceeded,
2913 .NAMETOOLONG => return error.NameTooLong,
2914 .NFILE => return error.SystemFdQuotaExceeded,
2915 .NODEV => return error.NoDevice,
2916 .NOENT => return error.FileNotFound,
2917 .NOMEM => return error.SystemResources,
2918 .NOTDIR => return error.NotDir,
2919 .PERM => return error.PermissionDenied,
2920 .BUSY => return error.DeviceBusy,
2921 .NOTCAPABLE => return error.AccessDenied,
2922 .ILSEQ => return error.BadPathName,
2923 else => |err| return posix.unexpectedErrno(err),
2924 }
2925 },
25842926 }
25852927 }
25862928}
......@@ -2598,6 +2940,7 @@ const fileReadStreaming = switch (native_os) {
25982940
25992941fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
26002942 const t: *Threaded = @ptrCast(@alignCast(userdata));
2943 const current_thread = Thread.getCurrent(t);
26012944
26022945 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
26032946 var i: usize = 0;
......@@ -2611,59 +2954,82 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io
26112954 const dest = iovecs_buffer[0..i];
26122955 assert(dest[0].len > 0);
26132956
2614 if (native_os == .wasi and !builtin.link_libc) while (true) {
2615 try t.checkCancel();
2616 var nread: usize = undefined;
2617 switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {
2618 .SUCCESS => return nread,
2619 .INTR => continue,
2620 .CANCELED => return error.Canceled,
2621
2622 .INVAL => |err| return errnoBug(err),
2623 .FAULT => |err| return errnoBug(err),
2624 .BADF => return error.NotOpenForReading, // File operation on directory.
2625 .IO => return error.InputOutput,
2626 .ISDIR => return error.IsDir,
2627 .NOBUFS => return error.SystemResources,
2628 .NOMEM => return error.SystemResources,
2629 .NOTCONN => return error.SocketUnconnected,
2630 .CONNRESET => return error.ConnectionResetByPeer,
2631 .TIMEDOUT => return error.Timeout,
2632 .NOTCAPABLE => return error.AccessDenied,
2633 else => |err| return posix.unexpectedErrno(err),
2957 if (native_os == .wasi and !builtin.link_libc) {
2958 try current_thread.beginSyscall();
2959 while (true) {
2960 var nread: usize = undefined;
2961 switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {
2962 .SUCCESS => {
2963 current_thread.endSyscall();
2964 return nread;
2965 },
2966 .INTR => {
2967 try current_thread.checkCancel();
2968 continue;
2969 },
2970 else => |e| {
2971 current_thread.endSyscall();
2972 switch (e) {
2973 .CANCELED => return error.Canceled,
2974 .INVAL => |err| return errnoBug(err),
2975 .FAULT => |err| return errnoBug(err),
2976 .BADF => return error.NotOpenForReading, // File operation on directory.
2977 .IO => return error.InputOutput,
2978 .ISDIR => return error.IsDir,
2979 .NOBUFS => return error.SystemResources,
2980 .NOMEM => return error.SystemResources,
2981 .NOTCONN => return error.SocketUnconnected,
2982 .CONNRESET => return error.ConnectionResetByPeer,
2983 .TIMEDOUT => return error.Timeout,
2984 .NOTCAPABLE => return error.AccessDenied,
2985 else => |err| return posix.unexpectedErrno(err),
2986 }
2987 },
2988 }
26342989 }
2635 };
2990 }
26362991
2992 try current_thread.beginSyscall();
26372993 while (true) {
2638 try t.checkCancel();
26392994 const rc = posix.system.readv(file.handle, dest.ptr, @intCast(dest.len));
26402995 switch (posix.errno(rc)) {
2641 .SUCCESS => return @intCast(rc),
2642 .INTR => continue,
2643 .CANCELED => return error.Canceled,
2644
2645 .INVAL => |err| return errnoBug(err),
2646 .FAULT => |err| return errnoBug(err),
2647 .SRCH => return error.ProcessNotFound,
2648 .AGAIN => return error.WouldBlock,
2649 .BADF => |err| {
2650 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
2651 return errnoBug(err); // File descriptor used after closed.
2652 },
2653 .IO => return error.InputOutput,
2654 .ISDIR => return error.IsDir,
2655 .NOBUFS => return error.SystemResources,
2656 .NOMEM => return error.SystemResources,
2657 .NOTCONN => return error.SocketUnconnected,
2658 .CONNRESET => return error.ConnectionResetByPeer,
2659 .TIMEDOUT => return error.Timeout,
2660 else => |err| return posix.unexpectedErrno(err),
2996 .SUCCESS => {
2997 current_thread.endSyscall();
2998 return @intCast(rc);
2999 },
3000 .INTR => {
3001 try current_thread.checkCancel();
3002 continue;
3003 },
3004 else => |e| {
3005 current_thread.endSyscall();
3006 switch (e) {
3007 .CANCELED => return error.Canceled,
3008 .INVAL => |err| return errnoBug(err),
3009 .FAULT => |err| return errnoBug(err),
3010 .SRCH => return error.ProcessNotFound,
3011 .AGAIN => return error.WouldBlock,
3012 .BADF => |err| {
3013 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
3014 return errnoBug(err); // File descriptor used after closed.
3015 },
3016 .IO => return error.InputOutput,
3017 .ISDIR => return error.IsDir,
3018 .NOBUFS => return error.SystemResources,
3019 .NOMEM => return error.SystemResources,
3020 .NOTCONN => return error.SocketUnconnected,
3021 .CONNRESET => return error.ConnectionResetByPeer,
3022 .TIMEDOUT => return error.Timeout,
3023 else => |err| return posix.unexpectedErrno(err),
3024 }
3025 },
26613026 }
26623027 }
26633028}
26643029
26653030fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
26663031 const t: *Threaded = @ptrCast(@alignCast(userdata));
3032 const current_thread = Thread.getCurrent(t);
26673033
26683034 const DWORD = windows.DWORD;
26693035 var index: usize = 0;
......@@ -2672,7 +3038,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
26723038 const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);
26733039
26743040 while (true) {
2675 try t.checkCancel();
3041 try current_thread.checkCancel();
26763042 var n: DWORD = undefined;
26773043 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0)
26783044 return n;
......@@ -2692,6 +3058,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
26923058
26933059fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
26943060 const t: *Threaded = @ptrCast(@alignCast(userdata));
3061 const current_thread = Thread.getCurrent(t);
26953062
26963063 if (!have_preadv) @compileError("TODO");
26973064
......@@ -2707,60 +3074,82 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o
27073074 const dest = iovecs_buffer[0..i];
27083075 assert(dest[0].len > 0);
27093076
2710 if (native_os == .wasi and !builtin.link_libc) while (true) {
2711 try t.checkCancel();
2712 var nread: usize = undefined;
2713 switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {
2714 .SUCCESS => return nread,
2715 .INTR => continue,
2716 .CANCELED => return error.Canceled,
2717
2718 .INVAL => |err| return errnoBug(err),
2719 .FAULT => |err| return errnoBug(err),
2720 .AGAIN => |err| return errnoBug(err),
2721 .BADF => return error.NotOpenForReading, // File operation on directory.
2722 .IO => return error.InputOutput,
2723 .ISDIR => return error.IsDir,
2724 .NOBUFS => return error.SystemResources,
2725 .NOMEM => return error.SystemResources,
2726 .NOTCONN => return error.SocketUnconnected,
2727 .CONNRESET => return error.ConnectionResetByPeer,
2728 .TIMEDOUT => return error.Timeout,
2729 .NXIO => return error.Unseekable,
2730 .SPIPE => return error.Unseekable,
2731 .OVERFLOW => return error.Unseekable,
2732 .NOTCAPABLE => return error.AccessDenied,
2733 else => |err| return posix.unexpectedErrno(err),
3077 if (native_os == .wasi and !builtin.link_libc) {
3078 try current_thread.beginSyscall();
3079 while (true) {
3080 var nread: usize = undefined;
3081 switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {
3082 .SUCCESS => {
3083 current_thread.endSyscall();
3084 return nread;
3085 },
3086 .INTR => {
3087 try current_thread.checkCancel();
3088 continue;
3089 },
3090 else => |e| {
3091 current_thread.endSyscall();
3092 switch (e) {
3093 .CANCELED => return error.Canceled,
3094 .INVAL => |err| return errnoBug(err),
3095 .FAULT => |err| return errnoBug(err),
3096 .AGAIN => |err| return errnoBug(err),
3097 .BADF => return error.NotOpenForReading, // File operation on directory.
3098 .IO => return error.InputOutput,
3099 .ISDIR => return error.IsDir,
3100 .NOBUFS => return error.SystemResources,
3101 .NOMEM => return error.SystemResources,
3102 .NOTCONN => return error.SocketUnconnected,
3103 .CONNRESET => return error.ConnectionResetByPeer,
3104 .TIMEDOUT => return error.Timeout,
3105 .NXIO => return error.Unseekable,
3106 .SPIPE => return error.Unseekable,
3107 .OVERFLOW => return error.Unseekable,
3108 .NOTCAPABLE => return error.AccessDenied,
3109 else => |err| return posix.unexpectedErrno(err),
3110 }
3111 },
3112 }
27343113 }
2735 };
3114 }
27363115
3116 try current_thread.beginSyscall();
27373117 while (true) {
2738 try t.checkCancel();
27393118 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
27403119 switch (posix.errno(rc)) {
2741 .SUCCESS => return @bitCast(rc),
2742 .INTR => continue,
2743 .CANCELED => return error.Canceled,
2744
2745 .INVAL => |err| return errnoBug(err),
2746 .FAULT => |err| return errnoBug(err),
2747 .SRCH => return error.ProcessNotFound,
2748 .AGAIN => return error.WouldBlock,
2749 .BADF => |err| {
2750 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
2751 return errnoBug(err); // File descriptor used after closed.
2752 },
2753 .IO => return error.InputOutput,
2754 .ISDIR => return error.IsDir,
2755 .NOBUFS => return error.SystemResources,
2756 .NOMEM => return error.SystemResources,
2757 .NOTCONN => return error.SocketUnconnected,
2758 .CONNRESET => return error.ConnectionResetByPeer,
2759 .TIMEDOUT => return error.Timeout,
2760 .NXIO => return error.Unseekable,
2761 .SPIPE => return error.Unseekable,
2762 .OVERFLOW => return error.Unseekable,
2763 else => |err| return posix.unexpectedErrno(err),
3120 .SUCCESS => {
3121 current_thread.endSyscall();
3122 return @bitCast(rc);
3123 },
3124 .INTR => {
3125 try current_thread.checkCancel();
3126 continue;
3127 },
3128 else => |e| {
3129 current_thread.endSyscall();
3130 switch (e) {
3131 .CANCELED => return error.Canceled,
3132 .INVAL => |err| return errnoBug(err),
3133 .FAULT => |err| return errnoBug(err),
3134 .SRCH => return error.ProcessNotFound,
3135 .AGAIN => return error.WouldBlock,
3136 .BADF => |err| {
3137 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
3138 return errnoBug(err); // File descriptor used after closed.
3139 },
3140 .IO => return error.InputOutput,
3141 .ISDIR => return error.IsDir,
3142 .NOBUFS => return error.SystemResources,
3143 .NOMEM => return error.SystemResources,
3144 .NOTCONN => return error.SocketUnconnected,
3145 .CONNRESET => return error.ConnectionResetByPeer,
3146 .TIMEDOUT => return error.Timeout,
3147 .NXIO => return error.Unseekable,
3148 .SPIPE => return error.Unseekable,
3149 .OVERFLOW => return error.Unseekable,
3150 else => |err| return posix.unexpectedErrno(err),
3151 }
3152 },
27643153 }
27653154 }
27663155}
......@@ -2772,6 +3161,7 @@ const fileReadPositional = switch (native_os) {
27723161
27733162fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
27743163 const t: *Threaded = @ptrCast(@alignCast(userdata));
3164 const current_thread = Thread.getCurrent(t);
27753165
27763166 const DWORD = windows.DWORD;
27773167
......@@ -2793,7 +3183,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
27933183 };
27943184
27953185 while (true) {
2796 try t.checkCancel();
3186 try current_thread.checkCancel();
27973187 var n: DWORD = undefined;
27983188 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0)
27993189 return n;
......@@ -2813,8 +3203,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
28133203
28143204fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekError!void {
28153205 const t: *Threaded = @ptrCast(@alignCast(userdata));
2816 try t.checkCancel();
2817
3206 _ = t;
28183207 _ = file;
28193208 _ = offset;
28203209 @panic("TODO implement fileSeekBy");
......@@ -2822,63 +3211,96 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr
28223211
28233212fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {
28243213 const t: *Threaded = @ptrCast(@alignCast(userdata));
3214 const current_thread = Thread.getCurrent(t);
28253215 const fd = file.handle;
28263216
2827 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) while (true) {
2828 try t.checkCancel();
2829 var result: u64 = undefined;
2830 switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {
2831 .SUCCESS => return,
2832 .INTR => continue,
2833 .CANCELED => return error.Canceled,
2834
2835 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2836 .INVAL => return error.Unseekable,
2837 .OVERFLOW => return error.Unseekable,
2838 .SPIPE => return error.Unseekable,
2839 .NXIO => return error.Unseekable,
2840 else => |err| return posix.unexpectedErrno(err),
3217 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
3218 try current_thread.beginSyscall();
3219 while (true) {
3220 var result: u64 = undefined;
3221 switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {
3222 .SUCCESS => {
3223 current_thread.endSyscall();
3224 return;
3225 },
3226 .INTR => {
3227 try current_thread.checkCancel();
3228 continue;
3229 },
3230 else => |e| {
3231 current_thread.endSyscall();
3232 switch (e) {
3233 .CANCELED => return error.Canceled,
3234 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3235 .INVAL => return error.Unseekable,
3236 .OVERFLOW => return error.Unseekable,
3237 .SPIPE => return error.Unseekable,
3238 .NXIO => return error.Unseekable,
3239 else => |err| return posix.unexpectedErrno(err),
3240 }
3241 },
3242 }
28413243 }
2842 };
3244 }
28433245
28443246 if (native_os == .windows) {
2845 try t.checkCancel();
3247 try current_thread.checkCancel();
28463248 return windows.SetFilePointerEx_BEGIN(fd, offset);
28473249 }
28483250
28493251 if (native_os == .wasi and !builtin.link_libc) while (true) {
2850 try t.checkCancel();
28513252 var new_offset: std.os.wasi.filesize_t = undefined;
3253 try current_thread.beginSyscall();
28523254 switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) {
2853 .SUCCESS => return,
2854 .INTR => continue,
2855 .CANCELED => return error.Canceled,
2856
2857 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2858 .INVAL => return error.Unseekable,
2859 .OVERFLOW => return error.Unseekable,
2860 .SPIPE => return error.Unseekable,
2861 .NXIO => return error.Unseekable,
2862 .NOTCAPABLE => return error.AccessDenied,
2863 else => |err| return posix.unexpectedErrno(err),
3255 .SUCCESS => {
3256 current_thread.endSyscall();
3257 return;
3258 },
3259 .INTR => {
3260 try current_thread.checkCancel();
3261 continue;
3262 },
3263 else => |e| {
3264 current_thread.endSyscall();
3265 switch (e) {
3266 .CANCELED => return error.Canceled,
3267 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3268 .INVAL => return error.Unseekable,
3269 .OVERFLOW => return error.Unseekable,
3270 .SPIPE => return error.Unseekable,
3271 .NXIO => return error.Unseekable,
3272 .NOTCAPABLE => return error.AccessDenied,
3273 else => |err| return posix.unexpectedErrno(err),
3274 }
3275 },
28643276 }
28653277 };
28663278
28673279 if (posix.SEEK == void) return error.Unseekable;
28683280
3281 try current_thread.beginSyscall();
28693282 while (true) {
2870 try t.checkCancel();
28713283 switch (posix.errno(lseek_sym(fd, @bitCast(offset), posix.SEEK.SET))) {
2872 .SUCCESS => return,
2873 .INTR => continue,
2874 .CANCELED => return error.Canceled,
2875
2876 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2877 .INVAL => return error.Unseekable,
2878 .OVERFLOW => return error.Unseekable,
2879 .SPIPE => return error.Unseekable,
2880 .NXIO => return error.Unseekable,
2881 else => |err| return posix.unexpectedErrno(err),
3284 .SUCCESS => {
3285 current_thread.endSyscall();
3286 return;
3287 },
3288 .INTR => {
3289 try current_thread.checkCancel();
3290 continue;
3291 },
3292 else => |e| {
3293 current_thread.endSyscall();
3294 switch (e) {
3295 .CANCELED => return error.Canceled,
3296 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3297 .INVAL => return error.Unseekable,
3298 .OVERFLOW => return error.Unseekable,
3299 .SPIPE => return error.Unseekable,
3300 .NXIO => return error.Unseekable,
3301 else => |err| return posix.unexpectedErrno(err),
3302 }
3303 },
28823304 }
28833305 }
28843306}
......@@ -2907,8 +3329,8 @@ fn fileWritePositional(
29073329 offset: u64,
29083330) Io.File.WritePositionalError!usize {
29093331 const t: *Threaded = @ptrCast(@alignCast(userdata));
3332 _ = t;
29103333 while (true) {
2911 try t.checkCancel();
29123334 _ = file;
29133335 _ = buffer;
29143336 _ = offset;
......@@ -2918,8 +3340,8 @@ fn fileWritePositional(
29183340
29193341fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8) Io.File.WriteStreamingError!usize {
29203342 const t: *Threaded = @ptrCast(@alignCast(userdata));
3343 _ = t;
29213344 while (true) {
2922 try t.checkCancel();
29233345 _ = file;
29243346 _ = buffer;
29253347 @panic("TODO implement fileWriteStreaming");
......@@ -2997,6 +3419,7 @@ const sleep = switch (native_os) {
29973419
29983420fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
29993421 const t: *Threaded = @ptrCast(@alignCast(userdata));
3422 const current_thread = Thread.getCurrent(t);
30003423 const clock_id: posix.clockid_t = clockToPosix(switch (timeout) {
30013424 .none => .awake,
30023425 .duration => |d| d.clock,
......@@ -3008,25 +3431,37 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30083431 .deadline => |deadline| deadline.raw.nanoseconds,
30093432 };
30103433 var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
3434 try current_thread.beginSyscall();
30113435 while (true) {
3012 try t.checkCancel();
30133436 switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
30143437 .none, .duration => false,
30153438 .deadline => true,
30163439 } }, &timespec, &timespec))) {
3017 .SUCCESS => return,
3018 .INTR => continue,
3019 .CANCELED => return error.Canceled,
3020 .INVAL => return error.UnsupportedClock,
3021 else => |err| return posix.unexpectedErrno(err),
3440 .SUCCESS => {
3441 current_thread.endSyscall();
3442 return;
3443 },
3444 .INTR => {
3445 try current_thread.checkCancel();
3446 continue;
3447 },
3448 else => |e| {
3449 current_thread.endSyscall();
3450 switch (e) {
3451 .CANCELED => return error.Canceled,
3452 .INVAL => return error.UnsupportedClock,
3453 else => |err| return posix.unexpectedErrno(err),
3454 }
3455 },
30223456 }
30233457 }
30243458}
30253459
30263460fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30273461 const t: *Threaded = @ptrCast(@alignCast(userdata));
3462 const current_thread = Thread.getCurrent(t);
30283463 const t_io = ioBasic(t);
3029 try t.checkCancel();
3464 try current_thread.checkCancel();
30303465 const ms = ms: {
30313466 const d = (try timeout.toDurationFromNow(t_io)) orelse
30323467 break :ms std.math.maxInt(windows.DWORD);
......@@ -3038,9 +3473,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30383473
30393474fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30403475 const t: *Threaded = @ptrCast(@alignCast(userdata));
3476 const current_thread = Thread.getCurrent(t);
30413477 const t_io = ioBasic(t);
3042 try t.checkCancel();
3043
30443478 const w = std.os.wasi;
30453479
30463480 const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t_io)) |d| .{
......@@ -3063,11 +3497,14 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30633497 };
30643498 var event: w.event_t = undefined;
30653499 var nevents: usize = undefined;
3500 try current_thread.beginSyscall();
30663501 _ = w.poll_oneoff(&in, &event, 1, &nevents);
3502 current_thread.endSyscall();
30673503}
30683504
30693505fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30703506 const t: *Threaded = @ptrCast(@alignCast(userdata));
3507 const current_thread = Thread.getCurrent(t);
30713508 const t_io = ioBasic(t);
30723509 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
30733510 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
......@@ -3079,12 +3516,18 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30793516 };
30803517 break :t timestampToPosix(d.raw.toNanoseconds());
30813518 };
3519 try current_thread.beginSyscall();
30823520 while (true) {
3083 try t.checkCancel();
30843521 switch (posix.errno(posix.system.nanosleep(&timespec, &timespec))) {
3085 .INTR => continue,
3086 .CANCELED => return error.Canceled,
3087 else => return, // This prong handles success as well as unexpected errors.
3522 .INTR => {
3523 try current_thread.checkCancel();
3524 continue;
3525 },
3526 else => {
3527 // This prong handles success as well as unexpected errors.
3528 current_thread.endSyscall();
3529 return;
3530 },
30883531 }
30893532 }
30903533}
......@@ -3127,34 +3570,48 @@ fn netListenIpPosix(
31273570) IpAddress.ListenError!net.Server {
31283571 if (!have_networking) return error.NetworkDown;
31293572 const t: *Threaded = @ptrCast(@alignCast(userdata));
3573 const current_thread = Thread.getCurrent(t);
31303574 const family = posixAddressFamily(&address);
3131 const socket_fd = try openSocketPosix(t, family, .{
3575 const socket_fd = try openSocketPosix(current_thread, family, .{
31323576 .mode = options.mode,
31333577 .protocol = options.protocol,
31343578 });
31353579 errdefer posix.close(socket_fd);
31363580
31373581 if (options.reuse_address) {
3138 try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
3582 try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
31393583 if (@hasDecl(posix.SO, "REUSEPORT"))
3140 try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);
3584 try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);
31413585 }
31423586
31433587 var storage: PosixAddress = undefined;
31443588 var addr_len = addressToPosix(&address, &storage);
3145 try posixBind(t, socket_fd, &storage.any, addr_len);
3589 try posixBind(current_thread, socket_fd, &storage.any, addr_len);
31463590
3591 try current_thread.beginSyscall();
31473592 while (true) {
3148 try t.checkCancel();
31493593 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
3150 .SUCCESS => break,
3151 .ADDRINUSE => return error.AddressInUse,
3152 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3153 else => |err| return posix.unexpectedErrno(err),
3594 .SUCCESS => {
3595 current_thread.endSyscall();
3596 break;
3597 },
3598 .INTR => {
3599 try current_thread.checkCancel();
3600 continue;
3601 },
3602 else => |e| {
3603 current_thread.endSyscall();
3604 switch (e) {
3605 .CANCELED => return error.Canceled,
3606 .ADDRINUSE => return error.AddressInUse,
3607 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3608 else => |err| return posix.unexpectedErrno(err),
3609 }
3610 },
31543611 }
31553612 }
31563613
3157 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);
3614 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
31583615 return .{
31593616 .socket = .{
31603617 .handle = socket_fd,
......@@ -3170,8 +3627,9 @@ fn netListenIpWindows(
31703627) IpAddress.ListenError!net.Server {
31713628 if (!have_networking) return error.NetworkDown;
31723629 const t: *Threaded = @ptrCast(@alignCast(userdata));
3630 const current_thread = Thread.getCurrent(t);
31733631 const family = posixAddressFamily(&address);
3174 const socket_handle = try openSocketWsa(t, family, .{
3632 const socket_handle = try openSocketWsa(t, current_thread, family, .{
31753633 .mode = options.mode,
31763634 .protocol = options.protocol,
31773635 });
......@@ -3183,52 +3641,73 @@ fn netListenIpWindows(
31833641 var storage: WsaAddress = undefined;
31843642 var addr_len = addressToWsa(&address, &storage);
31853643
3644 try current_thread.beginSyscall();
31863645 while (true) {
3187 try t.checkCancel();
31883646 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
31893647 if (rc != ws2_32.SOCKET_ERROR) break;
31903648 switch (ws2_32.WSAGetLastError()) {
3191 .EINTR => continue,
3192 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3649 .EINTR => {
3650 try current_thread.checkCancel();
3651 continue;
3652 },
31933653 .NOTINITIALISED => {
31943654 try initializeWsa(t);
3655 try current_thread.checkCancel();
31953656 continue;
31963657 },
3197 .EADDRINUSE => return error.AddressInUse,
3198 .EADDRNOTAVAIL => return error.AddressUnavailable,
3199 .ENOTSOCK => |err| return wsaErrorBug(err),
3200 .EFAULT => |err| return wsaErrorBug(err),
3201 .EINVAL => |err| return wsaErrorBug(err),
3202 .ENOBUFS => return error.SystemResources,
3203 .ENETDOWN => return error.NetworkDown,
3204 else => |err| return windows.unexpectedWSAError(err),
3658 else => |e| {
3659 current_thread.endSyscall();
3660 switch (e) {
3661 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3662 .EADDRINUSE => return error.AddressInUse,
3663 .EADDRNOTAVAIL => return error.AddressUnavailable,
3664 .ENOTSOCK => |err| return wsaErrorBug(err),
3665 .EFAULT => |err| return wsaErrorBug(err),
3666 .EINVAL => |err| return wsaErrorBug(err),
3667 .ENOBUFS => return error.SystemResources,
3668 .ENETDOWN => return error.NetworkDown,
3669 else => |err| return windows.unexpectedWSAError(err),
3670 }
3671 },
32053672 }
32063673 }
32073674
3675 try current_thread.checkCancel();
32083676 while (true) {
3209 try t.checkCancel();
32103677 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
3211 if (rc != ws2_32.SOCKET_ERROR) break;
3678 if (rc != ws2_32.SOCKET_ERROR) {
3679 current_thread.endSyscall();
3680 break;
3681 }
32123682 switch (ws2_32.WSAGetLastError()) {
3213 .EINTR => continue,
3214 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3683 .EINTR => {
3684 try current_thread.checkCancel();
3685 continue;
3686 },
32153687 .NOTINITIALISED => {
32163688 try initializeWsa(t);
3689 try current_thread.checkCancel();
32173690 continue;
32183691 },
3219 .ENETDOWN => return error.NetworkDown,
3220 .EADDRINUSE => return error.AddressInUse,
3221 .EISCONN => |err| return wsaErrorBug(err),
3222 .EINVAL => |err| return wsaErrorBug(err),
3223 .EMFILE, .ENOBUFS => return error.SystemResources,
3224 .ENOTSOCK => |err| return wsaErrorBug(err),
3225 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3226 .EINPROGRESS => |err| return wsaErrorBug(err),
3227 else => |err| return windows.unexpectedWSAError(err),
3692 else => |e| {
3693 current_thread.endSyscall();
3694 switch (e) {
3695 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3696 .ENETDOWN => return error.NetworkDown,
3697 .EADDRINUSE => return error.AddressInUse,
3698 .EISCONN => |err| return wsaErrorBug(err),
3699 .EINVAL => |err| return wsaErrorBug(err),
3700 .EMFILE, .ENOBUFS => return error.SystemResources,
3701 .ENOTSOCK => |err| return wsaErrorBug(err),
3702 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3703 .EINPROGRESS => |err| return wsaErrorBug(err),
3704 else => |err| return windows.unexpectedWSAError(err),
3705 }
3706 },
32283707 }
32293708 }
32303709
3231 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
3710 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
32323711
32333712 return .{
32343713 .socket = .{
......@@ -3256,7 +3735,8 @@ fn netListenUnixPosix(
32563735) net.UnixAddress.ListenError!net.Socket.Handle {
32573736 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
32583737 const t: *Threaded = @ptrCast(@alignCast(userdata));
3259 const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
3738 const current_thread = Thread.getCurrent(t);
3739 const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
32603740 error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,
32613741 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
32623742 error.SocketModeUnsupported => return error.AddressFamilyUnsupported,
......@@ -3267,15 +3747,28 @@ fn netListenUnixPosix(
32673747
32683748 var storage: UnixAddress = undefined;
32693749 const addr_len = addressUnixToPosix(address, &storage);
3270 try posixBindUnix(t, socket_fd, &storage.any, addr_len);
3750 try posixBindUnix(current_thread, socket_fd, &storage.any, addr_len);
32713751
3752 try current_thread.beginSyscall();
32723753 while (true) {
3273 try t.checkCancel();
32743754 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
3275 .SUCCESS => break,
3276 .ADDRINUSE => return error.AddressInUse,
3277 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3278 else => |err| return posix.unexpectedErrno(err),
3755 .SUCCESS => {
3756 current_thread.endSyscall();
3757 break;
3758 },
3759 .INTR => {
3760 try current_thread.checkCancel();
3761 continue;
3762 },
3763 else => |e| {
3764 current_thread.endSyscall();
3765 switch (e) {
3766 .CANCELED => return error.Canceled,
3767 .ADDRINUSE => return error.AddressInUse,
3768 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3769 else => |err| return posix.unexpectedErrno(err),
3770 }
3771 },
32793772 }
32803773 }
32813774
......@@ -3289,8 +3782,9 @@ fn netListenUnixWindows(
32893782) net.UnixAddress.ListenError!net.Socket.Handle {
32903783 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
32913784 const t: *Threaded = @ptrCast(@alignCast(userdata));
3785 const current_thread = Thread.getCurrent(t);
32923786
3293 const socket_handle = openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
3787 const socket_handle = openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
32943788 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
32953789 else => |e| return e,
32963790 };
......@@ -3299,52 +3793,67 @@ fn netListenUnixWindows(
32993793 var storage: WsaAddress = undefined;
33003794 const addr_len = addressUnixToWsa(address, &storage);
33013795
3796 try current_thread.beginSyscall();
33023797 while (true) {
3303 try t.checkCancel();
33043798 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
33053799 if (rc != ws2_32.SOCKET_ERROR) break;
33063800 switch (ws2_32.WSAGetLastError()) {
3307 .EINTR => continue,
3308 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3801 .EINTR => {
3802 try current_thread.checkCancel();
3803 continue;
3804 },
33093805 .NOTINITIALISED => {
33103806 try initializeWsa(t);
3807 try current_thread.checkCancel();
33113808 continue;
33123809 },
3313 .EADDRINUSE => return error.AddressInUse,
3314 .EADDRNOTAVAIL => return error.AddressUnavailable,
3315 .ENOTSOCK => |err| return wsaErrorBug(err),
3316 .EFAULT => |err| return wsaErrorBug(err),
3317 .EINVAL => |err| return wsaErrorBug(err),
3318 .ENOBUFS => return error.SystemResources,
3319 .ENETDOWN => return error.NetworkDown,
3320 else => |err| return windows.unexpectedWSAError(err),
3810 else => |e| {
3811 current_thread.endSyscall();
3812 switch (e) {
3813 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3814 .EADDRINUSE => return error.AddressInUse,
3815 .EADDRNOTAVAIL => return error.AddressUnavailable,
3816 .ENOTSOCK => |err| return wsaErrorBug(err),
3817 .EFAULT => |err| return wsaErrorBug(err),
3818 .EINVAL => |err| return wsaErrorBug(err),
3819 .ENOBUFS => return error.SystemResources,
3820 .ENETDOWN => return error.NetworkDown,
3821 else => |err| return windows.unexpectedWSAError(err),
3822 }
3823 },
33213824 }
33223825 }
33233826
33243827 while (true) {
3325 try t.checkCancel();
3828 try current_thread.checkCancel();
33263829 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
3327 if (rc != ws2_32.SOCKET_ERROR) break;
3830 if (rc != ws2_32.SOCKET_ERROR) {
3831 current_thread.endSyscall();
3832 return socket_handle;
3833 }
33283834 switch (ws2_32.WSAGetLastError()) {
33293835 .EINTR => continue,
3330 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
33313836 .NOTINITIALISED => {
33323837 try initializeWsa(t);
33333838 continue;
33343839 },
3335 .ENETDOWN => return error.NetworkDown,
3336 .EADDRINUSE => return error.AddressInUse,
3337 .EISCONN => |err| return wsaErrorBug(err),
3338 .EINVAL => |err| return wsaErrorBug(err),
3339 .EMFILE, .ENOBUFS => return error.SystemResources,
3340 .ENOTSOCK => |err| return wsaErrorBug(err),
3341 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3342 .EINPROGRESS => |err| return wsaErrorBug(err),
3343 else => |err| return windows.unexpectedWSAError(err),
3840 else => |e| {
3841 current_thread.endSyscall();
3842 switch (e) {
3843 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3844 .ENETDOWN => return error.NetworkDown,
3845 .EADDRINUSE => return error.AddressInUse,
3846 .EISCONN => |err| return wsaErrorBug(err),
3847 .EINVAL => |err| return wsaErrorBug(err),
3848 .EMFILE, .ENOBUFS => return error.SystemResources,
3849 .ENOTSOCK => |err| return wsaErrorBug(err),
3850 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3851 .EINPROGRESS => |err| return wsaErrorBug(err),
3852 else => |err| return windows.unexpectedWSAError(err),
3853 }
3854 },
33443855 }
33453856 }
3346
3347 return socket_handle;
33483857}
33493858
33503859fn netListenUnixUnavailable(
......@@ -3358,172 +3867,275 @@ fn netListenUnixUnavailable(
33583867 return error.AddressFamilyUnsupported;
33593868}
33603869
3361fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
3870fn posixBindUnix(
3871 current_thread: *Thread,
3872 fd: posix.socket_t,
3873 addr: *const posix.sockaddr,
3874 addr_len: posix.socklen_t,
3875) !void {
3876 try current_thread.beginSyscall();
33623877 while (true) {
3363 try t.checkCancel();
33643878 switch (posix.errno(posix.system.bind(fd, addr, addr_len))) {
3365 .SUCCESS => break,
3366 .INTR => continue,
3367 .CANCELED => return error.Canceled,
3368
3369 .ACCES => return error.AccessDenied,
3370 .ADDRINUSE => return error.AddressInUse,
3371 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3372 .ADDRNOTAVAIL => return error.AddressUnavailable,
3373 .NOMEM => return error.SystemResources,
3374
3375 .LOOP => return error.SymLinkLoop,
3376 .NOENT => return error.FileNotFound,
3377 .NOTDIR => return error.NotDir,
3378 .ROFS => return error.ReadOnlyFileSystem,
3379 .PERM => return error.PermissionDenied,
3380
3381 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3382 .INVAL => |err| return errnoBug(err), // invalid parameters
3383 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3384 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3385 .NAMETOOLONG => |err| return errnoBug(err),
3386 else => |err| return posix.unexpectedErrno(err),
3879 .SUCCESS => {
3880 current_thread.endSyscall();
3881 break;
3882 },
3883 .INTR => {
3884 try current_thread.checkCancel();
3885 continue;
3886 },
3887 else => |e| {
3888 current_thread.endSyscall();
3889 switch (e) {
3890 .CANCELED => return error.Canceled,
3891 .ACCES => return error.AccessDenied,
3892 .ADDRINUSE => return error.AddressInUse,
3893 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3894 .ADDRNOTAVAIL => return error.AddressUnavailable,
3895 .NOMEM => return error.SystemResources,
3896
3897 .LOOP => return error.SymLinkLoop,
3898 .NOENT => return error.FileNotFound,
3899 .NOTDIR => return error.NotDir,
3900 .ROFS => return error.ReadOnlyFileSystem,
3901 .PERM => return error.PermissionDenied,
3902
3903 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3904 .INVAL => |err| return errnoBug(err), // invalid parameters
3905 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3906 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3907 .NAMETOOLONG => |err| return errnoBug(err),
3908 else => |err| return posix.unexpectedErrno(err),
3909 }
3910 },
33873911 }
33883912 }
33893913}
33903914
3391fn posixBind(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
3915fn posixBind(
3916 current_thread: *Thread,
3917 socket_fd: posix.socket_t,
3918 addr: *const posix.sockaddr,
3919 addr_len: posix.socklen_t,
3920) !void {
3921 try current_thread.beginSyscall();
33923922 while (true) {
3393 try t.checkCancel();
33943923 switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) {
3395 .SUCCESS => break,
3396 .INTR => continue,
3397 .CANCELED => return error.Canceled,
3398
3399 .ADDRINUSE => return error.AddressInUse,
3400 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3401 .INVAL => |err| return errnoBug(err), // invalid parameters
3402 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3403 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3404 .ADDRNOTAVAIL => return error.AddressUnavailable,
3405 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3406 .NOMEM => return error.SystemResources,
3407 else => |err| return posix.unexpectedErrno(err),
3924 .SUCCESS => {
3925 current_thread.endSyscall();
3926 break;
3927 },
3928 .INTR => {
3929 try current_thread.checkCancel();
3930 continue;
3931 },
3932 else => |e| {
3933 current_thread.endSyscall();
3934 switch (e) {
3935 .CANCELED => return error.Canceled,
3936 .ADDRINUSE => return error.AddressInUse,
3937 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3938 .INVAL => |err| return errnoBug(err), // invalid parameters
3939 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3940 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3941 .ADDRNOTAVAIL => return error.AddressUnavailable,
3942 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3943 .NOMEM => return error.SystemResources,
3944 else => |err| return posix.unexpectedErrno(err),
3945 }
3946 },
34083947 }
34093948 }
34103949}
34113950
3412fn posixConnect(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
3951fn posixConnect(
3952 current_thread: *Thread,
3953 socket_fd: posix.socket_t,
3954 addr: *const posix.sockaddr,
3955 addr_len: posix.socklen_t,
3956) !void {
3957 try current_thread.beginSyscall();
34133958 while (true) {
3414 try t.checkCancel();
34153959 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {
3416 .SUCCESS => return,
3417 .INTR => continue,
3418 .CANCELED => return error.Canceled,
3419
3420 .ADDRNOTAVAIL => return error.AddressUnavailable,
3421 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3422 .AGAIN, .INPROGRESS => return error.WouldBlock,
3423 .ALREADY => return error.ConnectionPending,
3424 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3425 .CONNREFUSED => return error.ConnectionRefused,
3426 .CONNRESET => return error.ConnectionResetByPeer,
3427 .FAULT => |err| return errnoBug(err),
3428 .ISCONN => |err| return errnoBug(err),
3429 .HOSTUNREACH => return error.HostUnreachable,
3430 .NETUNREACH => return error.NetworkUnreachable,
3431 .NOTSOCK => |err| return errnoBug(err),
3432 .PROTOTYPE => |err| return errnoBug(err),
3433 .TIMEDOUT => return error.Timeout,
3434 .CONNABORTED => |err| return errnoBug(err),
3435 .ACCES => return error.AccessDenied,
3436 .PERM => |err| return errnoBug(err),
3437 .NOENT => |err| return errnoBug(err),
3438 .NETDOWN => return error.NetworkDown,
3439 else => |err| return posix.unexpectedErrno(err),
3960 .SUCCESS => {
3961 current_thread.endSyscall();
3962 return;
3963 },
3964 .INTR => {
3965 try current_thread.checkCancel();
3966 continue;
3967 },
3968 else => |e| {
3969 current_thread.endSyscall();
3970 switch (e) {
3971 .CANCELED => return error.Canceled,
3972 .ADDRNOTAVAIL => return error.AddressUnavailable,
3973 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3974 .AGAIN, .INPROGRESS => return error.WouldBlock,
3975 .ALREADY => return error.ConnectionPending,
3976 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3977 .CONNREFUSED => return error.ConnectionRefused,
3978 .CONNRESET => return error.ConnectionResetByPeer,
3979 .FAULT => |err| return errnoBug(err),
3980 .ISCONN => |err| return errnoBug(err),
3981 .HOSTUNREACH => return error.HostUnreachable,
3982 .NETUNREACH => return error.NetworkUnreachable,
3983 .NOTSOCK => |err| return errnoBug(err),
3984 .PROTOTYPE => |err| return errnoBug(err),
3985 .TIMEDOUT => return error.Timeout,
3986 .CONNABORTED => |err| return errnoBug(err),
3987 .ACCES => return error.AccessDenied,
3988 .PERM => |err| return errnoBug(err),
3989 .NOENT => |err| return errnoBug(err),
3990 .NETDOWN => return error.NetworkDown,
3991 else => |err| return posix.unexpectedErrno(err),
3992 }
3993 },
34403994 }
34413995 }
34423996}
34433997
3444fn posixConnectUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
3998fn posixConnectUnix(
3999 current_thread: *Thread,
4000 fd: posix.socket_t,
4001 addr: *const posix.sockaddr,
4002 addr_len: posix.socklen_t,
4003) !void {
4004 try current_thread.beginSyscall();
34454005 while (true) {
3446 try t.checkCancel();
34474006 switch (posix.errno(posix.system.connect(fd, addr, addr_len))) {
3448 .SUCCESS => return,
3449 .INTR => continue,
3450 .CANCELED => return error.Canceled,
3451
3452 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3453 .AGAIN => return error.WouldBlock,
3454 .INPROGRESS => return error.WouldBlock,
3455 .ACCES => return error.AccessDenied,
3456
3457 .LOOP => return error.SymLinkLoop,
3458 .NOENT => return error.FileNotFound,
3459 .NOTDIR => return error.NotDir,
3460 .ROFS => return error.ReadOnlyFileSystem,
3461 .PERM => return error.PermissionDenied,
3462
3463 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3464 .CONNABORTED => |err| return errnoBug(err),
3465 .FAULT => |err| return errnoBug(err),
3466 .ISCONN => |err| return errnoBug(err),
3467 .NOTSOCK => |err| return errnoBug(err),
3468 .PROTOTYPE => |err| return errnoBug(err),
3469 else => |err| return posix.unexpectedErrno(err),
4007 .SUCCESS => {
4008 current_thread.endSyscall();
4009 return;
4010 },
4011 .INTR => {
4012 try current_thread.checkCancel();
4013 continue;
4014 },
4015 else => |e| {
4016 current_thread.endSyscall();
4017 switch (e) {
4018 .CANCELED => return error.Canceled,
4019 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4020 .AGAIN => return error.WouldBlock,
4021 .INPROGRESS => return error.WouldBlock,
4022 .ACCES => return error.AccessDenied,
4023
4024 .LOOP => return error.SymLinkLoop,
4025 .NOENT => return error.FileNotFound,
4026 .NOTDIR => return error.NotDir,
4027 .ROFS => return error.ReadOnlyFileSystem,
4028 .PERM => return error.PermissionDenied,
4029
4030 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4031 .CONNABORTED => |err| return errnoBug(err),
4032 .FAULT => |err| return errnoBug(err),
4033 .ISCONN => |err| return errnoBug(err),
4034 .NOTSOCK => |err| return errnoBug(err),
4035 .PROTOTYPE => |err| return errnoBug(err),
4036 else => |err| return posix.unexpectedErrno(err),
4037 }
4038 },
34704039 }
34714040 }
34724041}
34734042
3474fn posixGetSockName(t: *Threaded, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void {
4043fn posixGetSockName(
4044 current_thread: *Thread,
4045 socket_fd: posix.fd_t,
4046 addr: *posix.sockaddr,
4047 addr_len: *posix.socklen_t,
4048) !void {
4049 try current_thread.beginSyscall();
34754050 while (true) {
3476 try t.checkCancel();
34774051 switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) {
3478 .SUCCESS => break,
3479 .INTR => continue,
3480 .CANCELED => return error.Canceled,
3481
3482 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3483 .FAULT => |err| return errnoBug(err),
3484 .INVAL => |err| return errnoBug(err), // invalid parameters
3485 .NOTSOCK => |err| return errnoBug(err), // always a race condition
3486 .NOBUFS => return error.SystemResources,
3487 else => |err| return posix.unexpectedErrno(err),
4052 .SUCCESS => {
4053 current_thread.endSyscall();
4054 break;
4055 },
4056 .INTR => {
4057 try current_thread.checkCancel();
4058 continue;
4059 },
4060 else => |e| {
4061 current_thread.endSyscall();
4062 switch (e) {
4063 .CANCELED => return error.Canceled,
4064 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4065 .FAULT => |err| return errnoBug(err),
4066 .INVAL => |err| return errnoBug(err), // invalid parameters
4067 .NOTSOCK => |err| return errnoBug(err), // always a race condition
4068 .NOBUFS => return error.SystemResources,
4069 else => |err| return posix.unexpectedErrno(err),
4070 }
4071 },
34884072 }
34894073 }
34904074}
34914075
3492fn wsaGetSockName(t: *Threaded, handle: ws2_32.SOCKET, addr: *ws2_32.sockaddr, addr_len: *i32) !void {
4076fn wsaGetSockName(
4077 t: *Threaded,
4078 current_thread: *Thread,
4079 handle: ws2_32.SOCKET,
4080 addr: *ws2_32.sockaddr,
4081 addr_len: *i32,
4082) !void {
4083 try current_thread.beginSyscall();
34934084 while (true) {
3494 try t.checkCancel();
34954085 const rc = ws2_32.getsockname(handle, addr, addr_len);
3496 if (rc != ws2_32.SOCKET_ERROR) break;
4086 if (rc != ws2_32.SOCKET_ERROR) {
4087 current_thread.endSyscall();
4088 return;
4089 }
34974090 switch (ws2_32.WSAGetLastError()) {
3498 .EINTR => continue,
3499 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4091 .EINTR => {
4092 try current_thread.checkCancel();
4093 continue;
4094 },
35004095 .NOTINITIALISED => {
35014096 try initializeWsa(t);
4097 try current_thread.checkCancel();
35024098 continue;
35034099 },
3504 .ENETDOWN => return error.NetworkDown,
3505 .EFAULT => |err| return wsaErrorBug(err),
3506 .ENOTSOCK => |err| return wsaErrorBug(err),
3507 .EINVAL => |err| return wsaErrorBug(err),
3508 else => |err| return windows.unexpectedWSAError(err),
4100 else => |e| {
4101 current_thread.endSyscall();
4102 switch (e) {
4103 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4104 .ENETDOWN => return error.NetworkDown,
4105 .EFAULT => |err| return wsaErrorBug(err),
4106 .ENOTSOCK => |err| return wsaErrorBug(err),
4107 .EINVAL => |err| return wsaErrorBug(err),
4108 else => |err| return windows.unexpectedWSAError(err),
4109 }
4110 },
35094111 }
35104112 }
35114113}
35124114
3513fn setSocketOption(t: *Threaded, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
4115fn setSocketOption(current_thread: *Thread, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
35144116 const o: []const u8 = @ptrCast(&option);
4117 try current_thread.beginSyscall();
35154118 while (true) {
3516 try t.checkCancel();
35174119 switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) {
3518 .SUCCESS => return,
3519 .INTR => continue,
3520 .CANCELED => return error.Canceled,
3521
3522 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3523 .NOTSOCK => |err| return errnoBug(err),
3524 .INVAL => |err| return errnoBug(err),
3525 .FAULT => |err| return errnoBug(err),
3526 else => |err| return posix.unexpectedErrno(err),
4120 .SUCCESS => {
4121 current_thread.endSyscall();
4122 return;
4123 },
4124 .INTR => {
4125 try current_thread.checkCancel();
4126 continue;
4127 },
4128 else => |e| {
4129 current_thread.endSyscall();
4130 switch (e) {
4131 .CANCELED => return error.Canceled,
4132 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4133 .NOTSOCK => |err| return errnoBug(err),
4134 .INVAL => |err| return errnoBug(err),
4135 .FAULT => |err| return errnoBug(err),
4136 else => |err| return posix.unexpectedErrno(err),
4137 }
4138 },
35274139 }
35284140 }
35294141}
......@@ -3557,16 +4169,17 @@ fn netConnectIpPosix(
35574169 if (!have_networking) return error.NetworkDown;
35584170 if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");
35594171 const t: *Threaded = @ptrCast(@alignCast(userdata));
4172 const current_thread = Thread.getCurrent(t);
35604173 const family = posixAddressFamily(address);
3561 const socket_fd = try openSocketPosix(t, family, .{
4174 const socket_fd = try openSocketPosix(current_thread, family, .{
35624175 .mode = options.mode,
35634176 .protocol = options.protocol,
35644177 });
35654178 errdefer posix.close(socket_fd);
35664179 var storage: PosixAddress = undefined;
35674180 var addr_len = addressToPosix(address, &storage);
3568 try posixConnect(t, socket_fd, &storage.any, addr_len);
3569 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);
4181 try posixConnect(current_thread, socket_fd, &storage.any, addr_len);
4182 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
35704183 return .{ .socket = .{
35714184 .handle = socket_fd,
35724185 .address = addressFromPosix(&storage),
......@@ -3581,8 +4194,9 @@ fn netConnectIpWindows(
35814194 if (!have_networking) return error.NetworkDown;
35824195 if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");
35834196 const t: *Threaded = @ptrCast(@alignCast(userdata));
4197 const current_thread = Thread.getCurrent(t);
35844198 const family = posixAddressFamily(address);
3585 const socket_handle = try openSocketWsa(t, family, .{
4199 const socket_handle = try openSocketWsa(t, current_thread, family, .{
35864200 .mode = options.mode,
35874201 .protocol = options.protocol,
35884202 });
......@@ -3591,36 +4205,48 @@ fn netConnectIpWindows(
35914205 var storage: WsaAddress = undefined;
35924206 var addr_len = addressToWsa(address, &storage);
35934207
4208 try current_thread.beginSyscall();
35944209 while (true) {
35954210 const rc = ws2_32.connect(socket_handle, &storage.any, addr_len);
3596 if (rc != ws2_32.SOCKET_ERROR) break;
4211 if (rc != ws2_32.SOCKET_ERROR) {
4212 current_thread.endSyscall();
4213 break;
4214 }
35974215 switch (ws2_32.WSAGetLastError()) {
3598 .EINTR => continue,
3599 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4216 .EINTR => {
4217 try current_thread.checkCancel();
4218 continue;
4219 },
36004220 .NOTINITIALISED => {
36014221 try initializeWsa(t);
4222 try current_thread.checkCancel();
36024223 continue;
36034224 },
3604
3605 .EADDRNOTAVAIL => return error.AddressUnavailable,
3606 .ECONNREFUSED => return error.ConnectionRefused,
3607 .ECONNRESET => return error.ConnectionResetByPeer,
3608 .ETIMEDOUT => return error.Timeout,
3609 .EHOSTUNREACH => return error.HostUnreachable,
3610 .ENETUNREACH => return error.NetworkUnreachable,
3611 .EFAULT => |err| return wsaErrorBug(err),
3612 .EINVAL => |err| return wsaErrorBug(err),
3613 .EISCONN => |err| return wsaErrorBug(err),
3614 .ENOTSOCK => |err| return wsaErrorBug(err),
3615 .EWOULDBLOCK => return error.WouldBlock,
3616 .EACCES => return error.AccessDenied,
3617 .ENOBUFS => return error.SystemResources,
3618 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
3619 else => |err| return windows.unexpectedWSAError(err),
4225 else => |e| {
4226 current_thread.endSyscall();
4227 switch (e) {
4228 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4229 .EADDRNOTAVAIL => return error.AddressUnavailable,
4230 .ECONNREFUSED => return error.ConnectionRefused,
4231 .ECONNRESET => return error.ConnectionResetByPeer,
4232 .ETIMEDOUT => return error.Timeout,
4233 .EHOSTUNREACH => return error.HostUnreachable,
4234 .ENETUNREACH => return error.NetworkUnreachable,
4235 .EFAULT => |err| return wsaErrorBug(err),
4236 .EINVAL => |err| return wsaErrorBug(err),
4237 .EISCONN => |err| return wsaErrorBug(err),
4238 .ENOTSOCK => |err| return wsaErrorBug(err),
4239 .EWOULDBLOCK => return error.WouldBlock,
4240 .EACCES => return error.AccessDenied,
4241 .ENOBUFS => return error.SystemResources,
4242 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4243 else => |err| return windows.unexpectedWSAError(err),
4244 }
4245 },
36204246 }
36214247 }
36224248
3623 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
4249 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
36244250
36254251 return .{ .socket = .{
36264252 .handle = socket_handle,
......@@ -3645,14 +4271,15 @@ fn netConnectUnixPosix(
36454271) net.UnixAddress.ConnectError!net.Socket.Handle {
36464272 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
36474273 const t: *Threaded = @ptrCast(@alignCast(userdata));
3648 const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
4274 const current_thread = Thread.getCurrent(t);
4275 const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
36494276 error.OptionUnsupported => return error.Unexpected,
36504277 else => |e| return e,
36514278 };
36524279 errdefer posix.close(socket_fd);
36534280 var storage: UnixAddress = undefined;
36544281 const addr_len = addressUnixToPosix(address, &storage);
3655 try posixConnectUnix(t, socket_fd, &storage.any, addr_len);
4282 try posixConnectUnix(current_thread, socket_fd, &storage.any, addr_len);
36564283 return socket_fd;
36574284}
36584285
......@@ -3662,8 +4289,9 @@ fn netConnectUnixWindows(
36624289) net.UnixAddress.ConnectError!net.Socket.Handle {
36634290 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
36644291 const t: *Threaded = @ptrCast(@alignCast(userdata));
4292 const current_thread = Thread.getCurrent(t);
36654293
3666 const socket_handle = try openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream });
4294 const socket_handle = try openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream });
36674295 errdefer closeSocketWindows(socket_handle);
36684296 var storage: WsaAddress = undefined;
36694297 const addr_len = addressUnixToWsa(address, &storage);
......@@ -3711,13 +4339,14 @@ fn netBindIpPosix(
37114339) IpAddress.BindError!net.Socket {
37124340 if (!have_networking) return error.NetworkDown;
37134341 const t: *Threaded = @ptrCast(@alignCast(userdata));
4342 const current_thread = Thread.getCurrent(t);
37144343 const family = posixAddressFamily(address);
3715 const socket_fd = try openSocketPosix(t, family, options);
4344 const socket_fd = try openSocketPosix(current_thread, family, options);
37164345 errdefer posix.close(socket_fd);
37174346 var storage: PosixAddress = undefined;
37184347 var addr_len = addressToPosix(address, &storage);
3719 try posixBind(t, socket_fd, &storage.any, addr_len);
3720 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);
4348 try posixBind(current_thread, socket_fd, &storage.any, addr_len);
4349 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
37214350 return .{
37224351 .handle = socket_fd,
37234352 .address = addressFromPosix(&storage),
......@@ -3731,8 +4360,9 @@ fn netBindIpWindows(
37314360) IpAddress.BindError!net.Socket {
37324361 if (!have_networking) return error.NetworkDown;
37334362 const t: *Threaded = @ptrCast(@alignCast(userdata));
4363 const current_thread = Thread.getCurrent(t);
37344364 const family = posixAddressFamily(address);
3735 const socket_handle = try openSocketWsa(t, family, .{
4365 const socket_handle = try openSocketWsa(t, current_thread, family, .{
37364366 .mode = options.mode,
37374367 .protocol = options.protocol,
37384368 });
......@@ -3741,29 +4371,41 @@ fn netBindIpWindows(
37414371 var storage: WsaAddress = undefined;
37424372 var addr_len = addressToWsa(address, &storage);
37434373
4374 try current_thread.beginSyscall();
37444375 while (true) {
3745 try t.checkCancel();
37464376 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
3747 if (rc != ws2_32.SOCKET_ERROR) break;
4377 if (rc != ws2_32.SOCKET_ERROR) {
4378 current_thread.endSyscall();
4379 break;
4380 }
37484381 switch (ws2_32.WSAGetLastError()) {
3749 .EINTR => continue,
3750 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4382 .EINTR => {
4383 try current_thread.checkCancel();
4384 continue;
4385 },
37514386 .NOTINITIALISED => {
37524387 try initializeWsa(t);
4388 try current_thread.checkCancel();
37534389 continue;
37544390 },
3755 .EADDRINUSE => return error.AddressInUse,
3756 .EADDRNOTAVAIL => return error.AddressUnavailable,
3757 .ENOTSOCK => |err| return wsaErrorBug(err),
3758 .EFAULT => |err| return wsaErrorBug(err),
3759 .EINVAL => |err| return wsaErrorBug(err),
3760 .ENOBUFS => return error.SystemResources,
3761 .ENETDOWN => return error.NetworkDown,
3762 else => |err| return windows.unexpectedWSAError(err),
4391 else => |e| {
4392 current_thread.endSyscall();
4393 switch (e) {
4394 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4395 .EADDRINUSE => return error.AddressInUse,
4396 .EADDRNOTAVAIL => return error.AddressUnavailable,
4397 .ENOTSOCK => |err| return wsaErrorBug(err),
4398 .EFAULT => |err| return wsaErrorBug(err),
4399 .EINVAL => |err| return wsaErrorBug(err),
4400 .ENOBUFS => return error.SystemResources,
4401 .ENETDOWN => return error.NetworkDown,
4402 else => |err| return windows.unexpectedWSAError(err),
4403 }
4404 },
37634405 }
37644406 }
37654407
3766 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
4408 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
37674409
37684410 return .{
37694411 .handle = socket_handle,
......@@ -3783,7 +4425,7 @@ fn netBindIpUnavailable(
37834425}
37844426
37854427fn openSocketPosix(
3786 t: *Threaded,
4428 current_thread: *Thread,
37874429 family: posix.sa_family_t,
37884430 options: IpAddress.BindOptions,
37894431) error{
......@@ -3800,8 +4442,8 @@ fn openSocketPosix(
38004442}!posix.socket_t {
38014443 const mode = posixSocketMode(options.mode);
38024444 const protocol = posixProtocol(options.protocol);
4445 try current_thread.beginSyscall();
38034446 const socket_fd = while (true) {
3804 try t.checkCancel();
38054447 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
38064448 const socket_rc = posix.system.socket(family, flags, protocol);
38074449 switch (posix.errno(socket_rc)) {
......@@ -3809,60 +4451,90 @@ fn openSocketPosix(
38094451 const fd: posix.fd_t = @intCast(socket_rc);
38104452 errdefer posix.close(fd);
38114453 if (socket_flags_unsupported) while (true) {
3812 try t.checkCancel();
4454 try current_thread.checkCancel();
38134455 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
38144456 .SUCCESS => break,
38154457 .INTR => continue,
3816 .CANCELED => return error.Canceled,
3817 else => |err| return posix.unexpectedErrno(err),
4458 else => |e| {
4459 current_thread.endSyscall();
4460 switch (e) {
4461 .CANCELED => return error.Canceled,
4462 else => |err| return posix.unexpectedErrno(err),
4463 }
4464 },
38184465 }
38194466 };
4467 current_thread.endSyscall();
38204468 break fd;
38214469 },
3822 .INTR => continue,
3823 .CANCELED => return error.Canceled,
3824
3825 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3826 .INVAL => return error.ProtocolUnsupportedBySystem,
3827 .MFILE => return error.ProcessFdQuotaExceeded,
3828 .NFILE => return error.SystemFdQuotaExceeded,
3829 .NOBUFS => return error.SystemResources,
3830 .NOMEM => return error.SystemResources,
3831 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
3832 .PROTOTYPE => return error.SocketModeUnsupported,
3833 else => |err| return posix.unexpectedErrno(err),
4470 .INTR => {
4471 try current_thread.checkCancel();
4472 continue;
4473 },
4474 else => |e| {
4475 current_thread.endSyscall();
4476 switch (e) {
4477 .CANCELED => return error.Canceled,
4478 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4479 .INVAL => return error.ProtocolUnsupportedBySystem,
4480 .MFILE => return error.ProcessFdQuotaExceeded,
4481 .NFILE => return error.SystemFdQuotaExceeded,
4482 .NOBUFS => return error.SystemResources,
4483 .NOMEM => return error.SystemResources,
4484 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
4485 .PROTOTYPE => return error.SocketModeUnsupported,
4486 else => |err| return posix.unexpectedErrno(err),
4487 }
4488 },
38344489 }
38354490 };
38364491 errdefer posix.close(socket_fd);
38374492
38384493 if (options.ip6_only) {
38394494 if (posix.IPV6 == void) return error.OptionUnsupported;
3840 try setSocketOption(t, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
4495 try setSocketOption(current_thread, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
38414496 }
38424497
38434498 return socket_fd;
38444499}
38454500
3846fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.BindOptions) !ws2_32.SOCKET {
4501fn openSocketWsa(
4502 t: *Threaded,
4503 current_thread: *Thread,
4504 family: posix.sa_family_t,
4505 options: IpAddress.BindOptions,
4506) !ws2_32.SOCKET {
38474507 const mode = posixSocketMode(options.mode);
38484508 const protocol = posixProtocol(options.protocol);
38494509 const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
4510 try current_thread.beginSyscall();
38504511 while (true) {
3851 try t.checkCancel();
38524512 const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);
3853 if (rc != ws2_32.INVALID_SOCKET) return rc;
4513 if (rc != ws2_32.INVALID_SOCKET) {
4514 current_thread.endSyscall();
4515 return rc;
4516 }
38544517 switch (ws2_32.WSAGetLastError()) {
3855 .EINTR => continue,
3856 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4518 .EINTR => {
4519 try current_thread.checkCancel();
4520 continue;
4521 },
38574522 .NOTINITIALISED => {
38584523 try initializeWsa(t);
4524 try current_thread.checkCancel();
38594525 continue;
38604526 },
3861 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
3862 .EMFILE => return error.ProcessFdQuotaExceeded,
3863 .ENOBUFS => return error.SystemResources,
3864 .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
3865 else => |err| return windows.unexpectedWSAError(err),
4527 else => |e| {
4528 current_thread.endSyscall();
4529 switch (e) {
4530 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4531 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4532 .EMFILE => return error.ProcessFdQuotaExceeded,
4533 .ENOBUFS => return error.SystemResources,
4534 .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
4535 else => |err| return windows.unexpectedWSAError(err),
4536 }
4537 },
38664538 }
38674539 }
38684540}
......@@ -3870,10 +4542,11 @@ fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.Bin
38704542fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {
38714543 if (!have_networking) return error.NetworkDown;
38724544 const t: *Threaded = @ptrCast(@alignCast(userdata));
4545 const current_thread = Thread.getCurrent(t);
38734546 var storage: PosixAddress = undefined;
38744547 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);
4548 try current_thread.beginSyscall();
38754549 const fd = while (true) {
3876 try t.checkCancel();
38774550 const rc = if (have_accept4)
38784551 posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC)
38794552 else
......@@ -3883,33 +4556,43 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
38834556 const fd: posix.fd_t = @intCast(rc);
38844557 errdefer posix.close(fd);
38854558 if (!have_accept4) while (true) {
3886 try t.checkCancel();
4559 try current_thread.checkCancel();
38874560 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
38884561 .SUCCESS => break,
38894562 .INTR => continue,
3890 .CANCELED => return error.Canceled,
3891 else => |err| return posix.unexpectedErrno(err),
4563 else => |err| {
4564 current_thread.endSyscall();
4565 return posix.unexpectedErrno(err);
4566 },
38924567 }
38934568 };
4569 current_thread.endSyscall();
38944570 break fd;
38954571 },
3896 .INTR => continue,
3897 .CANCELED => return error.Canceled,
3898
3899 .AGAIN => |err| return errnoBug(err),
3900 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3901 .CONNABORTED => return error.ConnectionAborted,
3902 .FAULT => |err| return errnoBug(err),
3903 .INVAL => return error.SocketNotListening,
3904 .NOTSOCK => |err| return errnoBug(err),
3905 .MFILE => return error.ProcessFdQuotaExceeded,
3906 .NFILE => return error.SystemFdQuotaExceeded,
3907 .NOBUFS => return error.SystemResources,
3908 .NOMEM => return error.SystemResources,
3909 .OPNOTSUPP => |err| return errnoBug(err),
3910 .PROTO => return error.ProtocolFailure,
3911 .PERM => return error.BlockedByFirewall,
3912 else => |err| return posix.unexpectedErrno(err),
4572 .INTR => {
4573 try current_thread.checkCancel();
4574 continue;
4575 },
4576 else => |e| {
4577 current_thread.endSyscall();
4578 switch (e) {
4579 .CANCELED => return error.Canceled,
4580 .AGAIN => |err| return errnoBug(err),
4581 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4582 .CONNABORTED => return error.ConnectionAborted,
4583 .FAULT => |err| return errnoBug(err),
4584 .INVAL => return error.SocketNotListening,
4585 .NOTSOCK => |err| return errnoBug(err),
4586 .MFILE => return error.ProcessFdQuotaExceeded,
4587 .NFILE => return error.SystemFdQuotaExceeded,
4588 .NOBUFS => return error.SystemResources,
4589 .NOMEM => return error.SystemResources,
4590 .OPNOTSUPP => |err| return errnoBug(err),
4591 .PROTO => return error.ProtocolFailure,
4592 .PERM => return error.BlockedByFirewall,
4593 else => |err| return posix.unexpectedErrno(err),
4594 }
4595 },
39134596 }
39144597 };
39154598 return .{ .socket = .{
......@@ -3921,31 +4604,44 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
39214604fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream {
39224605 if (!have_networking) return error.NetworkDown;
39234606 const t: *Threaded = @ptrCast(@alignCast(userdata));
4607 const current_thread = Thread.getCurrent(t);
39244608 var storage: WsaAddress = undefined;
39254609 var addr_len: i32 = @sizeOf(WsaAddress);
4610 try current_thread.beginSyscall();
39264611 while (true) {
3927 try t.checkCancel();
39284612 const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);
3929 if (rc != ws2_32.INVALID_SOCKET) return .{ .socket = .{
3930 .handle = rc,
3931 .address = addressFromWsa(&storage),
3932 } };
4613 if (rc != ws2_32.INVALID_SOCKET) {
4614 current_thread.endSyscall();
4615 return .{ .socket = .{
4616 .handle = rc,
4617 .address = addressFromWsa(&storage),
4618 } };
4619 }
39334620 switch (ws2_32.WSAGetLastError()) {
3934 .EINTR => continue,
3935 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4621 .EINTR => {
4622 try current_thread.checkCancel();
4623 continue;
4624 },
39364625 .NOTINITIALISED => {
39374626 try initializeWsa(t);
4627 try current_thread.checkCancel();
39384628 continue;
39394629 },
3940 .ECONNRESET => return error.ConnectionAborted,
3941 .EFAULT => |err| return wsaErrorBug(err),
3942 .ENOTSOCK => |err| return wsaErrorBug(err),
3943 .EINVAL => |err| return wsaErrorBug(err),
3944 .EMFILE => return error.ProcessFdQuotaExceeded,
3945 .ENETDOWN => return error.NetworkDown,
3946 .ENOBUFS => return error.SystemResources,
3947 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3948 else => |err| return windows.unexpectedWSAError(err),
4630 else => |e| {
4631 current_thread.endSyscall();
4632 switch (e) {
4633 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4634 .ECONNRESET => return error.ConnectionAborted,
4635 .EFAULT => |err| return wsaErrorBug(err),
4636 .ENOTSOCK => |err| return wsaErrorBug(err),
4637 .EINVAL => |err| return wsaErrorBug(err),
4638 .EMFILE => return error.ProcessFdQuotaExceeded,
4639 .ENETDOWN => return error.NetworkDown,
4640 .ENOBUFS => return error.SystemResources,
4641 .EOPNOTSUPP => |err| return wsaErrorBug(err),
4642 else => |err| return windows.unexpectedWSAError(err),
4643 }
4644 },
39494645 }
39504646 }
39514647}
......@@ -3959,6 +4655,7 @@ fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle)
39594655fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
39604656 if (!have_networking) return error.NetworkDown;
39614657 const t: *Threaded = @ptrCast(@alignCast(userdata));
4658 const current_thread = Thread.getCurrent(t);
39624659
39634660 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
39644661 var i: usize = 0;
......@@ -3972,48 +4669,70 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
39724669 const dest = iovecs_buffer[0..i];
39734670 assert(dest[0].len > 0);
39744671
3975 if (native_os == .wasi and !builtin.link_libc) while (true) {
3976 try t.checkCancel();
3977 var n: usize = undefined;
3978 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
3979 .SUCCESS => return n,
3980 .INTR => continue,
3981 .CANCELED => return error.Canceled,
3982
3983 .INVAL => |err| return errnoBug(err),
3984 .FAULT => |err| return errnoBug(err),
3985 .AGAIN => |err| return errnoBug(err),
3986 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3987 .NOBUFS => return error.SystemResources,
3988 .NOMEM => return error.SystemResources,
3989 .NOTCONN => return error.SocketUnconnected,
3990 .CONNRESET => return error.ConnectionResetByPeer,
3991 .TIMEDOUT => return error.Timeout,
3992 .NOTCAPABLE => return error.AccessDenied,
3993 else => |err| return posix.unexpectedErrno(err),
4672 if (native_os == .wasi and !builtin.link_libc) {
4673 try current_thread.beginSyscall();
4674 while (true) {
4675 var n: usize = undefined;
4676 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
4677 .SUCCESS => {
4678 current_thread.endSyscall();
4679 return n;
4680 },
4681 .INTR => {
4682 try current_thread.checkCancel();
4683 continue;
4684 },
4685 else => |e| {
4686 current_thread.endSyscall();
4687 switch (e) {
4688 .CANCELED => return error.Canceled,
4689 .INVAL => |err| return errnoBug(err),
4690 .FAULT => |err| return errnoBug(err),
4691 .AGAIN => |err| return errnoBug(err),
4692 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4693 .NOBUFS => return error.SystemResources,
4694 .NOMEM => return error.SystemResources,
4695 .NOTCONN => return error.SocketUnconnected,
4696 .CONNRESET => return error.ConnectionResetByPeer,
4697 .TIMEDOUT => return error.Timeout,
4698 .NOTCAPABLE => return error.AccessDenied,
4699 else => |err| return posix.unexpectedErrno(err),
4700 }
4701 },
4702 }
39944703 }
3995 };
4704 }
39964705
4706 try current_thread.beginSyscall();
39974707 while (true) {
3998 try t.checkCancel();
39994708 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
40004709 switch (posix.errno(rc)) {
4001 .SUCCESS => return @intCast(rc),
4002 .INTR => continue,
4003 .CANCELED => return error.Canceled,
4004
4005 .INVAL => |err| return errnoBug(err),
4006 .FAULT => |err| return errnoBug(err),
4007 .AGAIN => |err| return errnoBug(err),
4008 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4009 .NOBUFS => return error.SystemResources,
4010 .NOMEM => return error.SystemResources,
4011 .NOTCONN => return error.SocketUnconnected,
4012 .CONNRESET => return error.ConnectionResetByPeer,
4013 .TIMEDOUT => return error.Timeout,
4014 .PIPE => return error.SocketUnconnected,
4015 .NETDOWN => return error.NetworkDown,
4016 else => |err| return posix.unexpectedErrno(err),
4710 .SUCCESS => {
4711 current_thread.endSyscall();
4712 return @intCast(rc);
4713 },
4714 .INTR => {
4715 try current_thread.checkCancel();
4716 continue;
4717 },
4718 else => |e| {
4719 current_thread.endSyscall();
4720 switch (e) {
4721 .CANCELED => return error.Canceled,
4722 .INVAL => |err| return errnoBug(err),
4723 .FAULT => |err| return errnoBug(err),
4724 .AGAIN => |err| return errnoBug(err),
4725 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4726 .NOBUFS => return error.SystemResources,
4727 .NOMEM => return error.SystemResources,
4728 .NOTCONN => return error.SocketUnconnected,
4729 .CONNRESET => return error.ConnectionResetByPeer,
4730 .TIMEDOUT => return error.Timeout,
4731 .PIPE => return error.SocketUnconnected,
4732 .NETDOWN => return error.NetworkDown,
4733 else => |err| return posix.unexpectedErrno(err),
4734 }
4735 },
40174736 }
40184737 }
40194738}
......@@ -4021,6 +4740,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
40214740fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
40224741 if (!have_networking) return error.NetworkDown;
40234742 const t: *Threaded = @ptrCast(@alignCast(userdata));
4743 const current_thread = Thread.getCurrent(t);
40244744
40254745 const bufs = b: {
40264746 var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined;
......@@ -4048,7 +4768,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8
40484768 };
40494769
40504770 while (true) {
4051 try t.checkCancel();
4771 try current_thread.checkCancel();
40524772
40534773 var flags: u32 = 0;
40544774 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
......@@ -4108,6 +4828,7 @@ fn netSendPosix(
41084828) struct { ?net.Socket.SendError, usize } {
41094829 if (!have_networking) return .{ error.NetworkDown, 0 };
41104830 const t: *Threaded = @ptrCast(@alignCast(userdata));
4831 const current_thread = Thread.getCurrent(t);
41114832
41124833 const posix_flags: u32 =
41134834 @as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |
......@@ -4120,10 +4841,10 @@ fn netSendPosix(
41204841 var i: usize = 0;
41214842 while (messages.len - i != 0) {
41224843 if (have_sendmmsg) {
4123 i += netSendMany(t, handle, messages[i..], posix_flags) catch |err| return .{ err, i };
4844 i += netSendMany(current_thread, handle, messages[i..], posix_flags) catch |err| return .{ err, i };
41244845 continue;
41254846 }
4126 netSendOne(t, handle, &messages[i], posix_flags) catch |err| return .{ err, i };
4847 netSendOne(t, current_thread, handle, &messages[i], posix_flags) catch |err| return .{ err, i };
41274848 i += 1;
41284849 }
41294850 return .{ null, i };
......@@ -4159,6 +4880,7 @@ fn netSendUnavailable(
41594880
41604881fn netSendOne(
41614882 t: *Threaded,
4883 current_thread: *Thread,
41624884 handle: net.Socket.Handle,
41634885 message: *net.OutgoingMessage,
41644886 flags: u32,
......@@ -4175,75 +4897,92 @@ fn netSendOne(
41754897 .controllen = @intCast(message.control.len),
41764898 .flags = 0,
41774899 };
4900 try current_thread.beginSyscall();
41784901 while (true) {
4179 try t.checkCancel();
41804902 const rc = posix.system.sendmsg(handle, &msg, flags);
41814903 if (is_windows) {
4182 if (rc == ws2_32.SOCKET_ERROR) {
4183 switch (ws2_32.WSAGetLastError()) {
4184 .EINTR => continue,
4185 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4186 .NOTINITIALISED => {
4187 try initializeWsa(t);
4188 continue;
4189 },
4190 .EACCES => return error.AccessDenied,
4191 .EADDRNOTAVAIL => return error.AddressUnavailable,
4192 .ECONNRESET => return error.ConnectionResetByPeer,
4193 .EMSGSIZE => return error.MessageOversize,
4194 .ENOBUFS => return error.SystemResources,
4195 .ENOTSOCK => return error.FileDescriptorNotASocket,
4196 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4197 .EDESTADDRREQ => unreachable, // A destination address is required.
4198 .EFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small.
4199 .EHOSTUNREACH => return error.NetworkUnreachable,
4200 .EINVAL => unreachable,
4201 .ENETDOWN => return error.NetworkDown,
4202 .ENETRESET => return error.ConnectionResetByPeer,
4203 .ENETUNREACH => return error.NetworkUnreachable,
4204 .ENOTCONN => return error.SocketUnconnected,
4205 .ESHUTDOWN => |err| return wsaErrorBug(err),
4206 else => |err| return windows.unexpectedWSAError(err),
4207 }
4208 } else {
4904 if (rc != ws2_32.SOCKET_ERROR) {
4905 current_thread.endSyscall();
42094906 message.data_len = @intCast(rc);
42104907 return;
42114908 }
4909 switch (ws2_32.WSAGetLastError()) {
4910 .EINTR => {
4911 try current_thread.checkCancel();
4912 continue;
4913 },
4914 .NOTINITIALISED => {
4915 try initializeWsa(t);
4916 try current_thread.checkCancel();
4917 continue;
4918 },
4919 else => |e| {
4920 current_thread.endSyscall();
4921 switch (e) {
4922 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4923 .EACCES => return error.AccessDenied,
4924 .EADDRNOTAVAIL => return error.AddressUnavailable,
4925 .ECONNRESET => return error.ConnectionResetByPeer,
4926 .EMSGSIZE => return error.MessageOversize,
4927 .ENOBUFS => return error.SystemResources,
4928 .ENOTSOCK => return error.FileDescriptorNotASocket,
4929 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4930 .EDESTADDRREQ => unreachable, // A destination address is required.
4931 .EFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small.
4932 .EHOSTUNREACH => return error.NetworkUnreachable,
4933 .EINVAL => unreachable,
4934 .ENETDOWN => return error.NetworkDown,
4935 .ENETRESET => return error.ConnectionResetByPeer,
4936 .ENETUNREACH => return error.NetworkUnreachable,
4937 .ENOTCONN => return error.SocketUnconnected,
4938 .ESHUTDOWN => |err| return wsaErrorBug(err),
4939 else => |err| return windows.unexpectedWSAError(err),
4940 }
4941 },
4942 }
42124943 }
42134944 switch (posix.errno(rc)) {
42144945 .SUCCESS => {
4946 current_thread.endSyscall();
42154947 message.data_len = @intCast(rc);
42164948 return;
42174949 },
4218 .INTR => continue,
4219 .CANCELED => return error.Canceled,
4220
4221 .ACCES => return error.AccessDenied,
4222 .ALREADY => return error.FastOpenAlreadyInProgress,
4223 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4224 .CONNRESET => return error.ConnectionResetByPeer,
4225 .DESTADDRREQ => |err| return errnoBug(err),
4226 .FAULT => |err| return errnoBug(err),
4227 .INVAL => |err| return errnoBug(err),
4228 .ISCONN => |err| return errnoBug(err),
4229 .MSGSIZE => return error.MessageOversize,
4230 .NOBUFS => return error.SystemResources,
4231 .NOMEM => return error.SystemResources,
4232 .NOTSOCK => |err| return errnoBug(err),
4233 .OPNOTSUPP => |err| return errnoBug(err),
4234 .PIPE => return error.SocketUnconnected,
4235 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4236 .HOSTUNREACH => return error.HostUnreachable,
4237 .NETUNREACH => return error.NetworkUnreachable,
4238 .NOTCONN => return error.SocketUnconnected,
4239 .NETDOWN => return error.NetworkDown,
4240 else => |err| return posix.unexpectedErrno(err),
4950 .INTR => {
4951 try current_thread.checkCancel();
4952 continue;
4953 },
4954 else => |e| {
4955 current_thread.endSyscall();
4956 switch (e) {
4957 .CANCELED => return error.Canceled,
4958 .ACCES => return error.AccessDenied,
4959 .ALREADY => return error.FastOpenAlreadyInProgress,
4960 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4961 .CONNRESET => return error.ConnectionResetByPeer,
4962 .DESTADDRREQ => |err| return errnoBug(err),
4963 .FAULT => |err| return errnoBug(err),
4964 .INVAL => |err| return errnoBug(err),
4965 .ISCONN => |err| return errnoBug(err),
4966 .MSGSIZE => return error.MessageOversize,
4967 .NOBUFS => return error.SystemResources,
4968 .NOMEM => return error.SystemResources,
4969 .NOTSOCK => |err| return errnoBug(err),
4970 .OPNOTSUPP => |err| return errnoBug(err),
4971 .PIPE => return error.SocketUnconnected,
4972 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4973 .HOSTUNREACH => return error.HostUnreachable,
4974 .NETUNREACH => return error.NetworkUnreachable,
4975 .NOTCONN => return error.SocketUnconnected,
4976 .NETDOWN => return error.NetworkDown,
4977 else => |err| return posix.unexpectedErrno(err),
4978 }
4979 },
42414980 }
42424981 }
42434982}
42444983
42454984fn netSendMany(
4246 t: *Threaded,
4985 current_thread: *Thread,
42474986 handle: net.Socket.Handle,
42484987 messages: []net.OutgoingMessage,
42494988 flags: u32,
......@@ -4273,40 +5012,48 @@ fn netSendMany(
42735012 };
42745013 }
42755014
5015 try current_thread.beginSyscall();
42765016 while (true) {
4277 try t.checkCancel();
42785017 const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags);
42795018 switch (posix.errno(rc)) {
42805019 .SUCCESS => {
5020 current_thread.endSyscall();
42815021 const n: usize = @intCast(rc);
42825022 for (clamped_messages[0..n], clamped_msgs[0..n]) |*message, *msg| {
42835023 message.data_len = msg.len;
42845024 }
42855025 return n;
42865026 },
4287 .INTR => continue,
4288 .CANCELED => return error.Canceled,
4289
4290 .AGAIN => |err| return errnoBug(err),
4291 .ALREADY => return error.FastOpenAlreadyInProgress,
4292 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4293 .CONNRESET => return error.ConnectionResetByPeer,
4294 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
4295 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
4296 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
4297 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
4298 .MSGSIZE => return error.MessageOversize,
4299 .NOBUFS => return error.SystemResources,
4300 .NOMEM => return error.SystemResources,
4301 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
4302 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
4303 .PIPE => return error.SocketUnconnected,
4304 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4305 .HOSTUNREACH => return error.HostUnreachable,
4306 .NETUNREACH => return error.NetworkUnreachable,
4307 .NOTCONN => return error.SocketUnconnected,
4308 .NETDOWN => return error.NetworkDown,
4309 else => |err| return posix.unexpectedErrno(err),
5027 .INTR => {
5028 try current_thread.checkCancel();
5029 continue;
5030 },
5031 else => |e| {
5032 current_thread.endSyscall();
5033 switch (e) {
5034 .CANCELED => return error.Canceled,
5035 .AGAIN => |err| return errnoBug(err),
5036 .ALREADY => return error.FastOpenAlreadyInProgress,
5037 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5038 .CONNRESET => return error.ConnectionResetByPeer,
5039 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
5040 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
5041 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
5042 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
5043 .MSGSIZE => return error.MessageOversize,
5044 .NOBUFS => return error.SystemResources,
5045 .NOMEM => return error.SystemResources,
5046 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
5047 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
5048 .PIPE => return error.SocketUnconnected,
5049 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
5050 .HOSTUNREACH => return error.HostUnreachable,
5051 .NETUNREACH => return error.NetworkUnreachable,
5052 .NOTCONN => return error.SocketUnconnected,
5053 .NETDOWN => return error.NetworkDown,
5054 else => |err| return posix.unexpectedErrno(err),
5055 }
5056 },
43105057 }
43115058 }
43125059}
......@@ -4321,6 +5068,7 @@ fn netReceivePosix(
43215068) struct { ?net.Socket.ReceiveTimeoutError, usize } {
43225069 if (!have_networking) return .{ error.NetworkDown, 0 };
43235070 const t: *Threaded = @ptrCast(@alignCast(userdata));
5071 const current_thread = Thread.getCurrent(t);
43245072 const t_io = io(t);
43255073
43265074 // recvmmsg is useless, here's why:
......@@ -4351,8 +5099,6 @@ fn netReceivePosix(
43515099 const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i };
43525100
43535101 recv: while (true) {
4354 t.checkCancel() catch |err| return .{ err, message_i };
4355
43565102 if (message_buffer.len - message_i == 0) return .{ null, message_i };
43575103 const message = &message_buffer[message_i];
43585104 const remaining_data_buffer = data_buffer[data_i..];
......@@ -4368,7 +5114,9 @@ fn netReceivePosix(
43685114 .flags = undefined,
43695115 };
43705116
5117 current_thread.beginSyscall() catch |err| return .{ err, message_i };
43715118 const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags);
5119 current_thread.endSyscall();
43725120 switch (posix.errno(recv_rc)) {
43735121 .SUCCESS => {
43745122 const data = remaining_data_buffer[0..@intCast(recv_rc)];
......@@ -4389,7 +5137,6 @@ fn netReceivePosix(
43895137 continue;
43905138 },
43915139 .AGAIN => while (true) {
4392 t.checkCancel() catch |err| return .{ err, message_i };
43935140 if (message_i != 0) return .{ null, message_i };
43945141
43955142 const max_poll_ms = std.math.maxInt(u31);
......@@ -4399,7 +5146,10 @@ fn netReceivePosix(
43995146 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
44005147 } else max_poll_ms;
44015148
5149 current_thread.beginSyscall() catch |err| return .{ err, message_i };
44025150 const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
5151 current_thread.endSyscall();
5152
44035153 switch (posix.errno(poll_rc)) {
44045154 .SUCCESS => {
44055155 if (poll_rc == 0) {
......@@ -4486,6 +5236,7 @@ fn netWritePosix(
44865236) net.Stream.Writer.Error!usize {
44875237 if (!have_networking) return error.NetworkDown;
44885238 const t: *Threaded = @ptrCast(@alignCast(userdata));
5239 const current_thread = Thread.getCurrent(t);
44895240
44905241 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;
44915242 var msg: posix.msghdr_const = .{
......@@ -4526,35 +5277,45 @@ fn netWritePosix(
45265277 },
45275278 };
45285279 const flags = posix.MSG.NOSIGNAL;
5280 try current_thread.beginSyscall();
45295281 while (true) {
4530 try t.checkCancel();
45315282 const rc = posix.system.sendmsg(fd, &msg, flags);
45325283 switch (posix.errno(rc)) {
4533 .SUCCESS => return @intCast(rc),
4534 .INTR => continue,
4535 .CANCELED => return error.Canceled,
4536
4537 .ACCES => |err| return errnoBug(err),
4538 .AGAIN => |err| return errnoBug(err),
4539 .ALREADY => return error.FastOpenAlreadyInProgress,
4540 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4541 .CONNRESET => return error.ConnectionResetByPeer,
4542 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
4543 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
4544 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
4545 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
4546 .MSGSIZE => |err| return errnoBug(err),
4547 .NOBUFS => return error.SystemResources,
4548 .NOMEM => return error.SystemResources,
4549 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
4550 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
4551 .PIPE => return error.SocketUnconnected,
4552 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4553 .HOSTUNREACH => return error.HostUnreachable,
4554 .NETUNREACH => return error.NetworkUnreachable,
4555 .NOTCONN => return error.SocketUnconnected,
4556 .NETDOWN => return error.NetworkDown,
4557 else => |err| return posix.unexpectedErrno(err),
5284 .SUCCESS => {
5285 current_thread.endSyscall();
5286 return @intCast(rc);
5287 },
5288 .INTR => {
5289 try current_thread.checkCancel();
5290 continue;
5291 },
5292 else => |e| {
5293 current_thread.endSyscall();
5294 switch (e) {
5295 .CANCELED => return error.Canceled,
5296 .ACCES => |err| return errnoBug(err),
5297 .AGAIN => |err| return errnoBug(err),
5298 .ALREADY => return error.FastOpenAlreadyInProgress,
5299 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5300 .CONNRESET => return error.ConnectionResetByPeer,
5301 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
5302 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
5303 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
5304 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
5305 .MSGSIZE => |err| return errnoBug(err),
5306 .NOBUFS => return error.SystemResources,
5307 .NOMEM => return error.SystemResources,
5308 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
5309 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
5310 .PIPE => return error.SocketUnconnected,
5311 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
5312 .HOSTUNREACH => return error.HostUnreachable,
5313 .NETUNREACH => return error.NetworkUnreachable,
5314 .NOTCONN => return error.SocketUnconnected,
5315 .NETDOWN => return error.NetworkDown,
5316 else => |err| return posix.unexpectedErrno(err),
5317 }
5318 },
45585319 }
45595320 }
45605321}
......@@ -4567,6 +5328,7 @@ fn netWriteWindows(
45675328 splat: usize,
45685329) net.Stream.Writer.Error!usize {
45695330 const t: *Threaded = @ptrCast(@alignCast(userdata));
5331 const current_thread = Thread.getCurrent(t);
45705332 comptime assert(native_os == .windows);
45715333
45725334 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;
......@@ -4600,7 +5362,7 @@ fn netWriteWindows(
46005362 };
46015363
46025364 while (true) {
4603 try t.checkCancel();
5365 try current_thread.checkCancel();
46045366
46055367 var n: u32 = undefined;
46065368 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
......@@ -4707,9 +5469,10 @@ fn netInterfaceNameResolve(
47075469) net.Interface.Name.ResolveError!net.Interface {
47085470 if (!have_networking) return error.InterfaceNotFound;
47095471 const t: *Threaded = @ptrCast(@alignCast(userdata));
5472 const current_thread = Thread.getCurrent(t);
47105473
47115474 if (native_os == .linux) {
4712 const sock_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
5475 const sock_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
47135476 error.ProcessFdQuotaExceeded => return error.SystemResources,
47145477 error.SystemFdQuotaExceeded => return error.SystemResources,
47155478 error.AddressFamilyUnsupported => return error.Unexpected,
......@@ -4726,32 +5489,42 @@ fn netInterfaceNameResolve(
47265489 .ifru = undefined,
47275490 };
47285491
5492 try current_thread.beginSyscall();
47295493 while (true) {
4730 try t.checkCancel();
47315494 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {
4732 .SUCCESS => return .{ .index = @bitCast(ifr.ifru.ivalue) },
4733 .INTR => continue,
4734 .CANCELED => return error.Canceled,
4735
4736 .INVAL => |err| return errnoBug(err), // Bad parameters.
4737 .NOTTY => |err| return errnoBug(err),
4738 .NXIO => |err| return errnoBug(err),
4739 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4740 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
4741 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
4742 .NODEV => return error.InterfaceNotFound,
4743 else => |err| return posix.unexpectedErrno(err),
5495 .SUCCESS => {
5496 current_thread.endSyscall();
5497 return .{ .index = @bitCast(ifr.ifru.ivalue) };
5498 },
5499 .INTR => {
5500 try current_thread.checkCancel();
5501 continue;
5502 },
5503 else => |e| {
5504 current_thread.endSyscall();
5505 switch (e) {
5506 .CANCELED => return error.Canceled,
5507 .INVAL => |err| return errnoBug(err), // Bad parameters.
5508 .NOTTY => |err| return errnoBug(err),
5509 .NXIO => |err| return errnoBug(err),
5510 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5511 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
5512 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
5513 .NODEV => return error.InterfaceNotFound,
5514 else => |err| return posix.unexpectedErrno(err),
5515 }
5516 },
47445517 }
47455518 }
47465519 }
47475520
47485521 if (native_os == .windows) {
4749 try t.checkCancel();
5522 try current_thread.checkCancel();
47505523 @panic("TODO implement netInterfaceNameResolve for Windows");
47515524 }
47525525
47535526 if (builtin.link_libc) {
4754 try t.checkCancel();
5527 try current_thread.checkCancel();
47555528 const index = std.c.if_nametoindex(&name.bytes);
47565529 if (index == 0) return error.InterfaceNotFound;
47575530 return .{ .index = @bitCast(index) };
......@@ -4771,7 +5544,8 @@ fn netInterfaceNameResolveUnavailable(
47715544
47725545fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
47735546 const t: *Threaded = @ptrCast(@alignCast(userdata));
4774 try t.checkCancel();
5547 const current_thread = Thread.getCurrent(t);
5548 try current_thread.checkCancel();
47755549
47765550 if (native_os == .linux) {
47775551 _ = interface;
......@@ -4802,8 +5576,9 @@ fn netLookup(
48025576 options: HostName.LookupOptions,
48035577) void {
48045578 const t: *Threaded = @ptrCast(@alignCast(userdata));
5579 const current_thread = Thread.getCurrent(t);
48055580 const t_io = io(t);
4806 resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, host_name, resolved, options) });
5581 resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, current_thread, host_name, resolved, options) });
48075582}
48085583
48095584fn netLookupUnavailable(
......@@ -4821,6 +5596,7 @@ fn netLookupUnavailable(
48215596
48225597fn netLookupFallible(
48235598 t: *Threaded,
5599 current_thread: *Thread,
48245600 host_name: HostName,
48255601 resolved: *Io.Queue(HostName.LookupResult),
48265602 options: HostName.LookupOptions,
......@@ -4866,7 +5642,7 @@ fn netLookupFallible(
48665642 var res: *ws2_32.ADDRINFOEXW = undefined;
48675643 const timeout: ?*ws2_32.timeval = null;
48685644 while (true) {
4869 try t.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
5645 try current_thread.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
48705646 // TODO make this append to the queue eagerly rather than blocking until
48715647 // the whole thing finishes
48725648 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, cancel_handle));
......@@ -5013,23 +5789,39 @@ fn netLookupFallible(
50135789 .next = null,
50145790 };
50155791 var res: ?*posix.addrinfo = null;
5792 try current_thread.beginSyscall();
50165793 while (true) {
5017 try t.checkCancel();
50185794 switch (posix.system.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
5019 @as(posix.system.EAI, @enumFromInt(0)) => break,
5020 .ADDRFAMILY => return error.AddressFamilyUnsupported,
5021 .AGAIN => return error.NameServerFailure,
5022 .FAIL => return error.NameServerFailure,
5023 .FAMILY => return error.AddressFamilyUnsupported,
5024 .MEMORY => return error.SystemResources,
5025 .NODATA => return error.UnknownHostName,
5026 .NONAME => return error.UnknownHostName,
5795 @as(posix.system.EAI, @enumFromInt(0)) => {
5796 current_thread.endSyscall();
5797 break;
5798 },
50275799 .SYSTEM => switch (posix.errno(-1)) {
5028 .INTR => continue,
5029 .CANCELED => return error.Canceled,
5030 else => |e| return posix.unexpectedErrno(e),
5800 .INTR => {
5801 try current_thread.checkCancel();
5802 continue;
5803 },
5804 else => |e| {
5805 current_thread.endSyscall();
5806 switch (e) {
5807 .CANCELED => return error.Canceled,
5808 else => |inner| return posix.unexpectedErrno(inner),
5809 }
5810 },
5811 },
5812 else => |e| {
5813 current_thread.endSyscall();
5814 switch (e) {
5815 .ADDRFAMILY => return error.AddressFamilyUnsupported,
5816 .AGAIN => return error.NameServerFailure,
5817 .FAIL => return error.NameServerFailure,
5818 .FAMILY => return error.AddressFamilyUnsupported,
5819 .MEMORY => return error.SystemResources,
5820 .NODATA => return error.UnknownHostName,
5821 .NONAME => return error.UnknownHostName,
5822 else => return error.Unexpected,
5823 }
50315824 },
5032 else => return error.Unexpected,
50335825 }
50345826 }
50355827 defer if (res) |some| posix.system.freeaddrinfo(some);
......@@ -5726,12 +6518,12 @@ fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) Hos
57266518/// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention)
57276519const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11;
57286520
5729fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {
6521fn futexWait(current_thread: *Thread, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {
57306522 @branchHint(.cold);
57316523
57326524 if (builtin.cpu.arch.isWasm()) {
57336525 comptime assert(builtin.cpu.has(.wasm, .atomics));
5734 try t.checkCancel();
6526 try current_thread.checkCancel();
57356527 const timeout: i64 = -1;
57366528 const signed_expect: i32 = @bitCast(expect);
57376529 const result = asm volatile (
......@@ -5754,8 +6546,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
57546546 } else switch (native_os) {
57556547 .linux => {
57566548 const linux = std.os.linux;
5757 try t.checkCancel();
6549 try current_thread.beginSyscall();
57586550 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
6551 current_thread.endSyscall();
57596552 if (is_debug) switch (linux.errno(rc)) {
57606553 .SUCCESS => {}, // notified by `wake()`
57616554 .INTR => {}, // gives caller a chance to check cancellation
......@@ -5772,11 +6565,12 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
57726565 .op = .COMPARE_AND_WAIT,
57736566 .NO_ERRNO = true,
57746567 };
5775 try t.checkCancel();
6568 try current_thread.beginSyscall();
57766569 const status = if (darwin_supports_ulock_wait2)
57776570 c.__ulock_wait2(flags, ptr, expect, 0, 0)
57786571 else
57796572 c.__ulock_wait(flags, ptr, expect, 0);
6573 current_thread.endSyscall();
57806574
57816575 if (status >= 0) return;
57826576
......@@ -5791,7 +6585,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
57916585 };
57926586 },
57936587 .windows => {
5794 try t.checkCancel();
6588 try current_thread.checkCancel();
57956589 switch (windows.ntdll.RtlWaitOnAddress(ptr, &expect, @sizeOf(@TypeOf(expect)), null)) {
57966590 .SUCCESS => {},
57976591 .CANCELLED => return error.Canceled,
......@@ -5800,8 +6594,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
58006594 },
58016595 .freebsd => {
58026596 const flags = @intFromEnum(std.c.UMTX_OP.WAIT_UINT_PRIVATE);
5803 try t.checkCancel();
6597 try current_thread.beginSyscall();
58046598 const rc = std.c._umtx_op(@intFromPtr(&ptr.raw), flags, @as(c_ulong, expect), 0, 0);
6599 current_thread.endSyscall();
58056600 if (is_debug) switch (posix.errno(rc)) {
58066601 .SUCCESS => {},
58076602 .FAULT => unreachable, // one of the args points to invalid memory
......@@ -6050,8 +6845,9 @@ const ResetEventFutex = enum(u32) {
60506845 if (state == .unset) {
60516846 state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting;
60526847 }
6848 const current_thread = Thread.getCurrent(t);
60536849 while (state == .waiting) {
6054 try futexWait(t, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
6850 try futexWait(current_thread, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
60556851 state = @atomicLoad(ResetEventFutex, ref, .acquire);
60566852 }
60576853 assert(state == .is_set);
......@@ -6140,6 +6936,7 @@ const ResetEventPosix = struct {
61406936 .waiting => unreachable, // Invalid state.
61416937 .is_set => return,
61426938 };
6939 const current_thread = Thread.getCurrent(t);
61436940 assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS);
61446941 defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS);
61456942 sw: switch (rep.state) {
......@@ -6148,8 +6945,9 @@ const ResetEventPosix = struct {
61486945 continue :sw .waiting;
61496946 },
61506947 .waiting => {
6151 try t.checkCancel();
6948 try current_thread.beginSyscall();
61526949 assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS);
6950 current_thread.endSyscall();
61536951 continue :sw rep.state;
61546952 },
61556953 .is_set => return,
......@@ -6222,10 +7020,10 @@ const Wsa = struct {
62227020 } || Io.UnexpectedError;
62237021};
62247022
6225fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
7023fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
62267024 const t_io = io(t);
62277025 const wsa = &t.wsa;
6228 wsa.mutex.lockUncancelable(t_io);
7026 try wsa.mutex.lock(t_io);
62297027 defer wsa.mutex.unlock(t_io);
62307028 switch (wsa.status) {
62317029 .uninitialized => {
......@@ -6237,12 +7035,15 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
62377035 wsa.status = .initialized;
62387036 return;
62397037 },
6240 else => |err_int| switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
6241 .SYSNOTREADY => wsa.init_error = error.NetworkDown,
6242 .VERNOTSUPPORTED => wsa.init_error = error.VersionUnsupported,
6243 .EINPROGRESS => wsa.init_error = error.BlockingOperationInProgress,
6244 .EPROCLIM => wsa.init_error = error.ProcessFdQuotaExceeded,
6245 else => |err| wsa.init_error = windows.unexpectedWSAError(err),
7038 else => |err_int| {
7039 wsa.status = .failure;
7040 wsa.init_error = switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
7041 .SYSNOTREADY => error.NetworkDown,
7042 .VERNOTSUPPORTED => error.VersionUnsupported,
7043 .EINPROGRESS => error.BlockingOperationInProgress,
7044 .EPROCLIM => error.ProcessFdQuotaExceeded,
7045 else => |err| windows.unexpectedWSAError(err),
7046 };
62467047 },
62477048 }
62487049 },