authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-02 17:58:29+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-02 17:58:29+01:00
log52ad126bb4720ff894e994ff890532e7fc7b3364
treee018d8ea82b13a0b1a73c04b4688adecc963e3a4
parent95f93a0b281e32583edef36808231a5f61fb7de1
parentbb3f56d5d5424c7be42132c047a7146e82b49c74

Merge pull request 'std.Io.Threaded: rework cancellation' (#30033) from cancellation into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30033

7 files changed, 2019 insertions(+), 1201 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+1984-1161
......@@ -50,6 +50,19 @@ 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,
55/// When a cancel request is made, blocking syscalls can be unblocked by
56/// issuing a signal. However, if the signal arrives after the check and before
57/// the syscall instruction, it is missed.
58///
59/// This option solves the race condition by retrying the signal delivery
60/// until it is acknowledged, with an exponential backoff.
61///
62/// Unfortunately, trying again until the cancellation request is acknowledged
63/// has been observed to be relatively slow, and usually strong cancellation
64/// guarantees are not needed, so this defaults to off.
65robust_cancel: RobustCancel = .disabled,
5366
5467wsa: if (is_windows) Wsa else struct {} = .{},
5568
......@@ -57,7 +70,92 @@ have_signal_handler: bool,
5770old_sig_io: if (have_sig_io) posix.Sigaction else void,
5871old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void,
5972
60threadlocal var current_closure: ?*Closure = null;
73pub const RobustCancel = if (std.Thread.use_pthreads or native_os == .linux) enum {
74 enabled,
75 disabled,
76} else enum {
77 disabled,
78};
79
80pub const Pid = if (native_os == .linux) enum(posix.pid_t) {
81 unknown = 0,
82 _,
83} else enum(u0) { unknown = 0 };
84
85const Thread = struct {
86 /// The value that needs to be passed to pthread_kill or tgkill in order to
87 /// send a signal.
88 signal_id: SignaleeId,
89 current_closure: ?*Closure = null,
90
91 const SignaleeId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;
92
93 threadlocal var current: ?*Thread = null;
94
95 fn getCurrent(t: *Threaded) *Thread {
96 return current orelse return &t.main_thread;
97 }
98
99 fn checkCancel(thread: *Thread) error{Canceled}!void {
100 const closure = thread.current_closure orelse return;
101 switch (@cmpxchgStrong(
102 CancelStatus,
103 &closure.cancel_status,
104 .requested,
105 .acknowledged,
106 .acq_rel,
107 .acquire,
108 ) orelse return error.Canceled) {
109 .requested => unreachable,
110 .acknowledged => unreachable,
111 .none, _ => {},
112 }
113 }
114
115 fn beginSyscall(thread: *Thread) error{Canceled}!void {
116 const closure = thread.current_closure orelse return;
117
118 switch (@cmpxchgStrong(
119 CancelStatus,
120 &closure.cancel_status,
121 .none,
122 .fromSignaleeId(thread.signal_id),
123 .acq_rel,
124 .acquire,
125 ) orelse return) {
126 .none => unreachable,
127 .requested => {
128 @atomicStore(CancelStatus, &closure.cancel_status, .acknowledged, .release);
129 return error.Canceled;
130 },
131 .acknowledged => return,
132 _ => unreachable,
133 }
134 }
135
136 fn endSyscall(thread: *Thread) void {
137 const closure = thread.current_closure orelse return;
138 _ = @cmpxchgStrong(
139 CancelStatus,
140 &closure.cancel_status,
141 .fromSignaleeId(thread.signal_id),
142 .none,
143 .acq_rel,
144 .acquire,
145 ) orelse return;
146 }
147
148 fn endSyscallCanceled(thread: *Thread) Io.Cancelable {
149 if (thread.current_closure) |closure| {
150 @atomicStore(CancelStatus, &closure.cancel_status, .acknowledged, .release);
151 }
152 return error.Canceled;
153 }
154
155 fn currentSignalId() SignaleeId {
156 return if (std.Thread.use_pthreads) std.c.pthread_self() else std.Thread.getCurrentId();
157 }
158};
61159
62160const max_iovecs_len = 8;
63161const splat_buffer_size = 64;
......@@ -66,48 +164,110 @@ comptime {
66164 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
67165}
68166
69const CancelId = enum(usize) {
167const CancelStatus = enum(usize) {
168 /// Cancellation has neither been requested, nor checked. The async
169 /// operation will check status before entering a blocking syscall.
170 /// This is also the status used for uninteruptible tasks.
70171 none = 0,
71 canceling = std.math.maxInt(usize),
172 /// Cancellation has been requested and the status will be checked before
173 /// entering a blocking syscall.
174 requested = std.math.maxInt(usize) - 1,
175 /// Cancellation has been acknowledged and is in progress. Signals should
176 /// not be sent.
177 acknowledged = std.math.maxInt(usize),
178 /// Stores a `Thread.SignaleeId` and indicates that sending a signal to this thread
179 /// is needed in order to cancel. This state is set before going into
180 /// a blocking operation that needs to get unblocked via signal.
72181 _,
73182
74 const ThreadId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;
183 const Unpacked = union(enum) {
184 none,
185 requested,
186 acknowledged,
187 signal_id: Thread.SignaleeId,
188 };
75189
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 }
190 fn unpack(cs: CancelStatus) Unpacked {
191 return switch (cs) {
192 .none => .none,
193 .requested => .requested,
194 .acknowledged => .acknowledged,
195 _ => |signal_id| .{
196 .signal_id = if (std.Thread.use_pthreads)
197 @ptrFromInt(@intFromEnum(signal_id))
198 else
199 @truncate(@intFromEnum(signal_id)),
200 },
201 };
82202 }
83203
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 }
204 fn fromSignaleeId(signal_id: Thread.SignaleeId) CancelStatus {
205 return if (std.Thread.use_pthreads)
206 @enumFromInt(@intFromPtr(signal_id))
207 else
208 @enumFromInt(signal_id);
90209 }
91210};
92211
93212const Closure = struct {
94213 start: Start,
95214 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 },
215 cancel_status: CancelStatus,
216
217 const Start = *const fn (*Closure, *Threaded) void;
218
219 fn requestCancel(closure: *Closure, t: *Threaded) void {
220 var signal_id = switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
221 .none, .acknowledged, .requested => return,
222 .signal_id => |signal_id| signal_id,
223 };
224 // The task will enter a blocking syscall before checking for cancellation again.
225 // We can send a signal to interrupt the syscall, but if it arrives before
226 // the syscall instruction, it will be missed. Therefore, this code tries
227 // again until the cancellation request is acknowledged.
228
229 // 1 << 10 ns is about 1 microsecond, approximately syscall overhead.
230 // 1 << 20 ns is about 1 millisecond.
231 // 1 << 30 ns is about 1 second.
232 //
233 // On a heavily loaded Linux 6.17.5, I observed a maximum of 20
234 // attempts not acknowledged before the timeout (including exponential
235 // backoff) was sufficient, despite the heavy load.
236 const max_attempts = 22;
237
238 for (0..max_attempts) |attempt_index| {
239 if (std.Thread.use_pthreads) {
240 if (std.c.pthread_kill(signal_id, .IO) != 0) return;
241 } else if (native_os == .linux) {
242 const pid: posix.pid_t = p: {
243 const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
244 if (cached_pid != .unknown) break :p @intFromEnum(cached_pid);
245 const pid = std.os.linux.getpid();
246 @atomicStore(Pid, &t.pid, @enumFromInt(pid), .monotonic);
247 break :p pid;
248 };
249 if (std.os.linux.tgkill(pid, @bitCast(signal_id), .IO) != 0) return;
250 } else {
251 return;
252 }
253
254 if (t.robust_cancel != .enabled) return;
255
256 var timespec: posix.timespec = .{
257 .sec = 0,
258 .nsec = @as(isize, 1) << @intCast(attempt_index),
259 };
260 if (native_os == .linux) {
261 _ = std.os.linux.clock_nanosleep(posix.CLOCK.MONOTONIC, .{ .ABSTIME = false }, &timespec, &timespec);
262 } else {
263 _ = posix.system.nanosleep(&timespec, &timespec);
264 }
265
266 switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
267 .requested => continue, // Retry needed in case other thread hasn't yet entered the syscall.
268 .none, .acknowledged => return,
269 .signal_id => |new_signal_id| signal_id = new_signal_id,
270 }
111271 }
112272 }
113273};
......@@ -136,6 +296,9 @@ pub fn init(
136296 .old_sig_io = undefined,
137297 .old_sig_pipe = undefined,
138298 .have_signal_handler = false,
299 .main_thread = .{
300 .signal_id = Thread.currentSignalId(),
301 },
139302 };
140303
141304 if (posix.Sigaction != void) {
......@@ -169,6 +332,7 @@ pub const init_single_threaded: Threaded = .{
169332 .old_sig_io = undefined,
170333 .old_sig_pipe = undefined,
171334 .have_signal_handler = false,
335 .main_thread = .{ .signal_id = undefined },
172336};
173337
174338pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {
......@@ -201,6 +365,11 @@ fn join(t: *Threaded) void {
201365}
202366
203367fn worker(t: *Threaded) void {
368 var thread: Thread = .{
369 .signal_id = Thread.currentSignalId(),
370 };
371 Thread.current = &thread;
372
204373 defer t.wait_group.finish();
205374
206375 t.mutex.lock();
......@@ -210,7 +379,7 @@ fn worker(t: *Threaded) void {
210379 while (t.run_queue.popFirst()) |closure_node| {
211380 t.mutex.unlock();
212381 const closure: *Closure = @fieldParentPtr("node", closure_node);
213 closure.start(closure);
382 closure.start(closure, t);
214383 t.mutex.lock();
215384 t.busy_count -= 1;
216385 }
......@@ -227,7 +396,6 @@ pub fn io(t: *Threaded) Io {
227396 .concurrent = concurrent,
228397 .await = await,
229398 .cancel = cancel,
230 .cancelRequested = cancelRequested,
231399 .select = select,
232400
233401 .groupAsync = groupAsync,
......@@ -324,7 +492,6 @@ pub fn ioBasic(t: *Threaded) Io {
324492 .concurrent = concurrent,
325493 .await = await,
326494 .cancel = cancel,
327 .cancelRequested = cancelRequested,
328495 .select = select,
329496
330497 .groupAsync = groupAsync,
......@@ -418,24 +585,12 @@ const AsyncClosure = struct {
418585
419586 const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent));
420587
421 fn start(closure: *Closure) void {
588 fn start(closure: *Closure, t: *Threaded) void {
422589 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;
590 const current_thread = Thread.getCurrent(t);
591 current_thread.current_closure = closure;
431592 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 }
593 current_thread.current_closure = null;
439594
440595 if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| {
441596 assert(select_reset != done_reset_event);
......@@ -476,7 +631,7 @@ const AsyncClosure = struct {
476631 const actual_result_offset = actual_result_addr - @intFromPtr(ac);
477632 ac.* = .{
478633 .closure = .{
479 .cancel_tid = .none,
634 .cancel_status = .none,
480635 .start = start,
481636 },
482637 .func = func,
......@@ -493,7 +648,7 @@ const AsyncClosure = struct {
493648 fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void {
494649 ac.reset_event.wait(t) catch |err| switch (err) {
495650 error.Canceled => {
496 ac.closure.requestCancel();
651 ac.closure.requestCancel(t);
497652 ac.reset_event.waitUncancelable();
498653 },
499654 };
......@@ -604,7 +759,6 @@ fn concurrent(
604759
605760const GroupClosure = struct {
606761 closure: Closure,
607 t: *Threaded,
608762 group: *Io.Group,
609763 /// Points to sibling `GroupClosure`. Used for walking the group to cancel all.
610764 node: std.SinglyLinkedList.Node,
......@@ -612,26 +766,15 @@ const GroupClosure = struct {
612766 context_alignment: Alignment,
613767 alloc_len: usize,
614768
615 fn start(closure: *Closure) void {
769 fn start(closure: *Closure, t: *Threaded) void {
616770 const gc: *GroupClosure = @alignCast(@fieldParentPtr("closure", closure));
617 const tid: CancelId = .currentThread();
771 const current_thread = Thread.getCurrent(t);
618772 const group = gc.group;
619773 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);
620774 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;
775 current_thread.current_closure = closure;
627776 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 }
777 current_thread.current_closure = null;
635778
636779 const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel);
637780 assert((prev_state / sync_one_pending) > 0);
......@@ -647,7 +790,6 @@ const GroupClosure = struct {
647790 /// Does not initialize the `node` field.
648791 fn init(
649792 gpa: Allocator,
650 t: *Threaded,
651793 group: *Io.Group,
652794 context: []const u8,
653795 context_alignment: Alignment,
......@@ -662,10 +804,9 @@ const GroupClosure = struct {
662804
663805 gc.* = .{
664806 .closure = .{
665 .cancel_tid = .none,
807 .cancel_status = .none,
666808 .start = start,
667809 },
668 .t = t,
669810 .group = group,
670811 .node = undefined,
671812 .func = func,
......@@ -696,7 +837,7 @@ fn groupAsync(
696837 if (builtin.single_threaded) return start(group, context.ptr);
697838
698839 const gpa = t.allocator;
699 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch
840 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
700841 return start(group, context.ptr);
701842
702843 t.mutex.lock();
......@@ -752,7 +893,7 @@ fn groupConcurrent(
752893 const t: *Threaded = @ptrCast(@alignCast(userdata));
753894
754895 const gpa = t.allocator;
755 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch
896 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
756897 return error.ConcurrencyUnavailable;
757898
758899 t.mutex.lock();
......@@ -806,7 +947,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
806947 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
807948 while (true) {
808949 const gc: *GroupClosure = @fieldParentPtr("node", node);
809 gc.closure.requestCancel();
950 gc.closure.requestCancel(t);
810951 node = node.next orelse break;
811952 }
812953 reset_event.waitUncancelable();
......@@ -832,7 +973,7 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void
832973 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
833974 while (true) {
834975 const gc: *GroupClosure = @fieldParentPtr("node", node);
835 gc.closure.requestCancel();
976 gc.closure.requestCancel(t);
836977 node = node.next orelse break;
837978 }
838979 }
......@@ -875,30 +1016,20 @@ fn cancel(
8751016 _ = result_alignment;
8761017 const t: *Threaded = @ptrCast(@alignCast(userdata));
8771018 const ac: *AsyncClosure = @ptrCast(@alignCast(any_future));
878 ac.closure.requestCancel();
1019 ac.closure.requestCancel(t);
8791020 ac.waitAndDeinit(t, result);
8801021}
8811022
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
8931023fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {
8941024 if (builtin.single_threaded) unreachable; // Interface should have prevented this.
8951025 if (native_os == .netbsd) @panic("TODO");
8961026 const t: *Threaded = @ptrCast(@alignCast(userdata));
1027 const current_thread = Thread.getCurrent(t);
8971028 if (prev_state == .contended) {
898 try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
1029 try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
8991030 }
9001031 while (@atomicRmw(Io.Mutex.State, &mutex.state, .Xchg, .contended, .acquire) != .unlocked) {
901 try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
1032 try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
9021033 }
9031034}
9041035
......@@ -960,6 +1091,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
9601091 if (builtin.single_threaded) unreachable; // Deadlock.
9611092 if (native_os == .netbsd) @panic("TODO");
9621093 const t: *Threaded = @ptrCast(@alignCast(userdata));
1094 const current_thread = Thread.getCurrent(t);
9631095 const t_io = ioBasic(t);
9641096 comptime assert(@TypeOf(cond.state) == u64);
9651097 const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state);
......@@ -988,7 +1120,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
9881120 defer mutex.lockUncancelable(t_io);
9891121
9901122 while (true) {
991 try futexWait(t, cond_epoch, epoch);
1123 try futexWait(current_thread, cond_epoch, epoch);
9921124
9931125 epoch = cond_epoch.load(.acquire);
9941126 state = cond_state.load(.monotonic);
......@@ -1074,35 +1206,46 @@ const dirMake = switch (native_os) {
10741206
10751207fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
10761208 const t: *Threaded = @ptrCast(@alignCast(userdata));
1209 const current_thread = Thread.getCurrent(t);
10771210
10781211 var path_buffer: [posix.PATH_MAX]u8 = undefined;
10791212 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
10801213
1214 try current_thread.beginSyscall();
10811215 while (true) {
1082 try t.checkCancel();
10831216 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),
1217 .SUCCESS => {
1218 current_thread.endSyscall();
1219 return;
1220 },
1221 .INTR => {
1222 try current_thread.checkCancel();
1223 continue;
1224 },
1225 .CANCELED => return current_thread.endSyscallCanceled(),
1226 else => |e| {
1227 current_thread.endSyscall();
1228 switch (e) {
1229 .ACCES => return error.AccessDenied,
1230 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1231 .PERM => return error.PermissionDenied,
1232 .DQUOT => return error.DiskQuota,
1233 .EXIST => return error.PathAlreadyExists,
1234 .FAULT => |err| return errnoBug(err),
1235 .LOOP => return error.SymLinkLoop,
1236 .MLINK => return error.LinkQuotaExceeded,
1237 .NAMETOOLONG => return error.NameTooLong,
1238 .NOENT => return error.FileNotFound,
1239 .NOMEM => return error.SystemResources,
1240 .NOSPC => return error.NoSpaceLeft,
1241 .NOTDIR => return error.NotDir,
1242 .ROFS => return error.ReadOnlyFileSystem,
1243 // dragonfly: when dir_fd is unlinked from filesystem
1244 .NOTCONN => return error.FileNotFound,
1245 .ILSEQ => return error.BadPathName,
1246 else => |err| return posix.unexpectedErrno(err),
1247 }
1248 },
11061249 }
11071250 }
11081251}
......@@ -1110,37 +1253,49 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode:
11101253fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
11111254 if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode);
11121255 const t: *Threaded = @ptrCast(@alignCast(userdata));
1256 const current_thread = Thread.getCurrent(t);
1257 try current_thread.beginSyscall();
11131258 while (true) {
1114 try t.checkCancel();
11151259 switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) {
1116 .SUCCESS => return,
1117 .INTR => continue,
1118 .CANCELED => return error.Canceled,
1119
1120 .ACCES => return error.AccessDenied,
1121 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1122 .PERM => return error.PermissionDenied,
1123 .DQUOT => return error.DiskQuota,
1124 .EXIST => return error.PathAlreadyExists,
1125 .FAULT => |err| return errnoBug(err),
1126 .LOOP => return error.SymLinkLoop,
1127 .MLINK => return error.LinkQuotaExceeded,
1128 .NAMETOOLONG => return error.NameTooLong,
1129 .NOENT => return error.FileNotFound,
1130 .NOMEM => return error.SystemResources,
1131 .NOSPC => return error.NoSpaceLeft,
1132 .NOTDIR => return error.NotDir,
1133 .ROFS => return error.ReadOnlyFileSystem,
1134 .NOTCAPABLE => return error.AccessDenied,
1135 .ILSEQ => return error.BadPathName,
1136 else => |err| return posix.unexpectedErrno(err),
1260 .SUCCESS => {
1261 current_thread.endSyscall();
1262 return;
1263 },
1264 .INTR => {
1265 try current_thread.checkCancel();
1266 continue;
1267 },
1268 .CANCELED => return current_thread.endSyscallCanceled(),
1269 else => |e| {
1270 current_thread.endSyscall();
1271 switch (e) {
1272 .ACCES => return error.AccessDenied,
1273 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1274 .PERM => return error.PermissionDenied,
1275 .DQUOT => return error.DiskQuota,
1276 .EXIST => return error.PathAlreadyExists,
1277 .FAULT => |err| return errnoBug(err),
1278 .LOOP => return error.SymLinkLoop,
1279 .MLINK => return error.LinkQuotaExceeded,
1280 .NAMETOOLONG => return error.NameTooLong,
1281 .NOENT => return error.FileNotFound,
1282 .NOMEM => return error.SystemResources,
1283 .NOSPC => return error.NoSpaceLeft,
1284 .NOTDIR => return error.NotDir,
1285 .ROFS => return error.ReadOnlyFileSystem,
1286 .NOTCAPABLE => return error.AccessDenied,
1287 .ILSEQ => return error.BadPathName,
1288 else => |err| return posix.unexpectedErrno(err),
1289 }
1290 },
11371291 }
11381292 }
11391293}
11401294
11411295fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
11421296 const t: *Threaded = @ptrCast(@alignCast(userdata));
1143 try t.checkCancel();
1297 const current_thread = Thread.getCurrent(t);
1298 try current_thread.checkCancel();
11441299
11451300 const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
11461301 _ = mode;
......@@ -1213,6 +1368,7 @@ fn dirMakeOpenPathWindows(
12131368 options: Io.Dir.OpenOptions,
12141369) Io.Dir.MakeOpenPathError!Io.Dir {
12151370 const t: *Threaded = @ptrCast(@alignCast(userdata));
1371 const current_thread = Thread.getCurrent(t);
12161372 const w = windows;
12171373 const access_mask = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
12181374 w.SYNCHRONIZE | w.FILE_TRAVERSE |
......@@ -1226,7 +1382,7 @@ fn dirMakeOpenPathWindows(
12261382 };
12271383
12281384 while (true) {
1229 try t.checkCancel();
1385 try current_thread.checkCancel();
12301386
12311387 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, component.path);
12321388 const sub_path_w = sub_path_w_array.span();
......@@ -1328,8 +1484,7 @@ fn dirMakeOpenPathWasi(
13281484
13291485fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
13301486 const t: *Threaded = @ptrCast(@alignCast(userdata));
1331 try t.checkCancel();
1332
1487 _ = t;
13331488 _ = dir;
13341489 @panic("TODO implement dirStat");
13351490}
......@@ -1348,6 +1503,7 @@ fn dirStatPathLinux(
13481503 options: Io.Dir.StatPathOptions,
13491504) Io.Dir.StatPathError!Io.File.Stat {
13501505 const t: *Threaded = @ptrCast(@alignCast(userdata));
1506 const current_thread = Thread.getCurrent(t);
13511507 const linux = std.os.linux;
13521508
13531509 var path_buffer: [posix.PATH_MAX]u8 = undefined;
......@@ -1356,8 +1512,8 @@ fn dirStatPathLinux(
13561512 const flags: u32 = linux.AT.NO_AUTOMOUNT |
13571513 @as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);
13581514
1515 try current_thread.beginSyscall();
13591516 while (true) {
1360 try t.checkCancel();
13611517 var statx = std.mem.zeroes(linux.Statx);
13621518 const rc = linux.statx(
13631519 dir.handle,
......@@ -1367,20 +1523,30 @@ fn dirStatPathLinux(
13671523 &statx,
13681524 );
13691525 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),
1526 .SUCCESS => {
1527 current_thread.endSyscall();
1528 return statFromLinux(&statx);
1529 },
1530 .INTR => {
1531 try current_thread.checkCancel();
1532 continue;
1533 },
1534 .CANCELED => return current_thread.endSyscallCanceled(),
1535 else => |e| {
1536 current_thread.endSyscall();
1537 switch (e) {
1538 .ACCES => return error.AccessDenied,
1539 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1540 .FAULT => |err| return errnoBug(err),
1541 .INVAL => |err| return errnoBug(err),
1542 .LOOP => return error.SymLinkLoop,
1543 .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.
1544 .NOENT => return error.FileNotFound,
1545 .NOTDIR => return error.NotDir,
1546 .NOMEM => return error.SystemResources,
1547 else => |err| return posix.unexpectedErrno(err),
1548 }
1549 },
13841550 }
13851551 }
13861552}
......@@ -1392,32 +1558,43 @@ fn dirStatPathPosix(
13921558 options: Io.Dir.StatPathOptions,
13931559) Io.Dir.StatPathError!Io.File.Stat {
13941560 const t: *Threaded = @ptrCast(@alignCast(userdata));
1561 const current_thread = Thread.getCurrent(t);
13951562
13961563 var path_buffer: [posix.PATH_MAX]u8 = undefined;
13971564 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
13981565
13991566 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
14001567
1568 try current_thread.beginSyscall();
14011569 while (true) {
1402 try t.checkCancel();
14031570 var stat = std.mem.zeroes(posix.Stat);
14041571 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),
1572 .SUCCESS => {
1573 current_thread.endSyscall();
1574 return statFromPosix(&stat);
1575 },
1576 .INTR => {
1577 try current_thread.checkCancel();
1578 continue;
1579 },
1580 .CANCELED => return current_thread.endSyscallCanceled(),
1581 else => |e| {
1582 current_thread.endSyscall();
1583 switch (e) {
1584 .INVAL => |err| return errnoBug(err),
1585 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1586 .NOMEM => return error.SystemResources,
1587 .ACCES => return error.AccessDenied,
1588 .PERM => return error.PermissionDenied,
1589 .FAULT => |err| return errnoBug(err),
1590 .NAMETOOLONG => return error.NameTooLong,
1591 .LOOP => return error.SymLinkLoop,
1592 .NOENT => return error.FileNotFound,
1593 .NOTDIR => return error.FileNotFound,
1594 .ILSEQ => return error.BadPathName,
1595 else => |err| return posix.unexpectedErrno(err),
1596 }
1597 },
14211598 }
14221599 }
14231600}
......@@ -1444,29 +1621,40 @@ fn dirStatPathWasi(
14441621) Io.Dir.StatPathError!Io.File.Stat {
14451622 if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);
14461623 const t: *Threaded = @ptrCast(@alignCast(userdata));
1624 const current_thread = Thread.getCurrent(t);
14471625 const wasi = std.os.wasi;
14481626 const flags: wasi.lookupflags_t = .{
14491627 .SYMLINK_FOLLOW = options.follow_symlinks,
14501628 };
14511629 var stat: wasi.filestat_t = undefined;
1630 try current_thread.beginSyscall();
14521631 while (true) {
1453 try t.checkCancel();
14541632 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),
1633 .SUCCESS => {
1634 current_thread.endSyscall();
1635 return statFromWasi(&stat);
1636 },
1637 .INTR => {
1638 try current_thread.checkCancel();
1639 continue;
1640 },
1641 .CANCELED => return current_thread.endSyscallCanceled(),
1642 else => |e| {
1643 current_thread.endSyscall();
1644 switch (e) {
1645 .INVAL => |err| return errnoBug(err),
1646 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1647 .NOMEM => return error.SystemResources,
1648 .ACCES => return error.AccessDenied,
1649 .FAULT => |err| return errnoBug(err),
1650 .NAMETOOLONG => return error.NameTooLong,
1651 .NOENT => return error.FileNotFound,
1652 .NOTDIR => return error.FileNotFound,
1653 .NOTCAPABLE => return error.AccessDenied,
1654 .ILSEQ => return error.BadPathName,
1655 else => |err| return posix.unexpectedErrno(err),
1656 }
1657 },
14701658 }
14711659 }
14721660}
......@@ -1480,31 +1668,44 @@ const fileStat = switch (native_os) {
14801668
14811669fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
14821670 const t: *Threaded = @ptrCast(@alignCast(userdata));
1671 const current_thread = Thread.getCurrent(t);
14831672
14841673 if (posix.Stat == void) return error.Streaming;
14851674
1675 try current_thread.beginSyscall();
14861676 while (true) {
1487 try t.checkCancel();
14881677 var stat = std.mem.zeroes(posix.Stat);
14891678 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),
1679 .SUCCESS => {
1680 current_thread.endSyscall();
1681 return statFromPosix(&stat);
1682 },
1683 .INTR => {
1684 try current_thread.checkCancel();
1685 continue;
1686 },
1687 .CANCELED => return current_thread.endSyscallCanceled(),
1688 else => |e| {
1689 current_thread.endSyscall();
1690 switch (e) {
1691 .INVAL => |err| return errnoBug(err),
1692 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1693 .NOMEM => return error.SystemResources,
1694 .ACCES => return error.AccessDenied,
1695 else => |err| return posix.unexpectedErrno(err),
1696 }
1697 },
14991698 }
15001699 }
15011700}
15021701
15031702fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
15041703 const t: *Threaded = @ptrCast(@alignCast(userdata));
1704 const current_thread = Thread.getCurrent(t);
15051705 const linux = std.os.linux;
1706
1707 try current_thread.beginSyscall();
15061708 while (true) {
1507 try t.checkCancel();
15081709 var statx = std.mem.zeroes(linux.Statx);
15091710 const rc = linux.statx(
15101711 file.handle,
......@@ -1514,27 +1715,38 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
15141715 &statx,
15151716 );
15161717 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),
1718 .SUCCESS => {
1719 current_thread.endSyscall();
1720 return statFromLinux(&statx);
1721 },
1722 .INTR => {
1723 try current_thread.checkCancel();
1724 continue;
1725 },
1726 .CANCELED => return current_thread.endSyscallCanceled(),
1727 else => |e| {
1728 current_thread.endSyscall();
1729 switch (e) {
1730 .ACCES => |err| return errnoBug(err),
1731 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1732 .FAULT => |err| return errnoBug(err),
1733 .INVAL => |err| return errnoBug(err),
1734 .LOOP => |err| return errnoBug(err),
1735 .NAMETOOLONG => |err| return errnoBug(err),
1736 .NOENT => |err| return errnoBug(err),
1737 .NOMEM => return error.SystemResources,
1738 .NOTDIR => |err| return errnoBug(err),
1739 else => |err| return posix.unexpectedErrno(err),
1740 }
1741 },
15311742 }
15321743 }
15331744}
15341745
15351746fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
15361747 const t: *Threaded = @ptrCast(@alignCast(userdata));
1537 try t.checkCancel();
1748 const current_thread = Thread.getCurrent(t);
1749 try current_thread.checkCancel();
15381750
15391751 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
15401752 var info: windows.FILE_ALL_INFORMATION = undefined;
......@@ -1581,21 +1793,34 @@ fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.Fi
15811793
15821794fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
15831795 if (builtin.link_libc) return fileStatPosix(userdata, file);
1796
15841797 const t: *Threaded = @ptrCast(@alignCast(userdata));
1798 const current_thread = Thread.getCurrent(t);
1799
1800 try current_thread.beginSyscall();
15851801 while (true) {
1586 try t.checkCancel();
15871802 var stat: std.os.wasi.filestat_t = undefined;
15881803 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),
1804 .SUCCESS => {
1805 current_thread.endSyscall();
1806 return statFromWasi(&stat);
1807 },
1808 .INTR => {
1809 try current_thread.checkCancel();
1810 continue;
1811 },
1812 .CANCELED => return current_thread.endSyscallCanceled(),
1813 else => |e| {
1814 current_thread.endSyscall();
1815 switch (e) {
1816 .INVAL => |err| return errnoBug(err),
1817 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1818 .NOMEM => return error.SystemResources,
1819 .ACCES => return error.AccessDenied,
1820 .NOTCAPABLE => return error.AccessDenied,
1821 else => |err| return posix.unexpectedErrno(err),
1822 }
1823 },
15991824 }
16001825 }
16011826}
......@@ -1613,6 +1838,7 @@ fn dirAccessPosix(
16131838 options: Io.Dir.AccessOptions,
16141839) Io.Dir.AccessError!void {
16151840 const t: *Threaded = @ptrCast(@alignCast(userdata));
1841 const current_thread = Thread.getCurrent(t);
16161842
16171843 var path_buffer: [posix.PATH_MAX]u8 = undefined;
16181844 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
......@@ -1624,27 +1850,37 @@ fn dirAccessPosix(
16241850 @as(u32, if (options.write) posix.W_OK else 0) |
16251851 @as(u32, if (options.execute) posix.X_OK else 0);
16261852
1853 try current_thread.beginSyscall();
16271854 while (true) {
1628 try t.checkCancel();
16291855 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),
1856 .SUCCESS => {
1857 current_thread.endSyscall();
1858 return;
1859 },
1860 .INTR => {
1861 try current_thread.checkCancel();
1862 continue;
1863 },
1864 .CANCELED => return current_thread.endSyscallCanceled(),
1865 else => |e| {
1866 current_thread.endSyscall();
1867 switch (e) {
1868 .ACCES => return error.AccessDenied,
1869 .PERM => return error.PermissionDenied,
1870 .ROFS => return error.ReadOnlyFileSystem,
1871 .LOOP => return error.SymLinkLoop,
1872 .TXTBSY => return error.FileBusy,
1873 .NOTDIR => return error.FileNotFound,
1874 .NOENT => return error.FileNotFound,
1875 .NAMETOOLONG => return error.NameTooLong,
1876 .INVAL => |err| return errnoBug(err),
1877 .FAULT => |err| return errnoBug(err),
1878 .IO => return error.InputOutput,
1879 .NOMEM => return error.SystemResources,
1880 .ILSEQ => return error.BadPathName,
1881 else => |err| return posix.unexpectedErrno(err),
1882 }
1883 },
16481884 }
16491885 }
16501886}
......@@ -1657,29 +1893,41 @@ fn dirAccessWasi(
16571893) Io.Dir.AccessError!void {
16581894 if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options);
16591895 const t: *Threaded = @ptrCast(@alignCast(userdata));
1896 const current_thread = Thread.getCurrent(t);
16601897 const wasi = std.os.wasi;
16611898 const flags: wasi.lookupflags_t = .{
16621899 .SYMLINK_FOLLOW = options.follow_symlinks,
16631900 };
16641901 var stat: wasi.filestat_t = undefined;
1902
1903 try current_thread.beginSyscall();
16651904 while (true) {
1666 try t.checkCancel();
16671905 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),
1906 .SUCCESS => {
1907 current_thread.endSyscall();
1908 break;
1909 },
1910 .INTR => {
1911 try current_thread.checkCancel();
1912 continue;
1913 },
1914 .CANCELED => return current_thread.endSyscallCanceled(),
1915 else => |e| {
1916 current_thread.endSyscall();
1917 switch (e) {
1918 .INVAL => |err| return errnoBug(err),
1919 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1920 .NOMEM => return error.SystemResources,
1921 .ACCES => return error.AccessDenied,
1922 .FAULT => |err| return errnoBug(err),
1923 .NAMETOOLONG => return error.NameTooLong,
1924 .NOENT => return error.FileNotFound,
1925 .NOTDIR => return error.FileNotFound,
1926 .NOTCAPABLE => return error.AccessDenied,
1927 .ILSEQ => return error.BadPathName,
1928 else => |err| return posix.unexpectedErrno(err),
1929 }
1930 },
16831931 }
16841932 }
16851933
......@@ -1717,7 +1965,8 @@ fn dirAccessWindows(
17171965 options: Io.Dir.AccessOptions,
17181966) Io.Dir.AccessError!void {
17191967 const t: *Threaded = @ptrCast(@alignCast(userdata));
1720 try t.checkCancel();
1968 const current_thread = Thread.getCurrent(t);
1969 try current_thread.checkCancel();
17211970
17221971 _ = options; // TODO
17231972
......@@ -1768,6 +2017,7 @@ fn dirCreateFilePosix(
17682017 flags: Io.File.CreateFlags,
17692018) Io.File.OpenError!Io.File {
17702019 const t: *Threaded = @ptrCast(@alignCast(userdata));
2020 const current_thread = Thread.getCurrent(t);
17712021
17722022 var path_buffer: [posix.PATH_MAX]u8 = undefined;
17732023 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
......@@ -1796,40 +2046,50 @@ fn dirCreateFilePosix(
17962046 },
17972047 };
17982048
2049 try current_thread.beginSyscall();
17992050 const fd: posix.fd_t = while (true) {
1800 try t.checkCancel();
18012051 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
18022052 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),
2053 .SUCCESS => {
2054 current_thread.endSyscall();
2055 break @intCast(rc);
2056 },
2057 .INTR => {
2058 try current_thread.checkCancel();
2059 continue;
2060 },
2061 .CANCELED => return current_thread.endSyscallCanceled(),
2062 else => |e| {
2063 current_thread.endSyscall();
2064 switch (e) {
2065 .FAULT => |err| return errnoBug(err),
2066 .INVAL => return error.BadPathName,
2067 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2068 .ACCES => return error.AccessDenied,
2069 .FBIG => return error.FileTooBig,
2070 .OVERFLOW => return error.FileTooBig,
2071 .ISDIR => return error.IsDir,
2072 .LOOP => return error.SymLinkLoop,
2073 .MFILE => return error.ProcessFdQuotaExceeded,
2074 .NAMETOOLONG => return error.NameTooLong,
2075 .NFILE => return error.SystemFdQuotaExceeded,
2076 .NODEV => return error.NoDevice,
2077 .NOENT => return error.FileNotFound,
2078 .SRCH => return error.ProcessNotFound,
2079 .NOMEM => return error.SystemResources,
2080 .NOSPC => return error.NoSpaceLeft,
2081 .NOTDIR => return error.NotDir,
2082 .PERM => return error.PermissionDenied,
2083 .EXIST => return error.PathAlreadyExists,
2084 .BUSY => return error.DeviceBusy,
2085 .OPNOTSUPP => return error.FileLocksNotSupported,
2086 .AGAIN => return error.WouldBlock,
2087 .TXTBSY => return error.FileBusy,
2088 .NXIO => return error.NoDevice,
2089 .ILSEQ => return error.BadPathName,
2090 else => |err| return posix.unexpectedErrno(err),
2091 }
2092 },
18332093 }
18342094 };
18352095 errdefer posix.close(fd);
......@@ -1841,42 +2101,71 @@ fn dirCreateFilePosix(
18412101 .shared => posix.LOCK.SH | lock_nonblocking,
18422102 .exclusive => posix.LOCK.EX | lock_nonblocking,
18432103 };
2104
2105 try current_thread.beginSyscall();
18442106 while (true) {
1845 try t.checkCancel();
18462107 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),
2108 .SUCCESS => {
2109 current_thread.endSyscall();
2110 break;
2111 },
2112 .INTR => {
2113 try current_thread.checkCancel();
2114 continue;
2115 },
2116 .CANCELED => return current_thread.endSyscallCanceled(),
2117 else => |e| {
2118 current_thread.endSyscall();
2119 switch (e) {
2120 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2121 .INVAL => |err| return errnoBug(err), // invalid parameters
2122 .NOLCK => return error.SystemResources,
2123 .AGAIN => return error.WouldBlock,
2124 .OPNOTSUPP => return error.FileLocksNotSupported,
2125 else => |err| return posix.unexpectedErrno(err),
2126 }
2127 },
18572128 }
18582129 }
18592130 }
18602131
18612132 if (have_flock_open_flags and flags.lock_nonblocking) {
2133 try current_thread.beginSyscall();
18622134 var fl_flags: usize = while (true) {
1863 try t.checkCancel();
18642135 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
18652136 switch (posix.errno(rc)) {
1866 .SUCCESS => break @intCast(rc),
1867 .INTR => continue,
1868 .CANCELED => return error.Canceled,
1869 else => |err| return posix.unexpectedErrno(err),
2137 .SUCCESS => {
2138 current_thread.endSyscall();
2139 break @intCast(rc);
2140 },
2141 .INTR => {
2142 try current_thread.checkCancel();
2143 continue;
2144 },
2145 else => |err| {
2146 current_thread.endSyscall();
2147 return posix.unexpectedErrno(err);
2148 },
18702149 }
18712150 };
2151
18722152 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2153
2154 try current_thread.beginSyscall();
18732155 while (true) {
1874 try t.checkCancel();
18752156 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),
2157 .SUCCESS => {
2158 current_thread.endSyscall();
2159 break;
2160 },
2161 .INTR => {
2162 try current_thread.checkCancel();
2163 continue;
2164 },
2165 else => |err| {
2166 current_thread.endSyscall();
2167 return posix.unexpectedErrno(err);
2168 },
18802169 }
18812170 }
18822171 }
......@@ -1892,7 +2181,8 @@ fn dirCreateFileWindows(
18922181) Io.File.OpenError!Io.File {
18932182 const w = windows;
18942183 const t: *Threaded = @ptrCast(@alignCast(userdata));
1895 try t.checkCancel();
2184 const current_thread = Thread.getCurrent(t);
2185 try current_thread.checkCancel();
18962186
18972187 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);
18982188 const sub_path_w = sub_path_w_array.span();
......@@ -1939,6 +2229,7 @@ fn dirCreateFileWasi(
19392229 flags: Io.File.CreateFlags,
19402230) Io.File.OpenError!Io.File {
19412231 const t: *Threaded = @ptrCast(@alignCast(userdata));
2232 const current_thread = Thread.getCurrent(t);
19422233 const wasi = std.os.wasi;
19432234 const lookup_flags: wasi.lookupflags_t = .{};
19442235 const oflags: wasi.oflags_t = .{
......@@ -1966,35 +2257,45 @@ fn dirCreateFileWasi(
19662257 };
19672258 const inheriting: wasi.rights_t = .{};
19682259 var fd: posix.fd_t = undefined;
2260 try current_thread.beginSyscall();
19692261 while (true) {
1970 try t.checkCancel();
19712262 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),
2263 .SUCCESS => {
2264 current_thread.endSyscall();
2265 return .{ .handle = fd };
2266 },
2267 .INTR => {
2268 try current_thread.checkCancel();
2269 continue;
2270 },
2271 .CANCELED => return current_thread.endSyscallCanceled(),
2272 else => |e| {
2273 current_thread.endSyscall();
2274 switch (e) {
2275 .FAULT => |err| return errnoBug(err),
2276 .INVAL => return error.BadPathName,
2277 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2278 .ACCES => return error.AccessDenied,
2279 .FBIG => return error.FileTooBig,
2280 .OVERFLOW => return error.FileTooBig,
2281 .ISDIR => return error.IsDir,
2282 .LOOP => return error.SymLinkLoop,
2283 .MFILE => return error.ProcessFdQuotaExceeded,
2284 .NAMETOOLONG => return error.NameTooLong,
2285 .NFILE => return error.SystemFdQuotaExceeded,
2286 .NODEV => return error.NoDevice,
2287 .NOENT => return error.FileNotFound,
2288 .NOMEM => return error.SystemResources,
2289 .NOSPC => return error.NoSpaceLeft,
2290 .NOTDIR => return error.NotDir,
2291 .PERM => return error.PermissionDenied,
2292 .EXIST => return error.PathAlreadyExists,
2293 .BUSY => return error.DeviceBusy,
2294 .NOTCAPABLE => return error.AccessDenied,
2295 .ILSEQ => return error.BadPathName,
2296 else => |err| return posix.unexpectedErrno(err),
2297 }
2298 },
19982299 }
19992300 }
20002301}
......@@ -2012,6 +2313,7 @@ fn dirOpenFilePosix(
20122313 flags: Io.File.OpenFlags,
20132314) Io.File.OpenError!Io.File {
20142315 const t: *Threaded = @ptrCast(@alignCast(userdata));
2316 const current_thread = Thread.getCurrent(t);
20152317
20162318 var path_buffer: [posix.PATH_MAX]u8 = undefined;
20172319 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
......@@ -2048,40 +2350,50 @@ fn dirOpenFilePosix(
20482350 },
20492351 };
20502352
2353 try current_thread.beginSyscall();
20512354 const fd: posix.fd_t = while (true) {
2052 try t.checkCancel();
20532355 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, @as(posix.mode_t, 0));
20542356 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),
2357 .SUCCESS => {
2358 current_thread.endSyscall();
2359 break @intCast(rc);
2360 },
2361 .INTR => {
2362 try current_thread.checkCancel();
2363 continue;
2364 },
2365 .CANCELED => return current_thread.endSyscallCanceled(),
2366 else => |e| {
2367 current_thread.endSyscall();
2368 switch (e) {
2369 .FAULT => |err| return errnoBug(err),
2370 .INVAL => return error.BadPathName,
2371 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2372 .ACCES => return error.AccessDenied,
2373 .FBIG => return error.FileTooBig,
2374 .OVERFLOW => return error.FileTooBig,
2375 .ISDIR => return error.IsDir,
2376 .LOOP => return error.SymLinkLoop,
2377 .MFILE => return error.ProcessFdQuotaExceeded,
2378 .NAMETOOLONG => return error.NameTooLong,
2379 .NFILE => return error.SystemFdQuotaExceeded,
2380 .NODEV => return error.NoDevice,
2381 .NOENT => return error.FileNotFound,
2382 .SRCH => return error.ProcessNotFound,
2383 .NOMEM => return error.SystemResources,
2384 .NOSPC => return error.NoSpaceLeft,
2385 .NOTDIR => return error.NotDir,
2386 .PERM => return error.PermissionDenied,
2387 .EXIST => return error.PathAlreadyExists,
2388 .BUSY => return error.DeviceBusy,
2389 .OPNOTSUPP => return error.FileLocksNotSupported,
2390 .AGAIN => return error.WouldBlock,
2391 .TXTBSY => return error.FileBusy,
2392 .NXIO => return error.NoDevice,
2393 .ILSEQ => return error.BadPathName,
2394 else => |err| return posix.unexpectedErrno(err),
2395 }
2396 },
20852397 }
20862398 };
20872399 errdefer posix.close(fd);
......@@ -2093,42 +2405,72 @@ fn dirOpenFilePosix(
20932405 .shared => posix.LOCK.SH | lock_nonblocking,
20942406 .exclusive => posix.LOCK.EX | lock_nonblocking,
20952407 };
2408 try current_thread.beginSyscall();
20962409 while (true) {
2097 try t.checkCancel();
20982410 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),
2411 .SUCCESS => {
2412 current_thread.endSyscall();
2413 break;
2414 },
2415 .INTR => {
2416 try current_thread.checkCancel();
2417 continue;
2418 },
2419 .CANCELED => return current_thread.endSyscallCanceled(),
2420 else => |e| {
2421 current_thread.endSyscall();
2422 switch (e) {
2423 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2424 .INVAL => |err| return errnoBug(err), // invalid parameters
2425 .NOLCK => return error.SystemResources,
2426 .AGAIN => return error.WouldBlock,
2427 .OPNOTSUPP => return error.FileLocksNotSupported,
2428 else => |err| return posix.unexpectedErrno(err),
2429 }
2430 },
21092431 }
21102432 }
21112433 }
21122434
21132435 if (have_flock_open_flags and flags.lock_nonblocking) {
2436 try current_thread.beginSyscall();
21142437 var fl_flags: usize = while (true) {
2115 try t.checkCancel();
21162438 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
21172439 switch (posix.errno(rc)) {
2118 .SUCCESS => break @intCast(rc),
2119 .INTR => continue,
2120 .CANCELED => return error.Canceled,
2121 else => |err| return posix.unexpectedErrno(err),
2440 .SUCCESS => {
2441 current_thread.endSyscall();
2442 break @intCast(rc);
2443 },
2444 .INTR => {
2445 try current_thread.checkCancel();
2446 continue;
2447 },
2448 .CANCELED => return current_thread.endSyscallCanceled(),
2449 else => |err| {
2450 current_thread.endSyscall();
2451 return posix.unexpectedErrno(err);
2452 },
21222453 }
21232454 };
2455
21242456 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2457
2458 try current_thread.beginSyscall();
21252459 while (true) {
2126 try t.checkCancel();
21272460 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),
2461 .SUCCESS => {
2462 current_thread.endSyscall();
2463 break;
2464 },
2465 .INTR => {
2466 try current_thread.checkCancel();
2467 continue;
2468 },
2469 .CANCELED => return current_thread.endSyscallCanceled(),
2470 else => |err| {
2471 current_thread.endSyscall();
2472 return posix.unexpectedErrno(err);
2473 },
21322474 }
21332475 }
21342476 }
......@@ -2158,7 +2500,7 @@ pub fn dirOpenFileWtf16(
21582500 if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
21592501 if (std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;
21602502 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
2161
2503 const current_thread = Thread.getCurrent(t);
21622504 const w = windows;
21632505
21642506 var nt_name: w.UNICODE_STRING = .{
......@@ -2187,7 +2529,7 @@ pub fn dirOpenFileWtf16(
21872529 var attempt: u5 = 0;
21882530
21892531 const handle = while (true) {
2190 try t.checkCancel();
2532 try current_thread.checkCancel();
21912533
21922534 var result: w.HANDLE = undefined;
21932535 const rc = w.ntdll.NtCreateFile(
......@@ -2281,6 +2623,7 @@ fn dirOpenFileWasi(
22812623) Io.File.OpenError!Io.File {
22822624 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);
22832625 const t: *Threaded = @ptrCast(@alignCast(userdata));
2626 const current_thread = Thread.getCurrent(t);
22842627 const wasi = std.os.wasi;
22852628 var base: std.os.wasi.rights_t = .{};
22862629 // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE
......@@ -2310,33 +2653,44 @@ fn dirOpenFileWasi(
23102653 const inheriting: wasi.rights_t = .{};
23112654 const fdflags: wasi.fdflags_t = .{};
23122655 var fd: posix.fd_t = undefined;
2656 try current_thread.beginSyscall();
23132657 while (true) {
2314 try t.checkCancel();
23152658 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),
2659 .SUCCESS => {
2660 errdefer posix.close(fd);
2661 current_thread.endSyscall();
2662 return .{ .handle = fd };
2663 },
2664 .INTR => {
2665 try current_thread.checkCancel();
2666 continue;
2667 },
2668 .CANCELED => return current_thread.endSyscallCanceled(),
2669 else => |e| {
2670 current_thread.endSyscall();
2671 switch (e) {
2672 .FAULT => |err| return errnoBug(err),
2673 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2674 .ACCES => return error.AccessDenied,
2675 .FBIG => return error.FileTooBig,
2676 .OVERFLOW => return error.FileTooBig,
2677 .ISDIR => return error.IsDir,
2678 .LOOP => return error.SymLinkLoop,
2679 .MFILE => return error.ProcessFdQuotaExceeded,
2680 .NFILE => return error.SystemFdQuotaExceeded,
2681 .NODEV => return error.NoDevice,
2682 .NOENT => return error.FileNotFound,
2683 .NOMEM => return error.SystemResources,
2684 .NOTDIR => return error.NotDir,
2685 .PERM => return error.PermissionDenied,
2686 .BUSY => return error.DeviceBusy,
2687 .NOTCAPABLE => return error.AccessDenied,
2688 .NAMETOOLONG => return error.NameTooLong,
2689 .INVAL => return error.BadPathName,
2690 .ILSEQ => return error.BadPathName,
2691 else => |err| return posix.unexpectedErrno(err),
2692 }
2693 },
23402694 }
23412695 }
23422696}
......@@ -2361,6 +2715,8 @@ fn dirOpenDirPosix(
23612715 return dirOpenDirWindows(t, dir, sub_path_w.span(), options);
23622716 }
23632717
2718 const current_thread = Thread.getCurrent(t);
2719
23642720 var path_buffer: [posix.PATH_MAX]u8 = undefined;
23652721 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
23662722
......@@ -2381,31 +2737,41 @@ fn dirOpenDirPosix(
23812737 if (@hasField(posix.O, "PATH") and !options.iterate)
23822738 flags.PATH = true;
23832739
2740 try current_thread.beginSyscall();
23842741 while (true) {
2385 try t.checkCancel();
23862742 const rc = openat_sym(dir.handle, sub_path_posix, flags, @as(usize, 0));
23872743 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),
2744 .SUCCESS => {
2745 current_thread.endSyscall();
2746 return .{ .handle = @intCast(rc) };
2747 },
2748 .INTR => {
2749 try current_thread.checkCancel();
2750 continue;
2751 },
2752 .CANCELED => return current_thread.endSyscallCanceled(),
2753 else => |e| {
2754 current_thread.endSyscall();
2755 switch (e) {
2756 .FAULT => |err| return errnoBug(err),
2757 .INVAL => return error.BadPathName,
2758 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2759 .ACCES => return error.AccessDenied,
2760 .LOOP => return error.SymLinkLoop,
2761 .MFILE => return error.ProcessFdQuotaExceeded,
2762 .NAMETOOLONG => return error.NameTooLong,
2763 .NFILE => return error.SystemFdQuotaExceeded,
2764 .NODEV => return error.NoDevice,
2765 .NOENT => return error.FileNotFound,
2766 .NOMEM => return error.SystemResources,
2767 .NOTDIR => return error.NotDir,
2768 .PERM => return error.PermissionDenied,
2769 .BUSY => return error.DeviceBusy,
2770 .NXIO => return error.NoDevice,
2771 .ILSEQ => return error.BadPathName,
2772 else => |err| return posix.unexpectedErrno(err),
2773 }
2774 },
24092775 }
24102776 }
24112777}
......@@ -2417,34 +2783,46 @@ fn dirOpenDirHaiku(
24172783 options: Io.Dir.OpenOptions,
24182784) Io.Dir.OpenError!Io.Dir {
24192785 const t: *Threaded = @ptrCast(@alignCast(userdata));
2786 const current_thread = Thread.getCurrent(t);
24202787
24212788 var path_buffer: [posix.PATH_MAX]u8 = undefined;
24222789 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
24232790
24242791 _ = options;
24252792
2793 try current_thread.beginSyscall();
24262794 while (true) {
2427 try t.checkCancel();
24282795 const rc = posix.system._kern_open_dir(dir.handle, sub_path_posix);
2429 if (rc >= 0) return .{ .handle = rc };
2796 if (rc >= 0) {
2797 current_thread.endSyscall();
2798 return .{ .handle = rc };
2799 }
24302800 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),
2801 .INTR => {
2802 try current_thread.checkCancel();
2803 continue;
2804 },
2805 .CANCELED => return current_thread.endSyscallCanceled(),
2806 else => |e| {
2807 current_thread.endSyscall();
2808 switch (e) {
2809 .FAULT => |err| return errnoBug(err),
2810 .INVAL => |err| return errnoBug(err),
2811 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2812 .ACCES => return error.AccessDenied,
2813 .LOOP => return error.SymLinkLoop,
2814 .MFILE => return error.ProcessFdQuotaExceeded,
2815 .NAMETOOLONG => return error.NameTooLong,
2816 .NFILE => return error.SystemFdQuotaExceeded,
2817 .NODEV => return error.NoDevice,
2818 .NOENT => return error.FileNotFound,
2819 .NOMEM => return error.SystemResources,
2820 .NOTDIR => return error.NotDir,
2821 .PERM => return error.PermissionDenied,
2822 .BUSY => return error.DeviceBusy,
2823 else => |err| return posix.unexpectedErrno(err),
2824 }
2825 },
24482826 }
24492827 }
24502828}
......@@ -2455,6 +2833,7 @@ pub fn dirOpenDirWindows(
24552833 sub_path_w: [:0]const u16,
24562834 options: Io.Dir.OpenOptions,
24572835) Io.Dir.OpenError!Io.Dir {
2836 const current_thread = Thread.getCurrent(t);
24582837 const w = windows;
24592838 // TODO remove some of these flags if options.access_sub_paths is false
24602839 const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
......@@ -2478,7 +2857,7 @@ pub fn dirOpenDirWindows(
24782857 const open_reparse_point: w.DWORD = if (!options.follow_symlinks) w.FILE_OPEN_REPARSE_POINT else 0x0;
24792858 var io_status_block: w.IO_STATUS_BLOCK = undefined;
24802859 var result: Io.Dir = .{ .handle = undefined };
2481 try t.checkCancel();
2860 try current_thread.checkCancel();
24822861 const rc = w.ntdll.NtCreateFile(
24832862 &result.handle,
24842863 access_mask,
......@@ -2527,6 +2906,7 @@ fn dirOpenDirWasi(
25272906) Io.Dir.OpenError!Io.Dir {
25282907 if (builtin.link_libc) return dirOpenDirPosix(userdata, dir, sub_path, options);
25292908 const t: *Threaded = @ptrCast(@alignCast(userdata));
2909 const current_thread = Thread.getCurrent(t);
25302910 const wasi = std.os.wasi;
25312911
25322912 var base: std.os.wasi.rights_t = .{
......@@ -2556,31 +2936,40 @@ fn dirOpenDirWasi(
25562936 const oflags: wasi.oflags_t = .{ .DIRECTORY = true };
25572937 const fdflags: wasi.fdflags_t = .{};
25582938 var fd: posix.fd_t = undefined;
2559
2939 try current_thread.beginSyscall();
25602940 while (true) {
2561 try t.checkCancel();
25622941 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),
2942 .SUCCESS => {
2943 current_thread.endSyscall();
2944 return .{ .handle = fd };
2945 },
2946 .INTR => {
2947 try current_thread.checkCancel();
2948 continue;
2949 },
2950 .CANCELED => return current_thread.endSyscallCanceled(),
2951 else => |e| {
2952 current_thread.endSyscall();
2953 switch (e) {
2954 .FAULT => |err| return errnoBug(err),
2955 .INVAL => return error.BadPathName,
2956 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2957 .ACCES => return error.AccessDenied,
2958 .LOOP => return error.SymLinkLoop,
2959 .MFILE => return error.ProcessFdQuotaExceeded,
2960 .NAMETOOLONG => return error.NameTooLong,
2961 .NFILE => return error.SystemFdQuotaExceeded,
2962 .NODEV => return error.NoDevice,
2963 .NOENT => return error.FileNotFound,
2964 .NOMEM => return error.SystemResources,
2965 .NOTDIR => return error.NotDir,
2966 .PERM => return error.PermissionDenied,
2967 .BUSY => return error.DeviceBusy,
2968 .NOTCAPABLE => return error.AccessDenied,
2969 .ILSEQ => return error.BadPathName,
2970 else => |err| return posix.unexpectedErrno(err),
2971 }
2972 },
25842973 }
25852974 }
25862975}
......@@ -2598,6 +2987,7 @@ const fileReadStreaming = switch (native_os) {
25982987
25992988fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
26002989 const t: *Threaded = @ptrCast(@alignCast(userdata));
2990 const current_thread = Thread.getCurrent(t);
26012991
26022992 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
26032993 var i: usize = 0;
......@@ -2611,59 +3001,82 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io
26113001 const dest = iovecs_buffer[0..i];
26123002 assert(dest[0].len > 0);
26133003
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),
3004 if (native_os == .wasi and !builtin.link_libc) {
3005 try current_thread.beginSyscall();
3006 while (true) {
3007 var nread: usize = undefined;
3008 switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {
3009 .SUCCESS => {
3010 current_thread.endSyscall();
3011 return nread;
3012 },
3013 .INTR => {
3014 try current_thread.checkCancel();
3015 continue;
3016 },
3017 .CANCELED => return current_thread.endSyscallCanceled(),
3018 else => |e| {
3019 current_thread.endSyscall();
3020 switch (e) {
3021 .INVAL => |err| return errnoBug(err),
3022 .FAULT => |err| return errnoBug(err),
3023 .BADF => return error.NotOpenForReading, // File operation on directory.
3024 .IO => return error.InputOutput,
3025 .ISDIR => return error.IsDir,
3026 .NOBUFS => return error.SystemResources,
3027 .NOMEM => return error.SystemResources,
3028 .NOTCONN => return error.SocketUnconnected,
3029 .CONNRESET => return error.ConnectionResetByPeer,
3030 .TIMEDOUT => return error.Timeout,
3031 .NOTCAPABLE => return error.AccessDenied,
3032 else => |err| return posix.unexpectedErrno(err),
3033 }
3034 },
3035 }
26343036 }
2635 };
3037 }
26363038
3039 try current_thread.beginSyscall();
26373040 while (true) {
2638 try t.checkCancel();
26393041 const rc = posix.system.readv(file.handle, dest.ptr, @intCast(dest.len));
26403042 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),
3043 .SUCCESS => {
3044 current_thread.endSyscall();
3045 return @intCast(rc);
3046 },
3047 .INTR => {
3048 try current_thread.checkCancel();
3049 continue;
3050 },
3051 .CANCELED => return current_thread.endSyscallCanceled(),
3052 else => |e| {
3053 current_thread.endSyscall();
3054 switch (e) {
3055 .INVAL => |err| return errnoBug(err),
3056 .FAULT => |err| return errnoBug(err),
3057 .SRCH => return error.ProcessNotFound,
3058 .AGAIN => return error.WouldBlock,
3059 .BADF => |err| {
3060 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
3061 return errnoBug(err); // File descriptor used after closed.
3062 },
3063 .IO => return error.InputOutput,
3064 .ISDIR => return error.IsDir,
3065 .NOBUFS => return error.SystemResources,
3066 .NOMEM => return error.SystemResources,
3067 .NOTCONN => return error.SocketUnconnected,
3068 .CONNRESET => return error.ConnectionResetByPeer,
3069 .TIMEDOUT => return error.Timeout,
3070 else => |err| return posix.unexpectedErrno(err),
3071 }
3072 },
26613073 }
26623074 }
26633075}
26643076
26653077fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
26663078 const t: *Threaded = @ptrCast(@alignCast(userdata));
3079 const current_thread = Thread.getCurrent(t);
26673080
26683081 const DWORD = windows.DWORD;
26693082 var index: usize = 0;
......@@ -2672,7 +3085,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
26723085 const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);
26733086
26743087 while (true) {
2675 try t.checkCancel();
3088 try current_thread.checkCancel();
26763089 var n: DWORD = undefined;
26773090 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0)
26783091 return n;
......@@ -2692,6 +3105,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
26923105
26933106fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
26943107 const t: *Threaded = @ptrCast(@alignCast(userdata));
3108 const current_thread = Thread.getCurrent(t);
26953109
26963110 if (!have_preadv) @compileError("TODO");
26973111
......@@ -2707,60 +3121,82 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o
27073121 const dest = iovecs_buffer[0..i];
27083122 assert(dest[0].len > 0);
27093123
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),
3124 if (native_os == .wasi and !builtin.link_libc) {
3125 try current_thread.beginSyscall();
3126 while (true) {
3127 var nread: usize = undefined;
3128 switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {
3129 .SUCCESS => {
3130 current_thread.endSyscall();
3131 return nread;
3132 },
3133 .INTR => {
3134 try current_thread.checkCancel();
3135 continue;
3136 },
3137 .CANCELED => return current_thread.endSyscallCanceled(),
3138 else => |e| {
3139 current_thread.endSyscall();
3140 switch (e) {
3141 .INVAL => |err| return errnoBug(err),
3142 .FAULT => |err| return errnoBug(err),
3143 .AGAIN => |err| return errnoBug(err),
3144 .BADF => return error.NotOpenForReading, // File operation on directory.
3145 .IO => return error.InputOutput,
3146 .ISDIR => return error.IsDir,
3147 .NOBUFS => return error.SystemResources,
3148 .NOMEM => return error.SystemResources,
3149 .NOTCONN => return error.SocketUnconnected,
3150 .CONNRESET => return error.ConnectionResetByPeer,
3151 .TIMEDOUT => return error.Timeout,
3152 .NXIO => return error.Unseekable,
3153 .SPIPE => return error.Unseekable,
3154 .OVERFLOW => return error.Unseekable,
3155 .NOTCAPABLE => return error.AccessDenied,
3156 else => |err| return posix.unexpectedErrno(err),
3157 }
3158 },
3159 }
27343160 }
2735 };
3161 }
27363162
3163 try current_thread.beginSyscall();
27373164 while (true) {
2738 try t.checkCancel();
27393165 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
27403166 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),
3167 .SUCCESS => {
3168 current_thread.endSyscall();
3169 return @bitCast(rc);
3170 },
3171 .INTR => {
3172 try current_thread.checkCancel();
3173 continue;
3174 },
3175 .CANCELED => return current_thread.endSyscallCanceled(),
3176 else => |e| {
3177 current_thread.endSyscall();
3178 switch (e) {
3179 .INVAL => |err| return errnoBug(err),
3180 .FAULT => |err| return errnoBug(err),
3181 .SRCH => return error.ProcessNotFound,
3182 .AGAIN => return error.WouldBlock,
3183 .BADF => |err| {
3184 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
3185 return errnoBug(err); // File descriptor used after closed.
3186 },
3187 .IO => return error.InputOutput,
3188 .ISDIR => return error.IsDir,
3189 .NOBUFS => return error.SystemResources,
3190 .NOMEM => return error.SystemResources,
3191 .NOTCONN => return error.SocketUnconnected,
3192 .CONNRESET => return error.ConnectionResetByPeer,
3193 .TIMEDOUT => return error.Timeout,
3194 .NXIO => return error.Unseekable,
3195 .SPIPE => return error.Unseekable,
3196 .OVERFLOW => return error.Unseekable,
3197 else => |err| return posix.unexpectedErrno(err),
3198 }
3199 },
27643200 }
27653201 }
27663202}
......@@ -2772,6 +3208,7 @@ const fileReadPositional = switch (native_os) {
27723208
27733209fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
27743210 const t: *Threaded = @ptrCast(@alignCast(userdata));
3211 const current_thread = Thread.getCurrent(t);
27753212
27763213 const DWORD = windows.DWORD;
27773214
......@@ -2793,7 +3230,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
27933230 };
27943231
27953232 while (true) {
2796 try t.checkCancel();
3233 try current_thread.checkCancel();
27973234 var n: DWORD = undefined;
27983235 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0)
27993236 return n;
......@@ -2813,8 +3250,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
28133250
28143251fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekError!void {
28153252 const t: *Threaded = @ptrCast(@alignCast(userdata));
2816 try t.checkCancel();
2817
3253 _ = t;
28183254 _ = file;
28193255 _ = offset;
28203256 @panic("TODO implement fileSeekBy");
......@@ -2822,63 +3258,96 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr
28223258
28233259fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {
28243260 const t: *Threaded = @ptrCast(@alignCast(userdata));
3261 const current_thread = Thread.getCurrent(t);
28253262 const fd = file.handle;
28263263
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),
3264 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
3265 try current_thread.beginSyscall();
3266 while (true) {
3267 var result: u64 = undefined;
3268 switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {
3269 .SUCCESS => {
3270 current_thread.endSyscall();
3271 return;
3272 },
3273 .INTR => {
3274 try current_thread.checkCancel();
3275 continue;
3276 },
3277 .CANCELED => return current_thread.endSyscallCanceled(),
3278 else => |e| {
3279 current_thread.endSyscall();
3280 switch (e) {
3281 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3282 .INVAL => return error.Unseekable,
3283 .OVERFLOW => return error.Unseekable,
3284 .SPIPE => return error.Unseekable,
3285 .NXIO => return error.Unseekable,
3286 else => |err| return posix.unexpectedErrno(err),
3287 }
3288 },
3289 }
28413290 }
2842 };
3291 }
28433292
28443293 if (native_os == .windows) {
2845 try t.checkCancel();
3294 try current_thread.checkCancel();
28463295 return windows.SetFilePointerEx_BEGIN(fd, offset);
28473296 }
28483297
28493298 if (native_os == .wasi and !builtin.link_libc) while (true) {
2850 try t.checkCancel();
28513299 var new_offset: std.os.wasi.filesize_t = undefined;
3300 try current_thread.beginSyscall();
28523301 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),
3302 .SUCCESS => {
3303 current_thread.endSyscall();
3304 return;
3305 },
3306 .INTR => {
3307 try current_thread.checkCancel();
3308 continue;
3309 },
3310 .CANCELED => return current_thread.endSyscallCanceled(),
3311 else => |e| {
3312 current_thread.endSyscall();
3313 switch (e) {
3314 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3315 .INVAL => return error.Unseekable,
3316 .OVERFLOW => return error.Unseekable,
3317 .SPIPE => return error.Unseekable,
3318 .NXIO => return error.Unseekable,
3319 .NOTCAPABLE => return error.AccessDenied,
3320 else => |err| return posix.unexpectedErrno(err),
3321 }
3322 },
28643323 }
28653324 };
28663325
28673326 if (posix.SEEK == void) return error.Unseekable;
28683327
3328 try current_thread.beginSyscall();
28693329 while (true) {
2870 try t.checkCancel();
28713330 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),
3331 .SUCCESS => {
3332 current_thread.endSyscall();
3333 return;
3334 },
3335 .INTR => {
3336 try current_thread.checkCancel();
3337 continue;
3338 },
3339 .CANCELED => return current_thread.endSyscallCanceled(),
3340 else => |e| {
3341 current_thread.endSyscall();
3342 switch (e) {
3343 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3344 .INVAL => return error.Unseekable,
3345 .OVERFLOW => return error.Unseekable,
3346 .SPIPE => return error.Unseekable,
3347 .NXIO => return error.Unseekable,
3348 else => |err| return posix.unexpectedErrno(err),
3349 }
3350 },
28823351 }
28833352 }
28843353}
......@@ -2907,8 +3376,8 @@ fn fileWritePositional(
29073376 offset: u64,
29083377) Io.File.WritePositionalError!usize {
29093378 const t: *Threaded = @ptrCast(@alignCast(userdata));
3379 _ = t;
29103380 while (true) {
2911 try t.checkCancel();
29123381 _ = file;
29133382 _ = buffer;
29143383 _ = offset;
......@@ -2918,8 +3387,8 @@ fn fileWritePositional(
29183387
29193388fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8) Io.File.WriteStreamingError!usize {
29203389 const t: *Threaded = @ptrCast(@alignCast(userdata));
3390 _ = t;
29213391 while (true) {
2922 try t.checkCancel();
29233392 _ = file;
29243393 _ = buffer;
29253394 @panic("TODO implement fileWriteStreaming");
......@@ -2997,6 +3466,7 @@ const sleep = switch (native_os) {
29973466
29983467fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
29993468 const t: *Threaded = @ptrCast(@alignCast(userdata));
3469 const current_thread = Thread.getCurrent(t);
30003470 const clock_id: posix.clockid_t = clockToPosix(switch (timeout) {
30013471 .none => .awake,
30023472 .duration => |d| d.clock,
......@@ -3008,25 +3478,37 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30083478 .deadline => |deadline| deadline.raw.nanoseconds,
30093479 };
30103480 var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
3481 try current_thread.beginSyscall();
30113482 while (true) {
3012 try t.checkCancel();
30133483 switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
30143484 .none, .duration => false,
30153485 .deadline => true,
30163486 } }, &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),
3487 .SUCCESS => {
3488 current_thread.endSyscall();
3489 return;
3490 },
3491 .INTR => {
3492 try current_thread.checkCancel();
3493 continue;
3494 },
3495 .CANCELED => return current_thread.endSyscallCanceled(),
3496 else => |e| {
3497 current_thread.endSyscall();
3498 switch (e) {
3499 .INVAL => return error.UnsupportedClock,
3500 else => |err| return posix.unexpectedErrno(err),
3501 }
3502 },
30223503 }
30233504 }
30243505}
30253506
30263507fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30273508 const t: *Threaded = @ptrCast(@alignCast(userdata));
3509 const current_thread = Thread.getCurrent(t);
30283510 const t_io = ioBasic(t);
3029 try t.checkCancel();
3511 try current_thread.checkCancel();
30303512 const ms = ms: {
30313513 const d = (try timeout.toDurationFromNow(t_io)) orelse
30323514 break :ms std.math.maxInt(windows.DWORD);
......@@ -3038,9 +3520,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30383520
30393521fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30403522 const t: *Threaded = @ptrCast(@alignCast(userdata));
3523 const current_thread = Thread.getCurrent(t);
30413524 const t_io = ioBasic(t);
3042 try t.checkCancel();
3043
30443525 const w = std.os.wasi;
30453526
30463527 const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t_io)) |d| .{
......@@ -3063,11 +3544,14 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30633544 };
30643545 var event: w.event_t = undefined;
30653546 var nevents: usize = undefined;
3547 try current_thread.beginSyscall();
30663548 _ = w.poll_oneoff(&in, &event, 1, &nevents);
3549 current_thread.endSyscall();
30673550}
30683551
30693552fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30703553 const t: *Threaded = @ptrCast(@alignCast(userdata));
3554 const current_thread = Thread.getCurrent(t);
30713555 const t_io = ioBasic(t);
30723556 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
30733557 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
......@@ -3079,12 +3563,16 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30793563 };
30803564 break :t timestampToPosix(d.raw.toNanoseconds());
30813565 };
3566 try current_thread.beginSyscall();
30823567 while (true) {
3083 try t.checkCancel();
30843568 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.
3569 .INTR => {
3570 try current_thread.checkCancel();
3571 continue;
3572 },
3573 .CANCELED => return current_thread.endSyscallCanceled(),
3574 // This prong handles success as well as unexpected errors.
3575 else => return current_thread.endSyscall(),
30883576 }
30893577 }
30903578}
......@@ -3127,34 +3615,48 @@ fn netListenIpPosix(
31273615) IpAddress.ListenError!net.Server {
31283616 if (!have_networking) return error.NetworkDown;
31293617 const t: *Threaded = @ptrCast(@alignCast(userdata));
3618 const current_thread = Thread.getCurrent(t);
31303619 const family = posixAddressFamily(&address);
3131 const socket_fd = try openSocketPosix(t, family, .{
3620 const socket_fd = try openSocketPosix(current_thread, family, .{
31323621 .mode = options.mode,
31333622 .protocol = options.protocol,
31343623 });
31353624 errdefer posix.close(socket_fd);
31363625
31373626 if (options.reuse_address) {
3138 try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
3627 try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
31393628 if (@hasDecl(posix.SO, "REUSEPORT"))
3140 try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);
3629 try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);
31413630 }
31423631
31433632 var storage: PosixAddress = undefined;
31443633 var addr_len = addressToPosix(&address, &storage);
3145 try posixBind(t, socket_fd, &storage.any, addr_len);
3634 try posixBind(current_thread, socket_fd, &storage.any, addr_len);
31463635
3636 try current_thread.beginSyscall();
31473637 while (true) {
3148 try t.checkCancel();
31493638 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),
3639 .SUCCESS => {
3640 current_thread.endSyscall();
3641 break;
3642 },
3643 .INTR => {
3644 try current_thread.checkCancel();
3645 continue;
3646 },
3647 .CANCELED => return current_thread.endSyscallCanceled(),
3648 else => |e| {
3649 current_thread.endSyscall();
3650 switch (e) {
3651 .ADDRINUSE => return error.AddressInUse,
3652 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3653 else => |err| return posix.unexpectedErrno(err),
3654 }
3655 },
31543656 }
31553657 }
31563658
3157 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);
3659 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
31583660 return .{
31593661 .socket = .{
31603662 .handle = socket_fd,
......@@ -3170,8 +3672,9 @@ fn netListenIpWindows(
31703672) IpAddress.ListenError!net.Server {
31713673 if (!have_networking) return error.NetworkDown;
31723674 const t: *Threaded = @ptrCast(@alignCast(userdata));
3675 const current_thread = Thread.getCurrent(t);
31733676 const family = posixAddressFamily(&address);
3174 const socket_handle = try openSocketWsa(t, family, .{
3677 const socket_handle = try openSocketWsa(t, current_thread, family, .{
31753678 .mode = options.mode,
31763679 .protocol = options.protocol,
31773680 });
......@@ -3183,52 +3686,76 @@ fn netListenIpWindows(
31833686 var storage: WsaAddress = undefined;
31843687 var addr_len = addressToWsa(&address, &storage);
31853688
3689 try current_thread.beginSyscall();
31863690 while (true) {
3187 try t.checkCancel();
31883691 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
3189 if (rc != ws2_32.SOCKET_ERROR) break;
3692 if (rc != ws2_32.SOCKET_ERROR) {
3693 current_thread.endSyscall();
3694 break;
3695 }
31903696 switch (ws2_32.WSAGetLastError()) {
3191 .EINTR => continue,
3192 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3697 .EINTR => {
3698 try current_thread.checkCancel();
3699 continue;
3700 },
31933701 .NOTINITIALISED => {
31943702 try initializeWsa(t);
3703 try current_thread.checkCancel();
31953704 continue;
31963705 },
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),
3706 else => |e| {
3707 current_thread.endSyscall();
3708 switch (e) {
3709 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3710 .EADDRINUSE => return error.AddressInUse,
3711 .EADDRNOTAVAIL => return error.AddressUnavailable,
3712 .ENOTSOCK => |err| return wsaErrorBug(err),
3713 .EFAULT => |err| return wsaErrorBug(err),
3714 .EINVAL => |err| return wsaErrorBug(err),
3715 .ENOBUFS => return error.SystemResources,
3716 .ENETDOWN => return error.NetworkDown,
3717 else => |err| return windows.unexpectedWSAError(err),
3718 }
3719 },
32053720 }
32063721 }
32073722
3723 try current_thread.beginSyscall();
32083724 while (true) {
3209 try t.checkCancel();
32103725 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
3211 if (rc != ws2_32.SOCKET_ERROR) break;
3726 if (rc != ws2_32.SOCKET_ERROR) {
3727 current_thread.endSyscall();
3728 break;
3729 }
32123730 switch (ws2_32.WSAGetLastError()) {
3213 .EINTR => continue,
3214 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3731 .EINTR => {
3732 try current_thread.checkCancel();
3733 continue;
3734 },
32153735 .NOTINITIALISED => {
32163736 try initializeWsa(t);
3737 try current_thread.checkCancel();
32173738 continue;
32183739 },
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),
3740 else => |e| {
3741 current_thread.endSyscall();
3742 switch (e) {
3743 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3744 .ENETDOWN => return error.NetworkDown,
3745 .EADDRINUSE => return error.AddressInUse,
3746 .EISCONN => |err| return wsaErrorBug(err),
3747 .EINVAL => |err| return wsaErrorBug(err),
3748 .EMFILE, .ENOBUFS => return error.SystemResources,
3749 .ENOTSOCK => |err| return wsaErrorBug(err),
3750 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3751 .EINPROGRESS => |err| return wsaErrorBug(err),
3752 else => |err| return windows.unexpectedWSAError(err),
3753 }
3754 },
32283755 }
32293756 }
32303757
3231 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
3758 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
32323759
32333760 return .{
32343761 .socket = .{
......@@ -3256,7 +3783,8 @@ fn netListenUnixPosix(
32563783) net.UnixAddress.ListenError!net.Socket.Handle {
32573784 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
32583785 const t: *Threaded = @ptrCast(@alignCast(userdata));
3259 const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
3786 const current_thread = Thread.getCurrent(t);
3787 const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
32603788 error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,
32613789 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
32623790 error.SocketModeUnsupported => return error.AddressFamilyUnsupported,
......@@ -3267,15 +3795,28 @@ fn netListenUnixPosix(
32673795
32683796 var storage: UnixAddress = undefined;
32693797 const addr_len = addressUnixToPosix(address, &storage);
3270 try posixBindUnix(t, socket_fd, &storage.any, addr_len);
3798 try posixBindUnix(current_thread, socket_fd, &storage.any, addr_len);
32713799
3800 try current_thread.beginSyscall();
32723801 while (true) {
3273 try t.checkCancel();
32743802 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),
3803 .SUCCESS => {
3804 current_thread.endSyscall();
3805 break;
3806 },
3807 .INTR => {
3808 try current_thread.checkCancel();
3809 continue;
3810 },
3811 .CANCELED => return current_thread.endSyscallCanceled(),
3812 else => |e| {
3813 current_thread.endSyscall();
3814 switch (e) {
3815 .ADDRINUSE => return error.AddressInUse,
3816 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3817 else => |err| return posix.unexpectedErrno(err),
3818 }
3819 },
32793820 }
32803821 }
32813822
......@@ -3289,8 +3830,9 @@ fn netListenUnixWindows(
32893830) net.UnixAddress.ListenError!net.Socket.Handle {
32903831 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
32913832 const t: *Threaded = @ptrCast(@alignCast(userdata));
3833 const current_thread = Thread.getCurrent(t);
32923834
3293 const socket_handle = openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
3835 const socket_handle = openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
32943836 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
32953837 else => |e| return e,
32963838 };
......@@ -3299,52 +3841,67 @@ fn netListenUnixWindows(
32993841 var storage: WsaAddress = undefined;
33003842 const addr_len = addressUnixToWsa(address, &storage);
33013843
3844 try current_thread.beginSyscall();
33023845 while (true) {
3303 try t.checkCancel();
33043846 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
33053847 if (rc != ws2_32.SOCKET_ERROR) break;
33063848 switch (ws2_32.WSAGetLastError()) {
3307 .EINTR => continue,
3308 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3849 .EINTR => {
3850 try current_thread.checkCancel();
3851 continue;
3852 },
33093853 .NOTINITIALISED => {
33103854 try initializeWsa(t);
3855 try current_thread.checkCancel();
33113856 continue;
33123857 },
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),
3858 else => |e| {
3859 current_thread.endSyscall();
3860 switch (e) {
3861 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3862 .EADDRINUSE => return error.AddressInUse,
3863 .EADDRNOTAVAIL => return error.AddressUnavailable,
3864 .ENOTSOCK => |err| return wsaErrorBug(err),
3865 .EFAULT => |err| return wsaErrorBug(err),
3866 .EINVAL => |err| return wsaErrorBug(err),
3867 .ENOBUFS => return error.SystemResources,
3868 .ENETDOWN => return error.NetworkDown,
3869 else => |err| return windows.unexpectedWSAError(err),
3870 }
3871 },
33213872 }
33223873 }
33233874
33243875 while (true) {
3325 try t.checkCancel();
3876 try current_thread.checkCancel();
33263877 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
3327 if (rc != ws2_32.SOCKET_ERROR) break;
3878 if (rc != ws2_32.SOCKET_ERROR) {
3879 current_thread.endSyscall();
3880 return socket_handle;
3881 }
33283882 switch (ws2_32.WSAGetLastError()) {
33293883 .EINTR => continue,
3330 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
33313884 .NOTINITIALISED => {
33323885 try initializeWsa(t);
33333886 continue;
33343887 },
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),
3888 else => |e| {
3889 current_thread.endSyscall();
3890 switch (e) {
3891 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3892 .ENETDOWN => return error.NetworkDown,
3893 .EADDRINUSE => return error.AddressInUse,
3894 .EISCONN => |err| return wsaErrorBug(err),
3895 .EINVAL => |err| return wsaErrorBug(err),
3896 .EMFILE, .ENOBUFS => return error.SystemResources,
3897 .ENOTSOCK => |err| return wsaErrorBug(err),
3898 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3899 .EINPROGRESS => |err| return wsaErrorBug(err),
3900 else => |err| return windows.unexpectedWSAError(err),
3901 }
3902 },
33443903 }
33453904 }
3346
3347 return socket_handle;
33483905}
33493906
33503907fn netListenUnixUnavailable(
......@@ -3358,172 +3915,275 @@ fn netListenUnixUnavailable(
33583915 return error.AddressFamilyUnsupported;
33593916}
33603917
3361fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
3918fn posixBindUnix(
3919 current_thread: *Thread,
3920 fd: posix.socket_t,
3921 addr: *const posix.sockaddr,
3922 addr_len: posix.socklen_t,
3923) !void {
3924 try current_thread.beginSyscall();
33623925 while (true) {
3363 try t.checkCancel();
33643926 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),
3927 .SUCCESS => {
3928 current_thread.endSyscall();
3929 break;
3930 },
3931 .INTR => {
3932 try current_thread.checkCancel();
3933 continue;
3934 },
3935 .CANCELED => return current_thread.endSyscallCanceled(),
3936 else => |e| {
3937 current_thread.endSyscall();
3938 switch (e) {
3939 .ACCES => return error.AccessDenied,
3940 .ADDRINUSE => return error.AddressInUse,
3941 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3942 .ADDRNOTAVAIL => return error.AddressUnavailable,
3943 .NOMEM => return error.SystemResources,
3944
3945 .LOOP => return error.SymLinkLoop,
3946 .NOENT => return error.FileNotFound,
3947 .NOTDIR => return error.NotDir,
3948 .ROFS => return error.ReadOnlyFileSystem,
3949 .PERM => return error.PermissionDenied,
3950
3951 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3952 .INVAL => |err| return errnoBug(err), // invalid parameters
3953 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3954 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3955 .NAMETOOLONG => |err| return errnoBug(err),
3956 else => |err| return posix.unexpectedErrno(err),
3957 }
3958 },
33873959 }
33883960 }
33893961}
33903962
3391fn posixBind(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
3963fn posixBind(
3964 current_thread: *Thread,
3965 socket_fd: posix.socket_t,
3966 addr: *const posix.sockaddr,
3967 addr_len: posix.socklen_t,
3968) !void {
3969 try current_thread.beginSyscall();
33923970 while (true) {
3393 try t.checkCancel();
33943971 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),
3972 .SUCCESS => {
3973 current_thread.endSyscall();
3974 break;
3975 },
3976 .INTR => {
3977 try current_thread.checkCancel();
3978 continue;
3979 },
3980 .CANCELED => return current_thread.endSyscallCanceled(),
3981 else => |e| {
3982 current_thread.endSyscall();
3983 switch (e) {
3984 .ADDRINUSE => return error.AddressInUse,
3985 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3986 .INVAL => |err| return errnoBug(err), // invalid parameters
3987 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3988 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3989 .ADDRNOTAVAIL => return error.AddressUnavailable,
3990 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3991 .NOMEM => return error.SystemResources,
3992 else => |err| return posix.unexpectedErrno(err),
3993 }
3994 },
34083995 }
34093996 }
34103997}
34113998
3412fn posixConnect(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
3999fn posixConnect(
4000 current_thread: *Thread,
4001 socket_fd: posix.socket_t,
4002 addr: *const posix.sockaddr,
4003 addr_len: posix.socklen_t,
4004) !void {
4005 try current_thread.beginSyscall();
34134006 while (true) {
3414 try t.checkCancel();
34154007 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),
4008 .SUCCESS => {
4009 current_thread.endSyscall();
4010 return;
4011 },
4012 .INTR => {
4013 try current_thread.checkCancel();
4014 continue;
4015 },
4016 .CANCELED => return current_thread.endSyscallCanceled(),
4017 else => |e| {
4018 current_thread.endSyscall();
4019 switch (e) {
4020 .ADDRNOTAVAIL => return error.AddressUnavailable,
4021 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4022 .AGAIN, .INPROGRESS => return error.WouldBlock,
4023 .ALREADY => return error.ConnectionPending,
4024 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4025 .CONNREFUSED => return error.ConnectionRefused,
4026 .CONNRESET => return error.ConnectionResetByPeer,
4027 .FAULT => |err| return errnoBug(err),
4028 .ISCONN => |err| return errnoBug(err),
4029 .HOSTUNREACH => return error.HostUnreachable,
4030 .NETUNREACH => return error.NetworkUnreachable,
4031 .NOTSOCK => |err| return errnoBug(err),
4032 .PROTOTYPE => |err| return errnoBug(err),
4033 .TIMEDOUT => return error.Timeout,
4034 .CONNABORTED => |err| return errnoBug(err),
4035 .ACCES => return error.AccessDenied,
4036 .PERM => |err| return errnoBug(err),
4037 .NOENT => |err| return errnoBug(err),
4038 .NETDOWN => return error.NetworkDown,
4039 else => |err| return posix.unexpectedErrno(err),
4040 }
4041 },
34404042 }
34414043 }
34424044}
34434045
3444fn posixConnectUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
4046fn posixConnectUnix(
4047 current_thread: *Thread,
4048 fd: posix.socket_t,
4049 addr: *const posix.sockaddr,
4050 addr_len: posix.socklen_t,
4051) !void {
4052 try current_thread.beginSyscall();
34454053 while (true) {
3446 try t.checkCancel();
34474054 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),
4055 .SUCCESS => {
4056 current_thread.endSyscall();
4057 return;
4058 },
4059 .INTR => {
4060 try current_thread.checkCancel();
4061 continue;
4062 },
4063 .CANCELED => return current_thread.endSyscallCanceled(),
4064 else => |e| {
4065 current_thread.endSyscall();
4066 switch (e) {
4067 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4068 .AGAIN => return error.WouldBlock,
4069 .INPROGRESS => return error.WouldBlock,
4070 .ACCES => return error.AccessDenied,
4071
4072 .LOOP => return error.SymLinkLoop,
4073 .NOENT => return error.FileNotFound,
4074 .NOTDIR => return error.NotDir,
4075 .ROFS => return error.ReadOnlyFileSystem,
4076 .PERM => return error.PermissionDenied,
4077
4078 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4079 .CONNABORTED => |err| return errnoBug(err),
4080 .FAULT => |err| return errnoBug(err),
4081 .ISCONN => |err| return errnoBug(err),
4082 .NOTSOCK => |err| return errnoBug(err),
4083 .PROTOTYPE => |err| return errnoBug(err),
4084 else => |err| return posix.unexpectedErrno(err),
4085 }
4086 },
34704087 }
34714088 }
34724089}
34734090
3474fn posixGetSockName(t: *Threaded, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void {
4091fn posixGetSockName(
4092 current_thread: *Thread,
4093 socket_fd: posix.fd_t,
4094 addr: *posix.sockaddr,
4095 addr_len: *posix.socklen_t,
4096) !void {
4097 try current_thread.beginSyscall();
34754098 while (true) {
3476 try t.checkCancel();
34774099 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),
4100 .SUCCESS => {
4101 current_thread.endSyscall();
4102 break;
4103 },
4104 .INTR => {
4105 try current_thread.checkCancel();
4106 continue;
4107 },
4108 .CANCELED => return current_thread.endSyscallCanceled(),
4109 else => |e| {
4110 current_thread.endSyscall();
4111 switch (e) {
4112 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4113 .FAULT => |err| return errnoBug(err),
4114 .INVAL => |err| return errnoBug(err), // invalid parameters
4115 .NOTSOCK => |err| return errnoBug(err), // always a race condition
4116 .NOBUFS => return error.SystemResources,
4117 else => |err| return posix.unexpectedErrno(err),
4118 }
4119 },
34884120 }
34894121 }
34904122}
34914123
3492fn wsaGetSockName(t: *Threaded, handle: ws2_32.SOCKET, addr: *ws2_32.sockaddr, addr_len: *i32) !void {
4124fn wsaGetSockName(
4125 t: *Threaded,
4126 current_thread: *Thread,
4127 handle: ws2_32.SOCKET,
4128 addr: *ws2_32.sockaddr,
4129 addr_len: *i32,
4130) !void {
4131 try current_thread.beginSyscall();
34934132 while (true) {
3494 try t.checkCancel();
34954133 const rc = ws2_32.getsockname(handle, addr, addr_len);
3496 if (rc != ws2_32.SOCKET_ERROR) break;
4134 if (rc != ws2_32.SOCKET_ERROR) {
4135 current_thread.endSyscall();
4136 return;
4137 }
34974138 switch (ws2_32.WSAGetLastError()) {
3498 .EINTR => continue,
3499 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4139 .EINTR => {
4140 try current_thread.checkCancel();
4141 continue;
4142 },
35004143 .NOTINITIALISED => {
35014144 try initializeWsa(t);
4145 try current_thread.checkCancel();
35024146 continue;
35034147 },
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),
4148 else => |e| {
4149 current_thread.endSyscall();
4150 switch (e) {
4151 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4152 .ENETDOWN => return error.NetworkDown,
4153 .EFAULT => |err| return wsaErrorBug(err),
4154 .ENOTSOCK => |err| return wsaErrorBug(err),
4155 .EINVAL => |err| return wsaErrorBug(err),
4156 else => |err| return windows.unexpectedWSAError(err),
4157 }
4158 },
35094159 }
35104160 }
35114161}
35124162
3513fn setSocketOption(t: *Threaded, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
4163fn setSocketOption(current_thread: *Thread, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
35144164 const o: []const u8 = @ptrCast(&option);
4165 try current_thread.beginSyscall();
35154166 while (true) {
3516 try t.checkCancel();
35174167 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),
4168 .SUCCESS => {
4169 current_thread.endSyscall();
4170 return;
4171 },
4172 .INTR => {
4173 try current_thread.checkCancel();
4174 continue;
4175 },
4176 .CANCELED => return current_thread.endSyscallCanceled(),
4177 else => |e| {
4178 current_thread.endSyscall();
4179 switch (e) {
4180 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4181 .NOTSOCK => |err| return errnoBug(err),
4182 .INVAL => |err| return errnoBug(err),
4183 .FAULT => |err| return errnoBug(err),
4184 else => |err| return posix.unexpectedErrno(err),
4185 }
4186 },
35274187 }
35284188 }
35294189}
......@@ -3557,16 +4217,17 @@ fn netConnectIpPosix(
35574217 if (!have_networking) return error.NetworkDown;
35584218 if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");
35594219 const t: *Threaded = @ptrCast(@alignCast(userdata));
4220 const current_thread = Thread.getCurrent(t);
35604221 const family = posixAddressFamily(address);
3561 const socket_fd = try openSocketPosix(t, family, .{
4222 const socket_fd = try openSocketPosix(current_thread, family, .{
35624223 .mode = options.mode,
35634224 .protocol = options.protocol,
35644225 });
35654226 errdefer posix.close(socket_fd);
35664227 var storage: PosixAddress = undefined;
35674228 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);
4229 try posixConnect(current_thread, socket_fd, &storage.any, addr_len);
4230 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
35704231 return .{ .socket = .{
35714232 .handle = socket_fd,
35724233 .address = addressFromPosix(&storage),
......@@ -3581,8 +4242,9 @@ fn netConnectIpWindows(
35814242 if (!have_networking) return error.NetworkDown;
35824243 if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");
35834244 const t: *Threaded = @ptrCast(@alignCast(userdata));
4245 const current_thread = Thread.getCurrent(t);
35844246 const family = posixAddressFamily(address);
3585 const socket_handle = try openSocketWsa(t, family, .{
4247 const socket_handle = try openSocketWsa(t, current_thread, family, .{
35864248 .mode = options.mode,
35874249 .protocol = options.protocol,
35884250 });
......@@ -3591,36 +4253,48 @@ fn netConnectIpWindows(
35914253 var storage: WsaAddress = undefined;
35924254 var addr_len = addressToWsa(address, &storage);
35934255
4256 try current_thread.beginSyscall();
35944257 while (true) {
35954258 const rc = ws2_32.connect(socket_handle, &storage.any, addr_len);
3596 if (rc != ws2_32.SOCKET_ERROR) break;
4259 if (rc != ws2_32.SOCKET_ERROR) {
4260 current_thread.endSyscall();
4261 break;
4262 }
35974263 switch (ws2_32.WSAGetLastError()) {
3598 .EINTR => continue,
3599 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4264 .EINTR => {
4265 try current_thread.checkCancel();
4266 continue;
4267 },
36004268 .NOTINITIALISED => {
36014269 try initializeWsa(t);
4270 try current_thread.checkCancel();
36024271 continue;
36034272 },
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),
4273 else => |e| {
4274 current_thread.endSyscall();
4275 switch (e) {
4276 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4277 .EADDRNOTAVAIL => return error.AddressUnavailable,
4278 .ECONNREFUSED => return error.ConnectionRefused,
4279 .ECONNRESET => return error.ConnectionResetByPeer,
4280 .ETIMEDOUT => return error.Timeout,
4281 .EHOSTUNREACH => return error.HostUnreachable,
4282 .ENETUNREACH => return error.NetworkUnreachable,
4283 .EFAULT => |err| return wsaErrorBug(err),
4284 .EINVAL => |err| return wsaErrorBug(err),
4285 .EISCONN => |err| return wsaErrorBug(err),
4286 .ENOTSOCK => |err| return wsaErrorBug(err),
4287 .EWOULDBLOCK => return error.WouldBlock,
4288 .EACCES => return error.AccessDenied,
4289 .ENOBUFS => return error.SystemResources,
4290 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4291 else => |err| return windows.unexpectedWSAError(err),
4292 }
4293 },
36204294 }
36214295 }
36224296
3623 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
4297 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
36244298
36254299 return .{ .socket = .{
36264300 .handle = socket_handle,
......@@ -3645,14 +4319,15 @@ fn netConnectUnixPosix(
36454319) net.UnixAddress.ConnectError!net.Socket.Handle {
36464320 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
36474321 const t: *Threaded = @ptrCast(@alignCast(userdata));
3648 const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
4322 const current_thread = Thread.getCurrent(t);
4323 const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
36494324 error.OptionUnsupported => return error.Unexpected,
36504325 else => |e| return e,
36514326 };
36524327 errdefer posix.close(socket_fd);
36534328 var storage: UnixAddress = undefined;
36544329 const addr_len = addressUnixToPosix(address, &storage);
3655 try posixConnectUnix(t, socket_fd, &storage.any, addr_len);
4330 try posixConnectUnix(current_thread, socket_fd, &storage.any, addr_len);
36564331 return socket_fd;
36574332}
36584333
......@@ -3662,8 +4337,9 @@ fn netConnectUnixWindows(
36624337) net.UnixAddress.ConnectError!net.Socket.Handle {
36634338 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
36644339 const t: *Threaded = @ptrCast(@alignCast(userdata));
4340 const current_thread = Thread.getCurrent(t);
36654341
3666 const socket_handle = try openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream });
4342 const socket_handle = try openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream });
36674343 errdefer closeSocketWindows(socket_handle);
36684344 var storage: WsaAddress = undefined;
36694345 const addr_len = addressUnixToWsa(address, &storage);
......@@ -3711,13 +4387,14 @@ fn netBindIpPosix(
37114387) IpAddress.BindError!net.Socket {
37124388 if (!have_networking) return error.NetworkDown;
37134389 const t: *Threaded = @ptrCast(@alignCast(userdata));
4390 const current_thread = Thread.getCurrent(t);
37144391 const family = posixAddressFamily(address);
3715 const socket_fd = try openSocketPosix(t, family, options);
4392 const socket_fd = try openSocketPosix(current_thread, family, options);
37164393 errdefer posix.close(socket_fd);
37174394 var storage: PosixAddress = undefined;
37184395 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);
4396 try posixBind(current_thread, socket_fd, &storage.any, addr_len);
4397 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
37214398 return .{
37224399 .handle = socket_fd,
37234400 .address = addressFromPosix(&storage),
......@@ -3731,8 +4408,9 @@ fn netBindIpWindows(
37314408) IpAddress.BindError!net.Socket {
37324409 if (!have_networking) return error.NetworkDown;
37334410 const t: *Threaded = @ptrCast(@alignCast(userdata));
4411 const current_thread = Thread.getCurrent(t);
37344412 const family = posixAddressFamily(address);
3735 const socket_handle = try openSocketWsa(t, family, .{
4413 const socket_handle = try openSocketWsa(t, current_thread, family, .{
37364414 .mode = options.mode,
37374415 .protocol = options.protocol,
37384416 });
......@@ -3741,29 +4419,41 @@ fn netBindIpWindows(
37414419 var storage: WsaAddress = undefined;
37424420 var addr_len = addressToWsa(address, &storage);
37434421
4422 try current_thread.beginSyscall();
37444423 while (true) {
3745 try t.checkCancel();
37464424 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
3747 if (rc != ws2_32.SOCKET_ERROR) break;
4425 if (rc != ws2_32.SOCKET_ERROR) {
4426 current_thread.endSyscall();
4427 break;
4428 }
37484429 switch (ws2_32.WSAGetLastError()) {
3749 .EINTR => continue,
3750 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4430 .EINTR => {
4431 try current_thread.checkCancel();
4432 continue;
4433 },
37514434 .NOTINITIALISED => {
37524435 try initializeWsa(t);
4436 try current_thread.checkCancel();
37534437 continue;
37544438 },
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),
4439 else => |e| {
4440 current_thread.endSyscall();
4441 switch (e) {
4442 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4443 .EADDRINUSE => return error.AddressInUse,
4444 .EADDRNOTAVAIL => return error.AddressUnavailable,
4445 .ENOTSOCK => |err| return wsaErrorBug(err),
4446 .EFAULT => |err| return wsaErrorBug(err),
4447 .EINVAL => |err| return wsaErrorBug(err),
4448 .ENOBUFS => return error.SystemResources,
4449 .ENETDOWN => return error.NetworkDown,
4450 else => |err| return windows.unexpectedWSAError(err),
4451 }
4452 },
37634453 }
37644454 }
37654455
3766 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
4456 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
37674457
37684458 return .{
37694459 .handle = socket_handle,
......@@ -3783,7 +4473,7 @@ fn netBindIpUnavailable(
37834473}
37844474
37854475fn openSocketPosix(
3786 t: *Threaded,
4476 current_thread: *Thread,
37874477 family: posix.sa_family_t,
37884478 options: IpAddress.BindOptions,
37894479) error{
......@@ -3800,8 +4490,8 @@ fn openSocketPosix(
38004490}!posix.socket_t {
38014491 const mode = posixSocketMode(options.mode);
38024492 const protocol = posixProtocol(options.protocol);
4493 try current_thread.beginSyscall();
38034494 const socket_fd = while (true) {
3804 try t.checkCancel();
38054495 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
38064496 const socket_rc = posix.system.socket(family, flags, protocol);
38074497 switch (posix.errno(socket_rc)) {
......@@ -3809,60 +4499,88 @@ fn openSocketPosix(
38094499 const fd: posix.fd_t = @intCast(socket_rc);
38104500 errdefer posix.close(fd);
38114501 if (socket_flags_unsupported) while (true) {
3812 try t.checkCancel();
4502 try current_thread.checkCancel();
38134503 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
38144504 .SUCCESS => break,
38154505 .INTR => continue,
3816 .CANCELED => return error.Canceled,
3817 else => |err| return posix.unexpectedErrno(err),
4506 .CANCELED => return current_thread.endSyscallCanceled(),
4507 else => |err| {
4508 current_thread.endSyscall();
4509 return posix.unexpectedErrno(err);
4510 },
38184511 }
38194512 };
4513 current_thread.endSyscall();
38204514 break fd;
38214515 },
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),
4516 .INTR => {
4517 try current_thread.checkCancel();
4518 continue;
4519 },
4520 .CANCELED => return current_thread.endSyscallCanceled(),
4521 else => |e| {
4522 current_thread.endSyscall();
4523 switch (e) {
4524 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4525 .INVAL => return error.ProtocolUnsupportedBySystem,
4526 .MFILE => return error.ProcessFdQuotaExceeded,
4527 .NFILE => return error.SystemFdQuotaExceeded,
4528 .NOBUFS => return error.SystemResources,
4529 .NOMEM => return error.SystemResources,
4530 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
4531 .PROTOTYPE => return error.SocketModeUnsupported,
4532 else => |err| return posix.unexpectedErrno(err),
4533 }
4534 },
38344535 }
38354536 };
38364537 errdefer posix.close(socket_fd);
38374538
38384539 if (options.ip6_only) {
38394540 if (posix.IPV6 == void) return error.OptionUnsupported;
3840 try setSocketOption(t, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
4541 try setSocketOption(current_thread, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
38414542 }
38424543
38434544 return socket_fd;
38444545}
38454546
3846fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.BindOptions) !ws2_32.SOCKET {
4547fn openSocketWsa(
4548 t: *Threaded,
4549 current_thread: *Thread,
4550 family: posix.sa_family_t,
4551 options: IpAddress.BindOptions,
4552) !ws2_32.SOCKET {
38474553 const mode = posixSocketMode(options.mode);
38484554 const protocol = posixProtocol(options.protocol);
38494555 const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
4556 try current_thread.beginSyscall();
38504557 while (true) {
3851 try t.checkCancel();
38524558 const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);
3853 if (rc != ws2_32.INVALID_SOCKET) return rc;
4559 if (rc != ws2_32.INVALID_SOCKET) {
4560 current_thread.endSyscall();
4561 return rc;
4562 }
38544563 switch (ws2_32.WSAGetLastError()) {
3855 .EINTR => continue,
3856 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4564 .EINTR => {
4565 try current_thread.checkCancel();
4566 continue;
4567 },
38574568 .NOTINITIALISED => {
38584569 try initializeWsa(t);
4570 try current_thread.checkCancel();
38594571 continue;
38604572 },
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),
4573 else => |e| {
4574 current_thread.endSyscall();
4575 switch (e) {
4576 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4577 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4578 .EMFILE => return error.ProcessFdQuotaExceeded,
4579 .ENOBUFS => return error.SystemResources,
4580 .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
4581 else => |err| return windows.unexpectedWSAError(err),
4582 }
4583 },
38664584 }
38674585 }
38684586}
......@@ -3870,10 +4588,11 @@ fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.Bin
38704588fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {
38714589 if (!have_networking) return error.NetworkDown;
38724590 const t: *Threaded = @ptrCast(@alignCast(userdata));
4591 const current_thread = Thread.getCurrent(t);
38734592 var storage: PosixAddress = undefined;
38744593 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);
4594 try current_thread.beginSyscall();
38754595 const fd = while (true) {
3876 try t.checkCancel();
38774596 const rc = if (have_accept4)
38784597 posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC)
38794598 else
......@@ -3883,33 +4602,43 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
38834602 const fd: posix.fd_t = @intCast(rc);
38844603 errdefer posix.close(fd);
38854604 if (!have_accept4) while (true) {
3886 try t.checkCancel();
4605 try current_thread.checkCancel();
38874606 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
38884607 .SUCCESS => break,
38894608 .INTR => continue,
3890 .CANCELED => return error.Canceled,
3891 else => |err| return posix.unexpectedErrno(err),
4609 else => |err| {
4610 current_thread.endSyscall();
4611 return posix.unexpectedErrno(err);
4612 },
38924613 }
38934614 };
4615 current_thread.endSyscall();
38944616 break fd;
38954617 },
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),
4618 .INTR => {
4619 try current_thread.checkCancel();
4620 continue;
4621 },
4622 .CANCELED => return current_thread.endSyscallCanceled(),
4623 else => |e| {
4624 current_thread.endSyscall();
4625 switch (e) {
4626 .AGAIN => |err| return errnoBug(err),
4627 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4628 .CONNABORTED => return error.ConnectionAborted,
4629 .FAULT => |err| return errnoBug(err),
4630 .INVAL => return error.SocketNotListening,
4631 .NOTSOCK => |err| return errnoBug(err),
4632 .MFILE => return error.ProcessFdQuotaExceeded,
4633 .NFILE => return error.SystemFdQuotaExceeded,
4634 .NOBUFS => return error.SystemResources,
4635 .NOMEM => return error.SystemResources,
4636 .OPNOTSUPP => |err| return errnoBug(err),
4637 .PROTO => return error.ProtocolFailure,
4638 .PERM => return error.BlockedByFirewall,
4639 else => |err| return posix.unexpectedErrno(err),
4640 }
4641 },
39134642 }
39144643 };
39154644 return .{ .socket = .{
......@@ -3921,31 +4650,44 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
39214650fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream {
39224651 if (!have_networking) return error.NetworkDown;
39234652 const t: *Threaded = @ptrCast(@alignCast(userdata));
4653 const current_thread = Thread.getCurrent(t);
39244654 var storage: WsaAddress = undefined;
39254655 var addr_len: i32 = @sizeOf(WsaAddress);
4656 try current_thread.beginSyscall();
39264657 while (true) {
3927 try t.checkCancel();
39284658 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 } };
4659 if (rc != ws2_32.INVALID_SOCKET) {
4660 current_thread.endSyscall();
4661 return .{ .socket = .{
4662 .handle = rc,
4663 .address = addressFromWsa(&storage),
4664 } };
4665 }
39334666 switch (ws2_32.WSAGetLastError()) {
3934 .EINTR => continue,
3935 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4667 .EINTR => {
4668 try current_thread.checkCancel();
4669 continue;
4670 },
39364671 .NOTINITIALISED => {
39374672 try initializeWsa(t);
4673 try current_thread.checkCancel();
39384674 continue;
39394675 },
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),
4676 else => |e| {
4677 current_thread.endSyscall();
4678 switch (e) {
4679 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4680 .ECONNRESET => return error.ConnectionAborted,
4681 .EFAULT => |err| return wsaErrorBug(err),
4682 .ENOTSOCK => |err| return wsaErrorBug(err),
4683 .EINVAL => |err| return wsaErrorBug(err),
4684 .EMFILE => return error.ProcessFdQuotaExceeded,
4685 .ENETDOWN => return error.NetworkDown,
4686 .ENOBUFS => return error.SystemResources,
4687 .EOPNOTSUPP => |err| return wsaErrorBug(err),
4688 else => |err| return windows.unexpectedWSAError(err),
4689 }
4690 },
39494691 }
39504692 }
39514693}
......@@ -3959,6 +4701,7 @@ fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle)
39594701fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
39604702 if (!have_networking) return error.NetworkDown;
39614703 const t: *Threaded = @ptrCast(@alignCast(userdata));
4704 const current_thread = Thread.getCurrent(t);
39624705
39634706 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
39644707 var i: usize = 0;
......@@ -3972,48 +4715,70 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
39724715 const dest = iovecs_buffer[0..i];
39734716 assert(dest[0].len > 0);
39744717
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),
4718 if (native_os == .wasi and !builtin.link_libc) {
4719 try current_thread.beginSyscall();
4720 while (true) {
4721 var n: usize = undefined;
4722 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
4723 .SUCCESS => {
4724 current_thread.endSyscall();
4725 return n;
4726 },
4727 .INTR => {
4728 try current_thread.checkCancel();
4729 continue;
4730 },
4731 .CANCELED => return current_thread.endSyscallCanceled(),
4732 else => |e| {
4733 current_thread.endSyscall();
4734 switch (e) {
4735 .INVAL => |err| return errnoBug(err),
4736 .FAULT => |err| return errnoBug(err),
4737 .AGAIN => |err| return errnoBug(err),
4738 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4739 .NOBUFS => return error.SystemResources,
4740 .NOMEM => return error.SystemResources,
4741 .NOTCONN => return error.SocketUnconnected,
4742 .CONNRESET => return error.ConnectionResetByPeer,
4743 .TIMEDOUT => return error.Timeout,
4744 .NOTCAPABLE => return error.AccessDenied,
4745 else => |err| return posix.unexpectedErrno(err),
4746 }
4747 },
4748 }
39944749 }
3995 };
4750 }
39964751
4752 try current_thread.beginSyscall();
39974753 while (true) {
3998 try t.checkCancel();
39994754 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
40004755 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),
4756 .SUCCESS => {
4757 current_thread.endSyscall();
4758 return @intCast(rc);
4759 },
4760 .INTR => {
4761 try current_thread.checkCancel();
4762 continue;
4763 },
4764 .CANCELED => return current_thread.endSyscallCanceled(),
4765 else => |e| {
4766 current_thread.endSyscall();
4767 switch (e) {
4768 .INVAL => |err| return errnoBug(err),
4769 .FAULT => |err| return errnoBug(err),
4770 .AGAIN => |err| return errnoBug(err),
4771 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4772 .NOBUFS => return error.SystemResources,
4773 .NOMEM => return error.SystemResources,
4774 .NOTCONN => return error.SocketUnconnected,
4775 .CONNRESET => return error.ConnectionResetByPeer,
4776 .TIMEDOUT => return error.Timeout,
4777 .PIPE => return error.SocketUnconnected,
4778 .NETDOWN => return error.NetworkDown,
4779 else => |err| return posix.unexpectedErrno(err),
4780 }
4781 },
40174782 }
40184783 }
40194784}
......@@ -4021,6 +4786,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
40214786fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
40224787 if (!have_networking) return error.NetworkDown;
40234788 const t: *Threaded = @ptrCast(@alignCast(userdata));
4789 const current_thread = Thread.getCurrent(t);
40244790
40254791 const bufs = b: {
40264792 var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined;
......@@ -4048,7 +4814,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8
40484814 };
40494815
40504816 while (true) {
4051 try t.checkCancel();
4817 try current_thread.checkCancel();
40524818
40534819 var flags: u32 = 0;
40544820 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
......@@ -4108,6 +4874,7 @@ fn netSendPosix(
41084874) struct { ?net.Socket.SendError, usize } {
41094875 if (!have_networking) return .{ error.NetworkDown, 0 };
41104876 const t: *Threaded = @ptrCast(@alignCast(userdata));
4877 const current_thread = Thread.getCurrent(t);
41114878
41124879 const posix_flags: u32 =
41134880 @as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |
......@@ -4120,10 +4887,10 @@ fn netSendPosix(
41204887 var i: usize = 0;
41214888 while (messages.len - i != 0) {
41224889 if (have_sendmmsg) {
4123 i += netSendMany(t, handle, messages[i..], posix_flags) catch |err| return .{ err, i };
4890 i += netSendMany(current_thread, handle, messages[i..], posix_flags) catch |err| return .{ err, i };
41244891 continue;
41254892 }
4126 netSendOne(t, handle, &messages[i], posix_flags) catch |err| return .{ err, i };
4893 netSendOne(t, current_thread, handle, &messages[i], posix_flags) catch |err| return .{ err, i };
41274894 i += 1;
41284895 }
41294896 return .{ null, i };
......@@ -4159,6 +4926,7 @@ fn netSendUnavailable(
41594926
41604927fn netSendOne(
41614928 t: *Threaded,
4929 current_thread: *Thread,
41624930 handle: net.Socket.Handle,
41634931 message: *net.OutgoingMessage,
41644932 flags: u32,
......@@ -4175,80 +4943,97 @@ fn netSendOne(
41754943 .controllen = @intCast(message.control.len),
41764944 .flags = 0,
41774945 };
4946 try current_thread.beginSyscall();
41784947 while (true) {
4179 try t.checkCancel();
41804948 const rc = posix.system.sendmsg(handle, &msg, flags);
41814949 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 {
4950 if (rc != ws2_32.SOCKET_ERROR) {
4951 current_thread.endSyscall();
42094952 message.data_len = @intCast(rc);
42104953 return;
42114954 }
4955 switch (ws2_32.WSAGetLastError()) {
4956 .EINTR => {
4957 try current_thread.checkCancel();
4958 continue;
4959 },
4960 .NOTINITIALISED => {
4961 try initializeWsa(t);
4962 try current_thread.checkCancel();
4963 continue;
4964 },
4965 else => |e| {
4966 current_thread.endSyscall();
4967 switch (e) {
4968 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4969 .EACCES => return error.AccessDenied,
4970 .EADDRNOTAVAIL => return error.AddressUnavailable,
4971 .ECONNRESET => return error.ConnectionResetByPeer,
4972 .EMSGSIZE => return error.MessageOversize,
4973 .ENOBUFS => return error.SystemResources,
4974 .ENOTSOCK => return error.FileDescriptorNotASocket,
4975 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4976 .EDESTADDRREQ => unreachable, // A destination address is required.
4977 .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.
4978 .EHOSTUNREACH => return error.NetworkUnreachable,
4979 .EINVAL => unreachable,
4980 .ENETDOWN => return error.NetworkDown,
4981 .ENETRESET => return error.ConnectionResetByPeer,
4982 .ENETUNREACH => return error.NetworkUnreachable,
4983 .ENOTCONN => return error.SocketUnconnected,
4984 .ESHUTDOWN => |err| return wsaErrorBug(err),
4985 else => |err| return windows.unexpectedWSAError(err),
4986 }
4987 },
4988 }
42124989 }
42134990 switch (posix.errno(rc)) {
42144991 .SUCCESS => {
4992 current_thread.endSyscall();
42154993 message.data_len = @intCast(rc);
42164994 return;
42174995 },
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),
4996 .INTR => {
4997 try current_thread.checkCancel();
4998 continue;
4999 },
5000 .CANCELED => return current_thread.endSyscallCanceled(),
5001 else => |e| {
5002 current_thread.endSyscall();
5003 switch (e) {
5004 .ACCES => return error.AccessDenied,
5005 .ALREADY => return error.FastOpenAlreadyInProgress,
5006 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5007 .CONNRESET => return error.ConnectionResetByPeer,
5008 .DESTADDRREQ => |err| return errnoBug(err),
5009 .FAULT => |err| return errnoBug(err),
5010 .INVAL => |err| return errnoBug(err),
5011 .ISCONN => |err| return errnoBug(err),
5012 .MSGSIZE => return error.MessageOversize,
5013 .NOBUFS => return error.SystemResources,
5014 .NOMEM => return error.SystemResources,
5015 .NOTSOCK => |err| return errnoBug(err),
5016 .OPNOTSUPP => |err| return errnoBug(err),
5017 .PIPE => return error.SocketUnconnected,
5018 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
5019 .HOSTUNREACH => return error.HostUnreachable,
5020 .NETUNREACH => return error.NetworkUnreachable,
5021 .NOTCONN => return error.SocketUnconnected,
5022 .NETDOWN => return error.NetworkDown,
5023 else => |err| return posix.unexpectedErrno(err),
5024 }
5025 },
42415026 }
42425027 }
42435028}
42445029
42455030fn netSendMany(
4246 t: *Threaded,
5031 current_thread: *Thread,
42475032 handle: net.Socket.Handle,
42485033 messages: []net.OutgoingMessage,
42495034 flags: u32,
42505035) net.Socket.SendError!usize {
4251 var msg_buffer: [64]std.os.linux.mmsghdr = undefined;
5036 var msg_buffer: [64]posix.system.mmsghdr = undefined;
42525037 var addr_buffer: [msg_buffer.len]PosixAddress = undefined;
42535038 var iovecs_buffer: [msg_buffer.len]posix.iovec = undefined;
42545039 const min_len: usize = @min(messages.len, msg_buffer.len);
......@@ -4273,40 +5058,48 @@ fn netSendMany(
42735058 };
42745059 }
42755060
5061 try current_thread.beginSyscall();
42765062 while (true) {
4277 try t.checkCancel();
42785063 const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags);
42795064 switch (posix.errno(rc)) {
42805065 .SUCCESS => {
5066 current_thread.endSyscall();
42815067 const n: usize = @intCast(rc);
42825068 for (clamped_messages[0..n], clamped_msgs[0..n]) |*message, *msg| {
42835069 message.data_len = msg.len;
42845070 }
42855071 return n;
42865072 },
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),
5073 .INTR => {
5074 try current_thread.checkCancel();
5075 continue;
5076 },
5077 .CANCELED => return current_thread.endSyscallCanceled(),
5078 else => |e| {
5079 current_thread.endSyscall();
5080 switch (e) {
5081 .AGAIN => |err| return errnoBug(err),
5082 .ALREADY => return error.FastOpenAlreadyInProgress,
5083 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5084 .CONNRESET => return error.ConnectionResetByPeer,
5085 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
5086 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
5087 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
5088 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
5089 .MSGSIZE => return error.MessageOversize,
5090 .NOBUFS => return error.SystemResources,
5091 .NOMEM => return error.SystemResources,
5092 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
5093 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
5094 .PIPE => return error.SocketUnconnected,
5095 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
5096 .HOSTUNREACH => return error.HostUnreachable,
5097 .NETUNREACH => return error.NetworkUnreachable,
5098 .NOTCONN => return error.SocketUnconnected,
5099 .NETDOWN => return error.NetworkDown,
5100 else => |err| return posix.unexpectedErrno(err),
5101 }
5102 },
43105103 }
43115104 }
43125105}
......@@ -4321,6 +5114,7 @@ fn netReceivePosix(
43215114) struct { ?net.Socket.ReceiveTimeoutError, usize } {
43225115 if (!have_networking) return .{ error.NetworkDown, 0 };
43235116 const t: *Threaded = @ptrCast(@alignCast(userdata));
5117 const current_thread = Thread.getCurrent(t);
43245118 const t_io = io(t);
43255119
43265120 // recvmmsg is useless, here's why:
......@@ -4351,8 +5145,6 @@ fn netReceivePosix(
43515145 const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i };
43525146
43535147 recv: while (true) {
4354 t.checkCancel() catch |err| return .{ err, message_i };
4355
43565148 if (message_buffer.len - message_i == 0) return .{ null, message_i };
43575149 const message = &message_buffer[message_i];
43585150 const remaining_data_buffer = data_buffer[data_i..];
......@@ -4368,7 +5160,9 @@ fn netReceivePosix(
43685160 .flags = undefined,
43695161 };
43705162
5163 current_thread.beginSyscall() catch |err| return .{ err, message_i };
43715164 const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags);
5165 current_thread.endSyscall();
43725166 switch (posix.errno(recv_rc)) {
43735167 .SUCCESS => {
43745168 const data = remaining_data_buffer[0..@intCast(recv_rc)];
......@@ -4389,7 +5183,6 @@ fn netReceivePosix(
43895183 continue;
43905184 },
43915185 .AGAIN => while (true) {
4392 t.checkCancel() catch |err| return .{ err, message_i };
43935186 if (message_i != 0) return .{ null, message_i };
43945187
43955188 const max_poll_ms = std.math.maxInt(u31);
......@@ -4399,7 +5192,10 @@ fn netReceivePosix(
43995192 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
44005193 } else max_poll_ms;
44015194
5195 current_thread.beginSyscall() catch |err| return .{ err, message_i };
44025196 const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
5197 current_thread.endSyscall();
5198
44035199 switch (posix.errno(poll_rc)) {
44045200 .SUCCESS => {
44055201 if (poll_rc == 0) {
......@@ -4411,7 +5207,7 @@ fn netReceivePosix(
44115207 continue :recv;
44125208 },
44135209 .INTR => continue,
4414 .CANCELED => return .{ error.Canceled, message_i },
5210 .CANCELED => return .{ current_thread.endSyscallCanceled(), message_i },
44155211
44165212 .FAULT => |err| return .{ errnoBug(err), message_i },
44175213 .INVAL => |err| return .{ errnoBug(err), message_i },
......@@ -4420,7 +5216,7 @@ fn netReceivePosix(
44205216 }
44215217 },
44225218 .INTR => continue,
4423 .CANCELED => return .{ error.Canceled, message_i },
5219 .CANCELED => return .{ current_thread.endSyscallCanceled(), message_i },
44245220
44255221 .BADF => |err| return .{ errnoBug(err), message_i },
44265222 .NFILE => return .{ error.SystemFdQuotaExceeded, message_i },
......@@ -4486,6 +5282,7 @@ fn netWritePosix(
44865282) net.Stream.Writer.Error!usize {
44875283 if (!have_networking) return error.NetworkDown;
44885284 const t: *Threaded = @ptrCast(@alignCast(userdata));
5285 const current_thread = Thread.getCurrent(t);
44895286
44905287 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;
44915288 var msg: posix.msghdr_const = .{
......@@ -4526,35 +5323,45 @@ fn netWritePosix(
45265323 },
45275324 };
45285325 const flags = posix.MSG.NOSIGNAL;
5326 try current_thread.beginSyscall();
45295327 while (true) {
4530 try t.checkCancel();
45315328 const rc = posix.system.sendmsg(fd, &msg, flags);
45325329 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),
5330 .SUCCESS => {
5331 current_thread.endSyscall();
5332 return @intCast(rc);
5333 },
5334 .INTR => {
5335 try current_thread.checkCancel();
5336 continue;
5337 },
5338 .CANCELED => return current_thread.endSyscallCanceled(),
5339 else => |e| {
5340 current_thread.endSyscall();
5341 switch (e) {
5342 .ACCES => |err| return errnoBug(err),
5343 .AGAIN => |err| return errnoBug(err),
5344 .ALREADY => return error.FastOpenAlreadyInProgress,
5345 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5346 .CONNRESET => return error.ConnectionResetByPeer,
5347 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
5348 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
5349 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
5350 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
5351 .MSGSIZE => |err| return errnoBug(err),
5352 .NOBUFS => return error.SystemResources,
5353 .NOMEM => return error.SystemResources,
5354 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
5355 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
5356 .PIPE => return error.SocketUnconnected,
5357 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
5358 .HOSTUNREACH => return error.HostUnreachable,
5359 .NETUNREACH => return error.NetworkUnreachable,
5360 .NOTCONN => return error.SocketUnconnected,
5361 .NETDOWN => return error.NetworkDown,
5362 else => |err| return posix.unexpectedErrno(err),
5363 }
5364 },
45585365 }
45595366 }
45605367}
......@@ -4567,6 +5374,7 @@ fn netWriteWindows(
45675374 splat: usize,
45685375) net.Stream.Writer.Error!usize {
45695376 const t: *Threaded = @ptrCast(@alignCast(userdata));
5377 const current_thread = Thread.getCurrent(t);
45705378 comptime assert(native_os == .windows);
45715379
45725380 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;
......@@ -4600,7 +5408,7 @@ fn netWriteWindows(
46005408 };
46015409
46025410 while (true) {
4603 try t.checkCancel();
5411 try current_thread.checkCancel();
46045412
46055413 var n: u32 = undefined;
46065414 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
......@@ -4626,7 +5434,7 @@ fn netWriteWindows(
46265434 };
46275435 switch (wsa_error) {
46285436 .EINTR => continue,
4629 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
5437 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return current_thread.endSyscallCanceled(),
46305438 .NOTINITIALISED => {
46315439 try initializeWsa(t);
46325440 continue;
......@@ -4707,9 +5515,10 @@ fn netInterfaceNameResolve(
47075515) net.Interface.Name.ResolveError!net.Interface {
47085516 if (!have_networking) return error.InterfaceNotFound;
47095517 const t: *Threaded = @ptrCast(@alignCast(userdata));
5518 const current_thread = Thread.getCurrent(t);
47105519
47115520 if (native_os == .linux) {
4712 const sock_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
5521 const sock_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
47135522 error.ProcessFdQuotaExceeded => return error.SystemResources,
47145523 error.SystemFdQuotaExceeded => return error.SystemResources,
47155524 error.AddressFamilyUnsupported => return error.Unexpected,
......@@ -4726,32 +5535,42 @@ fn netInterfaceNameResolve(
47265535 .ifru = undefined,
47275536 };
47285537
5538 try current_thread.beginSyscall();
47295539 while (true) {
4730 try t.checkCancel();
47315540 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),
5541 .SUCCESS => {
5542 current_thread.endSyscall();
5543 return .{ .index = @bitCast(ifr.ifru.ivalue) };
5544 },
5545 .INTR => {
5546 try current_thread.checkCancel();
5547 continue;
5548 },
5549 .CANCELED => return current_thread.endSyscallCanceled(),
5550 else => |e| {
5551 current_thread.endSyscall();
5552 switch (e) {
5553 .INVAL => |err| return errnoBug(err), // Bad parameters.
5554 .NOTTY => |err| return errnoBug(err),
5555 .NXIO => |err| return errnoBug(err),
5556 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5557 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
5558 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
5559 .NODEV => return error.InterfaceNotFound,
5560 else => |err| return posix.unexpectedErrno(err),
5561 }
5562 },
47445563 }
47455564 }
47465565 }
47475566
47485567 if (native_os == .windows) {
4749 try t.checkCancel();
5568 try current_thread.checkCancel();
47505569 @panic("TODO implement netInterfaceNameResolve for Windows");
47515570 }
47525571
47535572 if (builtin.link_libc) {
4754 try t.checkCancel();
5573 try current_thread.checkCancel();
47555574 const index = std.c.if_nametoindex(&name.bytes);
47565575 if (index == 0) return error.InterfaceNotFound;
47575576 return .{ .index = @bitCast(index) };
......@@ -4771,7 +5590,8 @@ fn netInterfaceNameResolveUnavailable(
47715590
47725591fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
47735592 const t: *Threaded = @ptrCast(@alignCast(userdata));
4774 try t.checkCancel();
5593 const current_thread = Thread.getCurrent(t);
5594 try current_thread.checkCancel();
47755595
47765596 if (native_os == .linux) {
47775597 _ = interface;
......@@ -4802,8 +5622,9 @@ fn netLookup(
48025622 options: HostName.LookupOptions,
48035623) void {
48045624 const t: *Threaded = @ptrCast(@alignCast(userdata));
5625 const current_thread = Thread.getCurrent(t);
48055626 const t_io = io(t);
4806 resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, host_name, resolved, options) });
5627 resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, current_thread, host_name, resolved, options) });
48075628}
48085629
48095630fn netLookupUnavailable(
......@@ -4821,6 +5642,7 @@ fn netLookupUnavailable(
48215642
48225643fn netLookupFallible(
48235644 t: *Threaded,
5645 current_thread: *Thread,
48245646 host_name: HostName,
48255647 resolved: *Io.Queue(HostName.LookupResult),
48265648 options: HostName.LookupOptions,
......@@ -4866,7 +5688,7 @@ fn netLookupFallible(
48665688 var res: *ws2_32.ADDRINFOEXW = undefined;
48675689 const timeout: ?*ws2_32.timeval = null;
48685690 while (true) {
4869 try t.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
5691 try current_thread.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
48705692 // TODO make this append to the queue eagerly rather than blocking until
48715693 // the whole thing finishes
48725694 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, cancel_handle));
......@@ -5013,23 +5835,37 @@ fn netLookupFallible(
50135835 .next = null,
50145836 };
50155837 var res: ?*posix.addrinfo = null;
5838 try current_thread.beginSyscall();
50165839 while (true) {
5017 try t.checkCancel();
50185840 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,
5841 @as(posix.system.EAI, @enumFromInt(0)) => {
5842 current_thread.endSyscall();
5843 break;
5844 },
50275845 .SYSTEM => switch (posix.errno(-1)) {
5028 .INTR => continue,
5029 .CANCELED => return error.Canceled,
5030 else => |e| return posix.unexpectedErrno(e),
5846 .INTR => {
5847 try current_thread.checkCancel();
5848 continue;
5849 },
5850 .CANCELED => return current_thread.endSyscallCanceled(),
5851 else => |e| {
5852 current_thread.endSyscall();
5853 return posix.unexpectedErrno(e);
5854 },
5855 },
5856 else => |e| {
5857 current_thread.endSyscall();
5858 switch (e) {
5859 .ADDRFAMILY => return error.AddressFamilyUnsupported,
5860 .AGAIN => return error.NameServerFailure,
5861 .FAIL => return error.NameServerFailure,
5862 .FAMILY => return error.AddressFamilyUnsupported,
5863 .MEMORY => return error.SystemResources,
5864 .NODATA => return error.UnknownHostName,
5865 .NONAME => return error.UnknownHostName,
5866 else => return error.Unexpected,
5867 }
50315868 },
5032 else => return error.Unexpected,
50335869 }
50345870 }
50355871 defer if (res) |some| posix.system.freeaddrinfo(some);
......@@ -5726,12 +6562,12 @@ fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) Hos
57266562/// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention)
57276563const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11;
57286564
5729fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {
6565fn futexWait(current_thread: *Thread, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {
57306566 @branchHint(.cold);
57316567
57326568 if (builtin.cpu.arch.isWasm()) {
57336569 comptime assert(builtin.cpu.has(.wasm, .atomics));
5734 try t.checkCancel();
6570 try current_thread.checkCancel();
57356571 const timeout: i64 = -1;
57366572 const signed_expect: i32 = @bitCast(expect);
57376573 const result = asm volatile (
......@@ -5754,17 +6590,18 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
57546590 } else switch (native_os) {
57556591 .linux => {
57566592 const linux = std.os.linux;
5757 try t.checkCancel();
6593 try current_thread.beginSyscall();
57586594 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
5759 if (is_debug) switch (linux.errno(rc)) {
6595 current_thread.endSyscall();
6596 switch (linux.errno(rc)) {
57606597 .SUCCESS => {}, // notified by `wake()`
5761 .INTR => {}, // gives caller a chance to check cancellation
6598 .INTR => {}, // caller's responsibility to retry
57626599 .AGAIN => {}, // ptr.* != expect
57636600 .INVAL => {}, // possibly timeout overflow
5764 .TIMEDOUT => unreachable,
5765 .FAULT => unreachable, // ptr was invalid
5766 else => unreachable,
5767 };
6601 .TIMEDOUT => recoverableOsBugDetected(),
6602 .FAULT => recoverableOsBugDetected(), // ptr was invalid
6603 else => recoverableOsBugDetected(),
6604 }
57686605 },
57696606 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => {
57706607 const c = std.c;
......@@ -5772,11 +6609,12 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
57726609 .op = .COMPARE_AND_WAIT,
57736610 .NO_ERRNO = true,
57746611 };
5775 try t.checkCancel();
6612 try current_thread.beginSyscall();
57766613 const status = if (darwin_supports_ulock_wait2)
57776614 c.__ulock_wait2(flags, ptr, expect, 0, 0)
57786615 else
57796616 c.__ulock_wait(flags, ptr, expect, 0);
6617 current_thread.endSyscall();
57806618
57816619 if (status >= 0) return;
57826620
......@@ -5791,7 +6629,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
57916629 };
57926630 },
57936631 .windows => {
5794 try t.checkCancel();
6632 try current_thread.checkCancel();
57956633 switch (windows.ntdll.RtlWaitOnAddress(ptr, &expect, @sizeOf(@TypeOf(expect)), null)) {
57966634 .SUCCESS => {},
57976635 .CANCELLED => return error.Canceled,
......@@ -5800,8 +6638,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
58006638 },
58016639 .freebsd => {
58026640 const flags = @intFromEnum(std.c.UMTX_OP.WAIT_UINT_PRIVATE);
5803 try t.checkCancel();
6641 try current_thread.beginSyscall();
58046642 const rc = std.c._umtx_op(@intFromPtr(&ptr.raw), flags, @as(c_ulong, expect), 0, 0);
6643 current_thread.endSyscall();
58056644 if (is_debug) switch (posix.errno(rc)) {
58066645 .SUCCESS => {},
58076646 .FAULT => unreachable, // one of the args points to invalid memory
......@@ -5845,7 +6684,7 @@ pub fn futexWaitUncancelable(ptr: *const std.atomic.Value(u32), expect: u32) voi
58456684 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
58466685 switch (linux.errno(rc)) {
58476686 .SUCCESS => {}, // notified by `wake()`
5848 .INTR => {}, // gives caller a chance to check cancellation
6687 .INTR => {}, // caller's responsibility to repeat
58496688 .AGAIN => {}, // ptr.* != expect
58506689 .INVAL => {}, // possibly timeout overflow
58516690 .TIMEDOUT => recoverableOsBugDetected(),
......@@ -5899,28 +6738,6 @@ pub fn futexWaitUncancelable(ptr: *const std.atomic.Value(u32), expect: u32) voi
58996738 }
59006739}
59016740
5902pub fn futexWaitDurationUncancelable(ptr: *const std.atomic.Value(u32), expect: u32, timeout: Io.Duration) void {
5903 @branchHint(.cold);
5904
5905 if (native_os == .linux) {
5906 const linux = std.os.linux;
5907 var ts = timestampToPosix(timeout.toNanoseconds());
5908 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, &ts);
5909 if (is_debug) switch (linux.errno(rc)) {
5910 .SUCCESS => {}, // notified by `wake()`
5911 .INTR => {}, // gives caller a chance to check cancellation
5912 .AGAIN => {}, // ptr.* != expect
5913 .TIMEDOUT => {},
5914 .INVAL => {}, // possibly timeout overflow
5915 .FAULT => unreachable, // ptr was invalid
5916 else => unreachable,
5917 };
5918 return;
5919 } else {
5920 @compileError("TODO");
5921 }
5922}
5923
59246741pub fn futexWake(ptr: *const std.atomic.Value(u32), max_waiters: u32) void {
59256742 @branchHint(.cold);
59266743
......@@ -6050,8 +6867,9 @@ const ResetEventFutex = enum(u32) {
60506867 if (state == .unset) {
60516868 state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting;
60526869 }
6870 const current_thread = Thread.getCurrent(t);
60536871 while (state == .waiting) {
6054 try futexWait(t, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
6872 try futexWait(current_thread, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
60556873 state = @atomicLoad(ResetEventFutex, ref, .acquire);
60566874 }
60576875 assert(state == .is_set);
......@@ -6140,6 +6958,7 @@ const ResetEventPosix = struct {
61406958 .waiting => unreachable, // Invalid state.
61416959 .is_set => return,
61426960 };
6961 const current_thread = Thread.getCurrent(t);
61436962 assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS);
61446963 defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS);
61456964 sw: switch (rep.state) {
......@@ -6148,8 +6967,9 @@ const ResetEventPosix = struct {
61486967 continue :sw .waiting;
61496968 },
61506969 .waiting => {
6151 try t.checkCancel();
6970 try current_thread.beginSyscall();
61526971 assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS);
6972 current_thread.endSyscall();
61536973 continue :sw rep.state;
61546974 },
61556975 .is_set => return,
......@@ -6222,10 +7042,10 @@ const Wsa = struct {
62227042 } || Io.UnexpectedError;
62237043};
62247044
6225fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
7045fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
62267046 const t_io = io(t);
62277047 const wsa = &t.wsa;
6228 wsa.mutex.lockUncancelable(t_io);
7048 try wsa.mutex.lock(t_io);
62297049 defer wsa.mutex.unlock(t_io);
62307050 switch (wsa.status) {
62317051 .uninitialized => {
......@@ -6237,12 +7057,15 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
62377057 wsa.status = .initialized;
62387058 return;
62397059 },
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),
7060 else => |err_int| {
7061 wsa.status = .failure;
7062 wsa.init_error = switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
7063 .SYSNOTREADY => error.NetworkDown,
7064 .VERNOTSUPPORTED => error.VersionUnsupported,
7065 .EINPROGRESS => error.BlockingOperationInProgress,
7066 .EPROCLIM => error.ProcessFdQuotaExceeded,
7067 else => |err| windows.unexpectedWSAError(err),
7068 };
62467069 },
62477070 }
62487071 },
lib/std/c.zig+17
......@@ -10881,6 +10881,23 @@ pub extern "c" fn pthread_create(
1088110881 start_routine: *const fn (?*anyopaque) callconv(.c) ?*anyopaque,
1088210882 noalias arg: ?*anyopaque,
1088310883) E;
10884pub const pthread_cancelstate = switch (native_os) {
10885 .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => enum(c_int) {
10886 ENABLE = 1,
10887 DISABLE = 0,
10888 },
10889 .linux => if (native_abi.isMusl()) enum(c_int) {
10890 ENABLE = 0,
10891 DISABLE = 1,
10892 MASKED = 2,
10893 } else if (native_abi.isGnu()) enum(c_int) {
10894 ENABLE = 0,
10895 DISABLE = 1,
10896 },
10897 else => void,
10898};
10899pub extern "c" fn pthread_setcancelstate(pthread_cancelstate, ?*pthread_cancelstate) E;
10900pub extern "c" fn pthread_cancel(pthread_t) E;
1088410901pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) E;
1088510902pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *anyopaque, stacksize: usize) E;
1088610903pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) E;
lib/std/os/linux.zig+4-3
......@@ -1748,9 +1748,7 @@ pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
17481748}
17491749
17501750pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
1751 if (native_arch == .riscv32) {
1752 @compileError("No nanosleep syscall on this architecture.");
1753 } else return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem));
1751 return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem));
17541752}
17551753
17561754pub fn pause() usize {
......@@ -3773,6 +3771,7 @@ pub const SIG = if (is_mips) enum(u32) {
37733771 PROF = 29,
37743772 XCPU = 30,
37753773 XFZ = 31,
3774 _,
37763775} else if (is_sparc) enum(u32) {
37773776 pub const BLOCK = 1;
37783777 pub const UNBLOCK = 2;
......@@ -3818,6 +3817,7 @@ pub const SIG = if (is_mips) enum(u32) {
38183817 LOST = 29,
38193818 USR1 = 30,
38203819 USR2 = 31,
3820 _,
38213821} else enum(u32) {
38223822 pub const BLOCK = 0;
38233823 pub const UNBLOCK = 1;
......@@ -3861,6 +3861,7 @@ pub const SIG = if (is_mips) enum(u32) {
38613861 IO = 29,
38623862 PWR = 30,
38633863 SYS = 31,
3864 _,
38643865};
38653866
38663867pub const kernel_rwf = u32;
lib/std/posix.zig+1
......@@ -1360,6 +1360,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
13601360 .PIPE => return error.BrokenPipe,
13611361 .CONNRESET => return error.ConnectionResetByPeer,
13621362 .BUSY => return error.DeviceBusy,
1363 .CANCELED => return error.Canceled,
13631364 else => |err| return unexpectedErrno(err),
13641365 }
13651366 }
src/link/Elf/Atom.zig+7-32
......@@ -1499,22 +1499,18 @@ const aarch64 = struct {
14991499 .ABS64 => {
15001500 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
15011501 },
1502
15031502 .ADR_PREL_PG_HI21 => {
15041503 try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);
15051504 },
1506
15071505 .ADR_GOT_PAGE => {
15081506 // TODO: relax if possible
15091507 symbol.flags.needs_got = true;
15101508 },
1511
15121509 .LD64_GOT_LO12_NC,
15131510 .LD64_GOTPAGE_LO15,
15141511 => {
15151512 symbol.flags.needs_got = true;
15161513 },
1517
15181514 .CALL26,
15191515 .JUMP26,
15201516 => {
......@@ -1522,25 +1518,21 @@ const aarch64 = struct {
15221518 symbol.flags.needs_plt = true;
15231519 }
15241520 },
1525
15261521 .TLSLE_ADD_TPREL_HI12,
15271522 .TLSLE_ADD_TPREL_LO12_NC,
15281523 => {
15291524 if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);
15301525 },
1531
15321526 .TLSIE_ADR_GOTTPREL_PAGE21,
15331527 .TLSIE_LD64_GOTTPREL_LO12_NC,
15341528 => {
15351529 symbol.flags.needs_gottp = true;
15361530 },
1537
15381531 .TLSGD_ADR_PAGE21,
15391532 .TLSGD_ADD_LO12_NC,
15401533 => {
15411534 symbol.flags.needs_tlsgd = true;
15421535 },
1543
15441536 .TLSDESC_ADR_PAGE21,
15451537 .TLSDESC_LD64_LO12,
15461538 .TLSDESC_ADD_LO12,
......@@ -1551,18 +1543,17 @@ const aarch64 = struct {
15511543 symbol.flags.needs_tlsdesc = true;
15521544 }
15531545 },
1554
15551546 .ADD_ABS_LO12_NC,
15561547 .ADR_PREL_LO21,
1557 .LDST8_ABS_LO12_NC,
1548 .CONDBR19,
1549 .LDST128_ABS_LO12_NC,
15581550 .LDST16_ABS_LO12_NC,
15591551 .LDST32_ABS_LO12_NC,
15601552 .LDST64_ABS_LO12_NC,
1561 .LDST128_ABS_LO12_NC,
1553 .LDST8_ABS_LO12_NC,
15621554 .PREL32,
15631555 .PREL64,
15641556 => {},
1565
15661557 else => try atom.reportUnhandledRelocError(rel, elf_file),
15671558 }
15681559 }
......@@ -1599,7 +1590,6 @@ const aarch64 = struct {
15991590 r_offset,
16001591 );
16011592 },
1602
16031593 .CALL26,
16041594 .JUMP26,
16051595 => {
......@@ -1611,27 +1601,26 @@ const aarch64 = struct {
16111601 };
16121602 util.writeBranchImm(disp, code);
16131603 },
1614
1604 .CONDBR19 => {
1605 const value = math.cast(i19, S + A - P) orelse return error.Overflow;
1606 util.writeCondBrImm(value, code);
1607 },
16151608 .PREL32 => {
16161609 const value = math.cast(i32, S + A - P) orelse return error.Overflow;
16171610 mem.writeInt(u32, code, @bitCast(value), .little);
16181611 },
1619
16201612 .PREL64 => {
16211613 const value = S + A - P;
16221614 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
16231615 },
1624
16251616 .ADR_PREL_LO21 => {
16261617 const value = math.cast(i21, S + A - P) orelse return error.Overflow;
16271618 util.writeAdrInst(value, code);
16281619 },
1629
16301620 .ADR_PREL_PG_HI21 => {
16311621 // TODO: check for relaxation of ADRP+ADD
16321622 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
16331623 },
1634
16351624 .ADR_GOT_PAGE => if (target.flags.has_got) {
16361625 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
16371626 } else {
......@@ -1644,18 +1633,15 @@ const aarch64 = struct {
16441633 r_offset,
16451634 });
16461635 },
1647
16481636 .LD64_GOT_LO12_NC => {
16491637 assert(target.flags.has_got);
16501638 const taddr = @as(u64, @intCast(G + GOT + A));
16511639 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
16521640 },
1653
16541641 .ADD_ABS_LO12_NC => {
16551642 const taddr = @as(u64, @intCast(S + A));
16561643 util.writeAddImmInst(@truncate(taddr), code);
16571644 },
1658
16591645 .LDST8_ABS_LO12_NC,
16601646 .LDST16_ABS_LO12_NC,
16611647 .LDST32_ABS_LO12_NC,
......@@ -1674,44 +1660,37 @@ const aarch64 = struct {
16741660 };
16751661 util.writeLoadStoreRegInst(off, code);
16761662 },
1677
16781663 .TLSLE_ADD_TPREL_HI12 => {
16791664 const value = math.cast(i12, (S + A - TP) >> 12) orelse
16801665 return error.Overflow;
16811666 util.writeAddImmInst(@bitCast(value), code);
16821667 },
1683
16841668 .TLSLE_ADD_TPREL_LO12_NC => {
16851669 const value: i12 = @truncate(S + A - TP);
16861670 util.writeAddImmInst(@bitCast(value), code);
16871671 },
1688
16891672 .TLSIE_ADR_GOTTPREL_PAGE21 => {
16901673 const S_ = target.gotTpAddress(elf_file);
16911674 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
16921675 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
16931676 },
1694
16951677 .TLSIE_LD64_GOTTPREL_LO12_NC => {
16961678 const S_ = target.gotTpAddress(elf_file);
16971679 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
16981680 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
16991681 util.writeLoadStoreRegInst(off, code);
17001682 },
1701
17021683 .TLSGD_ADR_PAGE21 => {
17031684 const S_ = target.tlsGdAddress(elf_file);
17041685 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17051686 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
17061687 },
1707
17081688 .TLSGD_ADD_LO12_NC => {
17091689 const S_ = target.tlsGdAddress(elf_file);
17101690 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17111691 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
17121692 util.writeAddImmInst(off, code);
17131693 },
1714
17151694 .TLSDESC_ADR_PAGE21 => {
17161695 if (target.flags.has_tlsdesc) {
17171696 const S_ = target.tlsDescAddress(elf_file);
......@@ -1722,7 +1701,6 @@ const aarch64 = struct {
17221701 util.encoding.Instruction.nop().write(code);
17231702 }
17241703 },
1725
17261704 .TLSDESC_LD64_LO12 => {
17271705 if (target.flags.has_tlsdesc) {
17281706 const S_ = target.tlsDescAddress(elf_file);
......@@ -1734,7 +1712,6 @@ const aarch64 = struct {
17341712 util.encoding.Instruction.nop().write(code);
17351713 }
17361714 },
1737
17381715 .TLSDESC_ADD_LO12 => {
17391716 if (target.flags.has_tlsdesc) {
17401717 const S_ = target.tlsDescAddress(elf_file);
......@@ -1747,13 +1724,11 @@ const aarch64 = struct {
17471724 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
17481725 }
17491726 },
1750
17511727 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
17521728 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
17531729 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
17541730 util.encoding.Instruction.movk(.x0, value, .{}).write(code);
17551731 },
1756
17571732 else => try atom.reportUnhandledRelocError(rel, elf_file),
17581733 }
17591734 }
src/link/aarch64.zig+6
......@@ -29,6 +29,12 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
2929 inst.write(code);
3030}
3131
32pub fn writeCondBrImm(disp: i19, code: *[4]u8) void {
33 var inst: encoding.Instruction = .read(code);
34 inst.branch_exception_generating_system.conditional_branch_immediate.group.imm19 = @intCast(@shrExact(disp, 2));
35 inst.write(code);
36}
37
3238const assert = std.debug.assert;
3339const builtin = @import("builtin");
3440const math = std.math;