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 {...@@ -620,11 +620,6 @@ pub const VTable = struct {
620 result: []u8,620 result: []u8,
621 result_alignment: std.mem.Alignment,621 result_alignment: std.mem.Alignment,
622 ) void,622 ) 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
629 /// When this function returns, implementation guarantees that `start` has624 /// When this function returns, implementation guarantees that `start` has
630 /// either already been called, or a unit of concurrency has been assigned625 /// 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,...@@ -50,6 +50,19 @@ cpu_count_error: ?std.Thread.CpuCountError,
50/// available count, subtract this from either `async_limit` or50/// available count, subtract this from either `async_limit` or
51/// `concurrent_limit`.51/// `concurrent_limit`.
52busy_count: usize = 0,52busy_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
54wsa: if (is_windows) Wsa else struct {} = .{},67wsa: if (is_windows) Wsa else struct {} = .{},
5568
...@@ -57,7 +70,92 @@ have_signal_handler: bool,...@@ -57,7 +70,92 @@ have_signal_handler: bool,
57old_sig_io: if (have_sig_io) posix.Sigaction else void,70old_sig_io: if (have_sig_io) posix.Sigaction else void,
58old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void,71old_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
62const max_iovecs_len = 8;160const max_iovecs_len = 8;
63const splat_buffer_size = 64;161const splat_buffer_size = 64;
...@@ -66,48 +164,110 @@ comptime {...@@ -66,48 +164,110 @@ comptime {
66 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);164 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
67}165}
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.
70 none = 0,171 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.
72 _,181 _,
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 {190 fn unpack(cs: CancelStatus) Unpacked {
77 if (std.Thread.use_pthreads) {191 return switch (cs) {
78 return @enumFromInt(@intFromPtr(std.c.pthread_self()));192 .none => .none,
79 } else {193 .requested => .requested,
80 return @enumFromInt(std.Thread.getCurrentId());194 .acknowledged => .acknowledged,
81 }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 };
82 }202 }
83203
84 fn toThreadId(cancel_id: CancelId) ThreadId {204 fn fromSignaleeId(signal_id: Thread.SignaleeId) CancelStatus {
85 if (std.Thread.use_pthreads) {205 return if (std.Thread.use_pthreads)
86 return @ptrFromInt(@intFromEnum(cancel_id));206 @enumFromInt(@intFromPtr(signal_id))
87 } else {207 else
88 return @intCast(@intFromEnum(cancel_id));208 @enumFromInt(signal_id);
89 }
90 }209 }
91};210};
92211
93const Closure = struct {212const Closure = struct {
94 start: Start,213 start: Start,
95 node: std.SinglyLinkedList.Node = .{},214 node: std.SinglyLinkedList.Node = .{},
96 cancel_tid: CancelId,215 cancel_status: CancelStatus,
97216
98 const Start = *const fn (*Closure) void;217 const Start = *const fn (*Closure, *Threaded) void;
99218
100 fn requestCancel(closure: *Closure) void {219 fn requestCancel(closure: *Closure, t: *Threaded) void {
101 switch (@atomicRmw(CancelId, &closure.cancel_tid, .Xchg, .canceling, .acq_rel)) {220 var signal_id = switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
102 .none, .canceling => {},221 .none, .acknowledged, .requested => return,
103 else => |tid| {222 .signal_id => |signal_id| signal_id,
104 if (std.Thread.use_pthreads) {223 };
105 const rc = std.c.pthread_kill(tid.toThreadId(), .IO);224 // The task will enter a blocking syscall before checking for cancellation again.
106 if (is_debug) assert(rc == 0);225 // We can send a signal to interrupt the syscall, but if it arrives before
107 } else if (native_os == .linux) {226 // the syscall instruction, it will be missed. Therefore, this code tries
108 _ = std.os.linux.tgkill(std.os.linux.getpid(), @bitCast(tid.toThreadId()), .IO);227 // again until the cancellation request is acknowledged.
109 }228
110 },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 }
111 }271 }
112 }272 }
113};273};
...@@ -136,6 +296,9 @@ pub fn init(...@@ -136,6 +296,9 @@ pub fn init(
136 .old_sig_io = undefined,296 .old_sig_io = undefined,
137 .old_sig_pipe = undefined,297 .old_sig_pipe = undefined,
138 .have_signal_handler = false,298 .have_signal_handler = false,
299 .main_thread = .{
300 .signal_id = Thread.currentSignalId(),
301 },
139 };302 };
140303
141 if (posix.Sigaction != void) {304 if (posix.Sigaction != void) {
...@@ -169,6 +332,7 @@ pub const init_single_threaded: Threaded = .{...@@ -169,6 +332,7 @@ pub const init_single_threaded: Threaded = .{
169 .old_sig_io = undefined,332 .old_sig_io = undefined,
170 .old_sig_pipe = undefined,333 .old_sig_pipe = undefined,
171 .have_signal_handler = false,334 .have_signal_handler = false,
335 .main_thread = .{ .signal_id = undefined },
172};336};
173337
174pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {338pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {
...@@ -201,6 +365,11 @@ fn join(t: *Threaded) void {...@@ -201,6 +365,11 @@ fn join(t: *Threaded) void {
201}365}
202366
203fn worker(t: *Threaded) void {367fn worker(t: *Threaded) void {
368 var thread: Thread = .{
369 .signal_id = Thread.currentSignalId(),
370 };
371 Thread.current = &thread;
372
204 defer t.wait_group.finish();373 defer t.wait_group.finish();
205374
206 t.mutex.lock();375 t.mutex.lock();
...@@ -210,7 +379,7 @@ fn worker(t: *Threaded) void {...@@ -210,7 +379,7 @@ fn worker(t: *Threaded) void {
210 while (t.run_queue.popFirst()) |closure_node| {379 while (t.run_queue.popFirst()) |closure_node| {
211 t.mutex.unlock();380 t.mutex.unlock();
212 const closure: *Closure = @fieldParentPtr("node", closure_node);381 const closure: *Closure = @fieldParentPtr("node", closure_node);
213 closure.start(closure);382 closure.start(closure, t);
214 t.mutex.lock();383 t.mutex.lock();
215 t.busy_count -= 1;384 t.busy_count -= 1;
216 }385 }
...@@ -227,7 +396,6 @@ pub fn io(t: *Threaded) Io {...@@ -227,7 +396,6 @@ pub fn io(t: *Threaded) Io {
227 .concurrent = concurrent,396 .concurrent = concurrent,
228 .await = await,397 .await = await,
229 .cancel = cancel,398 .cancel = cancel,
230 .cancelRequested = cancelRequested,
231 .select = select,399 .select = select,
232400
233 .groupAsync = groupAsync,401 .groupAsync = groupAsync,
...@@ -324,7 +492,6 @@ pub fn ioBasic(t: *Threaded) Io {...@@ -324,7 +492,6 @@ pub fn ioBasic(t: *Threaded) Io {
324 .concurrent = concurrent,492 .concurrent = concurrent,
325 .await = await,493 .await = await,
326 .cancel = cancel,494 .cancel = cancel,
327 .cancelRequested = cancelRequested,
328 .select = select,495 .select = select,
329496
330 .groupAsync = groupAsync,497 .groupAsync = groupAsync,
...@@ -418,24 +585,12 @@ const AsyncClosure = struct {...@@ -418,24 +585,12 @@ const AsyncClosure = struct {
418585
419 const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent));586 const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent));
420587
421 fn start(closure: *Closure) void {588 fn start(closure: *Closure, t: *Threaded) void {
422 const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure));589 const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure));
423 const tid: CancelId = .currentThread();590 const current_thread = Thread.getCurrent(t);
424 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {591 current_thread.current_closure = closure;
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;
431 ac.func(ac.contextPointer(), ac.resultPointer());592 ac.func(ac.contextPointer(), ac.resultPointer());
432 current_closure = null;593 current_thread.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 }
439594
440 if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| {595 if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| {
441 assert(select_reset != done_reset_event);596 assert(select_reset != done_reset_event);
...@@ -476,7 +631,7 @@ const AsyncClosure = struct {...@@ -476,7 +631,7 @@ const AsyncClosure = struct {
476 const actual_result_offset = actual_result_addr - @intFromPtr(ac);631 const actual_result_offset = actual_result_addr - @intFromPtr(ac);
477 ac.* = .{632 ac.* = .{
478 .closure = .{633 .closure = .{
479 .cancel_tid = .none,634 .cancel_status = .none,
480 .start = start,635 .start = start,
481 },636 },
482 .func = func,637 .func = func,
...@@ -493,7 +648,7 @@ const AsyncClosure = struct {...@@ -493,7 +648,7 @@ const AsyncClosure = struct {
493 fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void {648 fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void {
494 ac.reset_event.wait(t) catch |err| switch (err) {649 ac.reset_event.wait(t) catch |err| switch (err) {
495 error.Canceled => {650 error.Canceled => {
496 ac.closure.requestCancel();651 ac.closure.requestCancel(t);
497 ac.reset_event.waitUncancelable();652 ac.reset_event.waitUncancelable();
498 },653 },
499 };654 };
...@@ -604,7 +759,6 @@ fn concurrent(...@@ -604,7 +759,6 @@ fn concurrent(
604759
605const GroupClosure = struct {760const GroupClosure = struct {
606 closure: Closure,761 closure: Closure,
607 t: *Threaded,
608 group: *Io.Group,762 group: *Io.Group,
609 /// Points to sibling `GroupClosure`. Used for walking the group to cancel all.763 /// Points to sibling `GroupClosure`. Used for walking the group to cancel all.
610 node: std.SinglyLinkedList.Node,764 node: std.SinglyLinkedList.Node,
...@@ -612,26 +766,15 @@ const GroupClosure = struct {...@@ -612,26 +766,15 @@ const GroupClosure = struct {
612 context_alignment: Alignment,766 context_alignment: Alignment,
613 alloc_len: usize,767 alloc_len: usize,
614768
615 fn start(closure: *Closure) void {769 fn start(closure: *Closure, t: *Threaded) void {
616 const gc: *GroupClosure = @alignCast(@fieldParentPtr("closure", closure));770 const gc: *GroupClosure = @alignCast(@fieldParentPtr("closure", closure));
617 const tid: CancelId = .currentThread();771 const current_thread = Thread.getCurrent(t);
618 const group = gc.group;772 const group = gc.group;
619 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);773 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);
620 const reset_event: *ResetEvent = @ptrCast(&group.context);774 const reset_event: *ResetEvent = @ptrCast(&group.context);
621 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {775 current_thread.current_closure = closure;
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;
627 gc.func(group, gc.contextPointer());776 gc.func(group, gc.contextPointer());
628 current_closure = null;777 current_thread.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 }
635778
636 const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel);779 const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel);
637 assert((prev_state / sync_one_pending) > 0);780 assert((prev_state / sync_one_pending) > 0);
...@@ -647,7 +790,6 @@ const GroupClosure = struct {...@@ -647,7 +790,6 @@ const GroupClosure = struct {
647 /// Does not initialize the `node` field.790 /// Does not initialize the `node` field.
648 fn init(791 fn init(
649 gpa: Allocator,792 gpa: Allocator,
650 t: *Threaded,
651 group: *Io.Group,793 group: *Io.Group,
652 context: []const u8,794 context: []const u8,
653 context_alignment: Alignment,795 context_alignment: Alignment,
...@@ -662,10 +804,9 @@ const GroupClosure = struct {...@@ -662,10 +804,9 @@ const GroupClosure = struct {
662804
663 gc.* = .{805 gc.* = .{
664 .closure = .{806 .closure = .{
665 .cancel_tid = .none,807 .cancel_status = .none,
666 .start = start,808 .start = start,
667 },809 },
668 .t = t,
669 .group = group,810 .group = group,
670 .node = undefined,811 .node = undefined,
671 .func = func,812 .func = func,
...@@ -696,7 +837,7 @@ fn groupAsync(...@@ -696,7 +837,7 @@ fn groupAsync(
696 if (builtin.single_threaded) return start(group, context.ptr);837 if (builtin.single_threaded) return start(group, context.ptr);
697838
698 const gpa = t.allocator;839 const gpa = t.allocator;
699 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch840 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
700 return start(group, context.ptr);841 return start(group, context.ptr);
701842
702 t.mutex.lock();843 t.mutex.lock();
...@@ -752,7 +893,7 @@ fn groupConcurrent(...@@ -752,7 +893,7 @@ fn groupConcurrent(
752 const t: *Threaded = @ptrCast(@alignCast(userdata));893 const t: *Threaded = @ptrCast(@alignCast(userdata));
753894
754 const gpa = t.allocator;895 const gpa = t.allocator;
755 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch896 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
756 return error.ConcurrencyUnavailable;897 return error.ConcurrencyUnavailable;
757898
758 t.mutex.lock();899 t.mutex.lock();
...@@ -806,7 +947,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {...@@ -806,7 +947,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
806 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));947 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
807 while (true) {948 while (true) {
808 const gc: *GroupClosure = @fieldParentPtr("node", node);949 const gc: *GroupClosure = @fieldParentPtr("node", node);
809 gc.closure.requestCancel();950 gc.closure.requestCancel(t);
810 node = node.next orelse break;951 node = node.next orelse break;
811 }952 }
812 reset_event.waitUncancelable();953 reset_event.waitUncancelable();
...@@ -832,7 +973,7 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void...@@ -832,7 +973,7 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void
832 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));973 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
833 while (true) {974 while (true) {
834 const gc: *GroupClosure = @fieldParentPtr("node", node);975 const gc: *GroupClosure = @fieldParentPtr("node", node);
835 gc.closure.requestCancel();976 gc.closure.requestCancel(t);
836 node = node.next orelse break;977 node = node.next orelse break;
837 }978 }
838 }979 }
...@@ -875,30 +1016,20 @@ fn cancel(...@@ -875,30 +1016,20 @@ fn cancel(
875 _ = result_alignment;1016 _ = result_alignment;
876 const t: *Threaded = @ptrCast(@alignCast(userdata));1017 const t: *Threaded = @ptrCast(@alignCast(userdata));
877 const ac: *AsyncClosure = @ptrCast(@alignCast(any_future));1018 const ac: *AsyncClosure = @ptrCast(@alignCast(any_future));
878 ac.closure.requestCancel();1019 ac.closure.requestCancel(t);
879 ac.waitAndDeinit(t, result);1020 ac.waitAndDeinit(t, result);
880}1021}
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
893fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {1023fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {
894 if (builtin.single_threaded) unreachable; // Interface should have prevented this.1024 if (builtin.single_threaded) unreachable; // Interface should have prevented this.
895 if (native_os == .netbsd) @panic("TODO");1025 if (native_os == .netbsd) @panic("TODO");
896 const t: *Threaded = @ptrCast(@alignCast(userdata));1026 const t: *Threaded = @ptrCast(@alignCast(userdata));
1027 const current_thread = Thread.getCurrent(t);
897 if (prev_state == .contended) {1028 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));
899 }1030 }
900 while (@atomicRmw(Io.Mutex.State, &mutex.state, .Xchg, .contended, .acquire) != .unlocked) {1031 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));
902 }1033 }
903}1034}
9041035
...@@ -960,6 +1091,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I...@@ -960,6 +1091,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
960 if (builtin.single_threaded) unreachable; // Deadlock.1091 if (builtin.single_threaded) unreachable; // Deadlock.
961 if (native_os == .netbsd) @panic("TODO");1092 if (native_os == .netbsd) @panic("TODO");
962 const t: *Threaded = @ptrCast(@alignCast(userdata));1093 const t: *Threaded = @ptrCast(@alignCast(userdata));
1094 const current_thread = Thread.getCurrent(t);
963 const t_io = ioBasic(t);1095 const t_io = ioBasic(t);
964 comptime assert(@TypeOf(cond.state) == u64);1096 comptime assert(@TypeOf(cond.state) == u64);
965 const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state);1097 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...@@ -988,7 +1120,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
988 defer mutex.lockUncancelable(t_io);1120 defer mutex.lockUncancelable(t_io);
9891121
990 while (true) {1122 while (true) {
991 try futexWait(t, cond_epoch, epoch);1123 try futexWait(current_thread, cond_epoch, epoch);
9921124
993 epoch = cond_epoch.load(.acquire);1125 epoch = cond_epoch.load(.acquire);
994 state = cond_state.load(.monotonic);1126 state = cond_state.load(.monotonic);
...@@ -1074,35 +1206,46 @@ const dirMake = switch (native_os) {...@@ -1074,35 +1206,46 @@ const dirMake = switch (native_os) {
10741206
1075fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {1207fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
1076 const t: *Threaded = @ptrCast(@alignCast(userdata));1208 const t: *Threaded = @ptrCast(@alignCast(userdata));
1209 const current_thread = Thread.getCurrent(t);
10771210
1078 var path_buffer: [posix.PATH_MAX]u8 = undefined;1211 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1079 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);1212 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
10801213
1214 try current_thread.beginSyscall();
1081 while (true) {1215 while (true) {
1082 try t.checkCancel();
1083 switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) {1216 switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) {
1084 .SUCCESS => return,1217 .SUCCESS => {
1085 .INTR => continue,1218 current_thread.endSyscall();
1086 .CANCELED => return error.Canceled,1219 return;
10871220 },
1088 .ACCES => return error.AccessDenied,1221 .INTR => {
1089 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1222 try current_thread.checkCancel();
1090 .PERM => return error.PermissionDenied,1223 continue;
1091 .DQUOT => return error.DiskQuota,1224 },
1092 .EXIST => return error.PathAlreadyExists,1225 .CANCELED => return current_thread.endSyscallCanceled(),
1093 .FAULT => |err| return errnoBug(err),1226 else => |e| {
1094 .LOOP => return error.SymLinkLoop,1227 current_thread.endSyscall();
1095 .MLINK => return error.LinkQuotaExceeded,1228 switch (e) {
1096 .NAMETOOLONG => return error.NameTooLong,1229 .ACCES => return error.AccessDenied,
1097 .NOENT => return error.FileNotFound,1230 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1098 .NOMEM => return error.SystemResources,1231 .PERM => return error.PermissionDenied,
1099 .NOSPC => return error.NoSpaceLeft,1232 .DQUOT => return error.DiskQuota,
1100 .NOTDIR => return error.NotDir,1233 .EXIST => return error.PathAlreadyExists,
1101 .ROFS => return error.ReadOnlyFileSystem,1234 .FAULT => |err| return errnoBug(err),
1102 // dragonfly: when dir_fd is unlinked from filesystem1235 .LOOP => return error.SymLinkLoop,
1103 .NOTCONN => return error.FileNotFound,1236 .MLINK => return error.LinkQuotaExceeded,
1104 .ILSEQ => return error.BadPathName,1237 .NAMETOOLONG => return error.NameTooLong,
1105 else => |err| return posix.unexpectedErrno(err),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 },
1106 }1249 }
1107 }1250 }
1108}1251}
...@@ -1110,37 +1253,49 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode:...@@ -1110,37 +1253,49 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode:
1110fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {1253fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
1111 if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode);1254 if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode);
1112 const t: *Threaded = @ptrCast(@alignCast(userdata));1255 const t: *Threaded = @ptrCast(@alignCast(userdata));
1256 const current_thread = Thread.getCurrent(t);
1257 try current_thread.beginSyscall();
1113 while (true) {1258 while (true) {
1114 try t.checkCancel();
1115 switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) {1259 switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) {
1116 .SUCCESS => return,1260 .SUCCESS => {
1117 .INTR => continue,1261 current_thread.endSyscall();
1118 .CANCELED => return error.Canceled,1262 return;
11191263 },
1120 .ACCES => return error.AccessDenied,1264 .INTR => {
1121 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1265 try current_thread.checkCancel();
1122 .PERM => return error.PermissionDenied,1266 continue;
1123 .DQUOT => return error.DiskQuota,1267 },
1124 .EXIST => return error.PathAlreadyExists,1268 .CANCELED => return current_thread.endSyscallCanceled(),
1125 .FAULT => |err| return errnoBug(err),1269 else => |e| {
1126 .LOOP => return error.SymLinkLoop,1270 current_thread.endSyscall();
1127 .MLINK => return error.LinkQuotaExceeded,1271 switch (e) {
1128 .NAMETOOLONG => return error.NameTooLong,1272 .ACCES => return error.AccessDenied,
1129 .NOENT => return error.FileNotFound,1273 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1130 .NOMEM => return error.SystemResources,1274 .PERM => return error.PermissionDenied,
1131 .NOSPC => return error.NoSpaceLeft,1275 .DQUOT => return error.DiskQuota,
1132 .NOTDIR => return error.NotDir,1276 .EXIST => return error.PathAlreadyExists,
1133 .ROFS => return error.ReadOnlyFileSystem,1277 .FAULT => |err| return errnoBug(err),
1134 .NOTCAPABLE => return error.AccessDenied,1278 .LOOP => return error.SymLinkLoop,
1135 .ILSEQ => return error.BadPathName,1279 .MLINK => return error.LinkQuotaExceeded,
1136 else => |err| return posix.unexpectedErrno(err),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 },
1137 }1291 }
1138 }1292 }
1139}1293}
11401294
1141fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {1295fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
1142 const t: *Threaded = @ptrCast(@alignCast(userdata));1296 const t: *Threaded = @ptrCast(@alignCast(userdata));
1143 try t.checkCancel();1297 const current_thread = Thread.getCurrent(t);
1298 try current_thread.checkCancel();
11441299
1145 const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);1300 const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
1146 _ = mode;1301 _ = mode;
...@@ -1213,6 +1368,7 @@ fn dirMakeOpenPathWindows(...@@ -1213,6 +1368,7 @@ fn dirMakeOpenPathWindows(
1213 options: Io.Dir.OpenOptions,1368 options: Io.Dir.OpenOptions,
1214) Io.Dir.MakeOpenPathError!Io.Dir {1369) Io.Dir.MakeOpenPathError!Io.Dir {
1215 const t: *Threaded = @ptrCast(@alignCast(userdata));1370 const t: *Threaded = @ptrCast(@alignCast(userdata));
1371 const current_thread = Thread.getCurrent(t);
1216 const w = windows;1372 const w = windows;
1217 const access_mask = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |1373 const access_mask = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
1218 w.SYNCHRONIZE | w.FILE_TRAVERSE |1374 w.SYNCHRONIZE | w.FILE_TRAVERSE |
...@@ -1226,7 +1382,7 @@ fn dirMakeOpenPathWindows(...@@ -1226,7 +1382,7 @@ fn dirMakeOpenPathWindows(
1226 };1382 };
12271383
1228 while (true) {1384 while (true) {
1229 try t.checkCancel();1385 try current_thread.checkCancel();
12301386
1231 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, component.path);1387 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, component.path);
1232 const sub_path_w = sub_path_w_array.span();1388 const sub_path_w = sub_path_w_array.span();
...@@ -1328,8 +1484,7 @@ fn dirMakeOpenPathWasi(...@@ -1328,8 +1484,7 @@ fn dirMakeOpenPathWasi(
13281484
1329fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {1485fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
1330 const t: *Threaded = @ptrCast(@alignCast(userdata));1486 const t: *Threaded = @ptrCast(@alignCast(userdata));
1331 try t.checkCancel();1487 _ = t;
1332
1333 _ = dir;1488 _ = dir;
1334 @panic("TODO implement dirStat");1489 @panic("TODO implement dirStat");
1335}1490}
...@@ -1348,6 +1503,7 @@ fn dirStatPathLinux(...@@ -1348,6 +1503,7 @@ fn dirStatPathLinux(
1348 options: Io.Dir.StatPathOptions,1503 options: Io.Dir.StatPathOptions,
1349) Io.Dir.StatPathError!Io.File.Stat {1504) Io.Dir.StatPathError!Io.File.Stat {
1350 const t: *Threaded = @ptrCast(@alignCast(userdata));1505 const t: *Threaded = @ptrCast(@alignCast(userdata));
1506 const current_thread = Thread.getCurrent(t);
1351 const linux = std.os.linux;1507 const linux = std.os.linux;
13521508
1353 var path_buffer: [posix.PATH_MAX]u8 = undefined;1509 var path_buffer: [posix.PATH_MAX]u8 = undefined;
...@@ -1356,8 +1512,8 @@ fn dirStatPathLinux(...@@ -1356,8 +1512,8 @@ fn dirStatPathLinux(
1356 const flags: u32 = linux.AT.NO_AUTOMOUNT |1512 const flags: u32 = linux.AT.NO_AUTOMOUNT |
1357 @as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);1513 @as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);
13581514
1515 try current_thread.beginSyscall();
1359 while (true) {1516 while (true) {
1360 try t.checkCancel();
1361 var statx = std.mem.zeroes(linux.Statx);1517 var statx = std.mem.zeroes(linux.Statx);
1362 const rc = linux.statx(1518 const rc = linux.statx(
1363 dir.handle,1519 dir.handle,
...@@ -1367,20 +1523,30 @@ fn dirStatPathLinux(...@@ -1367,20 +1523,30 @@ fn dirStatPathLinux(
1367 &statx,1523 &statx,
1368 );1524 );
1369 switch (linux.errno(rc)) {1525 switch (linux.errno(rc)) {
1370 .SUCCESS => return statFromLinux(&statx),1526 .SUCCESS => {
1371 .INTR => continue,1527 current_thread.endSyscall();
1372 .CANCELED => return error.Canceled,1528 return statFromLinux(&statx);
13731529 },
1374 .ACCES => return error.AccessDenied,1530 .INTR => {
1375 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1531 try current_thread.checkCancel();
1376 .FAULT => |err| return errnoBug(err),1532 continue;
1377 .INVAL => |err| return errnoBug(err),1533 },
1378 .LOOP => return error.SymLinkLoop,1534 .CANCELED => return current_thread.endSyscallCanceled(),
1379 .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.1535 else => |e| {
1380 .NOENT => return error.FileNotFound,1536 current_thread.endSyscall();
1381 .NOTDIR => return error.NotDir,1537 switch (e) {
1382 .NOMEM => return error.SystemResources,1538 .ACCES => return error.AccessDenied,
1383 else => |err| return posix.unexpectedErrno(err),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 },
1384 }1550 }
1385 }1551 }
1386}1552}
...@@ -1392,32 +1558,43 @@ fn dirStatPathPosix(...@@ -1392,32 +1558,43 @@ fn dirStatPathPosix(
1392 options: Io.Dir.StatPathOptions,1558 options: Io.Dir.StatPathOptions,
1393) Io.Dir.StatPathError!Io.File.Stat {1559) Io.Dir.StatPathError!Io.File.Stat {
1394 const t: *Threaded = @ptrCast(@alignCast(userdata));1560 const t: *Threaded = @ptrCast(@alignCast(userdata));
1561 const current_thread = Thread.getCurrent(t);
13951562
1396 var path_buffer: [posix.PATH_MAX]u8 = undefined;1563 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1397 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);1564 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
13981565
1399 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;1566 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
14001567
1568 try current_thread.beginSyscall();
1401 while (true) {1569 while (true) {
1402 try t.checkCancel();
1403 var stat = std.mem.zeroes(posix.Stat);1570 var stat = std.mem.zeroes(posix.Stat);
1404 switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) {1571 switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) {
1405 .SUCCESS => return statFromPosix(&stat),1572 .SUCCESS => {
1406 .INTR => continue,1573 current_thread.endSyscall();
1407 .CANCELED => return error.Canceled,1574 return statFromPosix(&stat);
14081575 },
1409 .INVAL => |err| return errnoBug(err),1576 .INTR => {
1410 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1577 try current_thread.checkCancel();
1411 .NOMEM => return error.SystemResources,1578 continue;
1412 .ACCES => return error.AccessDenied,1579 },
1413 .PERM => return error.PermissionDenied,1580 .CANCELED => return current_thread.endSyscallCanceled(),
1414 .FAULT => |err| return errnoBug(err),1581 else => |e| {
1415 .NAMETOOLONG => return error.NameTooLong,1582 current_thread.endSyscall();
1416 .LOOP => return error.SymLinkLoop,1583 switch (e) {
1417 .NOENT => return error.FileNotFound,1584 .INVAL => |err| return errnoBug(err),
1418 .NOTDIR => return error.FileNotFound,1585 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1419 .ILSEQ => return error.BadPathName,1586 .NOMEM => return error.SystemResources,
1420 else => |err| return posix.unexpectedErrno(err),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 },
1421 }1598 }
1422 }1599 }
1423}1600}
...@@ -1444,29 +1621,40 @@ fn dirStatPathWasi(...@@ -1444,29 +1621,40 @@ fn dirStatPathWasi(
1444) Io.Dir.StatPathError!Io.File.Stat {1621) Io.Dir.StatPathError!Io.File.Stat {
1445 if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);1622 if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);
1446 const t: *Threaded = @ptrCast(@alignCast(userdata));1623 const t: *Threaded = @ptrCast(@alignCast(userdata));
1624 const current_thread = Thread.getCurrent(t);
1447 const wasi = std.os.wasi;1625 const wasi = std.os.wasi;
1448 const flags: wasi.lookupflags_t = .{1626 const flags: wasi.lookupflags_t = .{
1449 .SYMLINK_FOLLOW = options.follow_symlinks,1627 .SYMLINK_FOLLOW = options.follow_symlinks,
1450 };1628 };
1451 var stat: wasi.filestat_t = undefined;1629 var stat: wasi.filestat_t = undefined;
1630 try current_thread.beginSyscall();
1452 while (true) {1631 while (true) {
1453 try t.checkCancel();
1454 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {1632 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
1455 .SUCCESS => return statFromWasi(&stat),1633 .SUCCESS => {
1456 .INTR => continue,1634 current_thread.endSyscall();
1457 .CANCELED => return error.Canceled,1635 return statFromWasi(&stat);
14581636 },
1459 .INVAL => |err| return errnoBug(err),1637 .INTR => {
1460 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1638 try current_thread.checkCancel();
1461 .NOMEM => return error.SystemResources,1639 continue;
1462 .ACCES => return error.AccessDenied,1640 },
1463 .FAULT => |err| return errnoBug(err),1641 .CANCELED => return current_thread.endSyscallCanceled(),
1464 .NAMETOOLONG => return error.NameTooLong,1642 else => |e| {
1465 .NOENT => return error.FileNotFound,1643 current_thread.endSyscall();
1466 .NOTDIR => return error.FileNotFound,1644 switch (e) {
1467 .NOTCAPABLE => return error.AccessDenied,1645 .INVAL => |err| return errnoBug(err),
1468 .ILSEQ => return error.BadPathName,1646 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1469 else => |err| return posix.unexpectedErrno(err),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 },
1470 }1658 }
1471 }1659 }
1472}1660}
...@@ -1480,31 +1668,44 @@ const fileStat = switch (native_os) {...@@ -1480,31 +1668,44 @@ const fileStat = switch (native_os) {
14801668
1481fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1669fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1482 const t: *Threaded = @ptrCast(@alignCast(userdata));1670 const t: *Threaded = @ptrCast(@alignCast(userdata));
1671 const current_thread = Thread.getCurrent(t);
14831672
1484 if (posix.Stat == void) return error.Streaming;1673 if (posix.Stat == void) return error.Streaming;
14851674
1675 try current_thread.beginSyscall();
1486 while (true) {1676 while (true) {
1487 try t.checkCancel();
1488 var stat = std.mem.zeroes(posix.Stat);1677 var stat = std.mem.zeroes(posix.Stat);
1489 switch (posix.errno(fstat_sym(file.handle, &stat))) {1678 switch (posix.errno(fstat_sym(file.handle, &stat))) {
1490 .SUCCESS => return statFromPosix(&stat),1679 .SUCCESS => {
1491 .INTR => continue,1680 current_thread.endSyscall();
1492 .CANCELED => return error.Canceled,1681 return statFromPosix(&stat);
14931682 },
1494 .INVAL => |err| return errnoBug(err),1683 .INTR => {
1495 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1684 try current_thread.checkCancel();
1496 .NOMEM => return error.SystemResources,1685 continue;
1497 .ACCES => return error.AccessDenied,1686 },
1498 else => |err| return posix.unexpectedErrno(err),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 },
1499 }1698 }
1500 }1699 }
1501}1700}
15021701
1503fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1702fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1504 const t: *Threaded = @ptrCast(@alignCast(userdata));1703 const t: *Threaded = @ptrCast(@alignCast(userdata));
1704 const current_thread = Thread.getCurrent(t);
1505 const linux = std.os.linux;1705 const linux = std.os.linux;
1706
1707 try current_thread.beginSyscall();
1506 while (true) {1708 while (true) {
1507 try t.checkCancel();
1508 var statx = std.mem.zeroes(linux.Statx);1709 var statx = std.mem.zeroes(linux.Statx);
1509 const rc = linux.statx(1710 const rc = linux.statx(
1510 file.handle,1711 file.handle,
...@@ -1514,27 +1715,38 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File...@@ -1514,27 +1715,38 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
1514 &statx,1715 &statx,
1515 );1716 );
1516 switch (linux.errno(rc)) {1717 switch (linux.errno(rc)) {
1517 .SUCCESS => return statFromLinux(&statx),1718 .SUCCESS => {
1518 .INTR => continue,1719 current_thread.endSyscall();
1519 .CANCELED => return error.Canceled,1720 return statFromLinux(&statx);
15201721 },
1521 .ACCES => |err| return errnoBug(err),1722 .INTR => {
1522 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1723 try current_thread.checkCancel();
1523 .FAULT => |err| return errnoBug(err),1724 continue;
1524 .INVAL => |err| return errnoBug(err),1725 },
1525 .LOOP => |err| return errnoBug(err),1726 .CANCELED => return current_thread.endSyscallCanceled(),
1526 .NAMETOOLONG => |err| return errnoBug(err),1727 else => |e| {
1527 .NOENT => |err| return errnoBug(err),1728 current_thread.endSyscall();
1528 .NOMEM => return error.SystemResources,1729 switch (e) {
1529 .NOTDIR => |err| return errnoBug(err),1730 .ACCES => |err| return errnoBug(err),
1530 else => |err| return posix.unexpectedErrno(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 },
1531 }1742 }
1532 }1743 }
1533}1744}
15341745
1535fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1746fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1536 const t: *Threaded = @ptrCast(@alignCast(userdata));1747 const t: *Threaded = @ptrCast(@alignCast(userdata));
1537 try t.checkCancel();1748 const current_thread = Thread.getCurrent(t);
1749 try current_thread.checkCancel();
15381750
1539 var io_status_block: windows.IO_STATUS_BLOCK = undefined;1751 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
1540 var info: windows.FILE_ALL_INFORMATION = undefined;1752 var info: windows.FILE_ALL_INFORMATION = undefined;
...@@ -1581,21 +1793,34 @@ fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.Fi...@@ -1581,21 +1793,34 @@ fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.Fi
15811793
1582fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1794fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1583 if (builtin.link_libc) return fileStatPosix(userdata, file);1795 if (builtin.link_libc) return fileStatPosix(userdata, file);
1796
1584 const t: *Threaded = @ptrCast(@alignCast(userdata));1797 const t: *Threaded = @ptrCast(@alignCast(userdata));
1798 const current_thread = Thread.getCurrent(t);
1799
1800 try current_thread.beginSyscall();
1585 while (true) {1801 while (true) {
1586 try t.checkCancel();
1587 var stat: std.os.wasi.filestat_t = undefined;1802 var stat: std.os.wasi.filestat_t = undefined;
1588 switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {1803 switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {
1589 .SUCCESS => return statFromWasi(&stat),1804 .SUCCESS => {
1590 .INTR => continue,1805 current_thread.endSyscall();
1591 .CANCELED => return error.Canceled,1806 return statFromWasi(&stat);
15921807 },
1593 .INVAL => |err| return errnoBug(err),1808 .INTR => {
1594 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1809 try current_thread.checkCancel();
1595 .NOMEM => return error.SystemResources,1810 continue;
1596 .ACCES => return error.AccessDenied,1811 },
1597 .NOTCAPABLE => return error.AccessDenied,1812 .CANCELED => return current_thread.endSyscallCanceled(),
1598 else => |err| return posix.unexpectedErrno(err),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 },
1599 }1824 }
1600 }1825 }
1601}1826}
...@@ -1613,6 +1838,7 @@ fn dirAccessPosix(...@@ -1613,6 +1838,7 @@ fn dirAccessPosix(
1613 options: Io.Dir.AccessOptions,1838 options: Io.Dir.AccessOptions,
1614) Io.Dir.AccessError!void {1839) Io.Dir.AccessError!void {
1615 const t: *Threaded = @ptrCast(@alignCast(userdata));1840 const t: *Threaded = @ptrCast(@alignCast(userdata));
1841 const current_thread = Thread.getCurrent(t);
16161842
1617 var path_buffer: [posix.PATH_MAX]u8 = undefined;1843 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1618 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);1844 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
...@@ -1624,27 +1850,37 @@ fn dirAccessPosix(...@@ -1624,27 +1850,37 @@ fn dirAccessPosix(
1624 @as(u32, if (options.write) posix.W_OK else 0) |1850 @as(u32, if (options.write) posix.W_OK else 0) |
1625 @as(u32, if (options.execute) posix.X_OK else 0);1851 @as(u32, if (options.execute) posix.X_OK else 0);
16261852
1853 try current_thread.beginSyscall();
1627 while (true) {1854 while (true) {
1628 try t.checkCancel();
1629 switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, flags))) {1855 switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, flags))) {
1630 .SUCCESS => return,1856 .SUCCESS => {
1631 .INTR => continue,1857 current_thread.endSyscall();
1632 .CANCELED => return error.Canceled,1858 return;
16331859 },
1634 .ACCES => return error.AccessDenied,1860 .INTR => {
1635 .PERM => return error.PermissionDenied,1861 try current_thread.checkCancel();
1636 .ROFS => return error.ReadOnlyFileSystem,1862 continue;
1637 .LOOP => return error.SymLinkLoop,1863 },
1638 .TXTBSY => return error.FileBusy,1864 .CANCELED => return current_thread.endSyscallCanceled(),
1639 .NOTDIR => return error.FileNotFound,1865 else => |e| {
1640 .NOENT => return error.FileNotFound,1866 current_thread.endSyscall();
1641 .NAMETOOLONG => return error.NameTooLong,1867 switch (e) {
1642 .INVAL => |err| return errnoBug(err),1868 .ACCES => return error.AccessDenied,
1643 .FAULT => |err| return errnoBug(err),1869 .PERM => return error.PermissionDenied,
1644 .IO => return error.InputOutput,1870 .ROFS => return error.ReadOnlyFileSystem,
1645 .NOMEM => return error.SystemResources,1871 .LOOP => return error.SymLinkLoop,
1646 .ILSEQ => return error.BadPathName,1872 .TXTBSY => return error.FileBusy,
1647 else => |err| return posix.unexpectedErrno(err),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 },
1648 }1884 }
1649 }1885 }
1650}1886}
...@@ -1657,29 +1893,41 @@ fn dirAccessWasi(...@@ -1657,29 +1893,41 @@ fn dirAccessWasi(
1657) Io.Dir.AccessError!void {1893) Io.Dir.AccessError!void {
1658 if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options);1894 if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options);
1659 const t: *Threaded = @ptrCast(@alignCast(userdata));1895 const t: *Threaded = @ptrCast(@alignCast(userdata));
1896 const current_thread = Thread.getCurrent(t);
1660 const wasi = std.os.wasi;1897 const wasi = std.os.wasi;
1661 const flags: wasi.lookupflags_t = .{1898 const flags: wasi.lookupflags_t = .{
1662 .SYMLINK_FOLLOW = options.follow_symlinks,1899 .SYMLINK_FOLLOW = options.follow_symlinks,
1663 };1900 };
1664 var stat: wasi.filestat_t = undefined;1901 var stat: wasi.filestat_t = undefined;
1902
1903 try current_thread.beginSyscall();
1665 while (true) {1904 while (true) {
1666 try t.checkCancel();
1667 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {1905 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
1668 .SUCCESS => break,1906 .SUCCESS => {
1669 .INTR => continue,1907 current_thread.endSyscall();
1670 .CANCELED => return error.Canceled,1908 break;
16711909 },
1672 .INVAL => |err| return errnoBug(err),1910 .INTR => {
1673 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1911 try current_thread.checkCancel();
1674 .NOMEM => return error.SystemResources,1912 continue;
1675 .ACCES => return error.AccessDenied,1913 },
1676 .FAULT => |err| return errnoBug(err),1914 .CANCELED => return current_thread.endSyscallCanceled(),
1677 .NAMETOOLONG => return error.NameTooLong,1915 else => |e| {
1678 .NOENT => return error.FileNotFound,1916 current_thread.endSyscall();
1679 .NOTDIR => return error.FileNotFound,1917 switch (e) {
1680 .NOTCAPABLE => return error.AccessDenied,1918 .INVAL => |err| return errnoBug(err),
1681 .ILSEQ => return error.BadPathName,1919 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1682 else => |err| return posix.unexpectedErrno(err),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 },
1683 }1931 }
1684 }1932 }
16851933
...@@ -1717,7 +1965,8 @@ fn dirAccessWindows(...@@ -1717,7 +1965,8 @@ fn dirAccessWindows(
1717 options: Io.Dir.AccessOptions,1965 options: Io.Dir.AccessOptions,
1718) Io.Dir.AccessError!void {1966) Io.Dir.AccessError!void {
1719 const t: *Threaded = @ptrCast(@alignCast(userdata));1967 const t: *Threaded = @ptrCast(@alignCast(userdata));
1720 try t.checkCancel();1968 const current_thread = Thread.getCurrent(t);
1969 try current_thread.checkCancel();
17211970
1722 _ = options; // TODO1971 _ = options; // TODO
17231972
...@@ -1768,6 +2017,7 @@ fn dirCreateFilePosix(...@@ -1768,6 +2017,7 @@ fn dirCreateFilePosix(
1768 flags: Io.File.CreateFlags,2017 flags: Io.File.CreateFlags,
1769) Io.File.OpenError!Io.File {2018) Io.File.OpenError!Io.File {
1770 const t: *Threaded = @ptrCast(@alignCast(userdata));2019 const t: *Threaded = @ptrCast(@alignCast(userdata));
2020 const current_thread = Thread.getCurrent(t);
17712021
1772 var path_buffer: [posix.PATH_MAX]u8 = undefined;2022 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1773 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);2023 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
...@@ -1796,40 +2046,50 @@ fn dirCreateFilePosix(...@@ -1796,40 +2046,50 @@ fn dirCreateFilePosix(
1796 },2046 },
1797 };2047 };
17982048
2049 try current_thread.beginSyscall();
1799 const fd: posix.fd_t = while (true) {2050 const fd: posix.fd_t = while (true) {
1800 try t.checkCancel();
1801 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);2051 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
1802 switch (posix.errno(rc)) {2052 switch (posix.errno(rc)) {
1803 .SUCCESS => break @intCast(rc),2053 .SUCCESS => {
1804 .INTR => continue,2054 current_thread.endSyscall();
1805 .CANCELED => return error.Canceled,2055 break @intCast(rc);
18062056 },
1807 .FAULT => |err| return errnoBug(err),2057 .INTR => {
1808 .INVAL => return error.BadPathName,2058 try current_thread.checkCancel();
1809 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2059 continue;
1810 .ACCES => return error.AccessDenied,2060 },
1811 .FBIG => return error.FileTooBig,2061 .CANCELED => return current_thread.endSyscallCanceled(),
1812 .OVERFLOW => return error.FileTooBig,2062 else => |e| {
1813 .ISDIR => return error.IsDir,2063 current_thread.endSyscall();
1814 .LOOP => return error.SymLinkLoop,2064 switch (e) {
1815 .MFILE => return error.ProcessFdQuotaExceeded,2065 .FAULT => |err| return errnoBug(err),
1816 .NAMETOOLONG => return error.NameTooLong,2066 .INVAL => return error.BadPathName,
1817 .NFILE => return error.SystemFdQuotaExceeded,2067 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1818 .NODEV => return error.NoDevice,2068 .ACCES => return error.AccessDenied,
1819 .NOENT => return error.FileNotFound,2069 .FBIG => return error.FileTooBig,
1820 .SRCH => return error.ProcessNotFound,2070 .OVERFLOW => return error.FileTooBig,
1821 .NOMEM => return error.SystemResources,2071 .ISDIR => return error.IsDir,
1822 .NOSPC => return error.NoSpaceLeft,2072 .LOOP => return error.SymLinkLoop,
1823 .NOTDIR => return error.NotDir,2073 .MFILE => return error.ProcessFdQuotaExceeded,
1824 .PERM => return error.PermissionDenied,2074 .NAMETOOLONG => return error.NameTooLong,
1825 .EXIST => return error.PathAlreadyExists,2075 .NFILE => return error.SystemFdQuotaExceeded,
1826 .BUSY => return error.DeviceBusy,2076 .NODEV => return error.NoDevice,
1827 .OPNOTSUPP => return error.FileLocksNotSupported,2077 .NOENT => return error.FileNotFound,
1828 .AGAIN => return error.WouldBlock,2078 .SRCH => return error.ProcessNotFound,
1829 .TXTBSY => return error.FileBusy,2079 .NOMEM => return error.SystemResources,
1830 .NXIO => return error.NoDevice,2080 .NOSPC => return error.NoSpaceLeft,
1831 .ILSEQ => return error.BadPathName,2081 .NOTDIR => return error.NotDir,
1832 else => |err| return posix.unexpectedErrno(err),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 },
1833 }2093 }
1834 };2094 };
1835 errdefer posix.close(fd);2095 errdefer posix.close(fd);
...@@ -1841,42 +2101,71 @@ fn dirCreateFilePosix(...@@ -1841,42 +2101,71 @@ fn dirCreateFilePosix(
1841 .shared => posix.LOCK.SH | lock_nonblocking,2101 .shared => posix.LOCK.SH | lock_nonblocking,
1842 .exclusive => posix.LOCK.EX | lock_nonblocking,2102 .exclusive => posix.LOCK.EX | lock_nonblocking,
1843 };2103 };
2104
2105 try current_thread.beginSyscall();
1844 while (true) {2106 while (true) {
1845 try t.checkCancel();
1846 switch (posix.errno(posix.system.flock(fd, lock_flags))) {2107 switch (posix.errno(posix.system.flock(fd, lock_flags))) {
1847 .SUCCESS => break,2108 .SUCCESS => {
1848 .INTR => continue,2109 current_thread.endSyscall();
1849 .CANCELED => return error.Canceled,2110 break;
18502111 },
1851 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2112 .INTR => {
1852 .INVAL => |err| return errnoBug(err), // invalid parameters2113 try current_thread.checkCancel();
1853 .NOLCK => return error.SystemResources,2114 continue;
1854 .AGAIN => return error.WouldBlock,2115 },
1855 .OPNOTSUPP => return error.FileLocksNotSupported,2116 .CANCELED => return current_thread.endSyscallCanceled(),
1856 else => |err| return posix.unexpectedErrno(err),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 },
1857 }2128 }
1858 }2129 }
1859 }2130 }
18602131
1861 if (have_flock_open_flags and flags.lock_nonblocking) {2132 if (have_flock_open_flags and flags.lock_nonblocking) {
2133 try current_thread.beginSyscall();
1862 var fl_flags: usize = while (true) {2134 var fl_flags: usize = while (true) {
1863 try t.checkCancel();
1864 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));2135 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
1865 switch (posix.errno(rc)) {2136 switch (posix.errno(rc)) {
1866 .SUCCESS => break @intCast(rc),2137 .SUCCESS => {
1867 .INTR => continue,2138 current_thread.endSyscall();
1868 .CANCELED => return error.Canceled,2139 break @intCast(rc);
1869 else => |err| return posix.unexpectedErrno(err),2140 },
2141 .INTR => {
2142 try current_thread.checkCancel();
2143 continue;
2144 },
2145 else => |err| {
2146 current_thread.endSyscall();
2147 return posix.unexpectedErrno(err);
2148 },
1870 }2149 }
1871 };2150 };
2151
1872 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));2152 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2153
2154 try current_thread.beginSyscall();
1873 while (true) {2155 while (true) {
1874 try t.checkCancel();
1875 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {2156 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
1876 .SUCCESS => break,2157 .SUCCESS => {
1877 .INTR => continue,2158 current_thread.endSyscall();
1878 .CANCELED => return error.Canceled,2159 break;
1879 else => |err| return posix.unexpectedErrno(err),2160 },
2161 .INTR => {
2162 try current_thread.checkCancel();
2163 continue;
2164 },
2165 else => |err| {
2166 current_thread.endSyscall();
2167 return posix.unexpectedErrno(err);
2168 },
1880 }2169 }
1881 }2170 }
1882 }2171 }
...@@ -1892,7 +2181,8 @@ fn dirCreateFileWindows(...@@ -1892,7 +2181,8 @@ fn dirCreateFileWindows(
1892) Io.File.OpenError!Io.File {2181) Io.File.OpenError!Io.File {
1893 const w = windows;2182 const w = windows;
1894 const t: *Threaded = @ptrCast(@alignCast(userdata));2183 const t: *Threaded = @ptrCast(@alignCast(userdata));
1895 try t.checkCancel();2184 const current_thread = Thread.getCurrent(t);
2185 try current_thread.checkCancel();
18962186
1897 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);2187 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);
1898 const sub_path_w = sub_path_w_array.span();2188 const sub_path_w = sub_path_w_array.span();
...@@ -1939,6 +2229,7 @@ fn dirCreateFileWasi(...@@ -1939,6 +2229,7 @@ fn dirCreateFileWasi(
1939 flags: Io.File.CreateFlags,2229 flags: Io.File.CreateFlags,
1940) Io.File.OpenError!Io.File {2230) Io.File.OpenError!Io.File {
1941 const t: *Threaded = @ptrCast(@alignCast(userdata));2231 const t: *Threaded = @ptrCast(@alignCast(userdata));
2232 const current_thread = Thread.getCurrent(t);
1942 const wasi = std.os.wasi;2233 const wasi = std.os.wasi;
1943 const lookup_flags: wasi.lookupflags_t = .{};2234 const lookup_flags: wasi.lookupflags_t = .{};
1944 const oflags: wasi.oflags_t = .{2235 const oflags: wasi.oflags_t = .{
...@@ -1966,35 +2257,45 @@ fn dirCreateFileWasi(...@@ -1966,35 +2257,45 @@ fn dirCreateFileWasi(
1966 };2257 };
1967 const inheriting: wasi.rights_t = .{};2258 const inheriting: wasi.rights_t = .{};
1968 var fd: posix.fd_t = undefined;2259 var fd: posix.fd_t = undefined;
2260 try current_thread.beginSyscall();
1969 while (true) {2261 while (true) {
1970 try t.checkCancel();
1971 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {2262 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
1972 .SUCCESS => return .{ .handle = fd },2263 .SUCCESS => {
1973 .INTR => continue,2264 current_thread.endSyscall();
1974 .CANCELED => return error.Canceled,2265 return .{ .handle = fd };
19752266 },
1976 .FAULT => |err| return errnoBug(err),2267 .INTR => {
1977 .INVAL => return error.BadPathName,2268 try current_thread.checkCancel();
1978 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2269 continue;
1979 .ACCES => return error.AccessDenied,2270 },
1980 .FBIG => return error.FileTooBig,2271 .CANCELED => return current_thread.endSyscallCanceled(),
1981 .OVERFLOW => return error.FileTooBig,2272 else => |e| {
1982 .ISDIR => return error.IsDir,2273 current_thread.endSyscall();
1983 .LOOP => return error.SymLinkLoop,2274 switch (e) {
1984 .MFILE => return error.ProcessFdQuotaExceeded,2275 .FAULT => |err| return errnoBug(err),
1985 .NAMETOOLONG => return error.NameTooLong,2276 .INVAL => return error.BadPathName,
1986 .NFILE => return error.SystemFdQuotaExceeded,2277 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1987 .NODEV => return error.NoDevice,2278 .ACCES => return error.AccessDenied,
1988 .NOENT => return error.FileNotFound,2279 .FBIG => return error.FileTooBig,
1989 .NOMEM => return error.SystemResources,2280 .OVERFLOW => return error.FileTooBig,
1990 .NOSPC => return error.NoSpaceLeft,2281 .ISDIR => return error.IsDir,
1991 .NOTDIR => return error.NotDir,2282 .LOOP => return error.SymLinkLoop,
1992 .PERM => return error.PermissionDenied,2283 .MFILE => return error.ProcessFdQuotaExceeded,
1993 .EXIST => return error.PathAlreadyExists,2284 .NAMETOOLONG => return error.NameTooLong,
1994 .BUSY => return error.DeviceBusy,2285 .NFILE => return error.SystemFdQuotaExceeded,
1995 .NOTCAPABLE => return error.AccessDenied,2286 .NODEV => return error.NoDevice,
1996 .ILSEQ => return error.BadPathName,2287 .NOENT => return error.FileNotFound,
1997 else => |err| return posix.unexpectedErrno(err),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 },
1998 }2299 }
1999 }2300 }
2000}2301}
...@@ -2012,6 +2313,7 @@ fn dirOpenFilePosix(...@@ -2012,6 +2313,7 @@ fn dirOpenFilePosix(
2012 flags: Io.File.OpenFlags,2313 flags: Io.File.OpenFlags,
2013) Io.File.OpenError!Io.File {2314) Io.File.OpenError!Io.File {
2014 const t: *Threaded = @ptrCast(@alignCast(userdata));2315 const t: *Threaded = @ptrCast(@alignCast(userdata));
2316 const current_thread = Thread.getCurrent(t);
20152317
2016 var path_buffer: [posix.PATH_MAX]u8 = undefined;2318 var path_buffer: [posix.PATH_MAX]u8 = undefined;
2017 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);2319 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
...@@ -2048,40 +2350,50 @@ fn dirOpenFilePosix(...@@ -2048,40 +2350,50 @@ fn dirOpenFilePosix(
2048 },2350 },
2049 };2351 };
20502352
2353 try current_thread.beginSyscall();
2051 const fd: posix.fd_t = while (true) {2354 const fd: posix.fd_t = while (true) {
2052 try t.checkCancel();
2053 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, @as(posix.mode_t, 0));2355 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, @as(posix.mode_t, 0));
2054 switch (posix.errno(rc)) {2356 switch (posix.errno(rc)) {
2055 .SUCCESS => break @intCast(rc),2357 .SUCCESS => {
2056 .INTR => continue,2358 current_thread.endSyscall();
2057 .CANCELED => return error.Canceled,2359 break @intCast(rc);
20582360 },
2059 .FAULT => |err| return errnoBug(err),2361 .INTR => {
2060 .INVAL => return error.BadPathName,2362 try current_thread.checkCancel();
2061 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2363 continue;
2062 .ACCES => return error.AccessDenied,2364 },
2063 .FBIG => return error.FileTooBig,2365 .CANCELED => return current_thread.endSyscallCanceled(),
2064 .OVERFLOW => return error.FileTooBig,2366 else => |e| {
2065 .ISDIR => return error.IsDir,2367 current_thread.endSyscall();
2066 .LOOP => return error.SymLinkLoop,2368 switch (e) {
2067 .MFILE => return error.ProcessFdQuotaExceeded,2369 .FAULT => |err| return errnoBug(err),
2068 .NAMETOOLONG => return error.NameTooLong,2370 .INVAL => return error.BadPathName,
2069 .NFILE => return error.SystemFdQuotaExceeded,2371 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2070 .NODEV => return error.NoDevice,2372 .ACCES => return error.AccessDenied,
2071 .NOENT => return error.FileNotFound,2373 .FBIG => return error.FileTooBig,
2072 .SRCH => return error.ProcessNotFound,2374 .OVERFLOW => return error.FileTooBig,
2073 .NOMEM => return error.SystemResources,2375 .ISDIR => return error.IsDir,
2074 .NOSPC => return error.NoSpaceLeft,2376 .LOOP => return error.SymLinkLoop,
2075 .NOTDIR => return error.NotDir,2377 .MFILE => return error.ProcessFdQuotaExceeded,
2076 .PERM => return error.PermissionDenied,2378 .NAMETOOLONG => return error.NameTooLong,
2077 .EXIST => return error.PathAlreadyExists,2379 .NFILE => return error.SystemFdQuotaExceeded,
2078 .BUSY => return error.DeviceBusy,2380 .NODEV => return error.NoDevice,
2079 .OPNOTSUPP => return error.FileLocksNotSupported,2381 .NOENT => return error.FileNotFound,
2080 .AGAIN => return error.WouldBlock,2382 .SRCH => return error.ProcessNotFound,
2081 .TXTBSY => return error.FileBusy,2383 .NOMEM => return error.SystemResources,
2082 .NXIO => return error.NoDevice,2384 .NOSPC => return error.NoSpaceLeft,
2083 .ILSEQ => return error.BadPathName,2385 .NOTDIR => return error.NotDir,
2084 else => |err| return posix.unexpectedErrno(err),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 },
2085 }2397 }
2086 };2398 };
2087 errdefer posix.close(fd);2399 errdefer posix.close(fd);
...@@ -2093,42 +2405,72 @@ fn dirOpenFilePosix(...@@ -2093,42 +2405,72 @@ fn dirOpenFilePosix(
2093 .shared => posix.LOCK.SH | lock_nonblocking,2405 .shared => posix.LOCK.SH | lock_nonblocking,
2094 .exclusive => posix.LOCK.EX | lock_nonblocking,2406 .exclusive => posix.LOCK.EX | lock_nonblocking,
2095 };2407 };
2408 try current_thread.beginSyscall();
2096 while (true) {2409 while (true) {
2097 try t.checkCancel();
2098 switch (posix.errno(posix.system.flock(fd, lock_flags))) {2410 switch (posix.errno(posix.system.flock(fd, lock_flags))) {
2099 .SUCCESS => break,2411 .SUCCESS => {
2100 .INTR => continue,2412 current_thread.endSyscall();
2101 .CANCELED => return error.Canceled,2413 break;
21022414 },
2103 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2415 .INTR => {
2104 .INVAL => |err| return errnoBug(err), // invalid parameters2416 try current_thread.checkCancel();
2105 .NOLCK => return error.SystemResources,2417 continue;
2106 .AGAIN => return error.WouldBlock,2418 },
2107 .OPNOTSUPP => return error.FileLocksNotSupported,2419 .CANCELED => return current_thread.endSyscallCanceled(),
2108 else => |err| return posix.unexpectedErrno(err),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 },
2109 }2431 }
2110 }2432 }
2111 }2433 }
21122434
2113 if (have_flock_open_flags and flags.lock_nonblocking) {2435 if (have_flock_open_flags and flags.lock_nonblocking) {
2436 try current_thread.beginSyscall();
2114 var fl_flags: usize = while (true) {2437 var fl_flags: usize = while (true) {
2115 try t.checkCancel();
2116 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));2438 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
2117 switch (posix.errno(rc)) {2439 switch (posix.errno(rc)) {
2118 .SUCCESS => break @intCast(rc),2440 .SUCCESS => {
2119 .INTR => continue,2441 current_thread.endSyscall();
2120 .CANCELED => return error.Canceled,2442 break @intCast(rc);
2121 else => |err| return posix.unexpectedErrno(err),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 },
2122 }2453 }
2123 };2454 };
2455
2124 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));2456 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2457
2458 try current_thread.beginSyscall();
2125 while (true) {2459 while (true) {
2126 try t.checkCancel();
2127 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {2460 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
2128 .SUCCESS => break,2461 .SUCCESS => {
2129 .INTR => continue,2462 current_thread.endSyscall();
2130 .CANCELED => return error.Canceled,2463 break;
2131 else => |err| return posix.unexpectedErrno(err),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 },
2132 }2474 }
2133 }2475 }
2134 }2476 }
...@@ -2158,7 +2500,7 @@ pub fn dirOpenFileWtf16(...@@ -2158,7 +2500,7 @@ pub fn dirOpenFileWtf16(
2158 if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;2500 if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
2159 if (std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;2501 if (std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;
2160 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;2502 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
21612503 const current_thread = Thread.getCurrent(t);
2162 const w = windows;2504 const w = windows;
21632505
2164 var nt_name: w.UNICODE_STRING = .{2506 var nt_name: w.UNICODE_STRING = .{
...@@ -2187,7 +2529,7 @@ pub fn dirOpenFileWtf16(...@@ -2187,7 +2529,7 @@ pub fn dirOpenFileWtf16(
2187 var attempt: u5 = 0;2529 var attempt: u5 = 0;
21882530
2189 const handle = while (true) {2531 const handle = while (true) {
2190 try t.checkCancel();2532 try current_thread.checkCancel();
21912533
2192 var result: w.HANDLE = undefined;2534 var result: w.HANDLE = undefined;
2193 const rc = w.ntdll.NtCreateFile(2535 const rc = w.ntdll.NtCreateFile(
...@@ -2281,6 +2623,7 @@ fn dirOpenFileWasi(...@@ -2281,6 +2623,7 @@ fn dirOpenFileWasi(
2281) Io.File.OpenError!Io.File {2623) Io.File.OpenError!Io.File {
2282 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);2624 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);
2283 const t: *Threaded = @ptrCast(@alignCast(userdata));2625 const t: *Threaded = @ptrCast(@alignCast(userdata));
2626 const current_thread = Thread.getCurrent(t);
2284 const wasi = std.os.wasi;2627 const wasi = std.os.wasi;
2285 var base: std.os.wasi.rights_t = .{};2628 var base: std.os.wasi.rights_t = .{};
2286 // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE2629 // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE
...@@ -2310,33 +2653,44 @@ fn dirOpenFileWasi(...@@ -2310,33 +2653,44 @@ fn dirOpenFileWasi(
2310 const inheriting: wasi.rights_t = .{};2653 const inheriting: wasi.rights_t = .{};
2311 const fdflags: wasi.fdflags_t = .{};2654 const fdflags: wasi.fdflags_t = .{};
2312 var fd: posix.fd_t = undefined;2655 var fd: posix.fd_t = undefined;
2656 try current_thread.beginSyscall();
2313 while (true) {2657 while (true) {
2314 try t.checkCancel();
2315 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {2658 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
2316 .SUCCESS => return .{ .handle = fd },2659 .SUCCESS => {
2317 .INTR => continue,2660 errdefer posix.close(fd);
2318 .CANCELED => return error.Canceled,2661 current_thread.endSyscall();
23192662 return .{ .handle = fd };
2320 .FAULT => |err| return errnoBug(err),2663 },
2321 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2664 .INTR => {
2322 .ACCES => return error.AccessDenied,2665 try current_thread.checkCancel();
2323 .FBIG => return error.FileTooBig,2666 continue;
2324 .OVERFLOW => return error.FileTooBig,2667 },
2325 .ISDIR => return error.IsDir,2668 .CANCELED => return current_thread.endSyscallCanceled(),
2326 .LOOP => return error.SymLinkLoop,2669 else => |e| {
2327 .MFILE => return error.ProcessFdQuotaExceeded,2670 current_thread.endSyscall();
2328 .NFILE => return error.SystemFdQuotaExceeded,2671 switch (e) {
2329 .NODEV => return error.NoDevice,2672 .FAULT => |err| return errnoBug(err),
2330 .NOENT => return error.FileNotFound,2673 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2331 .NOMEM => return error.SystemResources,2674 .ACCES => return error.AccessDenied,
2332 .NOTDIR => return error.NotDir,2675 .FBIG => return error.FileTooBig,
2333 .PERM => return error.PermissionDenied,2676 .OVERFLOW => return error.FileTooBig,
2334 .BUSY => return error.DeviceBusy,2677 .ISDIR => return error.IsDir,
2335 .NOTCAPABLE => return error.AccessDenied,2678 .LOOP => return error.SymLinkLoop,
2336 .NAMETOOLONG => return error.NameTooLong,2679 .MFILE => return error.ProcessFdQuotaExceeded,
2337 .INVAL => return error.BadPathName,2680 .NFILE => return error.SystemFdQuotaExceeded,
2338 .ILSEQ => return error.BadPathName,2681 .NODEV => return error.NoDevice,
2339 else => |err| return posix.unexpectedErrno(err),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 },
2340 }2694 }
2341 }2695 }
2342}2696}
...@@ -2361,6 +2715,8 @@ fn dirOpenDirPosix(...@@ -2361,6 +2715,8 @@ fn dirOpenDirPosix(
2361 return dirOpenDirWindows(t, dir, sub_path_w.span(), options);2715 return dirOpenDirWindows(t, dir, sub_path_w.span(), options);
2362 }2716 }
23632717
2718 const current_thread = Thread.getCurrent(t);
2719
2364 var path_buffer: [posix.PATH_MAX]u8 = undefined;2720 var path_buffer: [posix.PATH_MAX]u8 = undefined;
2365 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);2721 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
23662722
...@@ -2381,31 +2737,41 @@ fn dirOpenDirPosix(...@@ -2381,31 +2737,41 @@ fn dirOpenDirPosix(
2381 if (@hasField(posix.O, "PATH") and !options.iterate)2737 if (@hasField(posix.O, "PATH") and !options.iterate)
2382 flags.PATH = true;2738 flags.PATH = true;
23832739
2740 try current_thread.beginSyscall();
2384 while (true) {2741 while (true) {
2385 try t.checkCancel();
2386 const rc = openat_sym(dir.handle, sub_path_posix, flags, @as(usize, 0));2742 const rc = openat_sym(dir.handle, sub_path_posix, flags, @as(usize, 0));
2387 switch (posix.errno(rc)) {2743 switch (posix.errno(rc)) {
2388 .SUCCESS => return .{ .handle = @intCast(rc) },2744 .SUCCESS => {
2389 .INTR => continue,2745 current_thread.endSyscall();
2390 .CANCELED => return error.Canceled,2746 return .{ .handle = @intCast(rc) };
23912747 },
2392 .FAULT => |err| return errnoBug(err),2748 .INTR => {
2393 .INVAL => return error.BadPathName,2749 try current_thread.checkCancel();
2394 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2750 continue;
2395 .ACCES => return error.AccessDenied,2751 },
2396 .LOOP => return error.SymLinkLoop,2752 .CANCELED => return current_thread.endSyscallCanceled(),
2397 .MFILE => return error.ProcessFdQuotaExceeded,2753 else => |e| {
2398 .NAMETOOLONG => return error.NameTooLong,2754 current_thread.endSyscall();
2399 .NFILE => return error.SystemFdQuotaExceeded,2755 switch (e) {
2400 .NODEV => return error.NoDevice,2756 .FAULT => |err| return errnoBug(err),
2401 .NOENT => return error.FileNotFound,2757 .INVAL => return error.BadPathName,
2402 .NOMEM => return error.SystemResources,2758 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2403 .NOTDIR => return error.NotDir,2759 .ACCES => return error.AccessDenied,
2404 .PERM => return error.PermissionDenied,2760 .LOOP => return error.SymLinkLoop,
2405 .BUSY => return error.DeviceBusy,2761 .MFILE => return error.ProcessFdQuotaExceeded,
2406 .NXIO => return error.NoDevice,2762 .NAMETOOLONG => return error.NameTooLong,
2407 .ILSEQ => return error.BadPathName,2763 .NFILE => return error.SystemFdQuotaExceeded,
2408 else => |err| return posix.unexpectedErrno(err),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 },
2409 }2775 }
2410 }2776 }
2411}2777}
...@@ -2417,34 +2783,46 @@ fn dirOpenDirHaiku(...@@ -2417,34 +2783,46 @@ fn dirOpenDirHaiku(
2417 options: Io.Dir.OpenOptions,2783 options: Io.Dir.OpenOptions,
2418) Io.Dir.OpenError!Io.Dir {2784) Io.Dir.OpenError!Io.Dir {
2419 const t: *Threaded = @ptrCast(@alignCast(userdata));2785 const t: *Threaded = @ptrCast(@alignCast(userdata));
2786 const current_thread = Thread.getCurrent(t);
24202787
2421 var path_buffer: [posix.PATH_MAX]u8 = undefined;2788 var path_buffer: [posix.PATH_MAX]u8 = undefined;
2422 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);2789 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
24232790
2424 _ = options;2791 _ = options;
24252792
2793 try current_thread.beginSyscall();
2426 while (true) {2794 while (true) {
2427 try t.checkCancel();
2428 const rc = posix.system._kern_open_dir(dir.handle, sub_path_posix);2795 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 }
2430 switch (@as(posix.E, @enumFromInt(rc))) {2800 switch (@as(posix.E, @enumFromInt(rc))) {
2431 .INTR => continue,2801 .INTR => {
2432 .CANCELED => return error.Canceled,2802 try current_thread.checkCancel();
2433 .FAULT => |err| return errnoBug(err),2803 continue;
2434 .INVAL => |err| return errnoBug(err),2804 },
2435 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2805 .CANCELED => return current_thread.endSyscallCanceled(),
2436 .ACCES => return error.AccessDenied,2806 else => |e| {
2437 .LOOP => return error.SymLinkLoop,2807 current_thread.endSyscall();
2438 .MFILE => return error.ProcessFdQuotaExceeded,2808 switch (e) {
2439 .NAMETOOLONG => return error.NameTooLong,2809 .FAULT => |err| return errnoBug(err),
2440 .NFILE => return error.SystemFdQuotaExceeded,2810 .INVAL => |err| return errnoBug(err),
2441 .NODEV => return error.NoDevice,2811 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2442 .NOENT => return error.FileNotFound,2812 .ACCES => return error.AccessDenied,
2443 .NOMEM => return error.SystemResources,2813 .LOOP => return error.SymLinkLoop,
2444 .NOTDIR => return error.NotDir,2814 .MFILE => return error.ProcessFdQuotaExceeded,
2445 .PERM => return error.PermissionDenied,2815 .NAMETOOLONG => return error.NameTooLong,
2446 .BUSY => return error.DeviceBusy,2816 .NFILE => return error.SystemFdQuotaExceeded,
2447 else => |err| return posix.unexpectedErrno(err),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 },
2448 }2826 }
2449 }2827 }
2450}2828}
...@@ -2455,6 +2833,7 @@ pub fn dirOpenDirWindows(...@@ -2455,6 +2833,7 @@ pub fn dirOpenDirWindows(
2455 sub_path_w: [:0]const u16,2833 sub_path_w: [:0]const u16,
2456 options: Io.Dir.OpenOptions,2834 options: Io.Dir.OpenOptions,
2457) Io.Dir.OpenError!Io.Dir {2835) Io.Dir.OpenError!Io.Dir {
2836 const current_thread = Thread.getCurrent(t);
2458 const w = windows;2837 const w = windows;
2459 // TODO remove some of these flags if options.access_sub_paths is false2838 // TODO remove some of these flags if options.access_sub_paths is false
2460 const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |2839 const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
...@@ -2478,7 +2857,7 @@ pub fn dirOpenDirWindows(...@@ -2478,7 +2857,7 @@ pub fn dirOpenDirWindows(
2478 const open_reparse_point: w.DWORD = if (!options.follow_symlinks) w.FILE_OPEN_REPARSE_POINT else 0x0;2857 const open_reparse_point: w.DWORD = if (!options.follow_symlinks) w.FILE_OPEN_REPARSE_POINT else 0x0;
2479 var io_status_block: w.IO_STATUS_BLOCK = undefined;2858 var io_status_block: w.IO_STATUS_BLOCK = undefined;
2480 var result: Io.Dir = .{ .handle = undefined };2859 var result: Io.Dir = .{ .handle = undefined };
2481 try t.checkCancel();2860 try current_thread.checkCancel();
2482 const rc = w.ntdll.NtCreateFile(2861 const rc = w.ntdll.NtCreateFile(
2483 &result.handle,2862 &result.handle,
2484 access_mask,2863 access_mask,
...@@ -2527,6 +2906,7 @@ fn dirOpenDirWasi(...@@ -2527,6 +2906,7 @@ fn dirOpenDirWasi(
2527) Io.Dir.OpenError!Io.Dir {2906) Io.Dir.OpenError!Io.Dir {
2528 if (builtin.link_libc) return dirOpenDirPosix(userdata, dir, sub_path, options);2907 if (builtin.link_libc) return dirOpenDirPosix(userdata, dir, sub_path, options);
2529 const t: *Threaded = @ptrCast(@alignCast(userdata));2908 const t: *Threaded = @ptrCast(@alignCast(userdata));
2909 const current_thread = Thread.getCurrent(t);
2530 const wasi = std.os.wasi;2910 const wasi = std.os.wasi;
25312911
2532 var base: std.os.wasi.rights_t = .{2912 var base: std.os.wasi.rights_t = .{
...@@ -2556,31 +2936,40 @@ fn dirOpenDirWasi(...@@ -2556,31 +2936,40 @@ fn dirOpenDirWasi(
2556 const oflags: wasi.oflags_t = .{ .DIRECTORY = true };2936 const oflags: wasi.oflags_t = .{ .DIRECTORY = true };
2557 const fdflags: wasi.fdflags_t = .{};2937 const fdflags: wasi.fdflags_t = .{};
2558 var fd: posix.fd_t = undefined;2938 var fd: posix.fd_t = undefined;
25592939 try current_thread.beginSyscall();
2560 while (true) {2940 while (true) {
2561 try t.checkCancel();
2562 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, base, fdflags, &fd)) {2941 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, base, fdflags, &fd)) {
2563 .SUCCESS => return .{ .handle = fd },2942 .SUCCESS => {
2564 .INTR => continue,2943 current_thread.endSyscall();
2565 .CANCELED => return error.Canceled,2944 return .{ .handle = fd };
25662945 },
2567 .FAULT => |err| return errnoBug(err),2946 .INTR => {
2568 .INVAL => return error.BadPathName,2947 try current_thread.checkCancel();
2569 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2948 continue;
2570 .ACCES => return error.AccessDenied,2949 },
2571 .LOOP => return error.SymLinkLoop,2950 .CANCELED => return current_thread.endSyscallCanceled(),
2572 .MFILE => return error.ProcessFdQuotaExceeded,2951 else => |e| {
2573 .NAMETOOLONG => return error.NameTooLong,2952 current_thread.endSyscall();
2574 .NFILE => return error.SystemFdQuotaExceeded,2953 switch (e) {
2575 .NODEV => return error.NoDevice,2954 .FAULT => |err| return errnoBug(err),
2576 .NOENT => return error.FileNotFound,2955 .INVAL => return error.BadPathName,
2577 .NOMEM => return error.SystemResources,2956 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2578 .NOTDIR => return error.NotDir,2957 .ACCES => return error.AccessDenied,
2579 .PERM => return error.PermissionDenied,2958 .LOOP => return error.SymLinkLoop,
2580 .BUSY => return error.DeviceBusy,2959 .MFILE => return error.ProcessFdQuotaExceeded,
2581 .NOTCAPABLE => return error.AccessDenied,2960 .NAMETOOLONG => return error.NameTooLong,
2582 .ILSEQ => return error.BadPathName,2961 .NFILE => return error.SystemFdQuotaExceeded,
2583 else => |err| return posix.unexpectedErrno(err),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 },
2584 }2973 }
2585 }2974 }
2586}2975}
...@@ -2598,6 +2987,7 @@ const fileReadStreaming = switch (native_os) {...@@ -2598,6 +2987,7 @@ const fileReadStreaming = switch (native_os) {
25982987
2599fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {2988fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
2600 const t: *Threaded = @ptrCast(@alignCast(userdata));2989 const t: *Threaded = @ptrCast(@alignCast(userdata));
2990 const current_thread = Thread.getCurrent(t);
26012991
2602 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;2992 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
2603 var i: usize = 0;2993 var i: usize = 0;
...@@ -2611,59 +3001,82 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io...@@ -2611,59 +3001,82 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io
2611 const dest = iovecs_buffer[0..i];3001 const dest = iovecs_buffer[0..i];
2612 assert(dest[0].len > 0);3002 assert(dest[0].len > 0);
26133003
2614 if (native_os == .wasi and !builtin.link_libc) while (true) {3004 if (native_os == .wasi and !builtin.link_libc) {
2615 try t.checkCancel();3005 try current_thread.beginSyscall();
2616 var nread: usize = undefined;3006 while (true) {
2617 switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {3007 var nread: usize = undefined;
2618 .SUCCESS => return nread,3008 switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {
2619 .INTR => continue,3009 .SUCCESS => {
2620 .CANCELED => return error.Canceled,3010 current_thread.endSyscall();
26213011 return nread;
2622 .INVAL => |err| return errnoBug(err),3012 },
2623 .FAULT => |err| return errnoBug(err),3013 .INTR => {
2624 .BADF => return error.NotOpenForReading, // File operation on directory.3014 try current_thread.checkCancel();
2625 .IO => return error.InputOutput,3015 continue;
2626 .ISDIR => return error.IsDir,3016 },
2627 .NOBUFS => return error.SystemResources,3017 .CANCELED => return current_thread.endSyscallCanceled(),
2628 .NOMEM => return error.SystemResources,3018 else => |e| {
2629 .NOTCONN => return error.SocketUnconnected,3019 current_thread.endSyscall();
2630 .CONNRESET => return error.ConnectionResetByPeer,3020 switch (e) {
2631 .TIMEDOUT => return error.Timeout,3021 .INVAL => |err| return errnoBug(err),
2632 .NOTCAPABLE => return error.AccessDenied,3022 .FAULT => |err| return errnoBug(err),
2633 else => |err| return posix.unexpectedErrno(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 }
2634 }3036 }
2635 };3037 }
26363038
3039 try current_thread.beginSyscall();
2637 while (true) {3040 while (true) {
2638 try t.checkCancel();
2639 const rc = posix.system.readv(file.handle, dest.ptr, @intCast(dest.len));3041 const rc = posix.system.readv(file.handle, dest.ptr, @intCast(dest.len));
2640 switch (posix.errno(rc)) {3042 switch (posix.errno(rc)) {
2641 .SUCCESS => return @intCast(rc),3043 .SUCCESS => {
2642 .INTR => continue,3044 current_thread.endSyscall();
2643 .CANCELED => return error.Canceled,3045 return @intCast(rc);
26443046 },
2645 .INVAL => |err| return errnoBug(err),3047 .INTR => {
2646 .FAULT => |err| return errnoBug(err),3048 try current_thread.checkCancel();
2647 .SRCH => return error.ProcessNotFound,3049 continue;
2648 .AGAIN => return error.WouldBlock,3050 },
2649 .BADF => |err| {3051 .CANCELED => return current_thread.endSyscallCanceled(),
2650 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.3052 else => |e| {
2651 return errnoBug(err); // File descriptor used after closed.3053 current_thread.endSyscall();
2652 },3054 switch (e) {
2653 .IO => return error.InputOutput,3055 .INVAL => |err| return errnoBug(err),
2654 .ISDIR => return error.IsDir,3056 .FAULT => |err| return errnoBug(err),
2655 .NOBUFS => return error.SystemResources,3057 .SRCH => return error.ProcessNotFound,
2656 .NOMEM => return error.SystemResources,3058 .AGAIN => return error.WouldBlock,
2657 .NOTCONN => return error.SocketUnconnected,3059 .BADF => |err| {
2658 .CONNRESET => return error.ConnectionResetByPeer,3060 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
2659 .TIMEDOUT => return error.Timeout,3061 return errnoBug(err); // File descriptor used after closed.
2660 else => |err| return posix.unexpectedErrno(err),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 },
2661 }3073 }
2662 }3074 }
2663}3075}
26643076
2665fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {3077fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
2666 const t: *Threaded = @ptrCast(@alignCast(userdata));3078 const t: *Threaded = @ptrCast(@alignCast(userdata));
3079 const current_thread = Thread.getCurrent(t);
26673080
2668 const DWORD = windows.DWORD;3081 const DWORD = windows.DWORD;
2669 var index: usize = 0;3082 var index: usize = 0;
...@@ -2672,7 +3085,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)...@@ -2672,7 +3085,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
2672 const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);3085 const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);
26733086
2674 while (true) {3087 while (true) {
2675 try t.checkCancel();3088 try current_thread.checkCancel();
2676 var n: DWORD = undefined;3089 var n: DWORD = undefined;
2677 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0)3090 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0)
2678 return n;3091 return n;
...@@ -2692,6 +3105,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)...@@ -2692,6 +3105,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
26923105
2693fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {3106fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
2694 const t: *Threaded = @ptrCast(@alignCast(userdata));3107 const t: *Threaded = @ptrCast(@alignCast(userdata));
3108 const current_thread = Thread.getCurrent(t);
26953109
2696 if (!have_preadv) @compileError("TODO");3110 if (!have_preadv) @compileError("TODO");
26973111
...@@ -2707,60 +3121,82 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o...@@ -2707,60 +3121,82 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o
2707 const dest = iovecs_buffer[0..i];3121 const dest = iovecs_buffer[0..i];
2708 assert(dest[0].len > 0);3122 assert(dest[0].len > 0);
27093123
2710 if (native_os == .wasi and !builtin.link_libc) while (true) {3124 if (native_os == .wasi and !builtin.link_libc) {
2711 try t.checkCancel();3125 try current_thread.beginSyscall();
2712 var nread: usize = undefined;3126 while (true) {
2713 switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {3127 var nread: usize = undefined;
2714 .SUCCESS => return nread,3128 switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {
2715 .INTR => continue,3129 .SUCCESS => {
2716 .CANCELED => return error.Canceled,3130 current_thread.endSyscall();
27173131 return nread;
2718 .INVAL => |err| return errnoBug(err),3132 },
2719 .FAULT => |err| return errnoBug(err),3133 .INTR => {
2720 .AGAIN => |err| return errnoBug(err),3134 try current_thread.checkCancel();
2721 .BADF => return error.NotOpenForReading, // File operation on directory.3135 continue;
2722 .IO => return error.InputOutput,3136 },
2723 .ISDIR => return error.IsDir,3137 .CANCELED => return current_thread.endSyscallCanceled(),
2724 .NOBUFS => return error.SystemResources,3138 else => |e| {
2725 .NOMEM => return error.SystemResources,3139 current_thread.endSyscall();
2726 .NOTCONN => return error.SocketUnconnected,3140 switch (e) {
2727 .CONNRESET => return error.ConnectionResetByPeer,3141 .INVAL => |err| return errnoBug(err),
2728 .TIMEDOUT => return error.Timeout,3142 .FAULT => |err| return errnoBug(err),
2729 .NXIO => return error.Unseekable,3143 .AGAIN => |err| return errnoBug(err),
2730 .SPIPE => return error.Unseekable,3144 .BADF => return error.NotOpenForReading, // File operation on directory.
2731 .OVERFLOW => return error.Unseekable,3145 .IO => return error.InputOutput,
2732 .NOTCAPABLE => return error.AccessDenied,3146 .ISDIR => return error.IsDir,
2733 else => |err| return posix.unexpectedErrno(err),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 }
2734 }3160 }
2735 };3161 }
27363162
3163 try current_thread.beginSyscall();
2737 while (true) {3164 while (true) {
2738 try t.checkCancel();
2739 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));3165 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
2740 switch (posix.errno(rc)) {3166 switch (posix.errno(rc)) {
2741 .SUCCESS => return @bitCast(rc),3167 .SUCCESS => {
2742 .INTR => continue,3168 current_thread.endSyscall();
2743 .CANCELED => return error.Canceled,3169 return @bitCast(rc);
27443170 },
2745 .INVAL => |err| return errnoBug(err),3171 .INTR => {
2746 .FAULT => |err| return errnoBug(err),3172 try current_thread.checkCancel();
2747 .SRCH => return error.ProcessNotFound,3173 continue;
2748 .AGAIN => return error.WouldBlock,3174 },
2749 .BADF => |err| {3175 .CANCELED => return current_thread.endSyscallCanceled(),
2750 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.3176 else => |e| {
2751 return errnoBug(err); // File descriptor used after closed.3177 current_thread.endSyscall();
2752 },3178 switch (e) {
2753 .IO => return error.InputOutput,3179 .INVAL => |err| return errnoBug(err),
2754 .ISDIR => return error.IsDir,3180 .FAULT => |err| return errnoBug(err),
2755 .NOBUFS => return error.SystemResources,3181 .SRCH => return error.ProcessNotFound,
2756 .NOMEM => return error.SystemResources,3182 .AGAIN => return error.WouldBlock,
2757 .NOTCONN => return error.SocketUnconnected,3183 .BADF => |err| {
2758 .CONNRESET => return error.ConnectionResetByPeer,3184 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
2759 .TIMEDOUT => return error.Timeout,3185 return errnoBug(err); // File descriptor used after closed.
2760 .NXIO => return error.Unseekable,3186 },
2761 .SPIPE => return error.Unseekable,3187 .IO => return error.InputOutput,
2762 .OVERFLOW => return error.Unseekable,3188 .ISDIR => return error.IsDir,
2763 else => |err| return posix.unexpectedErrno(err),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 },
2764 }3200 }
2765 }3201 }
2766}3202}
...@@ -2772,6 +3208,7 @@ const fileReadPositional = switch (native_os) {...@@ -2772,6 +3208,7 @@ const fileReadPositional = switch (native_os) {
27723208
2773fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {3209fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
2774 const t: *Threaded = @ptrCast(@alignCast(userdata));3210 const t: *Threaded = @ptrCast(@alignCast(userdata));
3211 const current_thread = Thread.getCurrent(t);
27753212
2776 const DWORD = windows.DWORD;3213 const DWORD = windows.DWORD;
27773214
...@@ -2793,7 +3230,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,...@@ -2793,7 +3230,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
2793 };3230 };
27943231
2795 while (true) {3232 while (true) {
2796 try t.checkCancel();3233 try current_thread.checkCancel();
2797 var n: DWORD = undefined;3234 var n: DWORD = undefined;
2798 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0)3235 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0)
2799 return n;3236 return n;
...@@ -2813,8 +3250,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,...@@ -2813,8 +3250,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
28133250
2814fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekError!void {3251fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekError!void {
2815 const t: *Threaded = @ptrCast(@alignCast(userdata));3252 const t: *Threaded = @ptrCast(@alignCast(userdata));
2816 try t.checkCancel();3253 _ = t;
2817
2818 _ = file;3254 _ = file;
2819 _ = offset;3255 _ = offset;
2820 @panic("TODO implement fileSeekBy");3256 @panic("TODO implement fileSeekBy");
...@@ -2822,63 +3258,96 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr...@@ -2822,63 +3258,96 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr
28223258
2823fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {3259fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {
2824 const t: *Threaded = @ptrCast(@alignCast(userdata));3260 const t: *Threaded = @ptrCast(@alignCast(userdata));
3261 const current_thread = Thread.getCurrent(t);
2825 const fd = file.handle;3262 const fd = file.handle;
28263263
2827 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) while (true) {3264 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2828 try t.checkCancel();3265 try current_thread.beginSyscall();
2829 var result: u64 = undefined;3266 while (true) {
2830 switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {3267 var result: u64 = undefined;
2831 .SUCCESS => return,3268 switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {
2832 .INTR => continue,3269 .SUCCESS => {
2833 .CANCELED => return error.Canceled,3270 current_thread.endSyscall();
28343271 return;
2835 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3272 },
2836 .INVAL => return error.Unseekable,3273 .INTR => {
2837 .OVERFLOW => return error.Unseekable,3274 try current_thread.checkCancel();
2838 .SPIPE => return error.Unseekable,3275 continue;
2839 .NXIO => return error.Unseekable,3276 },
2840 else => |err| return posix.unexpectedErrno(err),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 }
2841 }3290 }
2842 };3291 }
28433292
2844 if (native_os == .windows) {3293 if (native_os == .windows) {
2845 try t.checkCancel();3294 try current_thread.checkCancel();
2846 return windows.SetFilePointerEx_BEGIN(fd, offset);3295 return windows.SetFilePointerEx_BEGIN(fd, offset);
2847 }3296 }
28483297
2849 if (native_os == .wasi and !builtin.link_libc) while (true) {3298 if (native_os == .wasi and !builtin.link_libc) while (true) {
2850 try t.checkCancel();
2851 var new_offset: std.os.wasi.filesize_t = undefined;3299 var new_offset: std.os.wasi.filesize_t = undefined;
3300 try current_thread.beginSyscall();
2852 switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) {3301 switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) {
2853 .SUCCESS => return,3302 .SUCCESS => {
2854 .INTR => continue,3303 current_thread.endSyscall();
2855 .CANCELED => return error.Canceled,3304 return;
28563305 },
2857 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3306 .INTR => {
2858 .INVAL => return error.Unseekable,3307 try current_thread.checkCancel();
2859 .OVERFLOW => return error.Unseekable,3308 continue;
2860 .SPIPE => return error.Unseekable,3309 },
2861 .NXIO => return error.Unseekable,3310 .CANCELED => return current_thread.endSyscallCanceled(),
2862 .NOTCAPABLE => return error.AccessDenied,3311 else => |e| {
2863 else => |err| return posix.unexpectedErrno(err),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 },
2864 }3323 }
2865 };3324 };
28663325
2867 if (posix.SEEK == void) return error.Unseekable;3326 if (posix.SEEK == void) return error.Unseekable;
28683327
3328 try current_thread.beginSyscall();
2869 while (true) {3329 while (true) {
2870 try t.checkCancel();
2871 switch (posix.errno(lseek_sym(fd, @bitCast(offset), posix.SEEK.SET))) {3330 switch (posix.errno(lseek_sym(fd, @bitCast(offset), posix.SEEK.SET))) {
2872 .SUCCESS => return,3331 .SUCCESS => {
2873 .INTR => continue,3332 current_thread.endSyscall();
2874 .CANCELED => return error.Canceled,3333 return;
28753334 },
2876 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3335 .INTR => {
2877 .INVAL => return error.Unseekable,3336 try current_thread.checkCancel();
2878 .OVERFLOW => return error.Unseekable,3337 continue;
2879 .SPIPE => return error.Unseekable,3338 },
2880 .NXIO => return error.Unseekable,3339 .CANCELED => return current_thread.endSyscallCanceled(),
2881 else => |err| return posix.unexpectedErrno(err),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 },
2882 }3351 }
2883 }3352 }
2884}3353}
...@@ -2907,8 +3376,8 @@ fn fileWritePositional(...@@ -2907,8 +3376,8 @@ fn fileWritePositional(
2907 offset: u64,3376 offset: u64,
2908) Io.File.WritePositionalError!usize {3377) Io.File.WritePositionalError!usize {
2909 const t: *Threaded = @ptrCast(@alignCast(userdata));3378 const t: *Threaded = @ptrCast(@alignCast(userdata));
3379 _ = t;
2910 while (true) {3380 while (true) {
2911 try t.checkCancel();
2912 _ = file;3381 _ = file;
2913 _ = buffer;3382 _ = buffer;
2914 _ = offset;3383 _ = offset;
...@@ -2918,8 +3387,8 @@ fn fileWritePositional(...@@ -2918,8 +3387,8 @@ fn fileWritePositional(
29183387
2919fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8) Io.File.WriteStreamingError!usize {3388fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8) Io.File.WriteStreamingError!usize {
2920 const t: *Threaded = @ptrCast(@alignCast(userdata));3389 const t: *Threaded = @ptrCast(@alignCast(userdata));
3390 _ = t;
2921 while (true) {3391 while (true) {
2922 try t.checkCancel();
2923 _ = file;3392 _ = file;
2924 _ = buffer;3393 _ = buffer;
2925 @panic("TODO implement fileWriteStreaming");3394 @panic("TODO implement fileWriteStreaming");
...@@ -2997,6 +3466,7 @@ const sleep = switch (native_os) {...@@ -2997,6 +3466,7 @@ const sleep = switch (native_os) {
29973466
2998fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3467fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
2999 const t: *Threaded = @ptrCast(@alignCast(userdata));3468 const t: *Threaded = @ptrCast(@alignCast(userdata));
3469 const current_thread = Thread.getCurrent(t);
3000 const clock_id: posix.clockid_t = clockToPosix(switch (timeout) {3470 const clock_id: posix.clockid_t = clockToPosix(switch (timeout) {
3001 .none => .awake,3471 .none => .awake,
3002 .duration => |d| d.clock,3472 .duration => |d| d.clock,
...@@ -3008,25 +3478,37 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {...@@ -3008,25 +3478,37 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3008 .deadline => |deadline| deadline.raw.nanoseconds,3478 .deadline => |deadline| deadline.raw.nanoseconds,
3009 };3479 };
3010 var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);3480 var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
3481 try current_thread.beginSyscall();
3011 while (true) {3482 while (true) {
3012 try t.checkCancel();
3013 switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {3483 switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
3014 .none, .duration => false,3484 .none, .duration => false,
3015 .deadline => true,3485 .deadline => true,
3016 } }, &timespec, &timespec))) {3486 } }, &timespec, &timespec))) {
3017 .SUCCESS => return,3487 .SUCCESS => {
3018 .INTR => continue,3488 current_thread.endSyscall();
3019 .CANCELED => return error.Canceled,3489 return;
3020 .INVAL => return error.UnsupportedClock,3490 },
3021 else => |err| return posix.unexpectedErrno(err),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 },
3022 }3503 }
3023 }3504 }
3024}3505}
30253506
3026fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3507fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3027 const t: *Threaded = @ptrCast(@alignCast(userdata));3508 const t: *Threaded = @ptrCast(@alignCast(userdata));
3509 const current_thread = Thread.getCurrent(t);
3028 const t_io = ioBasic(t);3510 const t_io = ioBasic(t);
3029 try t.checkCancel();3511 try current_thread.checkCancel();
3030 const ms = ms: {3512 const ms = ms: {
3031 const d = (try timeout.toDurationFromNow(t_io)) orelse3513 const d = (try timeout.toDurationFromNow(t_io)) orelse
3032 break :ms std.math.maxInt(windows.DWORD);3514 break :ms std.math.maxInt(windows.DWORD);
...@@ -3038,9 +3520,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {...@@ -3038,9 +3520,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30383520
3039fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3521fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3040 const t: *Threaded = @ptrCast(@alignCast(userdata));3522 const t: *Threaded = @ptrCast(@alignCast(userdata));
3523 const current_thread = Thread.getCurrent(t);
3041 const t_io = ioBasic(t);3524 const t_io = ioBasic(t);
3042 try t.checkCancel();
3043
3044 const w = std.os.wasi;3525 const w = std.os.wasi;
30453526
3046 const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t_io)) |d| .{3527 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 {...@@ -3063,11 +3544,14 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3063 };3544 };
3064 var event: w.event_t = undefined;3545 var event: w.event_t = undefined;
3065 var nevents: usize = undefined;3546 var nevents: usize = undefined;
3547 try current_thread.beginSyscall();
3066 _ = w.poll_oneoff(&in, &event, 1, &nevents);3548 _ = w.poll_oneoff(&in, &event, 1, &nevents);
3549 current_thread.endSyscall();
3067}3550}
30683551
3069fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3552fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3070 const t: *Threaded = @ptrCast(@alignCast(userdata));3553 const t: *Threaded = @ptrCast(@alignCast(userdata));
3554 const current_thread = Thread.getCurrent(t);
3071 const t_io = ioBasic(t);3555 const t_io = ioBasic(t);
3072 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;3556 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
3073 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;3557 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
...@@ -3079,12 +3563,16 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {...@@ -3079,12 +3563,16 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3079 };3563 };
3080 break :t timestampToPosix(d.raw.toNanoseconds());3564 break :t timestampToPosix(d.raw.toNanoseconds());
3081 };3565 };
3566 try current_thread.beginSyscall();
3082 while (true) {3567 while (true) {
3083 try t.checkCancel();
3084 switch (posix.errno(posix.system.nanosleep(&timespec, &timespec))) {3568 switch (posix.errno(posix.system.nanosleep(&timespec, &timespec))) {
3085 .INTR => continue,3569 .INTR => {
3086 .CANCELED => return error.Canceled,3570 try current_thread.checkCancel();
3087 else => return, // This prong handles success as well as unexpected errors.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(),
3088 }3576 }
3089 }3577 }
3090}3578}
...@@ -3127,34 +3615,48 @@ fn netListenIpPosix(...@@ -3127,34 +3615,48 @@ fn netListenIpPosix(
3127) IpAddress.ListenError!net.Server {3615) IpAddress.ListenError!net.Server {
3128 if (!have_networking) return error.NetworkDown;3616 if (!have_networking) return error.NetworkDown;
3129 const t: *Threaded = @ptrCast(@alignCast(userdata));3617 const t: *Threaded = @ptrCast(@alignCast(userdata));
3618 const current_thread = Thread.getCurrent(t);
3130 const family = posixAddressFamily(&address);3619 const family = posixAddressFamily(&address);
3131 const socket_fd = try openSocketPosix(t, family, .{3620 const socket_fd = try openSocketPosix(current_thread, family, .{
3132 .mode = options.mode,3621 .mode = options.mode,
3133 .protocol = options.protocol,3622 .protocol = options.protocol,
3134 });3623 });
3135 errdefer posix.close(socket_fd);3624 errdefer posix.close(socket_fd);
31363625
3137 if (options.reuse_address) {3626 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);
3139 if (@hasDecl(posix.SO, "REUSEPORT"))3628 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);
3141 }3630 }
31423631
3143 var storage: PosixAddress = undefined;3632 var storage: PosixAddress = undefined;
3144 var addr_len = addressToPosix(&address, &storage);3633 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();
3147 while (true) {3637 while (true) {
3148 try t.checkCancel();
3149 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {3638 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
3150 .SUCCESS => break,3639 .SUCCESS => {
3151 .ADDRINUSE => return error.AddressInUse,3640 current_thread.endSyscall();
3152 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3641 break;
3153 else => |err| return posix.unexpectedErrno(err),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 },
3154 }3656 }
3155 }3657 }
31563658
3157 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);3659 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
3158 return .{3660 return .{
3159 .socket = .{3661 .socket = .{
3160 .handle = socket_fd,3662 .handle = socket_fd,
...@@ -3170,8 +3672,9 @@ fn netListenIpWindows(...@@ -3170,8 +3672,9 @@ fn netListenIpWindows(
3170) IpAddress.ListenError!net.Server {3672) IpAddress.ListenError!net.Server {
3171 if (!have_networking) return error.NetworkDown;3673 if (!have_networking) return error.NetworkDown;
3172 const t: *Threaded = @ptrCast(@alignCast(userdata));3674 const t: *Threaded = @ptrCast(@alignCast(userdata));
3675 const current_thread = Thread.getCurrent(t);
3173 const family = posixAddressFamily(&address);3676 const family = posixAddressFamily(&address);
3174 const socket_handle = try openSocketWsa(t, family, .{3677 const socket_handle = try openSocketWsa(t, current_thread, family, .{
3175 .mode = options.mode,3678 .mode = options.mode,
3176 .protocol = options.protocol,3679 .protocol = options.protocol,
3177 });3680 });
...@@ -3183,52 +3686,76 @@ fn netListenIpWindows(...@@ -3183,52 +3686,76 @@ fn netListenIpWindows(
3183 var storage: WsaAddress = undefined;3686 var storage: WsaAddress = undefined;
3184 var addr_len = addressToWsa(&address, &storage);3687 var addr_len = addressToWsa(&address, &storage);
31853688
3689 try current_thread.beginSyscall();
3186 while (true) {3690 while (true) {
3187 try t.checkCancel();
3188 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);3691 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 }
3190 switch (ws2_32.WSAGetLastError()) {3696 switch (ws2_32.WSAGetLastError()) {
3191 .EINTR => continue,3697 .EINTR => {
3192 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,3698 try current_thread.checkCancel();
3699 continue;
3700 },
3193 .NOTINITIALISED => {3701 .NOTINITIALISED => {
3194 try initializeWsa(t);3702 try initializeWsa(t);
3703 try current_thread.checkCancel();
3195 continue;3704 continue;
3196 },3705 },
3197 .EADDRINUSE => return error.AddressInUse,3706 else => |e| {
3198 .EADDRNOTAVAIL => return error.AddressUnavailable,3707 current_thread.endSyscall();
3199 .ENOTSOCK => |err| return wsaErrorBug(err),3708 switch (e) {
3200 .EFAULT => |err| return wsaErrorBug(err),3709 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3201 .EINVAL => |err| return wsaErrorBug(err),3710 .EADDRINUSE => return error.AddressInUse,
3202 .ENOBUFS => return error.SystemResources,3711 .EADDRNOTAVAIL => return error.AddressUnavailable,
3203 .ENETDOWN => return error.NetworkDown,3712 .ENOTSOCK => |err| return wsaErrorBug(err),
3204 else => |err| return windows.unexpectedWSAError(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 },
3205 }3720 }
3206 }3721 }
32073722
3723 try current_thread.beginSyscall();
3208 while (true) {3724 while (true) {
3209 try t.checkCancel();
3210 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);3725 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 }
3212 switch (ws2_32.WSAGetLastError()) {3730 switch (ws2_32.WSAGetLastError()) {
3213 .EINTR => continue,3731 .EINTR => {
3214 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,3732 try current_thread.checkCancel();
3733 continue;
3734 },
3215 .NOTINITIALISED => {3735 .NOTINITIALISED => {
3216 try initializeWsa(t);3736 try initializeWsa(t);
3737 try current_thread.checkCancel();
3217 continue;3738 continue;
3218 },3739 },
3219 .ENETDOWN => return error.NetworkDown,3740 else => |e| {
3220 .EADDRINUSE => return error.AddressInUse,3741 current_thread.endSyscall();
3221 .EISCONN => |err| return wsaErrorBug(err),3742 switch (e) {
3222 .EINVAL => |err| return wsaErrorBug(err),3743 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3223 .EMFILE, .ENOBUFS => return error.SystemResources,3744 .ENETDOWN => return error.NetworkDown,
3224 .ENOTSOCK => |err| return wsaErrorBug(err),3745 .EADDRINUSE => return error.AddressInUse,
3225 .EOPNOTSUPP => |err| return wsaErrorBug(err),3746 .EISCONN => |err| return wsaErrorBug(err),
3226 .EINPROGRESS => |err| return wsaErrorBug(err),3747 .EINVAL => |err| return wsaErrorBug(err),
3227 else => |err| return windows.unexpectedWSAError(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 },
3228 }3755 }
3229 }3756 }
32303757
3231 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);3758 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
32323759
3233 return .{3760 return .{
3234 .socket = .{3761 .socket = .{
...@@ -3256,7 +3783,8 @@ fn netListenUnixPosix(...@@ -3256,7 +3783,8 @@ fn netListenUnixPosix(
3256) net.UnixAddress.ListenError!net.Socket.Handle {3783) net.UnixAddress.ListenError!net.Socket.Handle {
3257 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;3784 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3258 const t: *Threaded = @ptrCast(@alignCast(userdata));3785 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) {
3260 error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,3788 error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,
3261 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,3789 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
3262 error.SocketModeUnsupported => return error.AddressFamilyUnsupported,3790 error.SocketModeUnsupported => return error.AddressFamilyUnsupported,
...@@ -3267,15 +3795,28 @@ fn netListenUnixPosix(...@@ -3267,15 +3795,28 @@ fn netListenUnixPosix(
32673795
3268 var storage: UnixAddress = undefined;3796 var storage: UnixAddress = undefined;
3269 const addr_len = addressUnixToPosix(address, &storage);3797 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();
3272 while (true) {3801 while (true) {
3273 try t.checkCancel();
3274 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {3802 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
3275 .SUCCESS => break,3803 .SUCCESS => {
3276 .ADDRINUSE => return error.AddressInUse,3804 current_thread.endSyscall();
3277 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3805 break;
3278 else => |err| return posix.unexpectedErrno(err),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 },
3279 }3820 }
3280 }3821 }
32813822
...@@ -3289,8 +3830,9 @@ fn netListenUnixWindows(...@@ -3289,8 +3830,9 @@ fn netListenUnixWindows(
3289) net.UnixAddress.ListenError!net.Socket.Handle {3830) net.UnixAddress.ListenError!net.Socket.Handle {
3290 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;3831 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3291 const t: *Threaded = @ptrCast(@alignCast(userdata));3832 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) {
3294 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,3836 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
3295 else => |e| return e,3837 else => |e| return e,
3296 };3838 };
...@@ -3299,52 +3841,67 @@ fn netListenUnixWindows(...@@ -3299,52 +3841,67 @@ fn netListenUnixWindows(
3299 var storage: WsaAddress = undefined;3841 var storage: WsaAddress = undefined;
3300 const addr_len = addressUnixToWsa(address, &storage);3842 const addr_len = addressUnixToWsa(address, &storage);
33013843
3844 try current_thread.beginSyscall();
3302 while (true) {3845 while (true) {
3303 try t.checkCancel();
3304 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);3846 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
3305 if (rc != ws2_32.SOCKET_ERROR) break;3847 if (rc != ws2_32.SOCKET_ERROR) break;
3306 switch (ws2_32.WSAGetLastError()) {3848 switch (ws2_32.WSAGetLastError()) {
3307 .EINTR => continue,3849 .EINTR => {
3308 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,3850 try current_thread.checkCancel();
3851 continue;
3852 },
3309 .NOTINITIALISED => {3853 .NOTINITIALISED => {
3310 try initializeWsa(t);3854 try initializeWsa(t);
3855 try current_thread.checkCancel();
3311 continue;3856 continue;
3312 },3857 },
3313 .EADDRINUSE => return error.AddressInUse,3858 else => |e| {
3314 .EADDRNOTAVAIL => return error.AddressUnavailable,3859 current_thread.endSyscall();
3315 .ENOTSOCK => |err| return wsaErrorBug(err),3860 switch (e) {
3316 .EFAULT => |err| return wsaErrorBug(err),3861 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3317 .EINVAL => |err| return wsaErrorBug(err),3862 .EADDRINUSE => return error.AddressInUse,
3318 .ENOBUFS => return error.SystemResources,3863 .EADDRNOTAVAIL => return error.AddressUnavailable,
3319 .ENETDOWN => return error.NetworkDown,3864 .ENOTSOCK => |err| return wsaErrorBug(err),
3320 else => |err| return windows.unexpectedWSAError(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 },
3321 }3872 }
3322 }3873 }
33233874
3324 while (true) {3875 while (true) {
3325 try t.checkCancel();3876 try current_thread.checkCancel();
3326 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);3877 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 }
3328 switch (ws2_32.WSAGetLastError()) {3882 switch (ws2_32.WSAGetLastError()) {
3329 .EINTR => continue,3883 .EINTR => continue,
3330 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3331 .NOTINITIALISED => {3884 .NOTINITIALISED => {
3332 try initializeWsa(t);3885 try initializeWsa(t);
3333 continue;3886 continue;
3334 },3887 },
3335 .ENETDOWN => return error.NetworkDown,3888 else => |e| {
3336 .EADDRINUSE => return error.AddressInUse,3889 current_thread.endSyscall();
3337 .EISCONN => |err| return wsaErrorBug(err),3890 switch (e) {
3338 .EINVAL => |err| return wsaErrorBug(err),3891 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3339 .EMFILE, .ENOBUFS => return error.SystemResources,3892 .ENETDOWN => return error.NetworkDown,
3340 .ENOTSOCK => |err| return wsaErrorBug(err),3893 .EADDRINUSE => return error.AddressInUse,
3341 .EOPNOTSUPP => |err| return wsaErrorBug(err),3894 .EISCONN => |err| return wsaErrorBug(err),
3342 .EINPROGRESS => |err| return wsaErrorBug(err),3895 .EINVAL => |err| return wsaErrorBug(err),
3343 else => |err| return windows.unexpectedWSAError(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 },
3344 }3903 }
3345 }3904 }
3346
3347 return socket_handle;
3348}3905}
33493906
3350fn netListenUnixUnavailable(3907fn netListenUnixUnavailable(
...@@ -3358,172 +3915,275 @@ fn netListenUnixUnavailable(...@@ -3358,172 +3915,275 @@ fn netListenUnixUnavailable(
3358 return error.AddressFamilyUnsupported;3915 return error.AddressFamilyUnsupported;
3359}3916}
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();
3362 while (true) {3925 while (true) {
3363 try t.checkCancel();
3364 switch (posix.errno(posix.system.bind(fd, addr, addr_len))) {3926 switch (posix.errno(posix.system.bind(fd, addr, addr_len))) {
3365 .SUCCESS => break,3927 .SUCCESS => {
3366 .INTR => continue,3928 current_thread.endSyscall();
3367 .CANCELED => return error.Canceled,3929 break;
33683930 },
3369 .ACCES => return error.AccessDenied,3931 .INTR => {
3370 .ADDRINUSE => return error.AddressInUse,3932 try current_thread.checkCancel();
3371 .AFNOSUPPORT => return error.AddressFamilyUnsupported,3933 continue;
3372 .ADDRNOTAVAIL => return error.AddressUnavailable,3934 },
3373 .NOMEM => return error.SystemResources,3935 .CANCELED => return current_thread.endSyscallCanceled(),
33743936 else => |e| {
3375 .LOOP => return error.SymLinkLoop,3937 current_thread.endSyscall();
3376 .NOENT => return error.FileNotFound,3938 switch (e) {
3377 .NOTDIR => return error.NotDir,3939 .ACCES => return error.AccessDenied,
3378 .ROFS => return error.ReadOnlyFileSystem,3940 .ADDRINUSE => return error.AddressInUse,
3379 .PERM => return error.PermissionDenied,3941 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
33803942 .ADDRNOTAVAIL => return error.AddressUnavailable,
3381 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3943 .NOMEM => return error.SystemResources,
3382 .INVAL => |err| return errnoBug(err), // invalid parameters3944
3383 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`3945 .LOOP => return error.SymLinkLoop,
3384 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer3946 .NOENT => return error.FileNotFound,
3385 .NAMETOOLONG => |err| return errnoBug(err),3947 .NOTDIR => return error.NotDir,
3386 else => |err| return posix.unexpectedErrno(err),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 },
3387 }3959 }
3388 }3960 }
3389}3961}
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();
3392 while (true) {3970 while (true) {
3393 try t.checkCancel();
3394 switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) {3971 switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) {
3395 .SUCCESS => break,3972 .SUCCESS => {
3396 .INTR => continue,3973 current_thread.endSyscall();
3397 .CANCELED => return error.Canceled,3974 break;
33983975 },
3399 .ADDRINUSE => return error.AddressInUse,3976 .INTR => {
3400 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3977 try current_thread.checkCancel();
3401 .INVAL => |err| return errnoBug(err), // invalid parameters3978 continue;
3402 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`3979 },
3403 .AFNOSUPPORT => return error.AddressFamilyUnsupported,3980 .CANCELED => return current_thread.endSyscallCanceled(),
3404 .ADDRNOTAVAIL => return error.AddressUnavailable,3981 else => |e| {
3405 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer3982 current_thread.endSyscall();
3406 .NOMEM => return error.SystemResources,3983 switch (e) {
3407 else => |err| return posix.unexpectedErrno(err),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 },
3408 }3995 }
3409 }3996 }
3410}3997}
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();
3413 while (true) {4006 while (true) {
3414 try t.checkCancel();
3415 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {4007 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {
3416 .SUCCESS => return,4008 .SUCCESS => {
3417 .INTR => continue,4009 current_thread.endSyscall();
3418 .CANCELED => return error.Canceled,4010 return;
34194011 },
3420 .ADDRNOTAVAIL => return error.AddressUnavailable,4012 .INTR => {
3421 .AFNOSUPPORT => return error.AddressFamilyUnsupported,4013 try current_thread.checkCancel();
3422 .AGAIN, .INPROGRESS => return error.WouldBlock,4014 continue;
3423 .ALREADY => return error.ConnectionPending,4015 },
3424 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4016 .CANCELED => return current_thread.endSyscallCanceled(),
3425 .CONNREFUSED => return error.ConnectionRefused,4017 else => |e| {
3426 .CONNRESET => return error.ConnectionResetByPeer,4018 current_thread.endSyscall();
3427 .FAULT => |err| return errnoBug(err),4019 switch (e) {
3428 .ISCONN => |err| return errnoBug(err),4020 .ADDRNOTAVAIL => return error.AddressUnavailable,
3429 .HOSTUNREACH => return error.HostUnreachable,4021 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3430 .NETUNREACH => return error.NetworkUnreachable,4022 .AGAIN, .INPROGRESS => return error.WouldBlock,
3431 .NOTSOCK => |err| return errnoBug(err),4023 .ALREADY => return error.ConnectionPending,
3432 .PROTOTYPE => |err| return errnoBug(err),4024 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3433 .TIMEDOUT => return error.Timeout,4025 .CONNREFUSED => return error.ConnectionRefused,
3434 .CONNABORTED => |err| return errnoBug(err),4026 .CONNRESET => return error.ConnectionResetByPeer,
3435 .ACCES => return error.AccessDenied,4027 .FAULT => |err| return errnoBug(err),
3436 .PERM => |err| return errnoBug(err),4028 .ISCONN => |err| return errnoBug(err),
3437 .NOENT => |err| return errnoBug(err),4029 .HOSTUNREACH => return error.HostUnreachable,
3438 .NETDOWN => return error.NetworkDown,4030 .NETUNREACH => return error.NetworkUnreachable,
3439 else => |err| return posix.unexpectedErrno(err),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 },
3440 }4042 }
3441 }4043 }
3442}4044}
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();
3445 while (true) {4053 while (true) {
3446 try t.checkCancel();
3447 switch (posix.errno(posix.system.connect(fd, addr, addr_len))) {4054 switch (posix.errno(posix.system.connect(fd, addr, addr_len))) {
3448 .SUCCESS => return,4055 .SUCCESS => {
3449 .INTR => continue,4056 current_thread.endSyscall();
3450 .CANCELED => return error.Canceled,4057 return;
34514058 },
3452 .AFNOSUPPORT => return error.AddressFamilyUnsupported,4059 .INTR => {
3453 .AGAIN => return error.WouldBlock,4060 try current_thread.checkCancel();
3454 .INPROGRESS => return error.WouldBlock,4061 continue;
3455 .ACCES => return error.AccessDenied,4062 },
34564063 .CANCELED => return current_thread.endSyscallCanceled(),
3457 .LOOP => return error.SymLinkLoop,4064 else => |e| {
3458 .NOENT => return error.FileNotFound,4065 current_thread.endSyscall();
3459 .NOTDIR => return error.NotDir,4066 switch (e) {
3460 .ROFS => return error.ReadOnlyFileSystem,4067 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3461 .PERM => return error.PermissionDenied,4068 .AGAIN => return error.WouldBlock,
34624069 .INPROGRESS => return error.WouldBlock,
3463 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4070 .ACCES => return error.AccessDenied,
3464 .CONNABORTED => |err| return errnoBug(err),4071
3465 .FAULT => |err| return errnoBug(err),4072 .LOOP => return error.SymLinkLoop,
3466 .ISCONN => |err| return errnoBug(err),4073 .NOENT => return error.FileNotFound,
3467 .NOTSOCK => |err| return errnoBug(err),4074 .NOTDIR => return error.NotDir,
3468 .PROTOTYPE => |err| return errnoBug(err),4075 .ROFS => return error.ReadOnlyFileSystem,
3469 else => |err| return posix.unexpectedErrno(err),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 },
3470 }4087 }
3471 }4088 }
3472}4089}
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();
3475 while (true) {4098 while (true) {
3476 try t.checkCancel();
3477 switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) {4099 switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) {
3478 .SUCCESS => break,4100 .SUCCESS => {
3479 .INTR => continue,4101 current_thread.endSyscall();
3480 .CANCELED => return error.Canceled,4102 break;
34814103 },
3482 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4104 .INTR => {
3483 .FAULT => |err| return errnoBug(err),4105 try current_thread.checkCancel();
3484 .INVAL => |err| return errnoBug(err), // invalid parameters4106 continue;
3485 .NOTSOCK => |err| return errnoBug(err), // always a race condition4107 },
3486 .NOBUFS => return error.SystemResources,4108 .CANCELED => return current_thread.endSyscallCanceled(),
3487 else => |err| return posix.unexpectedErrno(err),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 },
3488 }4120 }
3489 }4121 }
3490}4122}
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();
3493 while (true) {4132 while (true) {
3494 try t.checkCancel();
3495 const rc = ws2_32.getsockname(handle, addr, addr_len);4133 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 }
3497 switch (ws2_32.WSAGetLastError()) {4138 switch (ws2_32.WSAGetLastError()) {
3498 .EINTR => continue,4139 .EINTR => {
3499 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4140 try current_thread.checkCancel();
4141 continue;
4142 },
3500 .NOTINITIALISED => {4143 .NOTINITIALISED => {
3501 try initializeWsa(t);4144 try initializeWsa(t);
4145 try current_thread.checkCancel();
3502 continue;4146 continue;
3503 },4147 },
3504 .ENETDOWN => return error.NetworkDown,4148 else => |e| {
3505 .EFAULT => |err| return wsaErrorBug(err),4149 current_thread.endSyscall();
3506 .ENOTSOCK => |err| return wsaErrorBug(err),4150 switch (e) {
3507 .EINVAL => |err| return wsaErrorBug(err),4151 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3508 else => |err| return windows.unexpectedWSAError(err),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 },
3509 }4159 }
3510 }4160 }
3511}4161}
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 {
3514 const o: []const u8 = @ptrCast(&option);4164 const o: []const u8 = @ptrCast(&option);
4165 try current_thread.beginSyscall();
3515 while (true) {4166 while (true) {
3516 try t.checkCancel();
3517 switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) {4167 switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) {
3518 .SUCCESS => return,4168 .SUCCESS => {
3519 .INTR => continue,4169 current_thread.endSyscall();
3520 .CANCELED => return error.Canceled,4170 return;
35214171 },
3522 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4172 .INTR => {
3523 .NOTSOCK => |err| return errnoBug(err),4173 try current_thread.checkCancel();
3524 .INVAL => |err| return errnoBug(err),4174 continue;
3525 .FAULT => |err| return errnoBug(err),4175 },
3526 else => |err| return posix.unexpectedErrno(err),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 },
3527 }4187 }
3528 }4188 }
3529}4189}
...@@ -3557,16 +4217,17 @@ fn netConnectIpPosix(...@@ -3557,16 +4217,17 @@ fn netConnectIpPosix(
3557 if (!have_networking) return error.NetworkDown;4217 if (!have_networking) return error.NetworkDown;
3558 if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");4218 if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");
3559 const t: *Threaded = @ptrCast(@alignCast(userdata));4219 const t: *Threaded = @ptrCast(@alignCast(userdata));
4220 const current_thread = Thread.getCurrent(t);
3560 const family = posixAddressFamily(address);4221 const family = posixAddressFamily(address);
3561 const socket_fd = try openSocketPosix(t, family, .{4222 const socket_fd = try openSocketPosix(current_thread, family, .{
3562 .mode = options.mode,4223 .mode = options.mode,
3563 .protocol = options.protocol,4224 .protocol = options.protocol,
3564 });4225 });
3565 errdefer posix.close(socket_fd);4226 errdefer posix.close(socket_fd);
3566 var storage: PosixAddress = undefined;4227 var storage: PosixAddress = undefined;
3567 var addr_len = addressToPosix(address, &storage);4228 var addr_len = addressToPosix(address, &storage);
3568 try posixConnect(t, socket_fd, &storage.any, addr_len);4229 try posixConnect(current_thread, socket_fd, &storage.any, addr_len);
3569 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);4230 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
3570 return .{ .socket = .{4231 return .{ .socket = .{
3571 .handle = socket_fd,4232 .handle = socket_fd,
3572 .address = addressFromPosix(&storage),4233 .address = addressFromPosix(&storage),
...@@ -3581,8 +4242,9 @@ fn netConnectIpWindows(...@@ -3581,8 +4242,9 @@ fn netConnectIpWindows(
3581 if (!have_networking) return error.NetworkDown;4242 if (!have_networking) return error.NetworkDown;
3582 if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");4243 if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");
3583 const t: *Threaded = @ptrCast(@alignCast(userdata));4244 const t: *Threaded = @ptrCast(@alignCast(userdata));
4245 const current_thread = Thread.getCurrent(t);
3584 const family = posixAddressFamily(address);4246 const family = posixAddressFamily(address);
3585 const socket_handle = try openSocketWsa(t, family, .{4247 const socket_handle = try openSocketWsa(t, current_thread, family, .{
3586 .mode = options.mode,4248 .mode = options.mode,
3587 .protocol = options.protocol,4249 .protocol = options.protocol,
3588 });4250 });
...@@ -3591,36 +4253,48 @@ fn netConnectIpWindows(...@@ -3591,36 +4253,48 @@ fn netConnectIpWindows(
3591 var storage: WsaAddress = undefined;4253 var storage: WsaAddress = undefined;
3592 var addr_len = addressToWsa(address, &storage);4254 var addr_len = addressToWsa(address, &storage);
35934255
4256 try current_thread.beginSyscall();
3594 while (true) {4257 while (true) {
3595 const rc = ws2_32.connect(socket_handle, &storage.any, addr_len);4258 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 }
3597 switch (ws2_32.WSAGetLastError()) {4263 switch (ws2_32.WSAGetLastError()) {
3598 .EINTR => continue,4264 .EINTR => {
3599 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4265 try current_thread.checkCancel();
4266 continue;
4267 },
3600 .NOTINITIALISED => {4268 .NOTINITIALISED => {
3601 try initializeWsa(t);4269 try initializeWsa(t);
4270 try current_thread.checkCancel();
3602 continue;4271 continue;
3603 },4272 },
36044273 else => |e| {
3605 .EADDRNOTAVAIL => return error.AddressUnavailable,4274 current_thread.endSyscall();
3606 .ECONNREFUSED => return error.ConnectionRefused,4275 switch (e) {
3607 .ECONNRESET => return error.ConnectionResetByPeer,4276 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3608 .ETIMEDOUT => return error.Timeout,4277 .EADDRNOTAVAIL => return error.AddressUnavailable,
3609 .EHOSTUNREACH => return error.HostUnreachable,4278 .ECONNREFUSED => return error.ConnectionRefused,
3610 .ENETUNREACH => return error.NetworkUnreachable,4279 .ECONNRESET => return error.ConnectionResetByPeer,
3611 .EFAULT => |err| return wsaErrorBug(err),4280 .ETIMEDOUT => return error.Timeout,
3612 .EINVAL => |err| return wsaErrorBug(err),4281 .EHOSTUNREACH => return error.HostUnreachable,
3613 .EISCONN => |err| return wsaErrorBug(err),4282 .ENETUNREACH => return error.NetworkUnreachable,
3614 .ENOTSOCK => |err| return wsaErrorBug(err),4283 .EFAULT => |err| return wsaErrorBug(err),
3615 .EWOULDBLOCK => return error.WouldBlock,4284 .EINVAL => |err| return wsaErrorBug(err),
3616 .EACCES => return error.AccessDenied,4285 .EISCONN => |err| return wsaErrorBug(err),
3617 .ENOBUFS => return error.SystemResources,4286 .ENOTSOCK => |err| return wsaErrorBug(err),
3618 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,4287 .EWOULDBLOCK => return error.WouldBlock,
3619 else => |err| return windows.unexpectedWSAError(err),4288 .EACCES => return error.AccessDenied,
4289 .ENOBUFS => return error.SystemResources,
4290 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4291 else => |err| return windows.unexpectedWSAError(err),
4292 }
4293 },
3620 }4294 }
3621 }4295 }
36224296
3623 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);4297 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
36244298
3625 return .{ .socket = .{4299 return .{ .socket = .{
3626 .handle = socket_handle,4300 .handle = socket_handle,
...@@ -3645,14 +4319,15 @@ fn netConnectUnixPosix(...@@ -3645,14 +4319,15 @@ fn netConnectUnixPosix(
3645) net.UnixAddress.ConnectError!net.Socket.Handle {4319) net.UnixAddress.ConnectError!net.Socket.Handle {
3646 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;4320 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3647 const t: *Threaded = @ptrCast(@alignCast(userdata));4321 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) {
3649 error.OptionUnsupported => return error.Unexpected,4324 error.OptionUnsupported => return error.Unexpected,
3650 else => |e| return e,4325 else => |e| return e,
3651 };4326 };
3652 errdefer posix.close(socket_fd);4327 errdefer posix.close(socket_fd);
3653 var storage: UnixAddress = undefined;4328 var storage: UnixAddress = undefined;
3654 const addr_len = addressUnixToPosix(address, &storage);4329 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);
3656 return socket_fd;4331 return socket_fd;
3657}4332}
36584333
...@@ -3662,8 +4337,9 @@ fn netConnectUnixWindows(...@@ -3662,8 +4337,9 @@ fn netConnectUnixWindows(
3662) net.UnixAddress.ConnectError!net.Socket.Handle {4337) net.UnixAddress.ConnectError!net.Socket.Handle {
3663 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;4338 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3664 const t: *Threaded = @ptrCast(@alignCast(userdata));4339 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 });
3667 errdefer closeSocketWindows(socket_handle);4343 errdefer closeSocketWindows(socket_handle);
3668 var storage: WsaAddress = undefined;4344 var storage: WsaAddress = undefined;
3669 const addr_len = addressUnixToWsa(address, &storage);4345 const addr_len = addressUnixToWsa(address, &storage);
...@@ -3711,13 +4387,14 @@ fn netBindIpPosix(...@@ -3711,13 +4387,14 @@ fn netBindIpPosix(
3711) IpAddress.BindError!net.Socket {4387) IpAddress.BindError!net.Socket {
3712 if (!have_networking) return error.NetworkDown;4388 if (!have_networking) return error.NetworkDown;
3713 const t: *Threaded = @ptrCast(@alignCast(userdata));4389 const t: *Threaded = @ptrCast(@alignCast(userdata));
4390 const current_thread = Thread.getCurrent(t);
3714 const family = posixAddressFamily(address);4391 const family = posixAddressFamily(address);
3715 const socket_fd = try openSocketPosix(t, family, options);4392 const socket_fd = try openSocketPosix(current_thread, family, options);
3716 errdefer posix.close(socket_fd);4393 errdefer posix.close(socket_fd);
3717 var storage: PosixAddress = undefined;4394 var storage: PosixAddress = undefined;
3718 var addr_len = addressToPosix(address, &storage);4395 var addr_len = addressToPosix(address, &storage);
3719 try posixBind(t, socket_fd, &storage.any, addr_len);4396 try posixBind(current_thread, socket_fd, &storage.any, addr_len);
3720 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);4397 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
3721 return .{4398 return .{
3722 .handle = socket_fd,4399 .handle = socket_fd,
3723 .address = addressFromPosix(&storage),4400 .address = addressFromPosix(&storage),
...@@ -3731,8 +4408,9 @@ fn netBindIpWindows(...@@ -3731,8 +4408,9 @@ fn netBindIpWindows(
3731) IpAddress.BindError!net.Socket {4408) IpAddress.BindError!net.Socket {
3732 if (!have_networking) return error.NetworkDown;4409 if (!have_networking) return error.NetworkDown;
3733 const t: *Threaded = @ptrCast(@alignCast(userdata));4410 const t: *Threaded = @ptrCast(@alignCast(userdata));
4411 const current_thread = Thread.getCurrent(t);
3734 const family = posixAddressFamily(address);4412 const family = posixAddressFamily(address);
3735 const socket_handle = try openSocketWsa(t, family, .{4413 const socket_handle = try openSocketWsa(t, current_thread, family, .{
3736 .mode = options.mode,4414 .mode = options.mode,
3737 .protocol = options.protocol,4415 .protocol = options.protocol,
3738 });4416 });
...@@ -3741,29 +4419,41 @@ fn netBindIpWindows(...@@ -3741,29 +4419,41 @@ fn netBindIpWindows(
3741 var storage: WsaAddress = undefined;4419 var storage: WsaAddress = undefined;
3742 var addr_len = addressToWsa(address, &storage);4420 var addr_len = addressToWsa(address, &storage);
37434421
4422 try current_thread.beginSyscall();
3744 while (true) {4423 while (true) {
3745 try t.checkCancel();
3746 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);4424 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 }
3748 switch (ws2_32.WSAGetLastError()) {4429 switch (ws2_32.WSAGetLastError()) {
3749 .EINTR => continue,4430 .EINTR => {
3750 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4431 try current_thread.checkCancel();
4432 continue;
4433 },
3751 .NOTINITIALISED => {4434 .NOTINITIALISED => {
3752 try initializeWsa(t);4435 try initializeWsa(t);
4436 try current_thread.checkCancel();
3753 continue;4437 continue;
3754 },4438 },
3755 .EADDRINUSE => return error.AddressInUse,4439 else => |e| {
3756 .EADDRNOTAVAIL => return error.AddressUnavailable,4440 current_thread.endSyscall();
3757 .ENOTSOCK => |err| return wsaErrorBug(err),4441 switch (e) {
3758 .EFAULT => |err| return wsaErrorBug(err),4442 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3759 .EINVAL => |err| return wsaErrorBug(err),4443 .EADDRINUSE => return error.AddressInUse,
3760 .ENOBUFS => return error.SystemResources,4444 .EADDRNOTAVAIL => return error.AddressUnavailable,
3761 .ENETDOWN => return error.NetworkDown,4445 .ENOTSOCK => |err| return wsaErrorBug(err),
3762 else => |err| return windows.unexpectedWSAError(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 },
3763 }4453 }
3764 }4454 }
37654455
3766 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);4456 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
37674457
3768 return .{4458 return .{
3769 .handle = socket_handle,4459 .handle = socket_handle,
...@@ -3783,7 +4473,7 @@ fn netBindIpUnavailable(...@@ -3783,7 +4473,7 @@ fn netBindIpUnavailable(
3783}4473}
37844474
3785fn openSocketPosix(4475fn openSocketPosix(
3786 t: *Threaded,4476 current_thread: *Thread,
3787 family: posix.sa_family_t,4477 family: posix.sa_family_t,
3788 options: IpAddress.BindOptions,4478 options: IpAddress.BindOptions,
3789) error{4479) error{
...@@ -3800,8 +4490,8 @@ fn openSocketPosix(...@@ -3800,8 +4490,8 @@ fn openSocketPosix(
3800}!posix.socket_t {4490}!posix.socket_t {
3801 const mode = posixSocketMode(options.mode);4491 const mode = posixSocketMode(options.mode);
3802 const protocol = posixProtocol(options.protocol);4492 const protocol = posixProtocol(options.protocol);
4493 try current_thread.beginSyscall();
3803 const socket_fd = while (true) {4494 const socket_fd = while (true) {
3804 try t.checkCancel();
3805 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;4495 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
3806 const socket_rc = posix.system.socket(family, flags, protocol);4496 const socket_rc = posix.system.socket(family, flags, protocol);
3807 switch (posix.errno(socket_rc)) {4497 switch (posix.errno(socket_rc)) {
...@@ -3809,60 +4499,88 @@ fn openSocketPosix(...@@ -3809,60 +4499,88 @@ fn openSocketPosix(
3809 const fd: posix.fd_t = @intCast(socket_rc);4499 const fd: posix.fd_t = @intCast(socket_rc);
3810 errdefer posix.close(fd);4500 errdefer posix.close(fd);
3811 if (socket_flags_unsupported) while (true) {4501 if (socket_flags_unsupported) while (true) {
3812 try t.checkCancel();4502 try current_thread.checkCancel();
3813 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {4503 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
3814 .SUCCESS => break,4504 .SUCCESS => break,
3815 .INTR => continue,4505 .INTR => continue,
3816 .CANCELED => return error.Canceled,4506 .CANCELED => return current_thread.endSyscallCanceled(),
3817 else => |err| return posix.unexpectedErrno(err),4507 else => |err| {
4508 current_thread.endSyscall();
4509 return posix.unexpectedErrno(err);
4510 },
3818 }4511 }
3819 };4512 };
4513 current_thread.endSyscall();
3820 break fd;4514 break fd;
3821 },4515 },
3822 .INTR => continue,4516 .INTR => {
3823 .CANCELED => return error.Canceled,4517 try current_thread.checkCancel();
38244518 continue;
3825 .AFNOSUPPORT => return error.AddressFamilyUnsupported,4519 },
3826 .INVAL => return error.ProtocolUnsupportedBySystem,4520 .CANCELED => return current_thread.endSyscallCanceled(),
3827 .MFILE => return error.ProcessFdQuotaExceeded,4521 else => |e| {
3828 .NFILE => return error.SystemFdQuotaExceeded,4522 current_thread.endSyscall();
3829 .NOBUFS => return error.SystemResources,4523 switch (e) {
3830 .NOMEM => return error.SystemResources,4524 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3831 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,4525 .INVAL => return error.ProtocolUnsupportedBySystem,
3832 .PROTOTYPE => return error.SocketModeUnsupported,4526 .MFILE => return error.ProcessFdQuotaExceeded,
3833 else => |err| return posix.unexpectedErrno(err),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 },
3834 }4535 }
3835 };4536 };
3836 errdefer posix.close(socket_fd);4537 errdefer posix.close(socket_fd);
38374538
3838 if (options.ip6_only) {4539 if (options.ip6_only) {
3839 if (posix.IPV6 == void) return error.OptionUnsupported;4540 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);
3841 }4542 }
38424543
3843 return socket_fd;4544 return socket_fd;
3844}4545}
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 {
3847 const mode = posixSocketMode(options.mode);4553 const mode = posixSocketMode(options.mode);
3848 const protocol = posixProtocol(options.protocol);4554 const protocol = posixProtocol(options.protocol);
3849 const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;4555 const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
4556 try current_thread.beginSyscall();
3850 while (true) {4557 while (true) {
3851 try t.checkCancel();
3852 const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);4558 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 }
3854 switch (ws2_32.WSAGetLastError()) {4563 switch (ws2_32.WSAGetLastError()) {
3855 .EINTR => continue,4564 .EINTR => {
3856 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4565 try current_thread.checkCancel();
4566 continue;
4567 },
3857 .NOTINITIALISED => {4568 .NOTINITIALISED => {
3858 try initializeWsa(t);4569 try initializeWsa(t);
4570 try current_thread.checkCancel();
3859 continue;4571 continue;
3860 },4572 },
3861 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,4573 else => |e| {
3862 .EMFILE => return error.ProcessFdQuotaExceeded,4574 current_thread.endSyscall();
3863 .ENOBUFS => return error.SystemResources,4575 switch (e) {
3864 .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,4576 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3865 else => |err| return windows.unexpectedWSAError(err),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 },
3866 }4584 }
3867 }4585 }
3868}4586}
...@@ -3870,10 +4588,11 @@ fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.Bin...@@ -3870,10 +4588,11 @@ fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.Bin
3870fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {4588fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {
3871 if (!have_networking) return error.NetworkDown;4589 if (!have_networking) return error.NetworkDown;
3872 const t: *Threaded = @ptrCast(@alignCast(userdata));4590 const t: *Threaded = @ptrCast(@alignCast(userdata));
4591 const current_thread = Thread.getCurrent(t);
3873 var storage: PosixAddress = undefined;4592 var storage: PosixAddress = undefined;
3874 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);4593 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);
4594 try current_thread.beginSyscall();
3875 const fd = while (true) {4595 const fd = while (true) {
3876 try t.checkCancel();
3877 const rc = if (have_accept4)4596 const rc = if (have_accept4)
3878 posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC)4597 posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC)
3879 else4598 else
...@@ -3883,33 +4602,43 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve...@@ -3883,33 +4602,43 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
3883 const fd: posix.fd_t = @intCast(rc);4602 const fd: posix.fd_t = @intCast(rc);
3884 errdefer posix.close(fd);4603 errdefer posix.close(fd);
3885 if (!have_accept4) while (true) {4604 if (!have_accept4) while (true) {
3886 try t.checkCancel();4605 try current_thread.checkCancel();
3887 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {4606 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
3888 .SUCCESS => break,4607 .SUCCESS => break,
3889 .INTR => continue,4608 .INTR => continue,
3890 .CANCELED => return error.Canceled,4609 else => |err| {
3891 else => |err| return posix.unexpectedErrno(err),4610 current_thread.endSyscall();
4611 return posix.unexpectedErrno(err);
4612 },
3892 }4613 }
3893 };4614 };
4615 current_thread.endSyscall();
3894 break fd;4616 break fd;
3895 },4617 },
3896 .INTR => continue,4618 .INTR => {
3897 .CANCELED => return error.Canceled,4619 try current_thread.checkCancel();
38984620 continue;
3899 .AGAIN => |err| return errnoBug(err),4621 },
3900 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4622 .CANCELED => return current_thread.endSyscallCanceled(),
3901 .CONNABORTED => return error.ConnectionAborted,4623 else => |e| {
3902 .FAULT => |err| return errnoBug(err),4624 current_thread.endSyscall();
3903 .INVAL => return error.SocketNotListening,4625 switch (e) {
3904 .NOTSOCK => |err| return errnoBug(err),4626 .AGAIN => |err| return errnoBug(err),
3905 .MFILE => return error.ProcessFdQuotaExceeded,4627 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3906 .NFILE => return error.SystemFdQuotaExceeded,4628 .CONNABORTED => return error.ConnectionAborted,
3907 .NOBUFS => return error.SystemResources,4629 .FAULT => |err| return errnoBug(err),
3908 .NOMEM => return error.SystemResources,4630 .INVAL => return error.SocketNotListening,
3909 .OPNOTSUPP => |err| return errnoBug(err),4631 .NOTSOCK => |err| return errnoBug(err),
3910 .PROTO => return error.ProtocolFailure,4632 .MFILE => return error.ProcessFdQuotaExceeded,
3911 .PERM => return error.BlockedByFirewall,4633 .NFILE => return error.SystemFdQuotaExceeded,
3912 else => |err| return posix.unexpectedErrno(err),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 },
3913 }4642 }
3914 };4643 };
3915 return .{ .socket = .{4644 return .{ .socket = .{
...@@ -3921,31 +4650,44 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve...@@ -3921,31 +4650,44 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
3921fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream {4650fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream {
3922 if (!have_networking) return error.NetworkDown;4651 if (!have_networking) return error.NetworkDown;
3923 const t: *Threaded = @ptrCast(@alignCast(userdata));4652 const t: *Threaded = @ptrCast(@alignCast(userdata));
4653 const current_thread = Thread.getCurrent(t);
3924 var storage: WsaAddress = undefined;4654 var storage: WsaAddress = undefined;
3925 var addr_len: i32 = @sizeOf(WsaAddress);4655 var addr_len: i32 = @sizeOf(WsaAddress);
4656 try current_thread.beginSyscall();
3926 while (true) {4657 while (true) {
3927 try t.checkCancel();
3928 const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);4658 const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);
3929 if (rc != ws2_32.INVALID_SOCKET) return .{ .socket = .{4659 if (rc != ws2_32.INVALID_SOCKET) {
3930 .handle = rc,4660 current_thread.endSyscall();
3931 .address = addressFromWsa(&storage),4661 return .{ .socket = .{
3932 } };4662 .handle = rc,
4663 .address = addressFromWsa(&storage),
4664 } };
4665 }
3933 switch (ws2_32.WSAGetLastError()) {4666 switch (ws2_32.WSAGetLastError()) {
3934 .EINTR => continue,4667 .EINTR => {
3935 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4668 try current_thread.checkCancel();
4669 continue;
4670 },
3936 .NOTINITIALISED => {4671 .NOTINITIALISED => {
3937 try initializeWsa(t);4672 try initializeWsa(t);
4673 try current_thread.checkCancel();
3938 continue;4674 continue;
3939 },4675 },
3940 .ECONNRESET => return error.ConnectionAborted,4676 else => |e| {
3941 .EFAULT => |err| return wsaErrorBug(err),4677 current_thread.endSyscall();
3942 .ENOTSOCK => |err| return wsaErrorBug(err),4678 switch (e) {
3943 .EINVAL => |err| return wsaErrorBug(err),4679 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3944 .EMFILE => return error.ProcessFdQuotaExceeded,4680 .ECONNRESET => return error.ConnectionAborted,
3945 .ENETDOWN => return error.NetworkDown,4681 .EFAULT => |err| return wsaErrorBug(err),
3946 .ENOBUFS => return error.SystemResources,4682 .ENOTSOCK => |err| return wsaErrorBug(err),
3947 .EOPNOTSUPP => |err| return wsaErrorBug(err),4683 .EINVAL => |err| return wsaErrorBug(err),
3948 else => |err| return windows.unexpectedWSAError(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 },
3949 }4691 }
3950 }4692 }
3951}4693}
...@@ -3959,6 +4701,7 @@ fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle)...@@ -3959,6 +4701,7 @@ fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle)
3959fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {4701fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
3960 if (!have_networking) return error.NetworkDown;4702 if (!have_networking) return error.NetworkDown;
3961 const t: *Threaded = @ptrCast(@alignCast(userdata));4703 const t: *Threaded = @ptrCast(@alignCast(userdata));
4704 const current_thread = Thread.getCurrent(t);
39624705
3963 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;4706 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
3964 var i: usize = 0;4707 var i: usize = 0;
...@@ -3972,48 +4715,70 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net....@@ -3972,48 +4715,70 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
3972 const dest = iovecs_buffer[0..i];4715 const dest = iovecs_buffer[0..i];
3973 assert(dest[0].len > 0);4716 assert(dest[0].len > 0);
39744717
3975 if (native_os == .wasi and !builtin.link_libc) while (true) {4718 if (native_os == .wasi and !builtin.link_libc) {
3976 try t.checkCancel();4719 try current_thread.beginSyscall();
3977 var n: usize = undefined;4720 while (true) {
3978 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {4721 var n: usize = undefined;
3979 .SUCCESS => return n,4722 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
3980 .INTR => continue,4723 .SUCCESS => {
3981 .CANCELED => return error.Canceled,4724 current_thread.endSyscall();
39824725 return n;
3983 .INVAL => |err| return errnoBug(err),4726 },
3984 .FAULT => |err| return errnoBug(err),4727 .INTR => {
3985 .AGAIN => |err| return errnoBug(err),4728 try current_thread.checkCancel();
3986 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4729 continue;
3987 .NOBUFS => return error.SystemResources,4730 },
3988 .NOMEM => return error.SystemResources,4731 .CANCELED => return current_thread.endSyscallCanceled(),
3989 .NOTCONN => return error.SocketUnconnected,4732 else => |e| {
3990 .CONNRESET => return error.ConnectionResetByPeer,4733 current_thread.endSyscall();
3991 .TIMEDOUT => return error.Timeout,4734 switch (e) {
3992 .NOTCAPABLE => return error.AccessDenied,4735 .INVAL => |err| return errnoBug(err),
3993 else => |err| return posix.unexpectedErrno(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 }
3994 }4749 }
3995 };4750 }
39964751
4752 try current_thread.beginSyscall();
3997 while (true) {4753 while (true) {
3998 try t.checkCancel();
3999 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));4754 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
4000 switch (posix.errno(rc)) {4755 switch (posix.errno(rc)) {
4001 .SUCCESS => return @intCast(rc),4756 .SUCCESS => {
4002 .INTR => continue,4757 current_thread.endSyscall();
4003 .CANCELED => return error.Canceled,4758 return @intCast(rc);
40044759 },
4005 .INVAL => |err| return errnoBug(err),4760 .INTR => {
4006 .FAULT => |err| return errnoBug(err),4761 try current_thread.checkCancel();
4007 .AGAIN => |err| return errnoBug(err),4762 continue;
4008 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4763 },
4009 .NOBUFS => return error.SystemResources,4764 .CANCELED => return current_thread.endSyscallCanceled(),
4010 .NOMEM => return error.SystemResources,4765 else => |e| {
4011 .NOTCONN => return error.SocketUnconnected,4766 current_thread.endSyscall();
4012 .CONNRESET => return error.ConnectionResetByPeer,4767 switch (e) {
4013 .TIMEDOUT => return error.Timeout,4768 .INVAL => |err| return errnoBug(err),
4014 .PIPE => return error.SocketUnconnected,4769 .FAULT => |err| return errnoBug(err),
4015 .NETDOWN => return error.NetworkDown,4770 .AGAIN => |err| return errnoBug(err),
4016 else => |err| return posix.unexpectedErrno(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 },
4017 }4782 }
4018 }4783 }
4019}4784}
...@@ -4021,6 +4786,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net....@@ -4021,6 +4786,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
4021fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {4786fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
4022 if (!have_networking) return error.NetworkDown;4787 if (!have_networking) return error.NetworkDown;
4023 const t: *Threaded = @ptrCast(@alignCast(userdata));4788 const t: *Threaded = @ptrCast(@alignCast(userdata));
4789 const current_thread = Thread.getCurrent(t);
40244790
4025 const bufs = b: {4791 const bufs = b: {
4026 var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined;4792 var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined;
...@@ -4048,7 +4814,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8...@@ -4048,7 +4814,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8
4048 };4814 };
40494815
4050 while (true) {4816 while (true) {
4051 try t.checkCancel();4817 try current_thread.checkCancel();
40524818
4053 var flags: u32 = 0;4819 var flags: u32 = 0;
4054 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);4820 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
...@@ -4108,6 +4874,7 @@ fn netSendPosix(...@@ -4108,6 +4874,7 @@ fn netSendPosix(
4108) struct { ?net.Socket.SendError, usize } {4874) struct { ?net.Socket.SendError, usize } {
4109 if (!have_networking) return .{ error.NetworkDown, 0 };4875 if (!have_networking) return .{ error.NetworkDown, 0 };
4110 const t: *Threaded = @ptrCast(@alignCast(userdata));4876 const t: *Threaded = @ptrCast(@alignCast(userdata));
4877 const current_thread = Thread.getCurrent(t);
41114878
4112 const posix_flags: u32 =4879 const posix_flags: u32 =
4113 @as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |4880 @as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |
...@@ -4120,10 +4887,10 @@ fn netSendPosix(...@@ -4120,10 +4887,10 @@ fn netSendPosix(
4120 var i: usize = 0;4887 var i: usize = 0;
4121 while (messages.len - i != 0) {4888 while (messages.len - i != 0) {
4122 if (have_sendmmsg) {4889 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 };
4124 continue;4891 continue;
4125 }4892 }
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 };
4127 i += 1;4894 i += 1;
4128 }4895 }
4129 return .{ null, i };4896 return .{ null, i };
...@@ -4159,6 +4926,7 @@ fn netSendUnavailable(...@@ -4159,6 +4926,7 @@ fn netSendUnavailable(
41594926
4160fn netSendOne(4927fn netSendOne(
4161 t: *Threaded,4928 t: *Threaded,
4929 current_thread: *Thread,
4162 handle: net.Socket.Handle,4930 handle: net.Socket.Handle,
4163 message: *net.OutgoingMessage,4931 message: *net.OutgoingMessage,
4164 flags: u32,4932 flags: u32,
...@@ -4175,80 +4943,97 @@ fn netSendOne(...@@ -4175,80 +4943,97 @@ fn netSendOne(
4175 .controllen = @intCast(message.control.len),4943 .controllen = @intCast(message.control.len),
4176 .flags = 0,4944 .flags = 0,
4177 };4945 };
4946 try current_thread.beginSyscall();
4178 while (true) {4947 while (true) {
4179 try t.checkCancel();
4180 const rc = posix.system.sendmsg(handle, &msg, flags);4948 const rc = posix.system.sendmsg(handle, &msg, flags);
4181 if (is_windows) {4949 if (is_windows) {
4182 if (rc == ws2_32.SOCKET_ERROR) {4950 if (rc != ws2_32.SOCKET_ERROR) {
4183 switch (ws2_32.WSAGetLastError()) {4951 current_thread.endSyscall();
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 {
4209 message.data_len = @intCast(rc);4952 message.data_len = @intCast(rc);
4210 return;4953 return;
4211 }4954 }
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 }
4212 }4989 }
4213 switch (posix.errno(rc)) {4990 switch (posix.errno(rc)) {
4214 .SUCCESS => {4991 .SUCCESS => {
4992 current_thread.endSyscall();
4215 message.data_len = @intCast(rc);4993 message.data_len = @intCast(rc);
4216 return;4994 return;
4217 },4995 },
4218 .INTR => continue,4996 .INTR => {
4219 .CANCELED => return error.Canceled,4997 try current_thread.checkCancel();
42204998 continue;
4221 .ACCES => return error.AccessDenied,4999 },
4222 .ALREADY => return error.FastOpenAlreadyInProgress,5000 .CANCELED => return current_thread.endSyscallCanceled(),
4223 .BADF => |err| return errnoBug(err), // File descriptor used after closed.5001 else => |e| {
4224 .CONNRESET => return error.ConnectionResetByPeer,5002 current_thread.endSyscall();
4225 .DESTADDRREQ => |err| return errnoBug(err),5003 switch (e) {
4226 .FAULT => |err| return errnoBug(err),5004 .ACCES => return error.AccessDenied,
4227 .INVAL => |err| return errnoBug(err),5005 .ALREADY => return error.FastOpenAlreadyInProgress,
4228 .ISCONN => |err| return errnoBug(err),5006 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4229 .MSGSIZE => return error.MessageOversize,5007 .CONNRESET => return error.ConnectionResetByPeer,
4230 .NOBUFS => return error.SystemResources,5008 .DESTADDRREQ => |err| return errnoBug(err),
4231 .NOMEM => return error.SystemResources,5009 .FAULT => |err| return errnoBug(err),
4232 .NOTSOCK => |err| return errnoBug(err),5010 .INVAL => |err| return errnoBug(err),
4233 .OPNOTSUPP => |err| return errnoBug(err),5011 .ISCONN => |err| return errnoBug(err),
4234 .PIPE => return error.SocketUnconnected,5012 .MSGSIZE => return error.MessageOversize,
4235 .AFNOSUPPORT => return error.AddressFamilyUnsupported,5013 .NOBUFS => return error.SystemResources,
4236 .HOSTUNREACH => return error.HostUnreachable,5014 .NOMEM => return error.SystemResources,
4237 .NETUNREACH => return error.NetworkUnreachable,5015 .NOTSOCK => |err| return errnoBug(err),
4238 .NOTCONN => return error.SocketUnconnected,5016 .OPNOTSUPP => |err| return errnoBug(err),
4239 .NETDOWN => return error.NetworkDown,5017 .PIPE => return error.SocketUnconnected,
4240 else => |err| return posix.unexpectedErrno(err),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 },
4241 }5026 }
4242 }5027 }
4243}5028}
42445029
4245fn netSendMany(5030fn netSendMany(
4246 t: *Threaded,5031 current_thread: *Thread,
4247 handle: net.Socket.Handle,5032 handle: net.Socket.Handle,
4248 messages: []net.OutgoingMessage,5033 messages: []net.OutgoingMessage,
4249 flags: u32,5034 flags: u32,
4250) net.Socket.SendError!usize {5035) net.Socket.SendError!usize {
4251 var msg_buffer: [64]std.os.linux.mmsghdr = undefined;5036 var msg_buffer: [64]posix.system.mmsghdr = undefined;
4252 var addr_buffer: [msg_buffer.len]PosixAddress = undefined;5037 var addr_buffer: [msg_buffer.len]PosixAddress = undefined;
4253 var iovecs_buffer: [msg_buffer.len]posix.iovec = undefined;5038 var iovecs_buffer: [msg_buffer.len]posix.iovec = undefined;
4254 const min_len: usize = @min(messages.len, msg_buffer.len);5039 const min_len: usize = @min(messages.len, msg_buffer.len);
...@@ -4273,40 +5058,48 @@ fn netSendMany(...@@ -4273,40 +5058,48 @@ fn netSendMany(
4273 };5058 };
4274 }5059 }
42755060
5061 try current_thread.beginSyscall();
4276 while (true) {5062 while (true) {
4277 try t.checkCancel();
4278 const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags);5063 const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags);
4279 switch (posix.errno(rc)) {5064 switch (posix.errno(rc)) {
4280 .SUCCESS => {5065 .SUCCESS => {
5066 current_thread.endSyscall();
4281 const n: usize = @intCast(rc);5067 const n: usize = @intCast(rc);
4282 for (clamped_messages[0..n], clamped_msgs[0..n]) |*message, *msg| {5068 for (clamped_messages[0..n], clamped_msgs[0..n]) |*message, *msg| {
4283 message.data_len = msg.len;5069 message.data_len = msg.len;
4284 }5070 }
4285 return n;5071 return n;
4286 },5072 },
4287 .INTR => continue,5073 .INTR => {
4288 .CANCELED => return error.Canceled,5074 try current_thread.checkCancel();
42895075 continue;
4290 .AGAIN => |err| return errnoBug(err),5076 },
4291 .ALREADY => return error.FastOpenAlreadyInProgress,5077 .CANCELED => return current_thread.endSyscallCanceled(),
4292 .BADF => |err| return errnoBug(err), // File descriptor used after closed.5078 else => |e| {
4293 .CONNRESET => return error.ConnectionResetByPeer,5079 current_thread.endSyscall();
4294 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.5080 switch (e) {
4295 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.5081 .AGAIN => |err| return errnoBug(err),
4296 .INVAL => |err| return errnoBug(err), // Invalid argument passed.5082 .ALREADY => return error.FastOpenAlreadyInProgress,
4297 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified5083 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4298 .MSGSIZE => return error.MessageOversize,5084 .CONNRESET => return error.ConnectionResetByPeer,
4299 .NOBUFS => return error.SystemResources,5085 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
4300 .NOMEM => return error.SystemResources,5086 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
4301 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.5087 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
4302 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.5088 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
4303 .PIPE => return error.SocketUnconnected,5089 .MSGSIZE => return error.MessageOversize,
4304 .AFNOSUPPORT => return error.AddressFamilyUnsupported,5090 .NOBUFS => return error.SystemResources,
4305 .HOSTUNREACH => return error.HostUnreachable,5091 .NOMEM => return error.SystemResources,
4306 .NETUNREACH => return error.NetworkUnreachable,5092 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
4307 .NOTCONN => return error.SocketUnconnected,5093 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
4308 .NETDOWN => return error.NetworkDown,5094 .PIPE => return error.SocketUnconnected,
4309 else => |err| return posix.unexpectedErrno(err),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 },
4310 }5103 }
4311 }5104 }
4312}5105}
...@@ -4321,6 +5114,7 @@ fn netReceivePosix(...@@ -4321,6 +5114,7 @@ fn netReceivePosix(
4321) struct { ?net.Socket.ReceiveTimeoutError, usize } {5114) struct { ?net.Socket.ReceiveTimeoutError, usize } {
4322 if (!have_networking) return .{ error.NetworkDown, 0 };5115 if (!have_networking) return .{ error.NetworkDown, 0 };
4323 const t: *Threaded = @ptrCast(@alignCast(userdata));5116 const t: *Threaded = @ptrCast(@alignCast(userdata));
5117 const current_thread = Thread.getCurrent(t);
4324 const t_io = io(t);5118 const t_io = io(t);
43255119
4326 // recvmmsg is useless, here's why:5120 // recvmmsg is useless, here's why:
...@@ -4351,8 +5145,6 @@ fn netReceivePosix(...@@ -4351,8 +5145,6 @@ fn netReceivePosix(
4351 const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i };5145 const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i };
43525146
4353 recv: while (true) {5147 recv: while (true) {
4354 t.checkCancel() catch |err| return .{ err, message_i };
4355
4356 if (message_buffer.len - message_i == 0) return .{ null, message_i };5148 if (message_buffer.len - message_i == 0) return .{ null, message_i };
4357 const message = &message_buffer[message_i];5149 const message = &message_buffer[message_i];
4358 const remaining_data_buffer = data_buffer[data_i..];5150 const remaining_data_buffer = data_buffer[data_i..];
...@@ -4368,7 +5160,9 @@ fn netReceivePosix(...@@ -4368,7 +5160,9 @@ fn netReceivePosix(
4368 .flags = undefined,5160 .flags = undefined,
4369 };5161 };
43705162
5163 current_thread.beginSyscall() catch |err| return .{ err, message_i };
4371 const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags);5164 const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags);
5165 current_thread.endSyscall();
4372 switch (posix.errno(recv_rc)) {5166 switch (posix.errno(recv_rc)) {
4373 .SUCCESS => {5167 .SUCCESS => {
4374 const data = remaining_data_buffer[0..@intCast(recv_rc)];5168 const data = remaining_data_buffer[0..@intCast(recv_rc)];
...@@ -4389,7 +5183,6 @@ fn netReceivePosix(...@@ -4389,7 +5183,6 @@ fn netReceivePosix(
4389 continue;5183 continue;
4390 },5184 },
4391 .AGAIN => while (true) {5185 .AGAIN => while (true) {
4392 t.checkCancel() catch |err| return .{ err, message_i };
4393 if (message_i != 0) return .{ null, message_i };5186 if (message_i != 0) return .{ null, message_i };
43945187
4395 const max_poll_ms = std.math.maxInt(u31);5188 const max_poll_ms = std.math.maxInt(u31);
...@@ -4399,7 +5192,10 @@ fn netReceivePosix(...@@ -4399,7 +5192,10 @@ fn netReceivePosix(
4399 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));5192 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
4400 } else max_poll_ms;5193 } else max_poll_ms;
44015194
5195 current_thread.beginSyscall() catch |err| return .{ err, message_i };
4402 const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);5196 const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
5197 current_thread.endSyscall();
5198
4403 switch (posix.errno(poll_rc)) {5199 switch (posix.errno(poll_rc)) {
4404 .SUCCESS => {5200 .SUCCESS => {
4405 if (poll_rc == 0) {5201 if (poll_rc == 0) {
...@@ -4411,7 +5207,7 @@ fn netReceivePosix(...@@ -4411,7 +5207,7 @@ fn netReceivePosix(
4411 continue :recv;5207 continue :recv;
4412 },5208 },
4413 .INTR => continue,5209 .INTR => continue,
4414 .CANCELED => return .{ error.Canceled, message_i },5210 .CANCELED => return .{ current_thread.endSyscallCanceled(), message_i },
44155211
4416 .FAULT => |err| return .{ errnoBug(err), message_i },5212 .FAULT => |err| return .{ errnoBug(err), message_i },
4417 .INVAL => |err| return .{ errnoBug(err), message_i },5213 .INVAL => |err| return .{ errnoBug(err), message_i },
...@@ -4420,7 +5216,7 @@ fn netReceivePosix(...@@ -4420,7 +5216,7 @@ fn netReceivePosix(
4420 }5216 }
4421 },5217 },
4422 .INTR => continue,5218 .INTR => continue,
4423 .CANCELED => return .{ error.Canceled, message_i },5219 .CANCELED => return .{ current_thread.endSyscallCanceled(), message_i },
44245220
4425 .BADF => |err| return .{ errnoBug(err), message_i },5221 .BADF => |err| return .{ errnoBug(err), message_i },
4426 .NFILE => return .{ error.SystemFdQuotaExceeded, message_i },5222 .NFILE => return .{ error.SystemFdQuotaExceeded, message_i },
...@@ -4486,6 +5282,7 @@ fn netWritePosix(...@@ -4486,6 +5282,7 @@ fn netWritePosix(
4486) net.Stream.Writer.Error!usize {5282) net.Stream.Writer.Error!usize {
4487 if (!have_networking) return error.NetworkDown;5283 if (!have_networking) return error.NetworkDown;
4488 const t: *Threaded = @ptrCast(@alignCast(userdata));5284 const t: *Threaded = @ptrCast(@alignCast(userdata));
5285 const current_thread = Thread.getCurrent(t);
44895286
4490 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;5287 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;
4491 var msg: posix.msghdr_const = .{5288 var msg: posix.msghdr_const = .{
...@@ -4526,35 +5323,45 @@ fn netWritePosix(...@@ -4526,35 +5323,45 @@ fn netWritePosix(
4526 },5323 },
4527 };5324 };
4528 const flags = posix.MSG.NOSIGNAL;5325 const flags = posix.MSG.NOSIGNAL;
5326 try current_thread.beginSyscall();
4529 while (true) {5327 while (true) {
4530 try t.checkCancel();
4531 const rc = posix.system.sendmsg(fd, &msg, flags);5328 const rc = posix.system.sendmsg(fd, &msg, flags);
4532 switch (posix.errno(rc)) {5329 switch (posix.errno(rc)) {
4533 .SUCCESS => return @intCast(rc),5330 .SUCCESS => {
4534 .INTR => continue,5331 current_thread.endSyscall();
4535 .CANCELED => return error.Canceled,5332 return @intCast(rc);
45365333 },
4537 .ACCES => |err| return errnoBug(err),5334 .INTR => {
4538 .AGAIN => |err| return errnoBug(err),5335 try current_thread.checkCancel();
4539 .ALREADY => return error.FastOpenAlreadyInProgress,5336 continue;
4540 .BADF => |err| return errnoBug(err), // File descriptor used after closed.5337 },
4541 .CONNRESET => return error.ConnectionResetByPeer,5338 .CANCELED => return current_thread.endSyscallCanceled(),
4542 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.5339 else => |e| {
4543 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.5340 current_thread.endSyscall();
4544 .INVAL => |err| return errnoBug(err), // Invalid argument passed.5341 switch (e) {
4545 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified5342 .ACCES => |err| return errnoBug(err),
4546 .MSGSIZE => |err| return errnoBug(err),5343 .AGAIN => |err| return errnoBug(err),
4547 .NOBUFS => return error.SystemResources,5344 .ALREADY => return error.FastOpenAlreadyInProgress,
4548 .NOMEM => return error.SystemResources,5345 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4549 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.5346 .CONNRESET => return error.ConnectionResetByPeer,
4550 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.5347 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
4551 .PIPE => return error.SocketUnconnected,5348 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
4552 .AFNOSUPPORT => return error.AddressFamilyUnsupported,5349 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
4553 .HOSTUNREACH => return error.HostUnreachable,5350 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
4554 .NETUNREACH => return error.NetworkUnreachable,5351 .MSGSIZE => |err| return errnoBug(err),
4555 .NOTCONN => return error.SocketUnconnected,5352 .NOBUFS => return error.SystemResources,
4556 .NETDOWN => return error.NetworkDown,5353 .NOMEM => return error.SystemResources,
4557 else => |err| return posix.unexpectedErrno(err),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 },
4558 }5365 }
4559 }5366 }
4560}5367}
...@@ -4567,6 +5374,7 @@ fn netWriteWindows(...@@ -4567,6 +5374,7 @@ fn netWriteWindows(
4567 splat: usize,5374 splat: usize,
4568) net.Stream.Writer.Error!usize {5375) net.Stream.Writer.Error!usize {
4569 const t: *Threaded = @ptrCast(@alignCast(userdata));5376 const t: *Threaded = @ptrCast(@alignCast(userdata));
5377 const current_thread = Thread.getCurrent(t);
4570 comptime assert(native_os == .windows);5378 comptime assert(native_os == .windows);
45715379
4572 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;5380 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;
...@@ -4600,7 +5408,7 @@ fn netWriteWindows(...@@ -4600,7 +5408,7 @@ fn netWriteWindows(
4600 };5408 };
46015409
4602 while (true) {5410 while (true) {
4603 try t.checkCancel();5411 try current_thread.checkCancel();
46045412
4605 var n: u32 = undefined;5413 var n: u32 = undefined;
4606 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);5414 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
...@@ -4626,7 +5434,7 @@ fn netWriteWindows(...@@ -4626,7 +5434,7 @@ fn netWriteWindows(
4626 };5434 };
4627 switch (wsa_error) {5435 switch (wsa_error) {
4628 .EINTR => continue,5436 .EINTR => continue,
4629 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,5437 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return current_thread.endSyscallCanceled(),
4630 .NOTINITIALISED => {5438 .NOTINITIALISED => {
4631 try initializeWsa(t);5439 try initializeWsa(t);
4632 continue;5440 continue;
...@@ -4707,9 +5515,10 @@ fn netInterfaceNameResolve(...@@ -4707,9 +5515,10 @@ fn netInterfaceNameResolve(
4707) net.Interface.Name.ResolveError!net.Interface {5515) net.Interface.Name.ResolveError!net.Interface {
4708 if (!have_networking) return error.InterfaceNotFound;5516 if (!have_networking) return error.InterfaceNotFound;
4709 const t: *Threaded = @ptrCast(@alignCast(userdata));5517 const t: *Threaded = @ptrCast(@alignCast(userdata));
5518 const current_thread = Thread.getCurrent(t);
47105519
4711 if (native_os == .linux) {5520 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) {
4713 error.ProcessFdQuotaExceeded => return error.SystemResources,5522 error.ProcessFdQuotaExceeded => return error.SystemResources,
4714 error.SystemFdQuotaExceeded => return error.SystemResources,5523 error.SystemFdQuotaExceeded => return error.SystemResources,
4715 error.AddressFamilyUnsupported => return error.Unexpected,5524 error.AddressFamilyUnsupported => return error.Unexpected,
...@@ -4726,32 +5535,42 @@ fn netInterfaceNameResolve(...@@ -4726,32 +5535,42 @@ fn netInterfaceNameResolve(
4726 .ifru = undefined,5535 .ifru = undefined,
4727 };5536 };
47285537
5538 try current_thread.beginSyscall();
4729 while (true) {5539 while (true) {
4730 try t.checkCancel();
4731 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {5540 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {
4732 .SUCCESS => return .{ .index = @bitCast(ifr.ifru.ivalue) },5541 .SUCCESS => {
4733 .INTR => continue,5542 current_thread.endSyscall();
4734 .CANCELED => return error.Canceled,5543 return .{ .index = @bitCast(ifr.ifru.ivalue) };
47355544 },
4736 .INVAL => |err| return errnoBug(err), // Bad parameters.5545 .INTR => {
4737 .NOTTY => |err| return errnoBug(err),5546 try current_thread.checkCancel();
4738 .NXIO => |err| return errnoBug(err),5547 continue;
4739 .BADF => |err| return errnoBug(err), // File descriptor used after closed.5548 },
4740 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.5549 .CANCELED => return current_thread.endSyscallCanceled(),
4741 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor5550 else => |e| {
4742 .NODEV => return error.InterfaceNotFound,5551 current_thread.endSyscall();
4743 else => |err| return posix.unexpectedErrno(err),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 },
4744 }5563 }
4745 }5564 }
4746 }5565 }
47475566
4748 if (native_os == .windows) {5567 if (native_os == .windows) {
4749 try t.checkCancel();5568 try current_thread.checkCancel();
4750 @panic("TODO implement netInterfaceNameResolve for Windows");5569 @panic("TODO implement netInterfaceNameResolve for Windows");
4751 }5570 }
47525571
4753 if (builtin.link_libc) {5572 if (builtin.link_libc) {
4754 try t.checkCancel();5573 try current_thread.checkCancel();
4755 const index = std.c.if_nametoindex(&name.bytes);5574 const index = std.c.if_nametoindex(&name.bytes);
4756 if (index == 0) return error.InterfaceNotFound;5575 if (index == 0) return error.InterfaceNotFound;
4757 return .{ .index = @bitCast(index) };5576 return .{ .index = @bitCast(index) };
...@@ -4771,7 +5590,8 @@ fn netInterfaceNameResolveUnavailable(...@@ -4771,7 +5590,8 @@ fn netInterfaceNameResolveUnavailable(
47715590
4772fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {5591fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
4773 const t: *Threaded = @ptrCast(@alignCast(userdata));5592 const t: *Threaded = @ptrCast(@alignCast(userdata));
4774 try t.checkCancel();5593 const current_thread = Thread.getCurrent(t);
5594 try current_thread.checkCancel();
47755595
4776 if (native_os == .linux) {5596 if (native_os == .linux) {
4777 _ = interface;5597 _ = interface;
...@@ -4802,8 +5622,9 @@ fn netLookup(...@@ -4802,8 +5622,9 @@ fn netLookup(
4802 options: HostName.LookupOptions,5622 options: HostName.LookupOptions,
4803) void {5623) void {
4804 const t: *Threaded = @ptrCast(@alignCast(userdata));5624 const t: *Threaded = @ptrCast(@alignCast(userdata));
5625 const current_thread = Thread.getCurrent(t);
4805 const t_io = io(t);5626 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) });
4807}5628}
48085629
4809fn netLookupUnavailable(5630fn netLookupUnavailable(
...@@ -4821,6 +5642,7 @@ fn netLookupUnavailable(...@@ -4821,6 +5642,7 @@ fn netLookupUnavailable(
48215642
4822fn netLookupFallible(5643fn netLookupFallible(
4823 t: *Threaded,5644 t: *Threaded,
5645 current_thread: *Thread,
4824 host_name: HostName,5646 host_name: HostName,
4825 resolved: *Io.Queue(HostName.LookupResult),5647 resolved: *Io.Queue(HostName.LookupResult),
4826 options: HostName.LookupOptions,5648 options: HostName.LookupOptions,
...@@ -4866,7 +5688,7 @@ fn netLookupFallible(...@@ -4866,7 +5688,7 @@ fn netLookupFallible(
4866 var res: *ws2_32.ADDRINFOEXW = undefined;5688 var res: *ws2_32.ADDRINFOEXW = undefined;
4867 const timeout: ?*ws2_32.timeval = null;5689 const timeout: ?*ws2_32.timeval = null;
4868 while (true) {5690 while (true) {
4869 try t.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel5691 try current_thread.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
4870 // TODO make this append to the queue eagerly rather than blocking until5692 // TODO make this append to the queue eagerly rather than blocking until
4871 // the whole thing finishes5693 // the whole thing finishes
4872 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, cancel_handle));5694 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(...@@ -5013,23 +5835,37 @@ fn netLookupFallible(
5013 .next = null,5835 .next = null,
5014 };5836 };
5015 var res: ?*posix.addrinfo = null;5837 var res: ?*posix.addrinfo = null;
5838 try current_thread.beginSyscall();
5016 while (true) {5839 while (true) {
5017 try t.checkCancel();
5018 switch (posix.system.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {5840 switch (posix.system.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
5019 @as(posix.system.EAI, @enumFromInt(0)) => break,5841 @as(posix.system.EAI, @enumFromInt(0)) => {
5020 .ADDRFAMILY => return error.AddressFamilyUnsupported,5842 current_thread.endSyscall();
5021 .AGAIN => return error.NameServerFailure,5843 break;
5022 .FAIL => return error.NameServerFailure,5844 },
5023 .FAMILY => return error.AddressFamilyUnsupported,
5024 .MEMORY => return error.SystemResources,
5025 .NODATA => return error.UnknownHostName,
5026 .NONAME => return error.UnknownHostName,
5027 .SYSTEM => switch (posix.errno(-1)) {5845 .SYSTEM => switch (posix.errno(-1)) {
5028 .INTR => continue,5846 .INTR => {
5029 .CANCELED => return error.Canceled,5847 try current_thread.checkCancel();
5030 else => |e| return posix.unexpectedErrno(e),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 }
5031 },5868 },
5032 else => return error.Unexpected,
5033 }5869 }
5034 }5870 }
5035 defer if (res) |some| posix.system.freeaddrinfo(some);5871 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...@@ -5726,12 +6562,12 @@ fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) Hos
5726/// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention)6562/// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention)
5727const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11;6563const 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 {
5730 @branchHint(.cold);6566 @branchHint(.cold);
57316567
5732 if (builtin.cpu.arch.isWasm()) {6568 if (builtin.cpu.arch.isWasm()) {
5733 comptime assert(builtin.cpu.has(.wasm, .atomics));6569 comptime assert(builtin.cpu.has(.wasm, .atomics));
5734 try t.checkCancel();6570 try current_thread.checkCancel();
5735 const timeout: i64 = -1;6571 const timeout: i64 = -1;
5736 const signed_expect: i32 = @bitCast(expect);6572 const signed_expect: i32 = @bitCast(expect);
5737 const result = asm volatile (6573 const result = asm volatile (
...@@ -5754,17 +6590,18 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5754,17 +6590,18 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5754 } else switch (native_os) {6590 } else switch (native_os) {
5755 .linux => {6591 .linux => {
5756 const linux = std.os.linux;6592 const linux = std.os.linux;
5757 try t.checkCancel();6593 try current_thread.beginSyscall();
5758 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);6594 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)) {
5760 .SUCCESS => {}, // notified by `wake()`6597 .SUCCESS => {}, // notified by `wake()`
5761 .INTR => {}, // gives caller a chance to check cancellation6598 .INTR => {}, // caller's responsibility to retry
5762 .AGAIN => {}, // ptr.* != expect6599 .AGAIN => {}, // ptr.* != expect
5763 .INVAL => {}, // possibly timeout overflow6600 .INVAL => {}, // possibly timeout overflow
5764 .TIMEDOUT => unreachable,6601 .TIMEDOUT => recoverableOsBugDetected(),
5765 .FAULT => unreachable, // ptr was invalid6602 .FAULT => recoverableOsBugDetected(), // ptr was invalid
5766 else => unreachable,6603 else => recoverableOsBugDetected(),
5767 };6604 }
5768 },6605 },
5769 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => {6606 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => {
5770 const c = std.c;6607 const c = std.c;
...@@ -5772,11 +6609,12 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5772,11 +6609,12 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5772 .op = .COMPARE_AND_WAIT,6609 .op = .COMPARE_AND_WAIT,
5773 .NO_ERRNO = true,6610 .NO_ERRNO = true,
5774 };6611 };
5775 try t.checkCancel();6612 try current_thread.beginSyscall();
5776 const status = if (darwin_supports_ulock_wait2)6613 const status = if (darwin_supports_ulock_wait2)
5777 c.__ulock_wait2(flags, ptr, expect, 0, 0)6614 c.__ulock_wait2(flags, ptr, expect, 0, 0)
5778 else6615 else
5779 c.__ulock_wait(flags, ptr, expect, 0);6616 c.__ulock_wait(flags, ptr, expect, 0);
6617 current_thread.endSyscall();
57806618
5781 if (status >= 0) return;6619 if (status >= 0) return;
57826620
...@@ -5791,7 +6629,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5791,7 +6629,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5791 };6629 };
5792 },6630 },
5793 .windows => {6631 .windows => {
5794 try t.checkCancel();6632 try current_thread.checkCancel();
5795 switch (windows.ntdll.RtlWaitOnAddress(ptr, &expect, @sizeOf(@TypeOf(expect)), null)) {6633 switch (windows.ntdll.RtlWaitOnAddress(ptr, &expect, @sizeOf(@TypeOf(expect)), null)) {
5796 .SUCCESS => {},6634 .SUCCESS => {},
5797 .CANCELLED => return error.Canceled,6635 .CANCELLED => return error.Canceled,
...@@ -5800,8 +6638,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5800,8 +6638,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5800 },6638 },
5801 .freebsd => {6639 .freebsd => {
5802 const flags = @intFromEnum(std.c.UMTX_OP.WAIT_UINT_PRIVATE);6640 const flags = @intFromEnum(std.c.UMTX_OP.WAIT_UINT_PRIVATE);
5803 try t.checkCancel();6641 try current_thread.beginSyscall();
5804 const rc = std.c._umtx_op(@intFromPtr(&ptr.raw), flags, @as(c_ulong, expect), 0, 0);6642 const rc = std.c._umtx_op(@intFromPtr(&ptr.raw), flags, @as(c_ulong, expect), 0, 0);
6643 current_thread.endSyscall();
5805 if (is_debug) switch (posix.errno(rc)) {6644 if (is_debug) switch (posix.errno(rc)) {
5806 .SUCCESS => {},6645 .SUCCESS => {},
5807 .FAULT => unreachable, // one of the args points to invalid memory6646 .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...@@ -5845,7 +6684,7 @@ pub fn futexWaitUncancelable(ptr: *const std.atomic.Value(u32), expect: u32) voi
5845 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);6684 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
5846 switch (linux.errno(rc)) {6685 switch (linux.errno(rc)) {
5847 .SUCCESS => {}, // notified by `wake()`6686 .SUCCESS => {}, // notified by `wake()`
5848 .INTR => {}, // gives caller a chance to check cancellation6687 .INTR => {}, // caller's responsibility to repeat
5849 .AGAIN => {}, // ptr.* != expect6688 .AGAIN => {}, // ptr.* != expect
5850 .INVAL => {}, // possibly timeout overflow6689 .INVAL => {}, // possibly timeout overflow
5851 .TIMEDOUT => recoverableOsBugDetected(),6690 .TIMEDOUT => recoverableOsBugDetected(),
...@@ -5899,28 +6738,6 @@ pub fn futexWaitUncancelable(ptr: *const std.atomic.Value(u32), expect: u32) voi...@@ -5899,28 +6738,6 @@ pub fn futexWaitUncancelable(ptr: *const std.atomic.Value(u32), expect: u32) voi
5899 }6738 }
5900}6739}
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
5924pub fn futexWake(ptr: *const std.atomic.Value(u32), max_waiters: u32) void {6741pub fn futexWake(ptr: *const std.atomic.Value(u32), max_waiters: u32) void {
5925 @branchHint(.cold);6742 @branchHint(.cold);
59266743
...@@ -6050,8 +6867,9 @@ const ResetEventFutex = enum(u32) {...@@ -6050,8 +6867,9 @@ const ResetEventFutex = enum(u32) {
6050 if (state == .unset) {6867 if (state == .unset) {
6051 state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting;6868 state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting;
6052 }6869 }
6870 const current_thread = Thread.getCurrent(t);
6053 while (state == .waiting) {6871 while (state == .waiting) {
6054 try futexWait(t, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));6872 try futexWait(current_thread, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
6055 state = @atomicLoad(ResetEventFutex, ref, .acquire);6873 state = @atomicLoad(ResetEventFutex, ref, .acquire);
6056 }6874 }
6057 assert(state == .is_set);6875 assert(state == .is_set);
...@@ -6140,6 +6958,7 @@ const ResetEventPosix = struct {...@@ -6140,6 +6958,7 @@ const ResetEventPosix = struct {
6140 .waiting => unreachable, // Invalid state.6958 .waiting => unreachable, // Invalid state.
6141 .is_set => return,6959 .is_set => return,
6142 };6960 };
6961 const current_thread = Thread.getCurrent(t);
6143 assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS);6962 assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS);
6144 defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS);6963 defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS);
6145 sw: switch (rep.state) {6964 sw: switch (rep.state) {
...@@ -6148,8 +6967,9 @@ const ResetEventPosix = struct {...@@ -6148,8 +6967,9 @@ const ResetEventPosix = struct {
6148 continue :sw .waiting;6967 continue :sw .waiting;
6149 },6968 },
6150 .waiting => {6969 .waiting => {
6151 try t.checkCancel();6970 try current_thread.beginSyscall();
6152 assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS);6971 assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS);
6972 current_thread.endSyscall();
6153 continue :sw rep.state;6973 continue :sw rep.state;
6154 },6974 },
6155 .is_set => return,6975 .is_set => return,
...@@ -6222,10 +7042,10 @@ const Wsa = struct {...@@ -6222,10 +7042,10 @@ const Wsa = struct {
6222 } || Io.UnexpectedError;7042 } || Io.UnexpectedError;
6223};7043};
62247044
6225fn initializeWsa(t: *Threaded) error{NetworkDown}!void {7045fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
6226 const t_io = io(t);7046 const t_io = io(t);
6227 const wsa = &t.wsa;7047 const wsa = &t.wsa;
6228 wsa.mutex.lockUncancelable(t_io);7048 try wsa.mutex.lock(t_io);
6229 defer wsa.mutex.unlock(t_io);7049 defer wsa.mutex.unlock(t_io);
6230 switch (wsa.status) {7050 switch (wsa.status) {
6231 .uninitialized => {7051 .uninitialized => {
...@@ -6237,12 +7057,15 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {...@@ -6237,12 +7057,15 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
6237 wsa.status = .initialized;7057 wsa.status = .initialized;
6238 return;7058 return;
6239 },7059 },
6240 else => |err_int| switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {7060 else => |err_int| {
6241 .SYSNOTREADY => wsa.init_error = error.NetworkDown,7061 wsa.status = .failure;
6242 .VERNOTSUPPORTED => wsa.init_error = error.VersionUnsupported,7062 wsa.init_error = switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
6243 .EINPROGRESS => wsa.init_error = error.BlockingOperationInProgress,7063 .SYSNOTREADY => error.NetworkDown,
6244 .EPROCLIM => wsa.init_error = error.ProcessFdQuotaExceeded,7064 .VERNOTSUPPORTED => error.VersionUnsupported,
6245 else => |err| wsa.init_error = windows.unexpectedWSAError(err),7065 .EINPROGRESS => error.BlockingOperationInProgress,
7066 .EPROCLIM => error.ProcessFdQuotaExceeded,
7067 else => |err| windows.unexpectedWSAError(err),
7068 };
6246 },7069 },
6247 }7070 }
6248 },7071 },
lib/std/c.zig+17
...@@ -10881,6 +10881,23 @@ pub extern "c" fn pthread_create(...@@ -10881,6 +10881,23 @@ pub extern "c" fn pthread_create(
10881 start_routine: *const fn (?*anyopaque) callconv(.c) ?*anyopaque,10881 start_routine: *const fn (?*anyopaque) callconv(.c) ?*anyopaque,
10882 noalias arg: ?*anyopaque,10882 noalias arg: ?*anyopaque,
10883) E;10883) 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;
10884pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) E;10901pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) E;
10885pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *anyopaque, stacksize: usize) E;10902pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *anyopaque, stacksize: usize) E;
10886pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) E;10903pub 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 {...@@ -1748,9 +1748,7 @@ pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
1748}1748}
17491749
1750pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {1750pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
1751 if (native_arch == .riscv32) {1751 return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem));
1752 @compileError("No nanosleep syscall on this architecture.");
1753 } else return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem));
1754}1752}
17551753
1756pub fn pause() usize {1754pub fn pause() usize {
...@@ -3773,6 +3771,7 @@ pub const SIG = if (is_mips) enum(u32) {...@@ -3773,6 +3771,7 @@ pub const SIG = if (is_mips) enum(u32) {
3773 PROF = 29,3771 PROF = 29,
3774 XCPU = 30,3772 XCPU = 30,
3775 XFZ = 31,3773 XFZ = 31,
3774 _,
3776} else if (is_sparc) enum(u32) {3775} else if (is_sparc) enum(u32) {
3777 pub const BLOCK = 1;3776 pub const BLOCK = 1;
3778 pub const UNBLOCK = 2;3777 pub const UNBLOCK = 2;
...@@ -3818,6 +3817,7 @@ pub const SIG = if (is_mips) enum(u32) {...@@ -3818,6 +3817,7 @@ pub const SIG = if (is_mips) enum(u32) {
3818 LOST = 29,3817 LOST = 29,
3819 USR1 = 30,3818 USR1 = 30,
3820 USR2 = 31,3819 USR2 = 31,
3820 _,
3821} else enum(u32) {3821} else enum(u32) {
3822 pub const BLOCK = 0;3822 pub const BLOCK = 0;
3823 pub const UNBLOCK = 1;3823 pub const UNBLOCK = 1;
...@@ -3861,6 +3861,7 @@ pub const SIG = if (is_mips) enum(u32) {...@@ -3861,6 +3861,7 @@ pub const SIG = if (is_mips) enum(u32) {
3861 IO = 29,3861 IO = 29,
3862 PWR = 30,3862 PWR = 30,
3863 SYS = 31,3863 SYS = 31,
3864 _,
3864};3865};
38653866
3866pub const kernel_rwf = u32;3867pub 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 {...@@ -1360,6 +1360,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
1360 .PIPE => return error.BrokenPipe,1360 .PIPE => return error.BrokenPipe,
1361 .CONNRESET => return error.ConnectionResetByPeer,1361 .CONNRESET => return error.ConnectionResetByPeer,
1362 .BUSY => return error.DeviceBusy,1362 .BUSY => return error.DeviceBusy,
1363 .CANCELED => return error.Canceled,
1363 else => |err| return unexpectedErrno(err),1364 else => |err| return unexpectedErrno(err),
1364 }1365 }
1365 }1366 }
src/link/Elf/Atom.zig+7-32
...@@ -1499,22 +1499,18 @@ const aarch64 = struct {...@@ -1499,22 +1499,18 @@ const aarch64 = struct {
1499 .ABS64 => {1499 .ABS64 => {
1500 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);1500 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
1501 },1501 },
1502
1503 .ADR_PREL_PG_HI21 => {1502 .ADR_PREL_PG_HI21 => {
1504 try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);1503 try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);
1505 },1504 },
1506
1507 .ADR_GOT_PAGE => {1505 .ADR_GOT_PAGE => {
1508 // TODO: relax if possible1506 // TODO: relax if possible
1509 symbol.flags.needs_got = true;1507 symbol.flags.needs_got = true;
1510 },1508 },
1511
1512 .LD64_GOT_LO12_NC,1509 .LD64_GOT_LO12_NC,
1513 .LD64_GOTPAGE_LO15,1510 .LD64_GOTPAGE_LO15,
1514 => {1511 => {
1515 symbol.flags.needs_got = true;1512 symbol.flags.needs_got = true;
1516 },1513 },
1517
1518 .CALL26,1514 .CALL26,
1519 .JUMP26,1515 .JUMP26,
1520 => {1516 => {
...@@ -1522,25 +1518,21 @@ const aarch64 = struct {...@@ -1522,25 +1518,21 @@ const aarch64 = struct {
1522 symbol.flags.needs_plt = true;1518 symbol.flags.needs_plt = true;
1523 }1519 }
1524 },1520 },
1525
1526 .TLSLE_ADD_TPREL_HI12,1521 .TLSLE_ADD_TPREL_HI12,
1527 .TLSLE_ADD_TPREL_LO12_NC,1522 .TLSLE_ADD_TPREL_LO12_NC,
1528 => {1523 => {
1529 if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);1524 if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);
1530 },1525 },
1531
1532 .TLSIE_ADR_GOTTPREL_PAGE21,1526 .TLSIE_ADR_GOTTPREL_PAGE21,
1533 .TLSIE_LD64_GOTTPREL_LO12_NC,1527 .TLSIE_LD64_GOTTPREL_LO12_NC,
1534 => {1528 => {
1535 symbol.flags.needs_gottp = true;1529 symbol.flags.needs_gottp = true;
1536 },1530 },
1537
1538 .TLSGD_ADR_PAGE21,1531 .TLSGD_ADR_PAGE21,
1539 .TLSGD_ADD_LO12_NC,1532 .TLSGD_ADD_LO12_NC,
1540 => {1533 => {
1541 symbol.flags.needs_tlsgd = true;1534 symbol.flags.needs_tlsgd = true;
1542 },1535 },
1543
1544 .TLSDESC_ADR_PAGE21,1536 .TLSDESC_ADR_PAGE21,
1545 .TLSDESC_LD64_LO12,1537 .TLSDESC_LD64_LO12,
1546 .TLSDESC_ADD_LO12,1538 .TLSDESC_ADD_LO12,
...@@ -1551,18 +1543,17 @@ const aarch64 = struct {...@@ -1551,18 +1543,17 @@ const aarch64 = struct {
1551 symbol.flags.needs_tlsdesc = true;1543 symbol.flags.needs_tlsdesc = true;
1552 }1544 }
1553 },1545 },
1554
1555 .ADD_ABS_LO12_NC,1546 .ADD_ABS_LO12_NC,
1556 .ADR_PREL_LO21,1547 .ADR_PREL_LO21,
1557 .LDST8_ABS_LO12_NC,1548 .CONDBR19,
1549 .LDST128_ABS_LO12_NC,
1558 .LDST16_ABS_LO12_NC,1550 .LDST16_ABS_LO12_NC,
1559 .LDST32_ABS_LO12_NC,1551 .LDST32_ABS_LO12_NC,
1560 .LDST64_ABS_LO12_NC,1552 .LDST64_ABS_LO12_NC,
1561 .LDST128_ABS_LO12_NC,1553 .LDST8_ABS_LO12_NC,
1562 .PREL32,1554 .PREL32,
1563 .PREL64,1555 .PREL64,
1564 => {},1556 => {},
1565
1566 else => try atom.reportUnhandledRelocError(rel, elf_file),1557 else => try atom.reportUnhandledRelocError(rel, elf_file),
1567 }1558 }
1568 }1559 }
...@@ -1599,7 +1590,6 @@ const aarch64 = struct {...@@ -1599,7 +1590,6 @@ const aarch64 = struct {
1599 r_offset,1590 r_offset,
1600 );1591 );
1601 },1592 },
1602
1603 .CALL26,1593 .CALL26,
1604 .JUMP26,1594 .JUMP26,
1605 => {1595 => {
...@@ -1611,27 +1601,26 @@ const aarch64 = struct {...@@ -1611,27 +1601,26 @@ const aarch64 = struct {
1611 };1601 };
1612 util.writeBranchImm(disp, code);1602 util.writeBranchImm(disp, code);
1613 },1603 },
16141604 .CONDBR19 => {
1605 const value = math.cast(i19, S + A - P) orelse return error.Overflow;
1606 util.writeCondBrImm(value, code);
1607 },
1615 .PREL32 => {1608 .PREL32 => {
1616 const value = math.cast(i32, S + A - P) orelse return error.Overflow;1609 const value = math.cast(i32, S + A - P) orelse return error.Overflow;
1617 mem.writeInt(u32, code, @bitCast(value), .little);1610 mem.writeInt(u32, code, @bitCast(value), .little);
1618 },1611 },
1619
1620 .PREL64 => {1612 .PREL64 => {
1621 const value = S + A - P;1613 const value = S + A - P;
1622 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);1614 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
1623 },1615 },
1624
1625 .ADR_PREL_LO21 => {1616 .ADR_PREL_LO21 => {
1626 const value = math.cast(i21, S + A - P) orelse return error.Overflow;1617 const value = math.cast(i21, S + A - P) orelse return error.Overflow;
1627 util.writeAdrInst(value, code);1618 util.writeAdrInst(value, code);
1628 },1619 },
1629
1630 .ADR_PREL_PG_HI21 => {1620 .ADR_PREL_PG_HI21 => {
1631 // TODO: check for relaxation of ADRP+ADD1621 // TODO: check for relaxation of ADRP+ADD
1632 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);1622 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
1633 },1623 },
1634
1635 .ADR_GOT_PAGE => if (target.flags.has_got) {1624 .ADR_GOT_PAGE => if (target.flags.has_got) {
1636 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);1625 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
1637 } else {1626 } else {
...@@ -1644,18 +1633,15 @@ const aarch64 = struct {...@@ -1644,18 +1633,15 @@ const aarch64 = struct {
1644 r_offset,1633 r_offset,
1645 });1634 });
1646 },1635 },
1647
1648 .LD64_GOT_LO12_NC => {1636 .LD64_GOT_LO12_NC => {
1649 assert(target.flags.has_got);1637 assert(target.flags.has_got);
1650 const taddr = @as(u64, @intCast(G + GOT + A));1638 const taddr = @as(u64, @intCast(G + GOT + A));
1651 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);1639 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
1652 },1640 },
1653
1654 .ADD_ABS_LO12_NC => {1641 .ADD_ABS_LO12_NC => {
1655 const taddr = @as(u64, @intCast(S + A));1642 const taddr = @as(u64, @intCast(S + A));
1656 util.writeAddImmInst(@truncate(taddr), code);1643 util.writeAddImmInst(@truncate(taddr), code);
1657 },1644 },
1658
1659 .LDST8_ABS_LO12_NC,1645 .LDST8_ABS_LO12_NC,
1660 .LDST16_ABS_LO12_NC,1646 .LDST16_ABS_LO12_NC,
1661 .LDST32_ABS_LO12_NC,1647 .LDST32_ABS_LO12_NC,
...@@ -1674,44 +1660,37 @@ const aarch64 = struct {...@@ -1674,44 +1660,37 @@ const aarch64 = struct {
1674 };1660 };
1675 util.writeLoadStoreRegInst(off, code);1661 util.writeLoadStoreRegInst(off, code);
1676 },1662 },
1677
1678 .TLSLE_ADD_TPREL_HI12 => {1663 .TLSLE_ADD_TPREL_HI12 => {
1679 const value = math.cast(i12, (S + A - TP) >> 12) orelse1664 const value = math.cast(i12, (S + A - TP) >> 12) orelse
1680 return error.Overflow;1665 return error.Overflow;
1681 util.writeAddImmInst(@bitCast(value), code);1666 util.writeAddImmInst(@bitCast(value), code);
1682 },1667 },
1683
1684 .TLSLE_ADD_TPREL_LO12_NC => {1668 .TLSLE_ADD_TPREL_LO12_NC => {
1685 const value: i12 = @truncate(S + A - TP);1669 const value: i12 = @truncate(S + A - TP);
1686 util.writeAddImmInst(@bitCast(value), code);1670 util.writeAddImmInst(@bitCast(value), code);
1687 },1671 },
1688
1689 .TLSIE_ADR_GOTTPREL_PAGE21 => {1672 .TLSIE_ADR_GOTTPREL_PAGE21 => {
1690 const S_ = target.gotTpAddress(elf_file);1673 const S_ = target.gotTpAddress(elf_file);
1691 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1674 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1692 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);1675 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
1693 },1676 },
1694
1695 .TLSIE_LD64_GOTTPREL_LO12_NC => {1677 .TLSIE_LD64_GOTTPREL_LO12_NC => {
1696 const S_ = target.gotTpAddress(elf_file);1678 const S_ = target.gotTpAddress(elf_file);
1697 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1679 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1698 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);1680 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1699 util.writeLoadStoreRegInst(off, code);1681 util.writeLoadStoreRegInst(off, code);
1700 },1682 },
1701
1702 .TLSGD_ADR_PAGE21 => {1683 .TLSGD_ADR_PAGE21 => {
1703 const S_ = target.tlsGdAddress(elf_file);1684 const S_ = target.tlsGdAddress(elf_file);
1704 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1685 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1705 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);1686 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
1706 },1687 },
1707
1708 .TLSGD_ADD_LO12_NC => {1688 .TLSGD_ADD_LO12_NC => {
1709 const S_ = target.tlsGdAddress(elf_file);1689 const S_ = target.tlsGdAddress(elf_file);
1710 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1690 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1711 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));1691 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1712 util.writeAddImmInst(off, code);1692 util.writeAddImmInst(off, code);
1713 },1693 },
1714
1715 .TLSDESC_ADR_PAGE21 => {1694 .TLSDESC_ADR_PAGE21 => {
1716 if (target.flags.has_tlsdesc) {1695 if (target.flags.has_tlsdesc) {
1717 const S_ = target.tlsDescAddress(elf_file);1696 const S_ = target.tlsDescAddress(elf_file);
...@@ -1722,7 +1701,6 @@ const aarch64 = struct {...@@ -1722,7 +1701,6 @@ const aarch64 = struct {
1722 util.encoding.Instruction.nop().write(code);1701 util.encoding.Instruction.nop().write(code);
1723 }1702 }
1724 },1703 },
1725
1726 .TLSDESC_LD64_LO12 => {1704 .TLSDESC_LD64_LO12 => {
1727 if (target.flags.has_tlsdesc) {1705 if (target.flags.has_tlsdesc) {
1728 const S_ = target.tlsDescAddress(elf_file);1706 const S_ = target.tlsDescAddress(elf_file);
...@@ -1734,7 +1712,6 @@ const aarch64 = struct {...@@ -1734,7 +1712,6 @@ const aarch64 = struct {
1734 util.encoding.Instruction.nop().write(code);1712 util.encoding.Instruction.nop().write(code);
1735 }1713 }
1736 },1714 },
1737
1738 .TLSDESC_ADD_LO12 => {1715 .TLSDESC_ADD_LO12 => {
1739 if (target.flags.has_tlsdesc) {1716 if (target.flags.has_tlsdesc) {
1740 const S_ = target.tlsDescAddress(elf_file);1717 const S_ = target.tlsDescAddress(elf_file);
...@@ -1747,13 +1724,11 @@ const aarch64 = struct {...@@ -1747,13 +1724,11 @@ const aarch64 = struct {
1747 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);1724 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
1748 }1725 }
1749 },1726 },
1750
1751 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {1727 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
1752 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});1728 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
1753 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));1729 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
1754 util.encoding.Instruction.movk(.x0, value, .{}).write(code);1730 util.encoding.Instruction.movk(.x0, value, .{}).write(code);
1755 },1731 },
1756
1757 else => try atom.reportUnhandledRelocError(rel, elf_file),1732 else => try atom.reportUnhandledRelocError(rel, elf_file),
1758 }1733 }
1759 }1734 }
src/link/aarch64.zig+6
...@@ -29,6 +29,12 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) void {...@@ -29,6 +29,12 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
29 inst.write(code);29 inst.write(code);
30}30}
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
32const assert = std.debug.assert;38const assert = std.debug.assert;
33const builtin = @import("builtin");39const builtin = @import("builtin");
34const math = std.math;40const math = std.math;