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

std.Io.Threaded: fix the cancellation race

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

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

lib/std/Io.zig-5
...@@ -620,11 +620,6 @@ pub const VTable = struct {...@@ -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+1910-1109
...@@ -50,6 +50,8 @@ cpu_count_error: ?std.Thread.CpuCountError,...@@ -50,6 +50,8 @@ 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,
5355
54wsa: if (is_windows) Wsa else struct {} = .{},56wsa: if (is_windows) Wsa else struct {} = .{},
5557
...@@ -57,7 +59,79 @@ have_signal_handler: bool,...@@ -57,7 +59,79 @@ have_signal_handler: bool,
57old_sig_io: if (have_sig_io) posix.Sigaction else void,59old_sig_io: if (have_sig_io) posix.Sigaction else void,
58old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void,60old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void,
5961
60threadlocal var current_closure: ?*Closure = null;62pub const Pid = if (native_os == .linux) enum(posix.pid_t) {
63 unknown = 0,
64 _,
65} else enum(u0) { unknown = 0 };
66
67const Thread = struct {
68 /// The value that needs to be passed to pthread_kill or tgkill in order to
69 /// send a signal.
70 signal_id: SignalId,
71 current_closure: ?*Closure = null,
72
73 const SignalId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;
74
75 threadlocal var current: ?*Thread = null;
76
77 fn getCurrent(t: *Threaded) *Thread {
78 return current orelse return &t.main_thread;
79 }
80
81 fn checkCancel(thread: *Thread) error{Canceled}!void {
82 const closure = thread.current_closure orelse return;
83 switch (@cmpxchgStrong(
84 CancelStatus,
85 &closure.cancel_status,
86 .requested,
87 .acknowledged,
88 .acq_rel,
89 .acquire,
90 ) orelse return error.Canceled) {
91 .none => return,
92 .requested => unreachable,
93 .acknowledged => unreachable,
94 _ => return,
95 }
96 }
97
98 fn beginSyscall(thread: *Thread) error{Canceled}!void {
99 const closure = thread.current_closure orelse return;
100
101 switch (@cmpxchgStrong(
102 CancelStatus,
103 &closure.cancel_status,
104 .none,
105 .fromSignalId(thread.signal_id),
106 .acq_rel,
107 .acquire,
108 ) orelse return) {
109 .none => unreachable,
110 .requested => {
111 @atomicStore(CancelStatus, &closure.cancel_status, .acknowledged, .release);
112 return error.Canceled;
113 },
114 .acknowledged => unreachable,
115 _ => unreachable,
116 }
117 }
118
119 fn endSyscall(thread: *Thread) void {
120 const closure = thread.current_closure orelse return;
121 _ = @cmpxchgStrong(
122 CancelStatus,
123 &closure.cancel_status,
124 .fromSignalId(thread.signal_id),
125 .none,
126 .acq_rel,
127 .acquire,
128 );
129 }
130
131 fn currentSignalId() SignalId {
132 return if (std.Thread.use_pthreads) std.c.pthread_self() else std.Thread.getCurrentId();
133 }
134};
61135
62const max_iovecs_len = 8;136const max_iovecs_len = 8;
63const splat_buffer_size = 64;137const splat_buffer_size = 64;
...@@ -66,48 +140,93 @@ comptime {...@@ -66,48 +140,93 @@ comptime {
66 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);140 if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
67}141}
68142
69const CancelId = enum(usize) {143const CancelStatus = enum(usize) {
144 /// Cancellation has neither been requested, nor checked. The async
145 /// operation will check status before entering a blocking syscall.
146 /// This is also the status used for uninteruptible tasks.
70 none = 0,147 none = 0,
71 canceling = std.math.maxInt(usize),148 /// Cancellation has been requested and the status will be checked before
149 /// entering a blocking syscall.
150 requested = std.math.maxInt(usize) - 1,
151 /// Cancellation has been acknowledged and is in progress. Signals should
152 /// not be sent.
153 acknowledged = std.math.maxInt(usize),
154 /// Stores a `Thread.SignalId` and indicates that sending a signal to this thread
155 /// is needed in order to cancel. This state is set before going into
156 /// a blocking operation that needs to get unblocked via signal.
72 _,157 _,
73158
74 const ThreadId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;159 const Unpacked = union(enum) {
160 none,
161 requested,
162 acknowledged,
163 signal_id: Thread.SignalId,
164 };
75165
76 fn currentThread() CancelId {166 fn unpack(cs: CancelStatus) Unpacked {
77 if (std.Thread.use_pthreads) {167 return switch (cs) {
78 return @enumFromInt(@intFromPtr(std.c.pthread_self()));168 .none => .none,
79 } else {169 .requested => .requested,
80 return @enumFromInt(std.Thread.getCurrentId());170 .acknowledged => .acknowledged,
81 }171 _ => |signal_id| .{
172 .signal_id = if (std.Thread.use_pthreads)
173 @ptrFromInt(@intFromEnum(signal_id))
174 else
175 @truncate(@intFromEnum(signal_id)),
176 },
177 };
82 }178 }
83179
84 fn toThreadId(cancel_id: CancelId) ThreadId {180 fn fromSignalId(signal_id: Thread.SignalId) CancelStatus {
85 if (std.Thread.use_pthreads) {181 return if (std.Thread.use_pthreads)
86 return @ptrFromInt(@intFromEnum(cancel_id));182 @enumFromInt(@intFromPtr(signal_id))
87 } else {183 else
88 return @intCast(@intFromEnum(cancel_id));184 @enumFromInt(signal_id);
89 }
90 }185 }
91};186};
92187
93const Closure = struct {188const Closure = struct {
94 start: Start,189 start: Start,
95 node: std.SinglyLinkedList.Node = .{},190 node: std.SinglyLinkedList.Node = .{},
96 cancel_tid: CancelId,191 cancel_status: CancelStatus,
97192
98 const Start = *const fn (*Closure) void;193 const Start = *const fn (*Closure, *Threaded) void;
99194
100 fn requestCancel(closure: *Closure) void {195 fn requestCancel(closure: *Closure, t: *Threaded) void {
101 switch (@atomicRmw(CancelId, &closure.cancel_tid, .Xchg, .canceling, .acq_rel)) {196 var signal_id = switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
102 .none, .canceling => {},197 .none, .acknowledged, .requested => return,
103 else => |tid| {198 .signal_id => |signal_id| signal_id,
104 if (std.Thread.use_pthreads) {199 };
105 const rc = std.c.pthread_kill(tid.toThreadId(), .IO);200 // The task will enter a blocking syscall before checking for cancellation again.
106 if (is_debug) assert(rc == 0);201 // We can send a signal to interrupt the syscall, but if it arrives before
107 } else if (native_os == .linux) {202 // the syscall instruction, it will be missed. Therefore, this code tries
108 _ = std.os.linux.tgkill(std.os.linux.getpid(), @bitCast(tid.toThreadId()), .IO);203 // again until the cancellation request is acknowledged.
109 }204 const max_attempts = 3;
110 },205 for (0..max_attempts) |_| {
206 if (std.Thread.use_pthreads) {
207 const rc = std.c.pthread_kill(signal_id, .IO);
208 if (is_debug) assert(rc == 0);
209 } else if (native_os == .linux) {
210 const pid: posix.pid_t = p: {
211 const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
212 if (cached_pid != .unknown) break :p @intFromEnum(cached_pid);
213 const pid = std.os.linux.getpid();
214 @atomicStore(Pid, &t.pid, @enumFromInt(pid), .monotonic);
215 break :p pid;
216 };
217 _ = std.os.linux.tgkill(pid, @bitCast(signal_id), .IO);
218 } else {
219 return;
220 }
221
222 // TODO make this a nanosleep with 1 << attempt duration
223 std.Thread.yield() catch {};
224
225 switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
226 .requested => continue,
227 .none, .acknowledged => return,
228 .signal_id => |new_signal_id| signal_id = new_signal_id,
229 }
111 }230 }
112 }231 }
113};232};
...@@ -136,6 +255,9 @@ pub fn init(...@@ -136,6 +255,9 @@ pub fn init(
136 .old_sig_io = undefined,255 .old_sig_io = undefined,
137 .old_sig_pipe = undefined,256 .old_sig_pipe = undefined,
138 .have_signal_handler = false,257 .have_signal_handler = false,
258 .main_thread = .{
259 .signal_id = Thread.currentSignalId(),
260 },
139 };261 };
140262
141 if (posix.Sigaction != void) {263 if (posix.Sigaction != void) {
...@@ -169,6 +291,7 @@ pub const init_single_threaded: Threaded = .{...@@ -169,6 +291,7 @@ pub const init_single_threaded: Threaded = .{
169 .old_sig_io = undefined,291 .old_sig_io = undefined,
170 .old_sig_pipe = undefined,292 .old_sig_pipe = undefined,
171 .have_signal_handler = false,293 .have_signal_handler = false,
294 .main_thread = .{ .signal_id = undefined },
172};295};
173296
174pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {297pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {
...@@ -201,6 +324,11 @@ fn join(t: *Threaded) void {...@@ -201,6 +324,11 @@ fn join(t: *Threaded) void {
201}324}
202325
203fn worker(t: *Threaded) void {326fn worker(t: *Threaded) void {
327 var thread: Thread = .{
328 .signal_id = Thread.currentSignalId(),
329 };
330 Thread.current = &thread;
331
204 defer t.wait_group.finish();332 defer t.wait_group.finish();
205333
206 t.mutex.lock();334 t.mutex.lock();
...@@ -210,7 +338,7 @@ fn worker(t: *Threaded) void {...@@ -210,7 +338,7 @@ fn worker(t: *Threaded) void {
210 while (t.run_queue.popFirst()) |closure_node| {338 while (t.run_queue.popFirst()) |closure_node| {
211 t.mutex.unlock();339 t.mutex.unlock();
212 const closure: *Closure = @fieldParentPtr("node", closure_node);340 const closure: *Closure = @fieldParentPtr("node", closure_node);
213 closure.start(closure);341 closure.start(closure, t);
214 t.mutex.lock();342 t.mutex.lock();
215 t.busy_count -= 1;343 t.busy_count -= 1;
216 }344 }
...@@ -227,7 +355,6 @@ pub fn io(t: *Threaded) Io {...@@ -227,7 +355,6 @@ pub fn io(t: *Threaded) Io {
227 .concurrent = concurrent,355 .concurrent = concurrent,
228 .await = await,356 .await = await,
229 .cancel = cancel,357 .cancel = cancel,
230 .cancelRequested = cancelRequested,
231 .select = select,358 .select = select,
232359
233 .groupAsync = groupAsync,360 .groupAsync = groupAsync,
...@@ -324,7 +451,6 @@ pub fn ioBasic(t: *Threaded) Io {...@@ -324,7 +451,6 @@ pub fn ioBasic(t: *Threaded) Io {
324 .concurrent = concurrent,451 .concurrent = concurrent,
325 .await = await,452 .await = await,
326 .cancel = cancel,453 .cancel = cancel,
327 .cancelRequested = cancelRequested,
328 .select = select,454 .select = select,
329455
330 .groupAsync = groupAsync,456 .groupAsync = groupAsync,
...@@ -418,24 +544,12 @@ const AsyncClosure = struct {...@@ -418,24 +544,12 @@ const AsyncClosure = struct {
418544
419 const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent));545 const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent));
420546
421 fn start(closure: *Closure) void {547 fn start(closure: *Closure, t: *Threaded) void {
422 const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure));548 const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure));
423 const tid: CancelId = .currentThread();549 const current_thread = Thread.getCurrent(t);
424 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {550 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());551 ac.func(ac.contextPointer(), ac.resultPointer());
432 current_closure = null;552 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 }
439553
440 if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| {554 if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| {
441 assert(select_reset != done_reset_event);555 assert(select_reset != done_reset_event);
...@@ -476,7 +590,7 @@ const AsyncClosure = struct {...@@ -476,7 +590,7 @@ const AsyncClosure = struct {
476 const actual_result_offset = actual_result_addr - @intFromPtr(ac);590 const actual_result_offset = actual_result_addr - @intFromPtr(ac);
477 ac.* = .{591 ac.* = .{
478 .closure = .{592 .closure = .{
479 .cancel_tid = .none,593 .cancel_status = .none,
480 .start = start,594 .start = start,
481 },595 },
482 .func = func,596 .func = func,
...@@ -493,7 +607,7 @@ const AsyncClosure = struct {...@@ -493,7 +607,7 @@ const AsyncClosure = struct {
493 fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void {607 fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void {
494 ac.reset_event.wait(t) catch |err| switch (err) {608 ac.reset_event.wait(t) catch |err| switch (err) {
495 error.Canceled => {609 error.Canceled => {
496 ac.closure.requestCancel();610 ac.closure.requestCancel(t);
497 ac.reset_event.waitUncancelable();611 ac.reset_event.waitUncancelable();
498 },612 },
499 };613 };
...@@ -604,7 +718,6 @@ fn concurrent(...@@ -604,7 +718,6 @@ fn concurrent(
604718
605const GroupClosure = struct {719const GroupClosure = struct {
606 closure: Closure,720 closure: Closure,
607 t: *Threaded,
608 group: *Io.Group,721 group: *Io.Group,
609 /// Points to sibling `GroupClosure`. Used for walking the group to cancel all.722 /// Points to sibling `GroupClosure`. Used for walking the group to cancel all.
610 node: std.SinglyLinkedList.Node,723 node: std.SinglyLinkedList.Node,
...@@ -612,26 +725,15 @@ const GroupClosure = struct {...@@ -612,26 +725,15 @@ const GroupClosure = struct {
612 context_alignment: Alignment,725 context_alignment: Alignment,
613 alloc_len: usize,726 alloc_len: usize,
614727
615 fn start(closure: *Closure) void {728 fn start(closure: *Closure, t: *Threaded) void {
616 const gc: *GroupClosure = @alignCast(@fieldParentPtr("closure", closure));729 const gc: *GroupClosure = @alignCast(@fieldParentPtr("closure", closure));
617 const tid: CancelId = .currentThread();730 const current_thread = Thread.getCurrent(t);
618 const group = gc.group;731 const group = gc.group;
619 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);732 const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);
620 const reset_event: *ResetEvent = @ptrCast(&group.context);733 const reset_event: *ResetEvent = @ptrCast(&group.context);
621 if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {734 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());735 gc.func(group, gc.contextPointer());
628 current_closure = null;736 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 }
635737
636 const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel);738 const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel);
637 assert((prev_state / sync_one_pending) > 0);739 assert((prev_state / sync_one_pending) > 0);
...@@ -647,7 +749,6 @@ const GroupClosure = struct {...@@ -647,7 +749,6 @@ const GroupClosure = struct {
647 /// Does not initialize the `node` field.749 /// Does not initialize the `node` field.
648 fn init(750 fn init(
649 gpa: Allocator,751 gpa: Allocator,
650 t: *Threaded,
651 group: *Io.Group,752 group: *Io.Group,
652 context: []const u8,753 context: []const u8,
653 context_alignment: Alignment,754 context_alignment: Alignment,
...@@ -662,10 +763,9 @@ const GroupClosure = struct {...@@ -662,10 +763,9 @@ const GroupClosure = struct {
662763
663 gc.* = .{764 gc.* = .{
664 .closure = .{765 .closure = .{
665 .cancel_tid = .none,766 .cancel_status = .none,
666 .start = start,767 .start = start,
667 },768 },
668 .t = t,
669 .group = group,769 .group = group,
670 .node = undefined,770 .node = undefined,
671 .func = func,771 .func = func,
...@@ -696,7 +796,7 @@ fn groupAsync(...@@ -696,7 +796,7 @@ fn groupAsync(
696 if (builtin.single_threaded) return start(group, context.ptr);796 if (builtin.single_threaded) return start(group, context.ptr);
697797
698 const gpa = t.allocator;798 const gpa = t.allocator;
699 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch799 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
700 return start(group, context.ptr);800 return start(group, context.ptr);
701801
702 t.mutex.lock();802 t.mutex.lock();
...@@ -752,7 +852,7 @@ fn groupConcurrent(...@@ -752,7 +852,7 @@ fn groupConcurrent(
752 const t: *Threaded = @ptrCast(@alignCast(userdata));852 const t: *Threaded = @ptrCast(@alignCast(userdata));
753853
754 const gpa = t.allocator;854 const gpa = t.allocator;
755 const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch855 const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
756 return error.ConcurrencyUnavailable;856 return error.ConcurrencyUnavailable;
757857
758 t.mutex.lock();858 t.mutex.lock();
...@@ -806,7 +906,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {...@@ -806,7 +906,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
806 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));906 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
807 while (true) {907 while (true) {
808 const gc: *GroupClosure = @fieldParentPtr("node", node);908 const gc: *GroupClosure = @fieldParentPtr("node", node);
809 gc.closure.requestCancel();909 gc.closure.requestCancel(t);
810 node = node.next orelse break;910 node = node.next orelse break;
811 }911 }
812 reset_event.waitUncancelable();912 reset_event.waitUncancelable();
...@@ -832,7 +932,7 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void...@@ -832,7 +932,7 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void
832 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));932 var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
833 while (true) {933 while (true) {
834 const gc: *GroupClosure = @fieldParentPtr("node", node);934 const gc: *GroupClosure = @fieldParentPtr("node", node);
835 gc.closure.requestCancel();935 gc.closure.requestCancel(t);
836 node = node.next orelse break;936 node = node.next orelse break;
837 }937 }
838 }938 }
...@@ -875,30 +975,20 @@ fn cancel(...@@ -875,30 +975,20 @@ fn cancel(
875 _ = result_alignment;975 _ = result_alignment;
876 const t: *Threaded = @ptrCast(@alignCast(userdata));976 const t: *Threaded = @ptrCast(@alignCast(userdata));
877 const ac: *AsyncClosure = @ptrCast(@alignCast(any_future));977 const ac: *AsyncClosure = @ptrCast(@alignCast(any_future));
878 ac.closure.requestCancel();978 ac.closure.requestCancel(t);
879 ac.waitAndDeinit(t, result);979 ac.waitAndDeinit(t, result);
880}980}
881981
882fn cancelRequested(userdata: ?*anyopaque) bool {
883 const t: *Threaded = @ptrCast(@alignCast(userdata));
884 _ = t;
885 const closure = current_closure orelse return false;
886 return @atomicLoad(CancelId, &closure.cancel_tid, .acquire) == .canceling;
887}
888
889fn checkCancel(t: *Threaded) error{Canceled}!void {
890 if (cancelRequested(t)) return error.Canceled;
891}
892
893fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {982fn 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.983 if (builtin.single_threaded) unreachable; // Interface should have prevented this.
895 if (native_os == .netbsd) @panic("TODO");984 if (native_os == .netbsd) @panic("TODO");
896 const t: *Threaded = @ptrCast(@alignCast(userdata));985 const t: *Threaded = @ptrCast(@alignCast(userdata));
986 const current_thread = Thread.getCurrent(t);
897 if (prev_state == .contended) {987 if (prev_state == .contended) {
898 try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));988 try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
899 }989 }
900 while (@atomicRmw(Io.Mutex.State, &mutex.state, .Xchg, .contended, .acquire) != .unlocked) {990 while (@atomicRmw(Io.Mutex.State, &mutex.state, .Xchg, .contended, .acquire) != .unlocked) {
901 try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));991 try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
902 }992 }
903}993}
904994
...@@ -960,6 +1050,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I...@@ -960,6 +1050,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
960 if (builtin.single_threaded) unreachable; // Deadlock.1050 if (builtin.single_threaded) unreachable; // Deadlock.
961 if (native_os == .netbsd) @panic("TODO");1051 if (native_os == .netbsd) @panic("TODO");
962 const t: *Threaded = @ptrCast(@alignCast(userdata));1052 const t: *Threaded = @ptrCast(@alignCast(userdata));
1053 const current_thread = Thread.getCurrent(t);
963 const t_io = ioBasic(t);1054 const t_io = ioBasic(t);
964 comptime assert(@TypeOf(cond.state) == u64);1055 comptime assert(@TypeOf(cond.state) == u64);
965 const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state);1056 const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state);
...@@ -988,7 +1079,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I...@@ -988,7 +1079,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
988 defer mutex.lockUncancelable(t_io);1079 defer mutex.lockUncancelable(t_io);
9891080
990 while (true) {1081 while (true) {
991 try futexWait(t, cond_epoch, epoch);1082 try futexWait(current_thread, cond_epoch, epoch);
9921083
993 epoch = cond_epoch.load(.acquire);1084 epoch = cond_epoch.load(.acquire);
994 state = cond_state.load(.monotonic);1085 state = cond_state.load(.monotonic);
...@@ -1074,35 +1165,46 @@ const dirMake = switch (native_os) {...@@ -1074,35 +1165,46 @@ const dirMake = switch (native_os) {
10741165
1075fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {1166fn 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));1167 const t: *Threaded = @ptrCast(@alignCast(userdata));
1168 const current_thread = Thread.getCurrent(t);
10771169
1078 var path_buffer: [posix.PATH_MAX]u8 = undefined;1170 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1079 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);1171 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
10801172
1173 try current_thread.beginSyscall();
1081 while (true) {1174 while (true) {
1082 try t.checkCancel();
1083 switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) {1175 switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) {
1084 .SUCCESS => return,1176 .SUCCESS => {
1085 .INTR => continue,1177 current_thread.endSyscall();
1086 .CANCELED => return error.Canceled,1178 return;
10871179 },
1088 .ACCES => return error.AccessDenied,1180 .INTR => {
1089 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1181 try current_thread.checkCancel();
1090 .PERM => return error.PermissionDenied,1182 continue;
1091 .DQUOT => return error.DiskQuota,1183 },
1092 .EXIST => return error.PathAlreadyExists,1184 else => |e| {
1093 .FAULT => |err| return errnoBug(err),1185 current_thread.endSyscall();
1094 .LOOP => return error.SymLinkLoop,1186 switch (e) {
1095 .MLINK => return error.LinkQuotaExceeded,1187 .CANCELED => return error.Canceled,
1096 .NAMETOOLONG => return error.NameTooLong,1188 .ACCES => return error.AccessDenied,
1097 .NOENT => return error.FileNotFound,1189 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1098 .NOMEM => return error.SystemResources,1190 .PERM => return error.PermissionDenied,
1099 .NOSPC => return error.NoSpaceLeft,1191 .DQUOT => return error.DiskQuota,
1100 .NOTDIR => return error.NotDir,1192 .EXIST => return error.PathAlreadyExists,
1101 .ROFS => return error.ReadOnlyFileSystem,1193 .FAULT => |err| return errnoBug(err),
1102 // dragonfly: when dir_fd is unlinked from filesystem1194 .LOOP => return error.SymLinkLoop,
1103 .NOTCONN => return error.FileNotFound,1195 .MLINK => return error.LinkQuotaExceeded,
1104 .ILSEQ => return error.BadPathName,1196 .NAMETOOLONG => return error.NameTooLong,
1105 else => |err| return posix.unexpectedErrno(err),1197 .NOENT => return error.FileNotFound,
1198 .NOMEM => return error.SystemResources,
1199 .NOSPC => return error.NoSpaceLeft,
1200 .NOTDIR => return error.NotDir,
1201 .ROFS => return error.ReadOnlyFileSystem,
1202 // dragonfly: when dir_fd is unlinked from filesystem
1203 .NOTCONN => return error.FileNotFound,
1204 .ILSEQ => return error.BadPathName,
1205 else => |err| return posix.unexpectedErrno(err),
1206 }
1207 },
1106 }1208 }
1107 }1209 }
1108}1210}
...@@ -1110,11 +1212,18 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode:...@@ -1110,11 +1212,18 @@ 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 {1212fn 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);1213 if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode);
1112 const t: *Threaded = @ptrCast(@alignCast(userdata));1214 const t: *Threaded = @ptrCast(@alignCast(userdata));
1215 const current_thread = Thread.getCurrent(t);
1216 try current_thread.beginSyscall();
1113 while (true) {1217 while (true) {
1114 try t.checkCancel();
1115 switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) {1218 switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) {
1116 .SUCCESS => return,1219 .SUCCESS => {
1117 .INTR => continue,1220 current_thread.endSyscall();
1221 return;
1222 },
1223 .INTR => {
1224 try current_thread.checkCancel();
1225 continue;
1226 },
1118 .CANCELED => return error.Canceled,1227 .CANCELED => return error.Canceled,
11191228
1120 .ACCES => return error.AccessDenied,1229 .ACCES => return error.AccessDenied,
...@@ -1140,7 +1249,8 @@ fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: I...@@ -1140,7 +1249,8 @@ fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: I
11401249
1141fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {1250fn 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));1251 const t: *Threaded = @ptrCast(@alignCast(userdata));
1143 try t.checkCancel();1252 const current_thread = Thread.getCurrent(t);
1253 try current_thread.checkCancel();
11441254
1145 const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);1255 const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
1146 _ = mode;1256 _ = mode;
...@@ -1213,6 +1323,7 @@ fn dirMakeOpenPathWindows(...@@ -1213,6 +1323,7 @@ fn dirMakeOpenPathWindows(
1213 options: Io.Dir.OpenOptions,1323 options: Io.Dir.OpenOptions,
1214) Io.Dir.MakeOpenPathError!Io.Dir {1324) Io.Dir.MakeOpenPathError!Io.Dir {
1215 const t: *Threaded = @ptrCast(@alignCast(userdata));1325 const t: *Threaded = @ptrCast(@alignCast(userdata));
1326 const current_thread = Thread.getCurrent(t);
1216 const w = windows;1327 const w = windows;
1217 const access_mask = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |1328 const access_mask = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
1218 w.SYNCHRONIZE | w.FILE_TRAVERSE |1329 w.SYNCHRONIZE | w.FILE_TRAVERSE |
...@@ -1226,7 +1337,7 @@ fn dirMakeOpenPathWindows(...@@ -1226,7 +1337,7 @@ fn dirMakeOpenPathWindows(
1226 };1337 };
12271338
1228 while (true) {1339 while (true) {
1229 try t.checkCancel();1340 try current_thread.checkCancel();
12301341
1231 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, component.path);1342 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, component.path);
1232 const sub_path_w = sub_path_w_array.span();1343 const sub_path_w = sub_path_w_array.span();
...@@ -1328,8 +1439,7 @@ fn dirMakeOpenPathWasi(...@@ -1328,8 +1439,7 @@ fn dirMakeOpenPathWasi(
13281439
1329fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {1440fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
1330 const t: *Threaded = @ptrCast(@alignCast(userdata));1441 const t: *Threaded = @ptrCast(@alignCast(userdata));
1331 try t.checkCancel();1442 _ = t;
1332
1333 _ = dir;1443 _ = dir;
1334 @panic("TODO implement dirStat");1444 @panic("TODO implement dirStat");
1335}1445}
...@@ -1348,6 +1458,7 @@ fn dirStatPathLinux(...@@ -1348,6 +1458,7 @@ fn dirStatPathLinux(
1348 options: Io.Dir.StatPathOptions,1458 options: Io.Dir.StatPathOptions,
1349) Io.Dir.StatPathError!Io.File.Stat {1459) Io.Dir.StatPathError!Io.File.Stat {
1350 const t: *Threaded = @ptrCast(@alignCast(userdata));1460 const t: *Threaded = @ptrCast(@alignCast(userdata));
1461 const current_thread = Thread.getCurrent(t);
1351 const linux = std.os.linux;1462 const linux = std.os.linux;
13521463
1353 var path_buffer: [posix.PATH_MAX]u8 = undefined;1464 var path_buffer: [posix.PATH_MAX]u8 = undefined;
...@@ -1356,8 +1467,8 @@ fn dirStatPathLinux(...@@ -1356,8 +1467,8 @@ fn dirStatPathLinux(
1356 const flags: u32 = linux.AT.NO_AUTOMOUNT |1467 const flags: u32 = linux.AT.NO_AUTOMOUNT |
1357 @as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);1468 @as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);
13581469
1470 try current_thread.beginSyscall();
1359 while (true) {1471 while (true) {
1360 try t.checkCancel();
1361 var statx = std.mem.zeroes(linux.Statx);1472 var statx = std.mem.zeroes(linux.Statx);
1362 const rc = linux.statx(1473 const rc = linux.statx(
1363 dir.handle,1474 dir.handle,
...@@ -1367,20 +1478,30 @@ fn dirStatPathLinux(...@@ -1367,20 +1478,30 @@ fn dirStatPathLinux(
1367 &statx,1478 &statx,
1368 );1479 );
1369 switch (linux.errno(rc)) {1480 switch (linux.errno(rc)) {
1370 .SUCCESS => return statFromLinux(&statx),1481 .SUCCESS => {
1371 .INTR => continue,1482 current_thread.endSyscall();
1372 .CANCELED => return error.Canceled,1483 return statFromLinux(&statx);
13731484 },
1374 .ACCES => return error.AccessDenied,1485 .INTR => {
1375 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1486 try current_thread.checkCancel();
1376 .FAULT => |err| return errnoBug(err),1487 continue;
1377 .INVAL => |err| return errnoBug(err),1488 },
1378 .LOOP => return error.SymLinkLoop,1489 else => |e| {
1379 .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.1490 current_thread.endSyscall();
1380 .NOENT => return error.FileNotFound,1491 switch (e) {
1381 .NOTDIR => return error.NotDir,1492 .CANCELED => return error.Canceled,
1382 .NOMEM => return error.SystemResources,1493 .ACCES => return error.AccessDenied,
1383 else => |err| return posix.unexpectedErrno(err),1494 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1495 .FAULT => |err| return errnoBug(err),
1496 .INVAL => |err| return errnoBug(err),
1497 .LOOP => return error.SymLinkLoop,
1498 .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.
1499 .NOENT => return error.FileNotFound,
1500 .NOTDIR => return error.NotDir,
1501 .NOMEM => return error.SystemResources,
1502 else => |err| return posix.unexpectedErrno(err),
1503 }
1504 },
1384 }1505 }
1385 }1506 }
1386}1507}
...@@ -1392,32 +1513,43 @@ fn dirStatPathPosix(...@@ -1392,32 +1513,43 @@ fn dirStatPathPosix(
1392 options: Io.Dir.StatPathOptions,1513 options: Io.Dir.StatPathOptions,
1393) Io.Dir.StatPathError!Io.File.Stat {1514) Io.Dir.StatPathError!Io.File.Stat {
1394 const t: *Threaded = @ptrCast(@alignCast(userdata));1515 const t: *Threaded = @ptrCast(@alignCast(userdata));
1516 const current_thread = Thread.getCurrent(t);
13951517
1396 var path_buffer: [posix.PATH_MAX]u8 = undefined;1518 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1397 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);1519 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
13981520
1399 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;1521 const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
14001522
1523 try current_thread.beginSyscall();
1401 while (true) {1524 while (true) {
1402 try t.checkCancel();
1403 var stat = std.mem.zeroes(posix.Stat);1525 var stat = std.mem.zeroes(posix.Stat);
1404 switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) {1526 switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) {
1405 .SUCCESS => return statFromPosix(&stat),1527 .SUCCESS => {
1406 .INTR => continue,1528 current_thread.endSyscall();
1407 .CANCELED => return error.Canceled,1529 return statFromPosix(&stat);
14081530 },
1409 .INVAL => |err| return errnoBug(err),1531 .INTR => {
1410 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1532 try current_thread.checkCancel();
1411 .NOMEM => return error.SystemResources,1533 continue;
1412 .ACCES => return error.AccessDenied,1534 },
1413 .PERM => return error.PermissionDenied,1535 else => |e| {
1414 .FAULT => |err| return errnoBug(err),1536 current_thread.endSyscall();
1415 .NAMETOOLONG => return error.NameTooLong,1537 switch (e) {
1416 .LOOP => return error.SymLinkLoop,1538 .CANCELED => return error.Canceled,
1417 .NOENT => return error.FileNotFound,1539 .INVAL => |err| return errnoBug(err),
1418 .NOTDIR => return error.FileNotFound,1540 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1419 .ILSEQ => return error.BadPathName,1541 .NOMEM => return error.SystemResources,
1420 else => |err| return posix.unexpectedErrno(err),1542 .ACCES => return error.AccessDenied,
1543 .PERM => return error.PermissionDenied,
1544 .FAULT => |err| return errnoBug(err),
1545 .NAMETOOLONG => return error.NameTooLong,
1546 .LOOP => return error.SymLinkLoop,
1547 .NOENT => return error.FileNotFound,
1548 .NOTDIR => return error.FileNotFound,
1549 .ILSEQ => return error.BadPathName,
1550 else => |err| return posix.unexpectedErrno(err),
1551 }
1552 },
1421 }1553 }
1422 }1554 }
1423}1555}
...@@ -1444,29 +1576,40 @@ fn dirStatPathWasi(...@@ -1444,29 +1576,40 @@ fn dirStatPathWasi(
1444) Io.Dir.StatPathError!Io.File.Stat {1576) Io.Dir.StatPathError!Io.File.Stat {
1445 if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);1577 if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);
1446 const t: *Threaded = @ptrCast(@alignCast(userdata));1578 const t: *Threaded = @ptrCast(@alignCast(userdata));
1579 const current_thread = Thread.getCurrent(t);
1447 const wasi = std.os.wasi;1580 const wasi = std.os.wasi;
1448 const flags: wasi.lookupflags_t = .{1581 const flags: wasi.lookupflags_t = .{
1449 .SYMLINK_FOLLOW = options.follow_symlinks,1582 .SYMLINK_FOLLOW = options.follow_symlinks,
1450 };1583 };
1451 var stat: wasi.filestat_t = undefined;1584 var stat: wasi.filestat_t = undefined;
1585 try current_thread.beginSyscall();
1452 while (true) {1586 while (true) {
1453 try t.checkCancel();
1454 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {1587 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
1455 .SUCCESS => return statFromWasi(&stat),1588 .SUCCESS => {
1456 .INTR => continue,1589 current_thread.endSyscall();
1457 .CANCELED => return error.Canceled,1590 return statFromWasi(&stat);
14581591 },
1459 .INVAL => |err| return errnoBug(err),1592 .INTR => {
1460 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1593 try current_thread.checkCancel();
1461 .NOMEM => return error.SystemResources,1594 continue;
1462 .ACCES => return error.AccessDenied,1595 },
1463 .FAULT => |err| return errnoBug(err),1596 else => |e| {
1464 .NAMETOOLONG => return error.NameTooLong,1597 current_thread.endSyscall();
1465 .NOENT => return error.FileNotFound,1598 switch (e) {
1466 .NOTDIR => return error.FileNotFound,1599 .CANCELED => return error.Canceled,
1467 .NOTCAPABLE => return error.AccessDenied,1600 .INVAL => |err| return errnoBug(err),
1468 .ILSEQ => return error.BadPathName,1601 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1469 else => |err| return posix.unexpectedErrno(err),1602 .NOMEM => return error.SystemResources,
1603 .ACCES => return error.AccessDenied,
1604 .FAULT => |err| return errnoBug(err),
1605 .NAMETOOLONG => return error.NameTooLong,
1606 .NOENT => return error.FileNotFound,
1607 .NOTDIR => return error.FileNotFound,
1608 .NOTCAPABLE => return error.AccessDenied,
1609 .ILSEQ => return error.BadPathName,
1610 else => |err| return posix.unexpectedErrno(err),
1611 }
1612 },
1470 }1613 }
1471 }1614 }
1472}1615}
...@@ -1480,31 +1623,44 @@ const fileStat = switch (native_os) {...@@ -1480,31 +1623,44 @@ const fileStat = switch (native_os) {
14801623
1481fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1624fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1482 const t: *Threaded = @ptrCast(@alignCast(userdata));1625 const t: *Threaded = @ptrCast(@alignCast(userdata));
1626 const current_thread = Thread.getCurrent(t);
14831627
1484 if (posix.Stat == void) return error.Streaming;1628 if (posix.Stat == void) return error.Streaming;
14851629
1630 try current_thread.beginSyscall();
1486 while (true) {1631 while (true) {
1487 try t.checkCancel();
1488 var stat = std.mem.zeroes(posix.Stat);1632 var stat = std.mem.zeroes(posix.Stat);
1489 switch (posix.errno(fstat_sym(file.handle, &stat))) {1633 switch (posix.errno(fstat_sym(file.handle, &stat))) {
1490 .SUCCESS => return statFromPosix(&stat),1634 .SUCCESS => {
1491 .INTR => continue,1635 current_thread.endSyscall();
1492 .CANCELED => return error.Canceled,1636 return statFromPosix(&stat);
14931637 },
1494 .INVAL => |err| return errnoBug(err),1638 .INTR => {
1495 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1639 try current_thread.checkCancel();
1496 .NOMEM => return error.SystemResources,1640 continue;
1497 .ACCES => return error.AccessDenied,1641 },
1498 else => |err| return posix.unexpectedErrno(err),1642 else => |e| {
1643 current_thread.endSyscall();
1644 switch (e) {
1645 .CANCELED => return error.Canceled,
1646 .INVAL => |err| return errnoBug(err),
1647 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1648 .NOMEM => return error.SystemResources,
1649 .ACCES => return error.AccessDenied,
1650 else => |err| return posix.unexpectedErrno(err),
1651 }
1652 },
1499 }1653 }
1500 }1654 }
1501}1655}
15021656
1503fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1657fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1504 const t: *Threaded = @ptrCast(@alignCast(userdata));1658 const t: *Threaded = @ptrCast(@alignCast(userdata));
1659 const current_thread = Thread.getCurrent(t);
1505 const linux = std.os.linux;1660 const linux = std.os.linux;
1661
1662 try current_thread.beginSyscall();
1506 while (true) {1663 while (true) {
1507 try t.checkCancel();
1508 var statx = std.mem.zeroes(linux.Statx);1664 var statx = std.mem.zeroes(linux.Statx);
1509 const rc = linux.statx(1665 const rc = linux.statx(
1510 file.handle,1666 file.handle,
...@@ -1514,27 +1670,38 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File...@@ -1514,27 +1670,38 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
1514 &statx,1670 &statx,
1515 );1671 );
1516 switch (linux.errno(rc)) {1672 switch (linux.errno(rc)) {
1517 .SUCCESS => return statFromLinux(&statx),1673 .SUCCESS => {
1518 .INTR => continue,1674 current_thread.endSyscall();
1519 .CANCELED => return error.Canceled,1675 return statFromLinux(&statx);
15201676 },
1521 .ACCES => |err| return errnoBug(err),1677 .INTR => {
1522 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1678 try current_thread.checkCancel();
1523 .FAULT => |err| return errnoBug(err),1679 continue;
1524 .INVAL => |err| return errnoBug(err),1680 },
1525 .LOOP => |err| return errnoBug(err),1681 else => |e| {
1526 .NAMETOOLONG => |err| return errnoBug(err),1682 current_thread.endSyscall();
1527 .NOENT => |err| return errnoBug(err),1683 switch (e) {
1528 .NOMEM => return error.SystemResources,1684 .CANCELED => return error.Canceled,
1529 .NOTDIR => |err| return errnoBug(err),1685 .ACCES => |err| return errnoBug(err),
1530 else => |err| return posix.unexpectedErrno(err),1686 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1687 .FAULT => |err| return errnoBug(err),
1688 .INVAL => |err| return errnoBug(err),
1689 .LOOP => |err| return errnoBug(err),
1690 .NAMETOOLONG => |err| return errnoBug(err),
1691 .NOENT => |err| return errnoBug(err),
1692 .NOMEM => return error.SystemResources,
1693 .NOTDIR => |err| return errnoBug(err),
1694 else => |err| return posix.unexpectedErrno(err),
1695 }
1696 },
1531 }1697 }
1532 }1698 }
1533}1699}
15341700
1535fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1701fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1536 const t: *Threaded = @ptrCast(@alignCast(userdata));1702 const t: *Threaded = @ptrCast(@alignCast(userdata));
1537 try t.checkCancel();1703 const current_thread = Thread.getCurrent(t);
1704 try current_thread.checkCancel();
15381705
1539 var io_status_block: windows.IO_STATUS_BLOCK = undefined;1706 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
1540 var info: windows.FILE_ALL_INFORMATION = undefined;1707 var info: windows.FILE_ALL_INFORMATION = undefined;
...@@ -1581,21 +1748,34 @@ fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.Fi...@@ -1581,21 +1748,34 @@ fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.Fi
15811748
1582fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {1749fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
1583 if (builtin.link_libc) return fileStatPosix(userdata, file);1750 if (builtin.link_libc) return fileStatPosix(userdata, file);
1751
1584 const t: *Threaded = @ptrCast(@alignCast(userdata));1752 const t: *Threaded = @ptrCast(@alignCast(userdata));
1753 const current_thread = Thread.getCurrent(t);
1754
1755 try current_thread.beginSyscall();
1585 while (true) {1756 while (true) {
1586 try t.checkCancel();
1587 var stat: std.os.wasi.filestat_t = undefined;1757 var stat: std.os.wasi.filestat_t = undefined;
1588 switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {1758 switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {
1589 .SUCCESS => return statFromWasi(&stat),1759 .SUCCESS => {
1590 .INTR => continue,1760 current_thread.endSyscall();
1591 .CANCELED => return error.Canceled,1761 return statFromWasi(&stat);
15921762 },
1593 .INVAL => |err| return errnoBug(err),1763 .INTR => {
1594 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1764 try current_thread.checkCancel();
1595 .NOMEM => return error.SystemResources,1765 continue;
1596 .ACCES => return error.AccessDenied,1766 },
1597 .NOTCAPABLE => return error.AccessDenied,1767 else => |e| {
1598 else => |err| return posix.unexpectedErrno(err),1768 current_thread.endSyscall();
1769 switch (e) {
1770 .CANCELED => return error.Canceled,
1771 .INVAL => |err| return errnoBug(err),
1772 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1773 .NOMEM => return error.SystemResources,
1774 .ACCES => return error.AccessDenied,
1775 .NOTCAPABLE => return error.AccessDenied,
1776 else => |err| return posix.unexpectedErrno(err),
1777 }
1778 },
1599 }1779 }
1600 }1780 }
1601}1781}
...@@ -1613,6 +1793,7 @@ fn dirAccessPosix(...@@ -1613,6 +1793,7 @@ fn dirAccessPosix(
1613 options: Io.Dir.AccessOptions,1793 options: Io.Dir.AccessOptions,
1614) Io.Dir.AccessError!void {1794) Io.Dir.AccessError!void {
1615 const t: *Threaded = @ptrCast(@alignCast(userdata));1795 const t: *Threaded = @ptrCast(@alignCast(userdata));
1796 const current_thread = Thread.getCurrent(t);
16161797
1617 var path_buffer: [posix.PATH_MAX]u8 = undefined;1798 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1618 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);1799 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
...@@ -1624,27 +1805,37 @@ fn dirAccessPosix(...@@ -1624,27 +1805,37 @@ fn dirAccessPosix(
1624 @as(u32, if (options.write) posix.W_OK else 0) |1805 @as(u32, if (options.write) posix.W_OK else 0) |
1625 @as(u32, if (options.execute) posix.X_OK else 0);1806 @as(u32, if (options.execute) posix.X_OK else 0);
16261807
1808 try current_thread.beginSyscall();
1627 while (true) {1809 while (true) {
1628 try t.checkCancel();
1629 switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, flags))) {1810 switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, flags))) {
1630 .SUCCESS => return,1811 .SUCCESS => {
1631 .INTR => continue,1812 current_thread.endSyscall();
1632 .CANCELED => return error.Canceled,1813 return;
16331814 },
1634 .ACCES => return error.AccessDenied,1815 .INTR => {
1635 .PERM => return error.PermissionDenied,1816 try current_thread.checkCancel();
1636 .ROFS => return error.ReadOnlyFileSystem,1817 continue;
1637 .LOOP => return error.SymLinkLoop,1818 },
1638 .TXTBSY => return error.FileBusy,1819 else => |e| {
1639 .NOTDIR => return error.FileNotFound,1820 current_thread.endSyscall();
1640 .NOENT => return error.FileNotFound,1821 switch (e) {
1641 .NAMETOOLONG => return error.NameTooLong,1822 .CANCELED => return error.Canceled,
1642 .INVAL => |err| return errnoBug(err),1823 .ACCES => return error.AccessDenied,
1643 .FAULT => |err| return errnoBug(err),1824 .PERM => return error.PermissionDenied,
1644 .IO => return error.InputOutput,1825 .ROFS => return error.ReadOnlyFileSystem,
1645 .NOMEM => return error.SystemResources,1826 .LOOP => return error.SymLinkLoop,
1646 .ILSEQ => return error.BadPathName,1827 .TXTBSY => return error.FileBusy,
1647 else => |err| return posix.unexpectedErrno(err),1828 .NOTDIR => return error.FileNotFound,
1829 .NOENT => return error.FileNotFound,
1830 .NAMETOOLONG => return error.NameTooLong,
1831 .INVAL => |err| return errnoBug(err),
1832 .FAULT => |err| return errnoBug(err),
1833 .IO => return error.InputOutput,
1834 .NOMEM => return error.SystemResources,
1835 .ILSEQ => return error.BadPathName,
1836 else => |err| return posix.unexpectedErrno(err),
1837 }
1838 },
1648 }1839 }
1649 }1840 }
1650}1841}
...@@ -1657,29 +1848,41 @@ fn dirAccessWasi(...@@ -1657,29 +1848,41 @@ fn dirAccessWasi(
1657) Io.Dir.AccessError!void {1848) Io.Dir.AccessError!void {
1658 if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options);1849 if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options);
1659 const t: *Threaded = @ptrCast(@alignCast(userdata));1850 const t: *Threaded = @ptrCast(@alignCast(userdata));
1851 const current_thread = Thread.getCurrent(t);
1660 const wasi = std.os.wasi;1852 const wasi = std.os.wasi;
1661 const flags: wasi.lookupflags_t = .{1853 const flags: wasi.lookupflags_t = .{
1662 .SYMLINK_FOLLOW = options.follow_symlinks,1854 .SYMLINK_FOLLOW = options.follow_symlinks,
1663 };1855 };
1664 var stat: wasi.filestat_t = undefined;1856 var stat: wasi.filestat_t = undefined;
1857
1858 try current_thread.beginSyscall();
1665 while (true) {1859 while (true) {
1666 try t.checkCancel();
1667 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {1860 switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
1668 .SUCCESS => break,1861 .SUCCESS => {
1669 .INTR => continue,1862 current_thread.endSyscall();
1670 .CANCELED => return error.Canceled,1863 break;
16711864 },
1672 .INVAL => |err| return errnoBug(err),1865 .INTR => {
1673 .BADF => |err| return errnoBug(err), // File descriptor used after closed.1866 try current_thread.checkCancel();
1674 .NOMEM => return error.SystemResources,1867 continue;
1675 .ACCES => return error.AccessDenied,1868 },
1676 .FAULT => |err| return errnoBug(err),1869 else => |e| {
1677 .NAMETOOLONG => return error.NameTooLong,1870 current_thread.endSyscall();
1678 .NOENT => return error.FileNotFound,1871 switch (e) {
1679 .NOTDIR => return error.FileNotFound,1872 .CANCELED => return error.Canceled,
1680 .NOTCAPABLE => return error.AccessDenied,1873 .INVAL => |err| return errnoBug(err),
1681 .ILSEQ => return error.BadPathName,1874 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1682 else => |err| return posix.unexpectedErrno(err),1875 .NOMEM => return error.SystemResources,
1876 .ACCES => return error.AccessDenied,
1877 .FAULT => |err| return errnoBug(err),
1878 .NAMETOOLONG => return error.NameTooLong,
1879 .NOENT => return error.FileNotFound,
1880 .NOTDIR => return error.FileNotFound,
1881 .NOTCAPABLE => return error.AccessDenied,
1882 .ILSEQ => return error.BadPathName,
1883 else => |err| return posix.unexpectedErrno(err),
1884 }
1885 },
1683 }1886 }
1684 }1887 }
16851888
...@@ -1717,7 +1920,8 @@ fn dirAccessWindows(...@@ -1717,7 +1920,8 @@ fn dirAccessWindows(
1717 options: Io.Dir.AccessOptions,1920 options: Io.Dir.AccessOptions,
1718) Io.Dir.AccessError!void {1921) Io.Dir.AccessError!void {
1719 const t: *Threaded = @ptrCast(@alignCast(userdata));1922 const t: *Threaded = @ptrCast(@alignCast(userdata));
1720 try t.checkCancel();1923 const current_thread = Thread.getCurrent(t);
1924 try current_thread.checkCancel();
17211925
1722 _ = options; // TODO1926 _ = options; // TODO
17231927
...@@ -1768,6 +1972,7 @@ fn dirCreateFilePosix(...@@ -1768,6 +1972,7 @@ fn dirCreateFilePosix(
1768 flags: Io.File.CreateFlags,1972 flags: Io.File.CreateFlags,
1769) Io.File.OpenError!Io.File {1973) Io.File.OpenError!Io.File {
1770 const t: *Threaded = @ptrCast(@alignCast(userdata));1974 const t: *Threaded = @ptrCast(@alignCast(userdata));
1975 const current_thread = Thread.getCurrent(t);
17711976
1772 var path_buffer: [posix.PATH_MAX]u8 = undefined;1977 var path_buffer: [posix.PATH_MAX]u8 = undefined;
1773 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);1978 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
...@@ -1796,40 +2001,50 @@ fn dirCreateFilePosix(...@@ -1796,40 +2001,50 @@ fn dirCreateFilePosix(
1796 },2001 },
1797 };2002 };
17982003
2004 try current_thread.beginSyscall();
1799 const fd: posix.fd_t = while (true) {2005 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);2006 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
1802 switch (posix.errno(rc)) {2007 switch (posix.errno(rc)) {
1803 .SUCCESS => break @intCast(rc),2008 .SUCCESS => {
1804 .INTR => continue,2009 current_thread.endSyscall();
1805 .CANCELED => return error.Canceled,2010 break @intCast(rc);
18062011 },
1807 .FAULT => |err| return errnoBug(err),2012 .INTR => {
1808 .INVAL => return error.BadPathName,2013 try current_thread.checkCancel();
1809 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2014 continue;
1810 .ACCES => return error.AccessDenied,2015 },
1811 .FBIG => return error.FileTooBig,2016 else => |e| {
1812 .OVERFLOW => return error.FileTooBig,2017 current_thread.endSyscall();
1813 .ISDIR => return error.IsDir,2018 switch (e) {
1814 .LOOP => return error.SymLinkLoop,2019 .CANCELED => return error.Canceled,
1815 .MFILE => return error.ProcessFdQuotaExceeded,2020 .FAULT => |err| return errnoBug(err),
1816 .NAMETOOLONG => return error.NameTooLong,2021 .INVAL => return error.BadPathName,
1817 .NFILE => return error.SystemFdQuotaExceeded,2022 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1818 .NODEV => return error.NoDevice,2023 .ACCES => return error.AccessDenied,
1819 .NOENT => return error.FileNotFound,2024 .FBIG => return error.FileTooBig,
1820 .SRCH => return error.ProcessNotFound,2025 .OVERFLOW => return error.FileTooBig,
1821 .NOMEM => return error.SystemResources,2026 .ISDIR => return error.IsDir,
1822 .NOSPC => return error.NoSpaceLeft,2027 .LOOP => return error.SymLinkLoop,
1823 .NOTDIR => return error.NotDir,2028 .MFILE => return error.ProcessFdQuotaExceeded,
1824 .PERM => return error.PermissionDenied,2029 .NAMETOOLONG => return error.NameTooLong,
1825 .EXIST => return error.PathAlreadyExists,2030 .NFILE => return error.SystemFdQuotaExceeded,
1826 .BUSY => return error.DeviceBusy,2031 .NODEV => return error.NoDevice,
1827 .OPNOTSUPP => return error.FileLocksNotSupported,2032 .NOENT => return error.FileNotFound,
1828 .AGAIN => return error.WouldBlock,2033 .SRCH => return error.ProcessNotFound,
1829 .TXTBSY => return error.FileBusy,2034 .NOMEM => return error.SystemResources,
1830 .NXIO => return error.NoDevice,2035 .NOSPC => return error.NoSpaceLeft,
1831 .ILSEQ => return error.BadPathName,2036 .NOTDIR => return error.NotDir,
1832 else => |err| return posix.unexpectedErrno(err),2037 .PERM => return error.PermissionDenied,
2038 .EXIST => return error.PathAlreadyExists,
2039 .BUSY => return error.DeviceBusy,
2040 .OPNOTSUPP => return error.FileLocksNotSupported,
2041 .AGAIN => return error.WouldBlock,
2042 .TXTBSY => return error.FileBusy,
2043 .NXIO => return error.NoDevice,
2044 .ILSEQ => return error.BadPathName,
2045 else => |err| return posix.unexpectedErrno(err),
2046 }
2047 },
1833 }2048 }
1834 };2049 };
1835 errdefer posix.close(fd);2050 errdefer posix.close(fd);
...@@ -1841,42 +2056,71 @@ fn dirCreateFilePosix(...@@ -1841,42 +2056,71 @@ fn dirCreateFilePosix(
1841 .shared => posix.LOCK.SH | lock_nonblocking,2056 .shared => posix.LOCK.SH | lock_nonblocking,
1842 .exclusive => posix.LOCK.EX | lock_nonblocking,2057 .exclusive => posix.LOCK.EX | lock_nonblocking,
1843 };2058 };
2059
2060 try current_thread.beginSyscall();
1844 while (true) {2061 while (true) {
1845 try t.checkCancel();
1846 switch (posix.errno(posix.system.flock(fd, lock_flags))) {2062 switch (posix.errno(posix.system.flock(fd, lock_flags))) {
1847 .SUCCESS => break,2063 .SUCCESS => {
1848 .INTR => continue,2064 current_thread.endSyscall();
1849 .CANCELED => return error.Canceled,2065 break;
18502066 },
1851 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2067 .INTR => {
1852 .INVAL => |err| return errnoBug(err), // invalid parameters2068 try current_thread.checkCancel();
1853 .NOLCK => return error.SystemResources,2069 continue;
1854 .AGAIN => return error.WouldBlock,2070 },
1855 .OPNOTSUPP => return error.FileLocksNotSupported,2071 else => |e| {
1856 else => |err| return posix.unexpectedErrno(err),2072 current_thread.endSyscall();
1857 }2073 switch (e) {
2074 .CANCELED => return error.Canceled,
2075 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2076 .INVAL => |err| return errnoBug(err), // invalid parameters
2077 .NOLCK => return error.SystemResources,
2078 .AGAIN => return error.WouldBlock,
2079 .OPNOTSUPP => return error.FileLocksNotSupported,
2080 else => |err| return posix.unexpectedErrno(err),
2081 }
2082 },
2083 }
1858 }2084 }
1859 }2085 }
18602086
1861 if (have_flock_open_flags and flags.lock_nonblocking) {2087 if (have_flock_open_flags and flags.lock_nonblocking) {
2088 try current_thread.beginSyscall();
1862 var fl_flags: usize = while (true) {2089 var fl_flags: usize = while (true) {
1863 try t.checkCancel();
1864 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));2090 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
1865 switch (posix.errno(rc)) {2091 switch (posix.errno(rc)) {
1866 .SUCCESS => break @intCast(rc),2092 .SUCCESS => {
1867 .INTR => continue,2093 current_thread.endSyscall();
1868 .CANCELED => return error.Canceled,2094 break @intCast(rc);
1869 else => |err| return posix.unexpectedErrno(err),2095 },
2096 .INTR => {
2097 try current_thread.checkCancel();
2098 continue;
2099 },
2100 else => |err| {
2101 current_thread.endSyscall();
2102 return posix.unexpectedErrno(err);
2103 },
1870 }2104 }
1871 };2105 };
2106
1872 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));2107 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2108
2109 try current_thread.beginSyscall();
1873 while (true) {2110 while (true) {
1874 try t.checkCancel();
1875 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {2111 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
1876 .SUCCESS => break,2112 .SUCCESS => {
1877 .INTR => continue,2113 current_thread.endSyscall();
1878 .CANCELED => return error.Canceled,2114 break;
1879 else => |err| return posix.unexpectedErrno(err),2115 },
2116 .INTR => {
2117 try current_thread.checkCancel();
2118 continue;
2119 },
2120 else => |err| {
2121 current_thread.endSyscall();
2122 return posix.unexpectedErrno(err);
2123 },
1880 }2124 }
1881 }2125 }
1882 }2126 }
...@@ -1892,7 +2136,8 @@ fn dirCreateFileWindows(...@@ -1892,7 +2136,8 @@ fn dirCreateFileWindows(
1892) Io.File.OpenError!Io.File {2136) Io.File.OpenError!Io.File {
1893 const w = windows;2137 const w = windows;
1894 const t: *Threaded = @ptrCast(@alignCast(userdata));2138 const t: *Threaded = @ptrCast(@alignCast(userdata));
1895 try t.checkCancel();2139 const current_thread = Thread.getCurrent(t);
2140 try current_thread.checkCancel();
18962141
1897 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);2142 const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);
1898 const sub_path_w = sub_path_w_array.span();2143 const sub_path_w = sub_path_w_array.span();
...@@ -1939,6 +2184,7 @@ fn dirCreateFileWasi(...@@ -1939,6 +2184,7 @@ fn dirCreateFileWasi(
1939 flags: Io.File.CreateFlags,2184 flags: Io.File.CreateFlags,
1940) Io.File.OpenError!Io.File {2185) Io.File.OpenError!Io.File {
1941 const t: *Threaded = @ptrCast(@alignCast(userdata));2186 const t: *Threaded = @ptrCast(@alignCast(userdata));
2187 const current_thread = Thread.getCurrent(t);
1942 const wasi = std.os.wasi;2188 const wasi = std.os.wasi;
1943 const lookup_flags: wasi.lookupflags_t = .{};2189 const lookup_flags: wasi.lookupflags_t = .{};
1944 const oflags: wasi.oflags_t = .{2190 const oflags: wasi.oflags_t = .{
...@@ -1966,35 +2212,45 @@ fn dirCreateFileWasi(...@@ -1966,35 +2212,45 @@ fn dirCreateFileWasi(
1966 };2212 };
1967 const inheriting: wasi.rights_t = .{};2213 const inheriting: wasi.rights_t = .{};
1968 var fd: posix.fd_t = undefined;2214 var fd: posix.fd_t = undefined;
2215 try current_thread.beginSyscall();
1969 while (true) {2216 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)) {2217 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
1972 .SUCCESS => return .{ .handle = fd },2218 .SUCCESS => {
1973 .INTR => continue,2219 current_thread.endSyscall();
1974 .CANCELED => return error.Canceled,2220 return .{ .handle = fd };
19752221 },
1976 .FAULT => |err| return errnoBug(err),2222 .INTR => {
1977 .INVAL => return error.BadPathName,2223 try current_thread.checkCancel();
1978 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2224 continue;
1979 .ACCES => return error.AccessDenied,2225 },
1980 .FBIG => return error.FileTooBig,2226 else => |e| {
1981 .OVERFLOW => return error.FileTooBig,2227 current_thread.endSyscall();
1982 .ISDIR => return error.IsDir,2228 switch (e) {
1983 .LOOP => return error.SymLinkLoop,2229 .CANCELED => return error.Canceled,
1984 .MFILE => return error.ProcessFdQuotaExceeded,2230 .FAULT => |err| return errnoBug(err),
1985 .NAMETOOLONG => return error.NameTooLong,2231 .INVAL => return error.BadPathName,
1986 .NFILE => return error.SystemFdQuotaExceeded,2232 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
1987 .NODEV => return error.NoDevice,2233 .ACCES => return error.AccessDenied,
1988 .NOENT => return error.FileNotFound,2234 .FBIG => return error.FileTooBig,
1989 .NOMEM => return error.SystemResources,2235 .OVERFLOW => return error.FileTooBig,
1990 .NOSPC => return error.NoSpaceLeft,2236 .ISDIR => return error.IsDir,
1991 .NOTDIR => return error.NotDir,2237 .LOOP => return error.SymLinkLoop,
1992 .PERM => return error.PermissionDenied,2238 .MFILE => return error.ProcessFdQuotaExceeded,
1993 .EXIST => return error.PathAlreadyExists,2239 .NAMETOOLONG => return error.NameTooLong,
1994 .BUSY => return error.DeviceBusy,2240 .NFILE => return error.SystemFdQuotaExceeded,
1995 .NOTCAPABLE => return error.AccessDenied,2241 .NODEV => return error.NoDevice,
1996 .ILSEQ => return error.BadPathName,2242 .NOENT => return error.FileNotFound,
1997 else => |err| return posix.unexpectedErrno(err),2243 .NOMEM => return error.SystemResources,
2244 .NOSPC => return error.NoSpaceLeft,
2245 .NOTDIR => return error.NotDir,
2246 .PERM => return error.PermissionDenied,
2247 .EXIST => return error.PathAlreadyExists,
2248 .BUSY => return error.DeviceBusy,
2249 .NOTCAPABLE => return error.AccessDenied,
2250 .ILSEQ => return error.BadPathName,
2251 else => |err| return posix.unexpectedErrno(err),
2252 }
2253 },
1998 }2254 }
1999 }2255 }
2000}2256}
...@@ -2012,6 +2268,7 @@ fn dirOpenFilePosix(...@@ -2012,6 +2268,7 @@ fn dirOpenFilePosix(
2012 flags: Io.File.OpenFlags,2268 flags: Io.File.OpenFlags,
2013) Io.File.OpenError!Io.File {2269) Io.File.OpenError!Io.File {
2014 const t: *Threaded = @ptrCast(@alignCast(userdata));2270 const t: *Threaded = @ptrCast(@alignCast(userdata));
2271 const current_thread = Thread.getCurrent(t);
20152272
2016 var path_buffer: [posix.PATH_MAX]u8 = undefined;2273 var path_buffer: [posix.PATH_MAX]u8 = undefined;
2017 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);2274 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
...@@ -2048,40 +2305,50 @@ fn dirOpenFilePosix(...@@ -2048,40 +2305,50 @@ fn dirOpenFilePosix(
2048 },2305 },
2049 };2306 };
20502307
2308 try current_thread.beginSyscall();
2051 const fd: posix.fd_t = while (true) {2309 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));2310 const rc = openat_sym(dir.handle, sub_path_posix, os_flags, @as(posix.mode_t, 0));
2054 switch (posix.errno(rc)) {2311 switch (posix.errno(rc)) {
2055 .SUCCESS => break @intCast(rc),2312 .SUCCESS => {
2056 .INTR => continue,2313 current_thread.endSyscall();
2057 .CANCELED => return error.Canceled,2314 break @intCast(rc);
20582315 },
2059 .FAULT => |err| return errnoBug(err),2316 .INTR => {
2060 .INVAL => return error.BadPathName,2317 try current_thread.checkCancel();
2061 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2318 continue;
2062 .ACCES => return error.AccessDenied,2319 },
2063 .FBIG => return error.FileTooBig,2320 else => |e| {
2064 .OVERFLOW => return error.FileTooBig,2321 current_thread.endSyscall();
2065 .ISDIR => return error.IsDir,2322 switch (e) {
2066 .LOOP => return error.SymLinkLoop,2323 .CANCELED => return error.Canceled,
2067 .MFILE => return error.ProcessFdQuotaExceeded,2324 .FAULT => |err| return errnoBug(err),
2068 .NAMETOOLONG => return error.NameTooLong,2325 .INVAL => return error.BadPathName,
2069 .NFILE => return error.SystemFdQuotaExceeded,2326 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2070 .NODEV => return error.NoDevice,2327 .ACCES => return error.AccessDenied,
2071 .NOENT => return error.FileNotFound,2328 .FBIG => return error.FileTooBig,
2072 .SRCH => return error.ProcessNotFound,2329 .OVERFLOW => return error.FileTooBig,
2073 .NOMEM => return error.SystemResources,2330 .ISDIR => return error.IsDir,
2074 .NOSPC => return error.NoSpaceLeft,2331 .LOOP => return error.SymLinkLoop,
2075 .NOTDIR => return error.NotDir,2332 .MFILE => return error.ProcessFdQuotaExceeded,
2076 .PERM => return error.PermissionDenied,2333 .NAMETOOLONG => return error.NameTooLong,
2077 .EXIST => return error.PathAlreadyExists,2334 .NFILE => return error.SystemFdQuotaExceeded,
2078 .BUSY => return error.DeviceBusy,2335 .NODEV => return error.NoDevice,
2079 .OPNOTSUPP => return error.FileLocksNotSupported,2336 .NOENT => return error.FileNotFound,
2080 .AGAIN => return error.WouldBlock,2337 .SRCH => return error.ProcessNotFound,
2081 .TXTBSY => return error.FileBusy,2338 .NOMEM => return error.SystemResources,
2082 .NXIO => return error.NoDevice,2339 .NOSPC => return error.NoSpaceLeft,
2083 .ILSEQ => return error.BadPathName,2340 .NOTDIR => return error.NotDir,
2084 else => |err| return posix.unexpectedErrno(err),2341 .PERM => return error.PermissionDenied,
2342 .EXIST => return error.PathAlreadyExists,
2343 .BUSY => return error.DeviceBusy,
2344 .OPNOTSUPP => return error.FileLocksNotSupported,
2345 .AGAIN => return error.WouldBlock,
2346 .TXTBSY => return error.FileBusy,
2347 .NXIO => return error.NoDevice,
2348 .ILSEQ => return error.BadPathName,
2349 else => |err| return posix.unexpectedErrno(err),
2350 }
2351 },
2085 }2352 }
2086 };2353 };
2087 errdefer posix.close(fd);2354 errdefer posix.close(fd);
...@@ -2093,42 +2360,70 @@ fn dirOpenFilePosix(...@@ -2093,42 +2360,70 @@ fn dirOpenFilePosix(
2093 .shared => posix.LOCK.SH | lock_nonblocking,2360 .shared => posix.LOCK.SH | lock_nonblocking,
2094 .exclusive => posix.LOCK.EX | lock_nonblocking,2361 .exclusive => posix.LOCK.EX | lock_nonblocking,
2095 };2362 };
2363 try current_thread.beginSyscall();
2096 while (true) {2364 while (true) {
2097 try t.checkCancel();
2098 switch (posix.errno(posix.system.flock(fd, lock_flags))) {2365 switch (posix.errno(posix.system.flock(fd, lock_flags))) {
2099 .SUCCESS => break,2366 .SUCCESS => {
2100 .INTR => continue,2367 current_thread.endSyscall();
2101 .CANCELED => return error.Canceled,2368 break;
21022369 },
2103 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2370 .INTR => {
2104 .INVAL => |err| return errnoBug(err), // invalid parameters2371 try current_thread.checkCancel();
2105 .NOLCK => return error.SystemResources,2372 continue;
2106 .AGAIN => return error.WouldBlock,2373 },
2107 .OPNOTSUPP => return error.FileLocksNotSupported,2374 else => |e| {
2108 else => |err| return posix.unexpectedErrno(err),2375 current_thread.endSyscall();
2376 switch (e) {
2377 .CANCELED => return error.Canceled,
2378 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2379 .INVAL => |err| return errnoBug(err), // invalid parameters
2380 .NOLCK => return error.SystemResources,
2381 .AGAIN => return error.WouldBlock,
2382 .OPNOTSUPP => return error.FileLocksNotSupported,
2383 else => |err| return posix.unexpectedErrno(err),
2384 }
2385 },
2109 }2386 }
2110 }2387 }
2111 }2388 }
21122389
2113 if (have_flock_open_flags and flags.lock_nonblocking) {2390 if (have_flock_open_flags and flags.lock_nonblocking) {
2391 try current_thread.beginSyscall();
2114 var fl_flags: usize = while (true) {2392 var fl_flags: usize = while (true) {
2115 try t.checkCancel();
2116 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));2393 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
2117 switch (posix.errno(rc)) {2394 switch (posix.errno(rc)) {
2118 .SUCCESS => break @intCast(rc),2395 .SUCCESS => {
2119 .INTR => continue,2396 current_thread.endSyscall();
2120 .CANCELED => return error.Canceled,2397 break @intCast(rc);
2121 else => |err| return posix.unexpectedErrno(err),2398 },
2399 .INTR => {
2400 try current_thread.checkCancel();
2401 continue;
2402 },
2403 else => |err| {
2404 current_thread.endSyscall();
2405 return posix.unexpectedErrno(err);
2406 },
2122 }2407 }
2123 };2408 };
2409
2124 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));2410 fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
2411
2412 try current_thread.beginSyscall();
2125 while (true) {2413 while (true) {
2126 try t.checkCancel();
2127 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {2414 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
2128 .SUCCESS => break,2415 .SUCCESS => {
2129 .INTR => continue,2416 current_thread.endSyscall();
2130 .CANCELED => return error.Canceled,2417 break;
2131 else => |err| return posix.unexpectedErrno(err),2418 },
2419 .INTR => {
2420 try current_thread.checkCancel();
2421 continue;
2422 },
2423 else => |err| {
2424 current_thread.endSyscall();
2425 return posix.unexpectedErrno(err);
2426 },
2132 }2427 }
2133 }2428 }
2134 }2429 }
...@@ -2158,7 +2453,7 @@ pub fn dirOpenFileWtf16(...@@ -2158,7 +2453,7 @@ pub fn dirOpenFileWtf16(
2158 if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;2453 if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
2159 if (std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;2454 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;2455 const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
21612456 const current_thread = Thread.getCurrent(t);
2162 const w = windows;2457 const w = windows;
21632458
2164 var nt_name: w.UNICODE_STRING = .{2459 var nt_name: w.UNICODE_STRING = .{
...@@ -2187,7 +2482,7 @@ pub fn dirOpenFileWtf16(...@@ -2187,7 +2482,7 @@ pub fn dirOpenFileWtf16(
2187 var attempt: u5 = 0;2482 var attempt: u5 = 0;
21882483
2189 const handle = while (true) {2484 const handle = while (true) {
2190 try t.checkCancel();2485 try current_thread.checkCancel();
21912486
2192 var result: w.HANDLE = undefined;2487 var result: w.HANDLE = undefined;
2193 const rc = w.ntdll.NtCreateFile(2488 const rc = w.ntdll.NtCreateFile(
...@@ -2281,6 +2576,7 @@ fn dirOpenFileWasi(...@@ -2281,6 +2576,7 @@ fn dirOpenFileWasi(
2281) Io.File.OpenError!Io.File {2576) Io.File.OpenError!Io.File {
2282 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);2577 if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);
2283 const t: *Threaded = @ptrCast(@alignCast(userdata));2578 const t: *Threaded = @ptrCast(@alignCast(userdata));
2579 const current_thread = Thread.getCurrent(t);
2284 const wasi = std.os.wasi;2580 const wasi = std.os.wasi;
2285 var base: std.os.wasi.rights_t = .{};2581 var base: std.os.wasi.rights_t = .{};
2286 // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE2582 // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE
...@@ -2310,33 +2606,44 @@ fn dirOpenFileWasi(...@@ -2310,33 +2606,44 @@ fn dirOpenFileWasi(
2310 const inheriting: wasi.rights_t = .{};2606 const inheriting: wasi.rights_t = .{};
2311 const fdflags: wasi.fdflags_t = .{};2607 const fdflags: wasi.fdflags_t = .{};
2312 var fd: posix.fd_t = undefined;2608 var fd: posix.fd_t = undefined;
2609 try current_thread.beginSyscall();
2313 while (true) {2610 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)) {2611 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
2316 .SUCCESS => return .{ .handle = fd },2612 .SUCCESS => {
2317 .INTR => continue,2613 errdefer posix.close(fd);
2318 .CANCELED => return error.Canceled,2614 current_thread.endSyscall();
23192615 return .{ .handle = fd };
2320 .FAULT => |err| return errnoBug(err),2616 },
2321 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2617 .INTR => {
2322 .ACCES => return error.AccessDenied,2618 try current_thread.checkCancel();
2323 .FBIG => return error.FileTooBig,2619 continue;
2324 .OVERFLOW => return error.FileTooBig,2620 },
2325 .ISDIR => return error.IsDir,2621 else => |e| {
2326 .LOOP => return error.SymLinkLoop,2622 current_thread.endSyscall();
2327 .MFILE => return error.ProcessFdQuotaExceeded,2623 switch (e) {
2328 .NFILE => return error.SystemFdQuotaExceeded,2624 .CANCELED => return error.Canceled,
2329 .NODEV => return error.NoDevice,2625 .FAULT => |err| return errnoBug(err),
2330 .NOENT => return error.FileNotFound,2626 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2331 .NOMEM => return error.SystemResources,2627 .ACCES => return error.AccessDenied,
2332 .NOTDIR => return error.NotDir,2628 .FBIG => return error.FileTooBig,
2333 .PERM => return error.PermissionDenied,2629 .OVERFLOW => return error.FileTooBig,
2334 .BUSY => return error.DeviceBusy,2630 .ISDIR => return error.IsDir,
2335 .NOTCAPABLE => return error.AccessDenied,2631 .LOOP => return error.SymLinkLoop,
2336 .NAMETOOLONG => return error.NameTooLong,2632 .MFILE => return error.ProcessFdQuotaExceeded,
2337 .INVAL => return error.BadPathName,2633 .NFILE => return error.SystemFdQuotaExceeded,
2338 .ILSEQ => return error.BadPathName,2634 .NODEV => return error.NoDevice,
2339 else => |err| return posix.unexpectedErrno(err),2635 .NOENT => return error.FileNotFound,
2636 .NOMEM => return error.SystemResources,
2637 .NOTDIR => return error.NotDir,
2638 .PERM => return error.PermissionDenied,
2639 .BUSY => return error.DeviceBusy,
2640 .NOTCAPABLE => return error.AccessDenied,
2641 .NAMETOOLONG => return error.NameTooLong,
2642 .INVAL => return error.BadPathName,
2643 .ILSEQ => return error.BadPathName,
2644 else => |err| return posix.unexpectedErrno(err),
2645 }
2646 },
2340 }2647 }
2341 }2648 }
2342}2649}
...@@ -2361,6 +2668,8 @@ fn dirOpenDirPosix(...@@ -2361,6 +2668,8 @@ fn dirOpenDirPosix(
2361 return dirOpenDirWindows(t, dir, sub_path_w.span(), options);2668 return dirOpenDirWindows(t, dir, sub_path_w.span(), options);
2362 }2669 }
23632670
2671 const current_thread = Thread.getCurrent(t);
2672
2364 var path_buffer: [posix.PATH_MAX]u8 = undefined;2673 var path_buffer: [posix.PATH_MAX]u8 = undefined;
2365 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);2674 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
23662675
...@@ -2381,31 +2690,41 @@ fn dirOpenDirPosix(...@@ -2381,31 +2690,41 @@ fn dirOpenDirPosix(
2381 if (@hasField(posix.O, "PATH") and !options.iterate)2690 if (@hasField(posix.O, "PATH") and !options.iterate)
2382 flags.PATH = true;2691 flags.PATH = true;
23832692
2693 try current_thread.beginSyscall();
2384 while (true) {2694 while (true) {
2385 try t.checkCancel();
2386 const rc = openat_sym(dir.handle, sub_path_posix, flags, @as(usize, 0));2695 const rc = openat_sym(dir.handle, sub_path_posix, flags, @as(usize, 0));
2387 switch (posix.errno(rc)) {2696 switch (posix.errno(rc)) {
2388 .SUCCESS => return .{ .handle = @intCast(rc) },2697 .SUCCESS => {
2389 .INTR => continue,2698 current_thread.endSyscall();
2390 .CANCELED => return error.Canceled,2699 return .{ .handle = @intCast(rc) };
23912700 },
2392 .FAULT => |err| return errnoBug(err),2701 .INTR => {
2393 .INVAL => return error.BadPathName,2702 try current_thread.checkCancel();
2394 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2703 continue;
2395 .ACCES => return error.AccessDenied,2704 },
2396 .LOOP => return error.SymLinkLoop,2705 else => |e| {
2397 .MFILE => return error.ProcessFdQuotaExceeded,2706 current_thread.endSyscall();
2398 .NAMETOOLONG => return error.NameTooLong,2707 switch (e) {
2399 .NFILE => return error.SystemFdQuotaExceeded,2708 .CANCELED => return error.Canceled,
2400 .NODEV => return error.NoDevice,2709 .FAULT => |err| return errnoBug(err),
2401 .NOENT => return error.FileNotFound,2710 .INVAL => return error.BadPathName,
2402 .NOMEM => return error.SystemResources,2711 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2403 .NOTDIR => return error.NotDir,2712 .ACCES => return error.AccessDenied,
2404 .PERM => return error.PermissionDenied,2713 .LOOP => return error.SymLinkLoop,
2405 .BUSY => return error.DeviceBusy,2714 .MFILE => return error.ProcessFdQuotaExceeded,
2406 .NXIO => return error.NoDevice,2715 .NAMETOOLONG => return error.NameTooLong,
2407 .ILSEQ => return error.BadPathName,2716 .NFILE => return error.SystemFdQuotaExceeded,
2408 else => |err| return posix.unexpectedErrno(err),2717 .NODEV => return error.NoDevice,
2718 .NOENT => return error.FileNotFound,
2719 .NOMEM => return error.SystemResources,
2720 .NOTDIR => return error.NotDir,
2721 .PERM => return error.PermissionDenied,
2722 .BUSY => return error.DeviceBusy,
2723 .NXIO => return error.NoDevice,
2724 .ILSEQ => return error.BadPathName,
2725 else => |err| return posix.unexpectedErrno(err),
2726 }
2727 },
2409 }2728 }
2410 }2729 }
2411}2730}
...@@ -2417,34 +2736,46 @@ fn dirOpenDirHaiku(...@@ -2417,34 +2736,46 @@ fn dirOpenDirHaiku(
2417 options: Io.Dir.OpenOptions,2736 options: Io.Dir.OpenOptions,
2418) Io.Dir.OpenError!Io.Dir {2737) Io.Dir.OpenError!Io.Dir {
2419 const t: *Threaded = @ptrCast(@alignCast(userdata));2738 const t: *Threaded = @ptrCast(@alignCast(userdata));
2739 const current_thread = Thread.getCurrent(t);
24202740
2421 var path_buffer: [posix.PATH_MAX]u8 = undefined;2741 var path_buffer: [posix.PATH_MAX]u8 = undefined;
2422 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);2742 const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
24232743
2424 _ = options;2744 _ = options;
24252745
2746 try current_thread.beginSyscall();
2426 while (true) {2747 while (true) {
2427 try t.checkCancel();
2428 const rc = posix.system._kern_open_dir(dir.handle, sub_path_posix);2748 const rc = posix.system._kern_open_dir(dir.handle, sub_path_posix);
2429 if (rc >= 0) return .{ .handle = rc };2749 if (rc >= 0) {
2750 current_thread.endSyscall();
2751 return .{ .handle = rc };
2752 }
2430 switch (@as(posix.E, @enumFromInt(rc))) {2753 switch (@as(posix.E, @enumFromInt(rc))) {
2431 .INTR => continue,2754 .INTR => {
2432 .CANCELED => return error.Canceled,2755 try current_thread.checkCancel();
2433 .FAULT => |err| return errnoBug(err),2756 continue;
2434 .INVAL => |err| return errnoBug(err),2757 },
2435 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2758 else => |e| {
2436 .ACCES => return error.AccessDenied,2759 current_thread.endSyscall();
2437 .LOOP => return error.SymLinkLoop,2760 switch (e) {
2438 .MFILE => return error.ProcessFdQuotaExceeded,2761 .CANCELED => return error.Canceled,
2439 .NAMETOOLONG => return error.NameTooLong,2762 .FAULT => |err| return errnoBug(err),
2440 .NFILE => return error.SystemFdQuotaExceeded,2763 .INVAL => |err| return errnoBug(err),
2441 .NODEV => return error.NoDevice,2764 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2442 .NOENT => return error.FileNotFound,2765 .ACCES => return error.AccessDenied,
2443 .NOMEM => return error.SystemResources,2766 .LOOP => return error.SymLinkLoop,
2444 .NOTDIR => return error.NotDir,2767 .MFILE => return error.ProcessFdQuotaExceeded,
2445 .PERM => return error.PermissionDenied,2768 .NAMETOOLONG => return error.NameTooLong,
2446 .BUSY => return error.DeviceBusy,2769 .NFILE => return error.SystemFdQuotaExceeded,
2447 else => |err| return posix.unexpectedErrno(err),2770 .NODEV => return error.NoDevice,
2771 .NOENT => return error.FileNotFound,
2772 .NOMEM => return error.SystemResources,
2773 .NOTDIR => return error.NotDir,
2774 .PERM => return error.PermissionDenied,
2775 .BUSY => return error.DeviceBusy,
2776 else => |err| return posix.unexpectedErrno(err),
2777 }
2778 },
2448 }2779 }
2449 }2780 }
2450}2781}
...@@ -2455,6 +2786,7 @@ pub fn dirOpenDirWindows(...@@ -2455,6 +2786,7 @@ pub fn dirOpenDirWindows(
2455 sub_path_w: [:0]const u16,2786 sub_path_w: [:0]const u16,
2456 options: Io.Dir.OpenOptions,2787 options: Io.Dir.OpenOptions,
2457) Io.Dir.OpenError!Io.Dir {2788) Io.Dir.OpenError!Io.Dir {
2789 const current_thread = Thread.getCurrent(t);
2458 const w = windows;2790 const w = windows;
2459 // TODO remove some of these flags if options.access_sub_paths is false2791 // 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 |2792 const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
...@@ -2478,7 +2810,7 @@ pub fn dirOpenDirWindows(...@@ -2478,7 +2810,7 @@ pub fn dirOpenDirWindows(
2478 const open_reparse_point: w.DWORD = if (!options.follow_symlinks) w.FILE_OPEN_REPARSE_POINT else 0x0;2810 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;2811 var io_status_block: w.IO_STATUS_BLOCK = undefined;
2480 var result: Io.Dir = .{ .handle = undefined };2812 var result: Io.Dir = .{ .handle = undefined };
2481 try t.checkCancel();2813 try current_thread.checkCancel();
2482 const rc = w.ntdll.NtCreateFile(2814 const rc = w.ntdll.NtCreateFile(
2483 &result.handle,2815 &result.handle,
2484 access_mask,2816 access_mask,
...@@ -2527,6 +2859,7 @@ fn dirOpenDirWasi(...@@ -2527,6 +2859,7 @@ fn dirOpenDirWasi(
2527) Io.Dir.OpenError!Io.Dir {2859) Io.Dir.OpenError!Io.Dir {
2528 if (builtin.link_libc) return dirOpenDirPosix(userdata, dir, sub_path, options);2860 if (builtin.link_libc) return dirOpenDirPosix(userdata, dir, sub_path, options);
2529 const t: *Threaded = @ptrCast(@alignCast(userdata));2861 const t: *Threaded = @ptrCast(@alignCast(userdata));
2862 const current_thread = Thread.getCurrent(t);
2530 const wasi = std.os.wasi;2863 const wasi = std.os.wasi;
25312864
2532 var base: std.os.wasi.rights_t = .{2865 var base: std.os.wasi.rights_t = .{
...@@ -2556,31 +2889,40 @@ fn dirOpenDirWasi(...@@ -2556,31 +2889,40 @@ fn dirOpenDirWasi(
2556 const oflags: wasi.oflags_t = .{ .DIRECTORY = true };2889 const oflags: wasi.oflags_t = .{ .DIRECTORY = true };
2557 const fdflags: wasi.fdflags_t = .{};2890 const fdflags: wasi.fdflags_t = .{};
2558 var fd: posix.fd_t = undefined;2891 var fd: posix.fd_t = undefined;
25592892 try current_thread.beginSyscall();
2560 while (true) {2893 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)) {2894 switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, base, fdflags, &fd)) {
2563 .SUCCESS => return .{ .handle = fd },2895 .SUCCESS => {
2564 .INTR => continue,2896 current_thread.endSyscall();
2565 .CANCELED => return error.Canceled,2897 return .{ .handle = fd };
25662898 },
2567 .FAULT => |err| return errnoBug(err),2899 .INTR => {
2568 .INVAL => return error.BadPathName,2900 try current_thread.checkCancel();
2569 .BADF => |err| return errnoBug(err), // File descriptor used after closed.2901 continue;
2570 .ACCES => return error.AccessDenied,2902 },
2571 .LOOP => return error.SymLinkLoop,2903 else => |e| {
2572 .MFILE => return error.ProcessFdQuotaExceeded,2904 current_thread.endSyscall();
2573 .NAMETOOLONG => return error.NameTooLong,2905 switch (e) {
2574 .NFILE => return error.SystemFdQuotaExceeded,2906 .CANCELED => return error.Canceled,
2575 .NODEV => return error.NoDevice,2907 .FAULT => |err| return errnoBug(err),
2576 .NOENT => return error.FileNotFound,2908 .INVAL => return error.BadPathName,
2577 .NOMEM => return error.SystemResources,2909 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
2578 .NOTDIR => return error.NotDir,2910 .ACCES => return error.AccessDenied,
2579 .PERM => return error.PermissionDenied,2911 .LOOP => return error.SymLinkLoop,
2580 .BUSY => return error.DeviceBusy,2912 .MFILE => return error.ProcessFdQuotaExceeded,
2581 .NOTCAPABLE => return error.AccessDenied,2913 .NAMETOOLONG => return error.NameTooLong,
2582 .ILSEQ => return error.BadPathName,2914 .NFILE => return error.SystemFdQuotaExceeded,
2583 else => |err| return posix.unexpectedErrno(err),2915 .NODEV => return error.NoDevice,
2916 .NOENT => return error.FileNotFound,
2917 .NOMEM => return error.SystemResources,
2918 .NOTDIR => return error.NotDir,
2919 .PERM => return error.PermissionDenied,
2920 .BUSY => return error.DeviceBusy,
2921 .NOTCAPABLE => return error.AccessDenied,
2922 .ILSEQ => return error.BadPathName,
2923 else => |err| return posix.unexpectedErrno(err),
2924 }
2925 },
2584 }2926 }
2585 }2927 }
2586}2928}
...@@ -2598,6 +2940,7 @@ const fileReadStreaming = switch (native_os) {...@@ -2598,6 +2940,7 @@ const fileReadStreaming = switch (native_os) {
25982940
2599fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {2941fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
2600 const t: *Threaded = @ptrCast(@alignCast(userdata));2942 const t: *Threaded = @ptrCast(@alignCast(userdata));
2943 const current_thread = Thread.getCurrent(t);
26012944
2602 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;2945 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
2603 var i: usize = 0;2946 var i: usize = 0;
...@@ -2611,59 +2954,82 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io...@@ -2611,59 +2954,82 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io
2611 const dest = iovecs_buffer[0..i];2954 const dest = iovecs_buffer[0..i];
2612 assert(dest[0].len > 0);2955 assert(dest[0].len > 0);
26132956
2614 if (native_os == .wasi and !builtin.link_libc) while (true) {2957 if (native_os == .wasi and !builtin.link_libc) {
2615 try t.checkCancel();2958 try current_thread.beginSyscall();
2616 var nread: usize = undefined;2959 while (true) {
2617 switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {2960 var nread: usize = undefined;
2618 .SUCCESS => return nread,2961 switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {
2619 .INTR => continue,2962 .SUCCESS => {
2620 .CANCELED => return error.Canceled,2963 current_thread.endSyscall();
26212964 return nread;
2622 .INVAL => |err| return errnoBug(err),2965 },
2623 .FAULT => |err| return errnoBug(err),2966 .INTR => {
2624 .BADF => return error.NotOpenForReading, // File operation on directory.2967 try current_thread.checkCancel();
2625 .IO => return error.InputOutput,2968 continue;
2626 .ISDIR => return error.IsDir,2969 },
2627 .NOBUFS => return error.SystemResources,2970 else => |e| {
2628 .NOMEM => return error.SystemResources,2971 current_thread.endSyscall();
2629 .NOTCONN => return error.SocketUnconnected,2972 switch (e) {
2630 .CONNRESET => return error.ConnectionResetByPeer,2973 .CANCELED => return error.Canceled,
2631 .TIMEDOUT => return error.Timeout,2974 .INVAL => |err| return errnoBug(err),
2632 .NOTCAPABLE => return error.AccessDenied,2975 .FAULT => |err| return errnoBug(err),
2633 else => |err| return posix.unexpectedErrno(err),2976 .BADF => return error.NotOpenForReading, // File operation on directory.
2977 .IO => return error.InputOutput,
2978 .ISDIR => return error.IsDir,
2979 .NOBUFS => return error.SystemResources,
2980 .NOMEM => return error.SystemResources,
2981 .NOTCONN => return error.SocketUnconnected,
2982 .CONNRESET => return error.ConnectionResetByPeer,
2983 .TIMEDOUT => return error.Timeout,
2984 .NOTCAPABLE => return error.AccessDenied,
2985 else => |err| return posix.unexpectedErrno(err),
2986 }
2987 },
2988 }
2634 }2989 }
2635 };2990 }
26362991
2992 try current_thread.beginSyscall();
2637 while (true) {2993 while (true) {
2638 try t.checkCancel();
2639 const rc = posix.system.readv(file.handle, dest.ptr, @intCast(dest.len));2994 const rc = posix.system.readv(file.handle, dest.ptr, @intCast(dest.len));
2640 switch (posix.errno(rc)) {2995 switch (posix.errno(rc)) {
2641 .SUCCESS => return @intCast(rc),2996 .SUCCESS => {
2642 .INTR => continue,2997 current_thread.endSyscall();
2643 .CANCELED => return error.Canceled,2998 return @intCast(rc);
26442999 },
2645 .INVAL => |err| return errnoBug(err),3000 .INTR => {
2646 .FAULT => |err| return errnoBug(err),3001 try current_thread.checkCancel();
2647 .SRCH => return error.ProcessNotFound,3002 continue;
2648 .AGAIN => return error.WouldBlock,3003 },
2649 .BADF => |err| {3004 else => |e| {
2650 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.3005 current_thread.endSyscall();
2651 return errnoBug(err); // File descriptor used after closed.3006 switch (e) {
2652 },3007 .CANCELED => return error.Canceled,
2653 .IO => return error.InputOutput,3008 .INVAL => |err| return errnoBug(err),
2654 .ISDIR => return error.IsDir,3009 .FAULT => |err| return errnoBug(err),
2655 .NOBUFS => return error.SystemResources,3010 .SRCH => return error.ProcessNotFound,
2656 .NOMEM => return error.SystemResources,3011 .AGAIN => return error.WouldBlock,
2657 .NOTCONN => return error.SocketUnconnected,3012 .BADF => |err| {
2658 .CONNRESET => return error.ConnectionResetByPeer,3013 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
2659 .TIMEDOUT => return error.Timeout,3014 return errnoBug(err); // File descriptor used after closed.
2660 else => |err| return posix.unexpectedErrno(err),3015 },
3016 .IO => return error.InputOutput,
3017 .ISDIR => return error.IsDir,
3018 .NOBUFS => return error.SystemResources,
3019 .NOMEM => return error.SystemResources,
3020 .NOTCONN => return error.SocketUnconnected,
3021 .CONNRESET => return error.ConnectionResetByPeer,
3022 .TIMEDOUT => return error.Timeout,
3023 else => |err| return posix.unexpectedErrno(err),
3024 }
3025 },
2661 }3026 }
2662 }3027 }
2663}3028}
26643029
2665fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {3030fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
2666 const t: *Threaded = @ptrCast(@alignCast(userdata));3031 const t: *Threaded = @ptrCast(@alignCast(userdata));
3032 const current_thread = Thread.getCurrent(t);
26673033
2668 const DWORD = windows.DWORD;3034 const DWORD = windows.DWORD;
2669 var index: usize = 0;3035 var index: usize = 0;
...@@ -2672,7 +3038,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)...@@ -2672,7 +3038,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
2672 const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);3038 const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);
26733039
2674 while (true) {3040 while (true) {
2675 try t.checkCancel();3041 try current_thread.checkCancel();
2676 var n: DWORD = undefined;3042 var n: DWORD = undefined;
2677 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0)3043 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0)
2678 return n;3044 return n;
...@@ -2692,6 +3058,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)...@@ -2692,6 +3058,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
26923058
2693fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {3059fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
2694 const t: *Threaded = @ptrCast(@alignCast(userdata));3060 const t: *Threaded = @ptrCast(@alignCast(userdata));
3061 const current_thread = Thread.getCurrent(t);
26953062
2696 if (!have_preadv) @compileError("TODO");3063 if (!have_preadv) @compileError("TODO");
26973064
...@@ -2707,60 +3074,82 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o...@@ -2707,60 +3074,82 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o
2707 const dest = iovecs_buffer[0..i];3074 const dest = iovecs_buffer[0..i];
2708 assert(dest[0].len > 0);3075 assert(dest[0].len > 0);
27093076
2710 if (native_os == .wasi and !builtin.link_libc) while (true) {3077 if (native_os == .wasi and !builtin.link_libc) {
2711 try t.checkCancel();3078 try current_thread.beginSyscall();
2712 var nread: usize = undefined;3079 while (true) {
2713 switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {3080 var nread: usize = undefined;
2714 .SUCCESS => return nread,3081 switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {
2715 .INTR => continue,3082 .SUCCESS => {
2716 .CANCELED => return error.Canceled,3083 current_thread.endSyscall();
27173084 return nread;
2718 .INVAL => |err| return errnoBug(err),3085 },
2719 .FAULT => |err| return errnoBug(err),3086 .INTR => {
2720 .AGAIN => |err| return errnoBug(err),3087 try current_thread.checkCancel();
2721 .BADF => return error.NotOpenForReading, // File operation on directory.3088 continue;
2722 .IO => return error.InputOutput,3089 },
2723 .ISDIR => return error.IsDir,3090 else => |e| {
2724 .NOBUFS => return error.SystemResources,3091 current_thread.endSyscall();
2725 .NOMEM => return error.SystemResources,3092 switch (e) {
2726 .NOTCONN => return error.SocketUnconnected,3093 .CANCELED => return error.Canceled,
2727 .CONNRESET => return error.ConnectionResetByPeer,3094 .INVAL => |err| return errnoBug(err),
2728 .TIMEDOUT => return error.Timeout,3095 .FAULT => |err| return errnoBug(err),
2729 .NXIO => return error.Unseekable,3096 .AGAIN => |err| return errnoBug(err),
2730 .SPIPE => return error.Unseekable,3097 .BADF => return error.NotOpenForReading, // File operation on directory.
2731 .OVERFLOW => return error.Unseekable,3098 .IO => return error.InputOutput,
2732 .NOTCAPABLE => return error.AccessDenied,3099 .ISDIR => return error.IsDir,
2733 else => |err| return posix.unexpectedErrno(err),3100 .NOBUFS => return error.SystemResources,
3101 .NOMEM => return error.SystemResources,
3102 .NOTCONN => return error.SocketUnconnected,
3103 .CONNRESET => return error.ConnectionResetByPeer,
3104 .TIMEDOUT => return error.Timeout,
3105 .NXIO => return error.Unseekable,
3106 .SPIPE => return error.Unseekable,
3107 .OVERFLOW => return error.Unseekable,
3108 .NOTCAPABLE => return error.AccessDenied,
3109 else => |err| return posix.unexpectedErrno(err),
3110 }
3111 },
3112 }
2734 }3113 }
2735 };3114 }
27363115
3116 try current_thread.beginSyscall();
2737 while (true) {3117 while (true) {
2738 try t.checkCancel();
2739 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));3118 const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
2740 switch (posix.errno(rc)) {3119 switch (posix.errno(rc)) {
2741 .SUCCESS => return @bitCast(rc),3120 .SUCCESS => {
2742 .INTR => continue,3121 current_thread.endSyscall();
2743 .CANCELED => return error.Canceled,3122 return @bitCast(rc);
27443123 },
2745 .INVAL => |err| return errnoBug(err),3124 .INTR => {
2746 .FAULT => |err| return errnoBug(err),3125 try current_thread.checkCancel();
2747 .SRCH => return error.ProcessNotFound,3126 continue;
2748 .AGAIN => return error.WouldBlock,3127 },
2749 .BADF => |err| {3128 else => |e| {
2750 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.3129 current_thread.endSyscall();
2751 return errnoBug(err); // File descriptor used after closed.3130 switch (e) {
2752 },3131 .CANCELED => return error.Canceled,
2753 .IO => return error.InputOutput,3132 .INVAL => |err| return errnoBug(err),
2754 .ISDIR => return error.IsDir,3133 .FAULT => |err| return errnoBug(err),
2755 .NOBUFS => return error.SystemResources,3134 .SRCH => return error.ProcessNotFound,
2756 .NOMEM => return error.SystemResources,3135 .AGAIN => return error.WouldBlock,
2757 .NOTCONN => return error.SocketUnconnected,3136 .BADF => |err| {
2758 .CONNRESET => return error.ConnectionResetByPeer,3137 if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
2759 .TIMEDOUT => return error.Timeout,3138 return errnoBug(err); // File descriptor used after closed.
2760 .NXIO => return error.Unseekable,3139 },
2761 .SPIPE => return error.Unseekable,3140 .IO => return error.InputOutput,
2762 .OVERFLOW => return error.Unseekable,3141 .ISDIR => return error.IsDir,
2763 else => |err| return posix.unexpectedErrno(err),3142 .NOBUFS => return error.SystemResources,
3143 .NOMEM => return error.SystemResources,
3144 .NOTCONN => return error.SocketUnconnected,
3145 .CONNRESET => return error.ConnectionResetByPeer,
3146 .TIMEDOUT => return error.Timeout,
3147 .NXIO => return error.Unseekable,
3148 .SPIPE => return error.Unseekable,
3149 .OVERFLOW => return error.Unseekable,
3150 else => |err| return posix.unexpectedErrno(err),
3151 }
3152 },
2764 }3153 }
2765 }3154 }
2766}3155}
...@@ -2772,6 +3161,7 @@ const fileReadPositional = switch (native_os) {...@@ -2772,6 +3161,7 @@ const fileReadPositional = switch (native_os) {
27723161
2773fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {3162fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
2774 const t: *Threaded = @ptrCast(@alignCast(userdata));3163 const t: *Threaded = @ptrCast(@alignCast(userdata));
3164 const current_thread = Thread.getCurrent(t);
27753165
2776 const DWORD = windows.DWORD;3166 const DWORD = windows.DWORD;
27773167
...@@ -2793,7 +3183,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,...@@ -2793,7 +3183,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
2793 };3183 };
27943184
2795 while (true) {3185 while (true) {
2796 try t.checkCancel();3186 try current_thread.checkCancel();
2797 var n: DWORD = undefined;3187 var n: DWORD = undefined;
2798 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0)3188 if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0)
2799 return n;3189 return n;
...@@ -2813,8 +3203,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,...@@ -2813,8 +3203,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
28133203
2814fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekError!void {3204fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekError!void {
2815 const t: *Threaded = @ptrCast(@alignCast(userdata));3205 const t: *Threaded = @ptrCast(@alignCast(userdata));
2816 try t.checkCancel();3206 _ = t;
2817
2818 _ = file;3207 _ = file;
2819 _ = offset;3208 _ = offset;
2820 @panic("TODO implement fileSeekBy");3209 @panic("TODO implement fileSeekBy");
...@@ -2822,63 +3211,96 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr...@@ -2822,63 +3211,96 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr
28223211
2823fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {3212fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {
2824 const t: *Threaded = @ptrCast(@alignCast(userdata));3213 const t: *Threaded = @ptrCast(@alignCast(userdata));
3214 const current_thread = Thread.getCurrent(t);
2825 const fd = file.handle;3215 const fd = file.handle;
28263216
2827 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) while (true) {3217 if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
2828 try t.checkCancel();3218 try current_thread.beginSyscall();
2829 var result: u64 = undefined;3219 while (true) {
2830 switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {3220 var result: u64 = undefined;
2831 .SUCCESS => return,3221 switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {
2832 .INTR => continue,3222 .SUCCESS => {
2833 .CANCELED => return error.Canceled,3223 current_thread.endSyscall();
28343224 return;
2835 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3225 },
2836 .INVAL => return error.Unseekable,3226 .INTR => {
2837 .OVERFLOW => return error.Unseekable,3227 try current_thread.checkCancel();
2838 .SPIPE => return error.Unseekable,3228 continue;
2839 .NXIO => return error.Unseekable,3229 },
2840 else => |err| return posix.unexpectedErrno(err),3230 else => |e| {
3231 current_thread.endSyscall();
3232 switch (e) {
3233 .CANCELED => return error.Canceled,
3234 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3235 .INVAL => return error.Unseekable,
3236 .OVERFLOW => return error.Unseekable,
3237 .SPIPE => return error.Unseekable,
3238 .NXIO => return error.Unseekable,
3239 else => |err| return posix.unexpectedErrno(err),
3240 }
3241 },
3242 }
2841 }3243 }
2842 };3244 }
28433245
2844 if (native_os == .windows) {3246 if (native_os == .windows) {
2845 try t.checkCancel();3247 try current_thread.checkCancel();
2846 return windows.SetFilePointerEx_BEGIN(fd, offset);3248 return windows.SetFilePointerEx_BEGIN(fd, offset);
2847 }3249 }
28483250
2849 if (native_os == .wasi and !builtin.link_libc) while (true) {3251 if (native_os == .wasi and !builtin.link_libc) while (true) {
2850 try t.checkCancel();
2851 var new_offset: std.os.wasi.filesize_t = undefined;3252 var new_offset: std.os.wasi.filesize_t = undefined;
3253 try current_thread.beginSyscall();
2852 switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) {3254 switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) {
2853 .SUCCESS => return,3255 .SUCCESS => {
2854 .INTR => continue,3256 current_thread.endSyscall();
2855 .CANCELED => return error.Canceled,3257 return;
28563258 },
2857 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3259 .INTR => {
2858 .INVAL => return error.Unseekable,3260 try current_thread.checkCancel();
2859 .OVERFLOW => return error.Unseekable,3261 continue;
2860 .SPIPE => return error.Unseekable,3262 },
2861 .NXIO => return error.Unseekable,3263 else => |e| {
2862 .NOTCAPABLE => return error.AccessDenied,3264 current_thread.endSyscall();
2863 else => |err| return posix.unexpectedErrno(err),3265 switch (e) {
3266 .CANCELED => return error.Canceled,
3267 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3268 .INVAL => return error.Unseekable,
3269 .OVERFLOW => return error.Unseekable,
3270 .SPIPE => return error.Unseekable,
3271 .NXIO => return error.Unseekable,
3272 .NOTCAPABLE => return error.AccessDenied,
3273 else => |err| return posix.unexpectedErrno(err),
3274 }
3275 },
2864 }3276 }
2865 };3277 };
28663278
2867 if (posix.SEEK == void) return error.Unseekable;3279 if (posix.SEEK == void) return error.Unseekable;
28683280
3281 try current_thread.beginSyscall();
2869 while (true) {3282 while (true) {
2870 try t.checkCancel();
2871 switch (posix.errno(lseek_sym(fd, @bitCast(offset), posix.SEEK.SET))) {3283 switch (posix.errno(lseek_sym(fd, @bitCast(offset), posix.SEEK.SET))) {
2872 .SUCCESS => return,3284 .SUCCESS => {
2873 .INTR => continue,3285 current_thread.endSyscall();
2874 .CANCELED => return error.Canceled,3286 return;
28753287 },
2876 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3288 .INTR => {
2877 .INVAL => return error.Unseekable,3289 try current_thread.checkCancel();
2878 .OVERFLOW => return error.Unseekable,3290 continue;
2879 .SPIPE => return error.Unseekable,3291 },
2880 .NXIO => return error.Unseekable,3292 else => |e| {
2881 else => |err| return posix.unexpectedErrno(err),3293 current_thread.endSyscall();
3294 switch (e) {
3295 .CANCELED => return error.Canceled,
3296 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3297 .INVAL => return error.Unseekable,
3298 .OVERFLOW => return error.Unseekable,
3299 .SPIPE => return error.Unseekable,
3300 .NXIO => return error.Unseekable,
3301 else => |err| return posix.unexpectedErrno(err),
3302 }
3303 },
2882 }3304 }
2883 }3305 }
2884}3306}
...@@ -2907,8 +3329,8 @@ fn fileWritePositional(...@@ -2907,8 +3329,8 @@ fn fileWritePositional(
2907 offset: u64,3329 offset: u64,
2908) Io.File.WritePositionalError!usize {3330) Io.File.WritePositionalError!usize {
2909 const t: *Threaded = @ptrCast(@alignCast(userdata));3331 const t: *Threaded = @ptrCast(@alignCast(userdata));
3332 _ = t;
2910 while (true) {3333 while (true) {
2911 try t.checkCancel();
2912 _ = file;3334 _ = file;
2913 _ = buffer;3335 _ = buffer;
2914 _ = offset;3336 _ = offset;
...@@ -2918,8 +3340,8 @@ fn fileWritePositional(...@@ -2918,8 +3340,8 @@ fn fileWritePositional(
29183340
2919fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8) Io.File.WriteStreamingError!usize {3341fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8) Io.File.WriteStreamingError!usize {
2920 const t: *Threaded = @ptrCast(@alignCast(userdata));3342 const t: *Threaded = @ptrCast(@alignCast(userdata));
3343 _ = t;
2921 while (true) {3344 while (true) {
2922 try t.checkCancel();
2923 _ = file;3345 _ = file;
2924 _ = buffer;3346 _ = buffer;
2925 @panic("TODO implement fileWriteStreaming");3347 @panic("TODO implement fileWriteStreaming");
...@@ -2997,6 +3419,7 @@ const sleep = switch (native_os) {...@@ -2997,6 +3419,7 @@ const sleep = switch (native_os) {
29973419
2998fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3420fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
2999 const t: *Threaded = @ptrCast(@alignCast(userdata));3421 const t: *Threaded = @ptrCast(@alignCast(userdata));
3422 const current_thread = Thread.getCurrent(t);
3000 const clock_id: posix.clockid_t = clockToPosix(switch (timeout) {3423 const clock_id: posix.clockid_t = clockToPosix(switch (timeout) {
3001 .none => .awake,3424 .none => .awake,
3002 .duration => |d| d.clock,3425 .duration => |d| d.clock,
...@@ -3008,25 +3431,37 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {...@@ -3008,25 +3431,37 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3008 .deadline => |deadline| deadline.raw.nanoseconds,3431 .deadline => |deadline| deadline.raw.nanoseconds,
3009 };3432 };
3010 var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);3433 var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
3434 try current_thread.beginSyscall();
3011 while (true) {3435 while (true) {
3012 try t.checkCancel();
3013 switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {3436 switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
3014 .none, .duration => false,3437 .none, .duration => false,
3015 .deadline => true,3438 .deadline => true,
3016 } }, &timespec, &timespec))) {3439 } }, &timespec, &timespec))) {
3017 .SUCCESS => return,3440 .SUCCESS => {
3018 .INTR => continue,3441 current_thread.endSyscall();
3019 .CANCELED => return error.Canceled,3442 return;
3020 .INVAL => return error.UnsupportedClock,3443 },
3021 else => |err| return posix.unexpectedErrno(err),3444 .INTR => {
3445 try current_thread.checkCancel();
3446 continue;
3447 },
3448 else => |e| {
3449 current_thread.endSyscall();
3450 switch (e) {
3451 .CANCELED => return error.Canceled,
3452 .INVAL => return error.UnsupportedClock,
3453 else => |err| return posix.unexpectedErrno(err),
3454 }
3455 },
3022 }3456 }
3023 }3457 }
3024}3458}
30253459
3026fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3460fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3027 const t: *Threaded = @ptrCast(@alignCast(userdata));3461 const t: *Threaded = @ptrCast(@alignCast(userdata));
3462 const current_thread = Thread.getCurrent(t);
3028 const t_io = ioBasic(t);3463 const t_io = ioBasic(t);
3029 try t.checkCancel();3464 try current_thread.checkCancel();
3030 const ms = ms: {3465 const ms = ms: {
3031 const d = (try timeout.toDurationFromNow(t_io)) orelse3466 const d = (try timeout.toDurationFromNow(t_io)) orelse
3032 break :ms std.math.maxInt(windows.DWORD);3467 break :ms std.math.maxInt(windows.DWORD);
...@@ -3038,9 +3473,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {...@@ -3038,9 +3473,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
30383473
3039fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3474fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3040 const t: *Threaded = @ptrCast(@alignCast(userdata));3475 const t: *Threaded = @ptrCast(@alignCast(userdata));
3476 const current_thread = Thread.getCurrent(t);
3041 const t_io = ioBasic(t);3477 const t_io = ioBasic(t);
3042 try t.checkCancel();
3043
3044 const w = std.os.wasi;3478 const w = std.os.wasi;
30453479
3046 const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t_io)) |d| .{3480 const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t_io)) |d| .{
...@@ -3063,11 +3497,14 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {...@@ -3063,11 +3497,14 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3063 };3497 };
3064 var event: w.event_t = undefined;3498 var event: w.event_t = undefined;
3065 var nevents: usize = undefined;3499 var nevents: usize = undefined;
3500 try current_thread.beginSyscall();
3066 _ = w.poll_oneoff(&in, &event, 1, &nevents);3501 _ = w.poll_oneoff(&in, &event, 1, &nevents);
3502 current_thread.endSyscall();
3067}3503}
30683504
3069fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {3505fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3070 const t: *Threaded = @ptrCast(@alignCast(userdata));3506 const t: *Threaded = @ptrCast(@alignCast(userdata));
3507 const current_thread = Thread.getCurrent(t);
3071 const t_io = ioBasic(t);3508 const t_io = ioBasic(t);
3072 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;3509 const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
3073 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;3510 const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
...@@ -3079,12 +3516,18 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {...@@ -3079,12 +3516,18 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
3079 };3516 };
3080 break :t timestampToPosix(d.raw.toNanoseconds());3517 break :t timestampToPosix(d.raw.toNanoseconds());
3081 };3518 };
3519 try current_thread.beginSyscall();
3082 while (true) {3520 while (true) {
3083 try t.checkCancel();
3084 switch (posix.errno(posix.system.nanosleep(&timespec, &timespec))) {3521 switch (posix.errno(posix.system.nanosleep(&timespec, &timespec))) {
3085 .INTR => continue,3522 .INTR => {
3086 .CANCELED => return error.Canceled,3523 try current_thread.checkCancel();
3087 else => return, // This prong handles success as well as unexpected errors.3524 continue;
3525 },
3526 else => {
3527 // This prong handles success as well as unexpected errors.
3528 current_thread.endSyscall();
3529 return;
3530 },
3088 }3531 }
3089 }3532 }
3090}3533}
...@@ -3127,34 +3570,48 @@ fn netListenIpPosix(...@@ -3127,34 +3570,48 @@ fn netListenIpPosix(
3127) IpAddress.ListenError!net.Server {3570) IpAddress.ListenError!net.Server {
3128 if (!have_networking) return error.NetworkDown;3571 if (!have_networking) return error.NetworkDown;
3129 const t: *Threaded = @ptrCast(@alignCast(userdata));3572 const t: *Threaded = @ptrCast(@alignCast(userdata));
3573 const current_thread = Thread.getCurrent(t);
3130 const family = posixAddressFamily(&address);3574 const family = posixAddressFamily(&address);
3131 const socket_fd = try openSocketPosix(t, family, .{3575 const socket_fd = try openSocketPosix(current_thread, family, .{
3132 .mode = options.mode,3576 .mode = options.mode,
3133 .protocol = options.protocol,3577 .protocol = options.protocol,
3134 });3578 });
3135 errdefer posix.close(socket_fd);3579 errdefer posix.close(socket_fd);
31363580
3137 if (options.reuse_address) {3581 if (options.reuse_address) {
3138 try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);3582 try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
3139 if (@hasDecl(posix.SO, "REUSEPORT"))3583 if (@hasDecl(posix.SO, "REUSEPORT"))
3140 try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);3584 try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);
3141 }3585 }
31423586
3143 var storage: PosixAddress = undefined;3587 var storage: PosixAddress = undefined;
3144 var addr_len = addressToPosix(&address, &storage);3588 var addr_len = addressToPosix(&address, &storage);
3145 try posixBind(t, socket_fd, &storage.any, addr_len);3589 try posixBind(current_thread, socket_fd, &storage.any, addr_len);
31463590
3591 try current_thread.beginSyscall();
3147 while (true) {3592 while (true) {
3148 try t.checkCancel();
3149 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {3593 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
3150 .SUCCESS => break,3594 .SUCCESS => {
3151 .ADDRINUSE => return error.AddressInUse,3595 current_thread.endSyscall();
3152 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3596 break;
3153 else => |err| return posix.unexpectedErrno(err),3597 },
3598 .INTR => {
3599 try current_thread.checkCancel();
3600 continue;
3601 },
3602 else => |e| {
3603 current_thread.endSyscall();
3604 switch (e) {
3605 .CANCELED => return error.Canceled,
3606 .ADDRINUSE => return error.AddressInUse,
3607 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3608 else => |err| return posix.unexpectedErrno(err),
3609 }
3610 },
3154 }3611 }
3155 }3612 }
31563613
3157 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);3614 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
3158 return .{3615 return .{
3159 .socket = .{3616 .socket = .{
3160 .handle = socket_fd,3617 .handle = socket_fd,
...@@ -3170,8 +3627,9 @@ fn netListenIpWindows(...@@ -3170,8 +3627,9 @@ fn netListenIpWindows(
3170) IpAddress.ListenError!net.Server {3627) IpAddress.ListenError!net.Server {
3171 if (!have_networking) return error.NetworkDown;3628 if (!have_networking) return error.NetworkDown;
3172 const t: *Threaded = @ptrCast(@alignCast(userdata));3629 const t: *Threaded = @ptrCast(@alignCast(userdata));
3630 const current_thread = Thread.getCurrent(t);
3173 const family = posixAddressFamily(&address);3631 const family = posixAddressFamily(&address);
3174 const socket_handle = try openSocketWsa(t, family, .{3632 const socket_handle = try openSocketWsa(t, current_thread, family, .{
3175 .mode = options.mode,3633 .mode = options.mode,
3176 .protocol = options.protocol,3634 .protocol = options.protocol,
3177 });3635 });
...@@ -3183,52 +3641,73 @@ fn netListenIpWindows(...@@ -3183,52 +3641,73 @@ fn netListenIpWindows(
3183 var storage: WsaAddress = undefined;3641 var storage: WsaAddress = undefined;
3184 var addr_len = addressToWsa(&address, &storage);3642 var addr_len = addressToWsa(&address, &storage);
31853643
3644 try current_thread.beginSyscall();
3186 while (true) {3645 while (true) {
3187 try t.checkCancel();
3188 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);3646 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
3189 if (rc != ws2_32.SOCKET_ERROR) break;3647 if (rc != ws2_32.SOCKET_ERROR) break;
3190 switch (ws2_32.WSAGetLastError()) {3648 switch (ws2_32.WSAGetLastError()) {
3191 .EINTR => continue,3649 .EINTR => {
3192 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,3650 try current_thread.checkCancel();
3651 continue;
3652 },
3193 .NOTINITIALISED => {3653 .NOTINITIALISED => {
3194 try initializeWsa(t);3654 try initializeWsa(t);
3655 try current_thread.checkCancel();
3195 continue;3656 continue;
3196 },3657 },
3197 .EADDRINUSE => return error.AddressInUse,3658 else => |e| {
3198 .EADDRNOTAVAIL => return error.AddressUnavailable,3659 current_thread.endSyscall();
3199 .ENOTSOCK => |err| return wsaErrorBug(err),3660 switch (e) {
3200 .EFAULT => |err| return wsaErrorBug(err),3661 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3201 .EINVAL => |err| return wsaErrorBug(err),3662 .EADDRINUSE => return error.AddressInUse,
3202 .ENOBUFS => return error.SystemResources,3663 .EADDRNOTAVAIL => return error.AddressUnavailable,
3203 .ENETDOWN => return error.NetworkDown,3664 .ENOTSOCK => |err| return wsaErrorBug(err),
3204 else => |err| return windows.unexpectedWSAError(err),3665 .EFAULT => |err| return wsaErrorBug(err),
3666 .EINVAL => |err| return wsaErrorBug(err),
3667 .ENOBUFS => return error.SystemResources,
3668 .ENETDOWN => return error.NetworkDown,
3669 else => |err| return windows.unexpectedWSAError(err),
3670 }
3671 },
3205 }3672 }
3206 }3673 }
32073674
3675 try current_thread.checkCancel();
3208 while (true) {3676 while (true) {
3209 try t.checkCancel();
3210 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);3677 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
3211 if (rc != ws2_32.SOCKET_ERROR) break;3678 if (rc != ws2_32.SOCKET_ERROR) {
3679 current_thread.endSyscall();
3680 break;
3681 }
3212 switch (ws2_32.WSAGetLastError()) {3682 switch (ws2_32.WSAGetLastError()) {
3213 .EINTR => continue,3683 .EINTR => {
3214 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,3684 try current_thread.checkCancel();
3685 continue;
3686 },
3215 .NOTINITIALISED => {3687 .NOTINITIALISED => {
3216 try initializeWsa(t);3688 try initializeWsa(t);
3689 try current_thread.checkCancel();
3217 continue;3690 continue;
3218 },3691 },
3219 .ENETDOWN => return error.NetworkDown,3692 else => |e| {
3220 .EADDRINUSE => return error.AddressInUse,3693 current_thread.endSyscall();
3221 .EISCONN => |err| return wsaErrorBug(err),3694 switch (e) {
3222 .EINVAL => |err| return wsaErrorBug(err),3695 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3223 .EMFILE, .ENOBUFS => return error.SystemResources,3696 .ENETDOWN => return error.NetworkDown,
3224 .ENOTSOCK => |err| return wsaErrorBug(err),3697 .EADDRINUSE => return error.AddressInUse,
3225 .EOPNOTSUPP => |err| return wsaErrorBug(err),3698 .EISCONN => |err| return wsaErrorBug(err),
3226 .EINPROGRESS => |err| return wsaErrorBug(err),3699 .EINVAL => |err| return wsaErrorBug(err),
3227 else => |err| return windows.unexpectedWSAError(err),3700 .EMFILE, .ENOBUFS => return error.SystemResources,
3701 .ENOTSOCK => |err| return wsaErrorBug(err),
3702 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3703 .EINPROGRESS => |err| return wsaErrorBug(err),
3704 else => |err| return windows.unexpectedWSAError(err),
3705 }
3706 },
3228 }3707 }
3229 }3708 }
32303709
3231 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);3710 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
32323711
3233 return .{3712 return .{
3234 .socket = .{3713 .socket = .{
...@@ -3256,7 +3735,8 @@ fn netListenUnixPosix(...@@ -3256,7 +3735,8 @@ fn netListenUnixPosix(
3256) net.UnixAddress.ListenError!net.Socket.Handle {3735) net.UnixAddress.ListenError!net.Socket.Handle {
3257 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;3736 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3258 const t: *Threaded = @ptrCast(@alignCast(userdata));3737 const t: *Threaded = @ptrCast(@alignCast(userdata));
3259 const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {3738 const current_thread = Thread.getCurrent(t);
3739 const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
3260 error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,3740 error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,
3261 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,3741 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
3262 error.SocketModeUnsupported => return error.AddressFamilyUnsupported,3742 error.SocketModeUnsupported => return error.AddressFamilyUnsupported,
...@@ -3267,15 +3747,28 @@ fn netListenUnixPosix(...@@ -3267,15 +3747,28 @@ fn netListenUnixPosix(
32673747
3268 var storage: UnixAddress = undefined;3748 var storage: UnixAddress = undefined;
3269 const addr_len = addressUnixToPosix(address, &storage);3749 const addr_len = addressUnixToPosix(address, &storage);
3270 try posixBindUnix(t, socket_fd, &storage.any, addr_len);3750 try posixBindUnix(current_thread, socket_fd, &storage.any, addr_len);
32713751
3752 try current_thread.beginSyscall();
3272 while (true) {3753 while (true) {
3273 try t.checkCancel();
3274 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {3754 switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
3275 .SUCCESS => break,3755 .SUCCESS => {
3276 .ADDRINUSE => return error.AddressInUse,3756 current_thread.endSyscall();
3277 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3757 break;
3278 else => |err| return posix.unexpectedErrno(err),3758 },
3759 .INTR => {
3760 try current_thread.checkCancel();
3761 continue;
3762 },
3763 else => |e| {
3764 current_thread.endSyscall();
3765 switch (e) {
3766 .CANCELED => return error.Canceled,
3767 .ADDRINUSE => return error.AddressInUse,
3768 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3769 else => |err| return posix.unexpectedErrno(err),
3770 }
3771 },
3279 }3772 }
3280 }3773 }
32813774
...@@ -3289,8 +3782,9 @@ fn netListenUnixWindows(...@@ -3289,8 +3782,9 @@ fn netListenUnixWindows(
3289) net.UnixAddress.ListenError!net.Socket.Handle {3782) net.UnixAddress.ListenError!net.Socket.Handle {
3290 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;3783 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3291 const t: *Threaded = @ptrCast(@alignCast(userdata));3784 const t: *Threaded = @ptrCast(@alignCast(userdata));
3785 const current_thread = Thread.getCurrent(t);
32923786
3293 const socket_handle = openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {3787 const socket_handle = openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
3294 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,3788 error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
3295 else => |e| return e,3789 else => |e| return e,
3296 };3790 };
...@@ -3299,52 +3793,67 @@ fn netListenUnixWindows(...@@ -3299,52 +3793,67 @@ fn netListenUnixWindows(
3299 var storage: WsaAddress = undefined;3793 var storage: WsaAddress = undefined;
3300 const addr_len = addressUnixToWsa(address, &storage);3794 const addr_len = addressUnixToWsa(address, &storage);
33013795
3796 try current_thread.beginSyscall();
3302 while (true) {3797 while (true) {
3303 try t.checkCancel();
3304 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);3798 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
3305 if (rc != ws2_32.SOCKET_ERROR) break;3799 if (rc != ws2_32.SOCKET_ERROR) break;
3306 switch (ws2_32.WSAGetLastError()) {3800 switch (ws2_32.WSAGetLastError()) {
3307 .EINTR => continue,3801 .EINTR => {
3308 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,3802 try current_thread.checkCancel();
3803 continue;
3804 },
3309 .NOTINITIALISED => {3805 .NOTINITIALISED => {
3310 try initializeWsa(t);3806 try initializeWsa(t);
3807 try current_thread.checkCancel();
3311 continue;3808 continue;
3312 },3809 },
3313 .EADDRINUSE => return error.AddressInUse,3810 else => |e| {
3314 .EADDRNOTAVAIL => return error.AddressUnavailable,3811 current_thread.endSyscall();
3315 .ENOTSOCK => |err| return wsaErrorBug(err),3812 switch (e) {
3316 .EFAULT => |err| return wsaErrorBug(err),3813 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3317 .EINVAL => |err| return wsaErrorBug(err),3814 .EADDRINUSE => return error.AddressInUse,
3318 .ENOBUFS => return error.SystemResources,3815 .EADDRNOTAVAIL => return error.AddressUnavailable,
3319 .ENETDOWN => return error.NetworkDown,3816 .ENOTSOCK => |err| return wsaErrorBug(err),
3320 else => |err| return windows.unexpectedWSAError(err),3817 .EFAULT => |err| return wsaErrorBug(err),
3818 .EINVAL => |err| return wsaErrorBug(err),
3819 .ENOBUFS => return error.SystemResources,
3820 .ENETDOWN => return error.NetworkDown,
3821 else => |err| return windows.unexpectedWSAError(err),
3822 }
3823 },
3321 }3824 }
3322 }3825 }
33233826
3324 while (true) {3827 while (true) {
3325 try t.checkCancel();3828 try current_thread.checkCancel();
3326 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);3829 const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
3327 if (rc != ws2_32.SOCKET_ERROR) break;3830 if (rc != ws2_32.SOCKET_ERROR) {
3831 current_thread.endSyscall();
3832 return socket_handle;
3833 }
3328 switch (ws2_32.WSAGetLastError()) {3834 switch (ws2_32.WSAGetLastError()) {
3329 .EINTR => continue,3835 .EINTR => continue,
3330 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3331 .NOTINITIALISED => {3836 .NOTINITIALISED => {
3332 try initializeWsa(t);3837 try initializeWsa(t);
3333 continue;3838 continue;
3334 },3839 },
3335 .ENETDOWN => return error.NetworkDown,3840 else => |e| {
3336 .EADDRINUSE => return error.AddressInUse,3841 current_thread.endSyscall();
3337 .EISCONN => |err| return wsaErrorBug(err),3842 switch (e) {
3338 .EINVAL => |err| return wsaErrorBug(err),3843 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3339 .EMFILE, .ENOBUFS => return error.SystemResources,3844 .ENETDOWN => return error.NetworkDown,
3340 .ENOTSOCK => |err| return wsaErrorBug(err),3845 .EADDRINUSE => return error.AddressInUse,
3341 .EOPNOTSUPP => |err| return wsaErrorBug(err),3846 .EISCONN => |err| return wsaErrorBug(err),
3342 .EINPROGRESS => |err| return wsaErrorBug(err),3847 .EINVAL => |err| return wsaErrorBug(err),
3343 else => |err| return windows.unexpectedWSAError(err),3848 .EMFILE, .ENOBUFS => return error.SystemResources,
3849 .ENOTSOCK => |err| return wsaErrorBug(err),
3850 .EOPNOTSUPP => |err| return wsaErrorBug(err),
3851 .EINPROGRESS => |err| return wsaErrorBug(err),
3852 else => |err| return windows.unexpectedWSAError(err),
3853 }
3854 },
3344 }3855 }
3345 }3856 }
3346
3347 return socket_handle;
3348}3857}
33493858
3350fn netListenUnixUnavailable(3859fn netListenUnixUnavailable(
...@@ -3358,172 +3867,275 @@ fn netListenUnixUnavailable(...@@ -3358,172 +3867,275 @@ fn netListenUnixUnavailable(
3358 return error.AddressFamilyUnsupported;3867 return error.AddressFamilyUnsupported;
3359}3868}
33603869
3361fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {3870fn posixBindUnix(
3871 current_thread: *Thread,
3872 fd: posix.socket_t,
3873 addr: *const posix.sockaddr,
3874 addr_len: posix.socklen_t,
3875) !void {
3876 try current_thread.beginSyscall();
3362 while (true) {3877 while (true) {
3363 try t.checkCancel();
3364 switch (posix.errno(posix.system.bind(fd, addr, addr_len))) {3878 switch (posix.errno(posix.system.bind(fd, addr, addr_len))) {
3365 .SUCCESS => break,3879 .SUCCESS => {
3366 .INTR => continue,3880 current_thread.endSyscall();
3367 .CANCELED => return error.Canceled,3881 break;
33683882 },
3369 .ACCES => return error.AccessDenied,3883 .INTR => {
3370 .ADDRINUSE => return error.AddressInUse,3884 try current_thread.checkCancel();
3371 .AFNOSUPPORT => return error.AddressFamilyUnsupported,3885 continue;
3372 .ADDRNOTAVAIL => return error.AddressUnavailable,3886 },
3373 .NOMEM => return error.SystemResources,3887 else => |e| {
33743888 current_thread.endSyscall();
3375 .LOOP => return error.SymLinkLoop,3889 switch (e) {
3376 .NOENT => return error.FileNotFound,3890 .CANCELED => return error.Canceled,
3377 .NOTDIR => return error.NotDir,3891 .ACCES => return error.AccessDenied,
3378 .ROFS => return error.ReadOnlyFileSystem,3892 .ADDRINUSE => return error.AddressInUse,
3379 .PERM => return error.PermissionDenied,3893 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
33803894 .ADDRNOTAVAIL => return error.AddressUnavailable,
3381 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3895 .NOMEM => return error.SystemResources,
3382 .INVAL => |err| return errnoBug(err), // invalid parameters3896
3383 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`3897 .LOOP => return error.SymLinkLoop,
3384 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer3898 .NOENT => return error.FileNotFound,
3385 .NAMETOOLONG => |err| return errnoBug(err),3899 .NOTDIR => return error.NotDir,
3386 else => |err| return posix.unexpectedErrno(err),3900 .ROFS => return error.ReadOnlyFileSystem,
3901 .PERM => return error.PermissionDenied,
3902
3903 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3904 .INVAL => |err| return errnoBug(err), // invalid parameters
3905 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3906 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3907 .NAMETOOLONG => |err| return errnoBug(err),
3908 else => |err| return posix.unexpectedErrno(err),
3909 }
3910 },
3387 }3911 }
3388 }3912 }
3389}3913}
33903914
3391fn posixBind(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {3915fn posixBind(
3916 current_thread: *Thread,
3917 socket_fd: posix.socket_t,
3918 addr: *const posix.sockaddr,
3919 addr_len: posix.socklen_t,
3920) !void {
3921 try current_thread.beginSyscall();
3392 while (true) {3922 while (true) {
3393 try t.checkCancel();
3394 switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) {3923 switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) {
3395 .SUCCESS => break,3924 .SUCCESS => {
3396 .INTR => continue,3925 current_thread.endSyscall();
3397 .CANCELED => return error.Canceled,3926 break;
33983927 },
3399 .ADDRINUSE => return error.AddressInUse,3928 .INTR => {
3400 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3929 try current_thread.checkCancel();
3401 .INVAL => |err| return errnoBug(err), // invalid parameters3930 continue;
3402 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`3931 },
3403 .AFNOSUPPORT => return error.AddressFamilyUnsupported,3932 else => |e| {
3404 .ADDRNOTAVAIL => return error.AddressUnavailable,3933 current_thread.endSyscall();
3405 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer3934 switch (e) {
3406 .NOMEM => return error.SystemResources,3935 .CANCELED => return error.Canceled,
3407 else => |err| return posix.unexpectedErrno(err),3936 .ADDRINUSE => return error.AddressInUse,
3937 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3938 .INVAL => |err| return errnoBug(err), // invalid parameters
3939 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
3940 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3941 .ADDRNOTAVAIL => return error.AddressUnavailable,
3942 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
3943 .NOMEM => return error.SystemResources,
3944 else => |err| return posix.unexpectedErrno(err),
3945 }
3946 },
3408 }3947 }
3409 }3948 }
3410}3949}
34113950
3412fn posixConnect(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {3951fn posixConnect(
3952 current_thread: *Thread,
3953 socket_fd: posix.socket_t,
3954 addr: *const posix.sockaddr,
3955 addr_len: posix.socklen_t,
3956) !void {
3957 try current_thread.beginSyscall();
3413 while (true) {3958 while (true) {
3414 try t.checkCancel();
3415 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {3959 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {
3416 .SUCCESS => return,3960 .SUCCESS => {
3417 .INTR => continue,3961 current_thread.endSyscall();
3418 .CANCELED => return error.Canceled,3962 return;
34193963 },
3420 .ADDRNOTAVAIL => return error.AddressUnavailable,3964 .INTR => {
3421 .AFNOSUPPORT => return error.AddressFamilyUnsupported,3965 try current_thread.checkCancel();
3422 .AGAIN, .INPROGRESS => return error.WouldBlock,3966 continue;
3423 .ALREADY => return error.ConnectionPending,3967 },
3424 .BADF => |err| return errnoBug(err), // File descriptor used after closed.3968 else => |e| {
3425 .CONNREFUSED => return error.ConnectionRefused,3969 current_thread.endSyscall();
3426 .CONNRESET => return error.ConnectionResetByPeer,3970 switch (e) {
3427 .FAULT => |err| return errnoBug(err),3971 .CANCELED => return error.Canceled,
3428 .ISCONN => |err| return errnoBug(err),3972 .ADDRNOTAVAIL => return error.AddressUnavailable,
3429 .HOSTUNREACH => return error.HostUnreachable,3973 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3430 .NETUNREACH => return error.NetworkUnreachable,3974 .AGAIN, .INPROGRESS => return error.WouldBlock,
3431 .NOTSOCK => |err| return errnoBug(err),3975 .ALREADY => return error.ConnectionPending,
3432 .PROTOTYPE => |err| return errnoBug(err),3976 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3433 .TIMEDOUT => return error.Timeout,3977 .CONNREFUSED => return error.ConnectionRefused,
3434 .CONNABORTED => |err| return errnoBug(err),3978 .CONNRESET => return error.ConnectionResetByPeer,
3435 .ACCES => return error.AccessDenied,3979 .FAULT => |err| return errnoBug(err),
3436 .PERM => |err| return errnoBug(err),3980 .ISCONN => |err| return errnoBug(err),
3437 .NOENT => |err| return errnoBug(err),3981 .HOSTUNREACH => return error.HostUnreachable,
3438 .NETDOWN => return error.NetworkDown,3982 .NETUNREACH => return error.NetworkUnreachable,
3439 else => |err| return posix.unexpectedErrno(err),3983 .NOTSOCK => |err| return errnoBug(err),
3984 .PROTOTYPE => |err| return errnoBug(err),
3985 .TIMEDOUT => return error.Timeout,
3986 .CONNABORTED => |err| return errnoBug(err),
3987 .ACCES => return error.AccessDenied,
3988 .PERM => |err| return errnoBug(err),
3989 .NOENT => |err| return errnoBug(err),
3990 .NETDOWN => return error.NetworkDown,
3991 else => |err| return posix.unexpectedErrno(err),
3992 }
3993 },
3440 }3994 }
3441 }3995 }
3442}3996}
34433997
3444fn posixConnectUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {3998fn posixConnectUnix(
3999 current_thread: *Thread,
4000 fd: posix.socket_t,
4001 addr: *const posix.sockaddr,
4002 addr_len: posix.socklen_t,
4003) !void {
4004 try current_thread.beginSyscall();
3445 while (true) {4005 while (true) {
3446 try t.checkCancel();
3447 switch (posix.errno(posix.system.connect(fd, addr, addr_len))) {4006 switch (posix.errno(posix.system.connect(fd, addr, addr_len))) {
3448 .SUCCESS => return,4007 .SUCCESS => {
3449 .INTR => continue,4008 current_thread.endSyscall();
3450 .CANCELED => return error.Canceled,4009 return;
34514010 },
3452 .AFNOSUPPORT => return error.AddressFamilyUnsupported,4011 .INTR => {
3453 .AGAIN => return error.WouldBlock,4012 try current_thread.checkCancel();
3454 .INPROGRESS => return error.WouldBlock,4013 continue;
3455 .ACCES => return error.AccessDenied,4014 },
34564015 else => |e| {
3457 .LOOP => return error.SymLinkLoop,4016 current_thread.endSyscall();
3458 .NOENT => return error.FileNotFound,4017 switch (e) {
3459 .NOTDIR => return error.NotDir,4018 .CANCELED => return error.Canceled,
3460 .ROFS => return error.ReadOnlyFileSystem,4019 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3461 .PERM => return error.PermissionDenied,4020 .AGAIN => return error.WouldBlock,
34624021 .INPROGRESS => return error.WouldBlock,
3463 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4022 .ACCES => return error.AccessDenied,
3464 .CONNABORTED => |err| return errnoBug(err),4023
3465 .FAULT => |err| return errnoBug(err),4024 .LOOP => return error.SymLinkLoop,
3466 .ISCONN => |err| return errnoBug(err),4025 .NOENT => return error.FileNotFound,
3467 .NOTSOCK => |err| return errnoBug(err),4026 .NOTDIR => return error.NotDir,
3468 .PROTOTYPE => |err| return errnoBug(err),4027 .ROFS => return error.ReadOnlyFileSystem,
3469 else => |err| return posix.unexpectedErrno(err),4028 .PERM => return error.PermissionDenied,
4029
4030 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4031 .CONNABORTED => |err| return errnoBug(err),
4032 .FAULT => |err| return errnoBug(err),
4033 .ISCONN => |err| return errnoBug(err),
4034 .NOTSOCK => |err| return errnoBug(err),
4035 .PROTOTYPE => |err| return errnoBug(err),
4036 else => |err| return posix.unexpectedErrno(err),
4037 }
4038 },
3470 }4039 }
3471 }4040 }
3472}4041}
34734042
3474fn posixGetSockName(t: *Threaded, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void {4043fn posixGetSockName(
4044 current_thread: *Thread,
4045 socket_fd: posix.fd_t,
4046 addr: *posix.sockaddr,
4047 addr_len: *posix.socklen_t,
4048) !void {
4049 try current_thread.beginSyscall();
3475 while (true) {4050 while (true) {
3476 try t.checkCancel();
3477 switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) {4051 switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) {
3478 .SUCCESS => break,4052 .SUCCESS => {
3479 .INTR => continue,4053 current_thread.endSyscall();
3480 .CANCELED => return error.Canceled,4054 break;
34814055 },
3482 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4056 .INTR => {
3483 .FAULT => |err| return errnoBug(err),4057 try current_thread.checkCancel();
3484 .INVAL => |err| return errnoBug(err), // invalid parameters4058 continue;
3485 .NOTSOCK => |err| return errnoBug(err), // always a race condition4059 },
3486 .NOBUFS => return error.SystemResources,4060 else => |e| {
3487 else => |err| return posix.unexpectedErrno(err),4061 current_thread.endSyscall();
4062 switch (e) {
4063 .CANCELED => return error.Canceled,
4064 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4065 .FAULT => |err| return errnoBug(err),
4066 .INVAL => |err| return errnoBug(err), // invalid parameters
4067 .NOTSOCK => |err| return errnoBug(err), // always a race condition
4068 .NOBUFS => return error.SystemResources,
4069 else => |err| return posix.unexpectedErrno(err),
4070 }
4071 },
3488 }4072 }
3489 }4073 }
3490}4074}
34914075
3492fn wsaGetSockName(t: *Threaded, handle: ws2_32.SOCKET, addr: *ws2_32.sockaddr, addr_len: *i32) !void {4076fn wsaGetSockName(
4077 t: *Threaded,
4078 current_thread: *Thread,
4079 handle: ws2_32.SOCKET,
4080 addr: *ws2_32.sockaddr,
4081 addr_len: *i32,
4082) !void {
4083 try current_thread.beginSyscall();
3493 while (true) {4084 while (true) {
3494 try t.checkCancel();
3495 const rc = ws2_32.getsockname(handle, addr, addr_len);4085 const rc = ws2_32.getsockname(handle, addr, addr_len);
3496 if (rc != ws2_32.SOCKET_ERROR) break;4086 if (rc != ws2_32.SOCKET_ERROR) {
4087 current_thread.endSyscall();
4088 return;
4089 }
3497 switch (ws2_32.WSAGetLastError()) {4090 switch (ws2_32.WSAGetLastError()) {
3498 .EINTR => continue,4091 .EINTR => {
3499 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4092 try current_thread.checkCancel();
4093 continue;
4094 },
3500 .NOTINITIALISED => {4095 .NOTINITIALISED => {
3501 try initializeWsa(t);4096 try initializeWsa(t);
4097 try current_thread.checkCancel();
3502 continue;4098 continue;
3503 },4099 },
3504 .ENETDOWN => return error.NetworkDown,4100 else => |e| {
3505 .EFAULT => |err| return wsaErrorBug(err),4101 current_thread.endSyscall();
3506 .ENOTSOCK => |err| return wsaErrorBug(err),4102 switch (e) {
3507 .EINVAL => |err| return wsaErrorBug(err),4103 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3508 else => |err| return windows.unexpectedWSAError(err),4104 .ENETDOWN => return error.NetworkDown,
4105 .EFAULT => |err| return wsaErrorBug(err),
4106 .ENOTSOCK => |err| return wsaErrorBug(err),
4107 .EINVAL => |err| return wsaErrorBug(err),
4108 else => |err| return windows.unexpectedWSAError(err),
4109 }
4110 },
3509 }4111 }
3510 }4112 }
3511}4113}
35124114
3513fn setSocketOption(t: *Threaded, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {4115fn setSocketOption(current_thread: *Thread, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
3514 const o: []const u8 = @ptrCast(&option);4116 const o: []const u8 = @ptrCast(&option);
4117 try current_thread.beginSyscall();
3515 while (true) {4118 while (true) {
3516 try t.checkCancel();
3517 switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) {4119 switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) {
3518 .SUCCESS => return,4120 .SUCCESS => {
3519 .INTR => continue,4121 current_thread.endSyscall();
3520 .CANCELED => return error.Canceled,4122 return;
35214123 },
3522 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4124 .INTR => {
3523 .NOTSOCK => |err| return errnoBug(err),4125 try current_thread.checkCancel();
3524 .INVAL => |err| return errnoBug(err),4126 continue;
3525 .FAULT => |err| return errnoBug(err),4127 },
3526 else => |err| return posix.unexpectedErrno(err),4128 else => |e| {
4129 current_thread.endSyscall();
4130 switch (e) {
4131 .CANCELED => return error.Canceled,
4132 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4133 .NOTSOCK => |err| return errnoBug(err),
4134 .INVAL => |err| return errnoBug(err),
4135 .FAULT => |err| return errnoBug(err),
4136 else => |err| return posix.unexpectedErrno(err),
4137 }
4138 },
3527 }4139 }
3528 }4140 }
3529}4141}
...@@ -3557,16 +4169,17 @@ fn netConnectIpPosix(...@@ -3557,16 +4169,17 @@ fn netConnectIpPosix(
3557 if (!have_networking) return error.NetworkDown;4169 if (!have_networking) return error.NetworkDown;
3558 if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");4170 if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");
3559 const t: *Threaded = @ptrCast(@alignCast(userdata));4171 const t: *Threaded = @ptrCast(@alignCast(userdata));
4172 const current_thread = Thread.getCurrent(t);
3560 const family = posixAddressFamily(address);4173 const family = posixAddressFamily(address);
3561 const socket_fd = try openSocketPosix(t, family, .{4174 const socket_fd = try openSocketPosix(current_thread, family, .{
3562 .mode = options.mode,4175 .mode = options.mode,
3563 .protocol = options.protocol,4176 .protocol = options.protocol,
3564 });4177 });
3565 errdefer posix.close(socket_fd);4178 errdefer posix.close(socket_fd);
3566 var storage: PosixAddress = undefined;4179 var storage: PosixAddress = undefined;
3567 var addr_len = addressToPosix(address, &storage);4180 var addr_len = addressToPosix(address, &storage);
3568 try posixConnect(t, socket_fd, &storage.any, addr_len);4181 try posixConnect(current_thread, socket_fd, &storage.any, addr_len);
3569 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);4182 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
3570 return .{ .socket = .{4183 return .{ .socket = .{
3571 .handle = socket_fd,4184 .handle = socket_fd,
3572 .address = addressFromPosix(&storage),4185 .address = addressFromPosix(&storage),
...@@ -3581,8 +4194,9 @@ fn netConnectIpWindows(...@@ -3581,8 +4194,9 @@ fn netConnectIpWindows(
3581 if (!have_networking) return error.NetworkDown;4194 if (!have_networking) return error.NetworkDown;
3582 if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");4195 if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");
3583 const t: *Threaded = @ptrCast(@alignCast(userdata));4196 const t: *Threaded = @ptrCast(@alignCast(userdata));
4197 const current_thread = Thread.getCurrent(t);
3584 const family = posixAddressFamily(address);4198 const family = posixAddressFamily(address);
3585 const socket_handle = try openSocketWsa(t, family, .{4199 const socket_handle = try openSocketWsa(t, current_thread, family, .{
3586 .mode = options.mode,4200 .mode = options.mode,
3587 .protocol = options.protocol,4201 .protocol = options.protocol,
3588 });4202 });
...@@ -3591,36 +4205,48 @@ fn netConnectIpWindows(...@@ -3591,36 +4205,48 @@ fn netConnectIpWindows(
3591 var storage: WsaAddress = undefined;4205 var storage: WsaAddress = undefined;
3592 var addr_len = addressToWsa(address, &storage);4206 var addr_len = addressToWsa(address, &storage);
35934207
4208 try current_thread.beginSyscall();
3594 while (true) {4209 while (true) {
3595 const rc = ws2_32.connect(socket_handle, &storage.any, addr_len);4210 const rc = ws2_32.connect(socket_handle, &storage.any, addr_len);
3596 if (rc != ws2_32.SOCKET_ERROR) break;4211 if (rc != ws2_32.SOCKET_ERROR) {
4212 current_thread.endSyscall();
4213 break;
4214 }
3597 switch (ws2_32.WSAGetLastError()) {4215 switch (ws2_32.WSAGetLastError()) {
3598 .EINTR => continue,4216 .EINTR => {
3599 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4217 try current_thread.checkCancel();
4218 continue;
4219 },
3600 .NOTINITIALISED => {4220 .NOTINITIALISED => {
3601 try initializeWsa(t);4221 try initializeWsa(t);
4222 try current_thread.checkCancel();
3602 continue;4223 continue;
3603 },4224 },
36044225 else => |e| {
3605 .EADDRNOTAVAIL => return error.AddressUnavailable,4226 current_thread.endSyscall();
3606 .ECONNREFUSED => return error.ConnectionRefused,4227 switch (e) {
3607 .ECONNRESET => return error.ConnectionResetByPeer,4228 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3608 .ETIMEDOUT => return error.Timeout,4229 .EADDRNOTAVAIL => return error.AddressUnavailable,
3609 .EHOSTUNREACH => return error.HostUnreachable,4230 .ECONNREFUSED => return error.ConnectionRefused,
3610 .ENETUNREACH => return error.NetworkUnreachable,4231 .ECONNRESET => return error.ConnectionResetByPeer,
3611 .EFAULT => |err| return wsaErrorBug(err),4232 .ETIMEDOUT => return error.Timeout,
3612 .EINVAL => |err| return wsaErrorBug(err),4233 .EHOSTUNREACH => return error.HostUnreachable,
3613 .EISCONN => |err| return wsaErrorBug(err),4234 .ENETUNREACH => return error.NetworkUnreachable,
3614 .ENOTSOCK => |err| return wsaErrorBug(err),4235 .EFAULT => |err| return wsaErrorBug(err),
3615 .EWOULDBLOCK => return error.WouldBlock,4236 .EINVAL => |err| return wsaErrorBug(err),
3616 .EACCES => return error.AccessDenied,4237 .EISCONN => |err| return wsaErrorBug(err),
3617 .ENOBUFS => return error.SystemResources,4238 .ENOTSOCK => |err| return wsaErrorBug(err),
3618 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,4239 .EWOULDBLOCK => return error.WouldBlock,
3619 else => |err| return windows.unexpectedWSAError(err),4240 .EACCES => return error.AccessDenied,
4241 .ENOBUFS => return error.SystemResources,
4242 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4243 else => |err| return windows.unexpectedWSAError(err),
4244 }
4245 },
3620 }4246 }
3621 }4247 }
36224248
3623 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);4249 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
36244250
3625 return .{ .socket = .{4251 return .{ .socket = .{
3626 .handle = socket_handle,4252 .handle = socket_handle,
...@@ -3645,14 +4271,15 @@ fn netConnectUnixPosix(...@@ -3645,14 +4271,15 @@ fn netConnectUnixPosix(
3645) net.UnixAddress.ConnectError!net.Socket.Handle {4271) net.UnixAddress.ConnectError!net.Socket.Handle {
3646 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;4272 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3647 const t: *Threaded = @ptrCast(@alignCast(userdata));4273 const t: *Threaded = @ptrCast(@alignCast(userdata));
3648 const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {4274 const current_thread = Thread.getCurrent(t);
4275 const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
3649 error.OptionUnsupported => return error.Unexpected,4276 error.OptionUnsupported => return error.Unexpected,
3650 else => |e| return e,4277 else => |e| return e,
3651 };4278 };
3652 errdefer posix.close(socket_fd);4279 errdefer posix.close(socket_fd);
3653 var storage: UnixAddress = undefined;4280 var storage: UnixAddress = undefined;
3654 const addr_len = addressUnixToPosix(address, &storage);4281 const addr_len = addressUnixToPosix(address, &storage);
3655 try posixConnectUnix(t, socket_fd, &storage.any, addr_len);4282 try posixConnectUnix(current_thread, socket_fd, &storage.any, addr_len);
3656 return socket_fd;4283 return socket_fd;
3657}4284}
36584285
...@@ -3662,8 +4289,9 @@ fn netConnectUnixWindows(...@@ -3662,8 +4289,9 @@ fn netConnectUnixWindows(
3662) net.UnixAddress.ConnectError!net.Socket.Handle {4289) net.UnixAddress.ConnectError!net.Socket.Handle {
3663 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;4290 if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
3664 const t: *Threaded = @ptrCast(@alignCast(userdata));4291 const t: *Threaded = @ptrCast(@alignCast(userdata));
4292 const current_thread = Thread.getCurrent(t);
36654293
3666 const socket_handle = try openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream });4294 const socket_handle = try openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream });
3667 errdefer closeSocketWindows(socket_handle);4295 errdefer closeSocketWindows(socket_handle);
3668 var storage: WsaAddress = undefined;4296 var storage: WsaAddress = undefined;
3669 const addr_len = addressUnixToWsa(address, &storage);4297 const addr_len = addressUnixToWsa(address, &storage);
...@@ -3711,13 +4339,14 @@ fn netBindIpPosix(...@@ -3711,13 +4339,14 @@ fn netBindIpPosix(
3711) IpAddress.BindError!net.Socket {4339) IpAddress.BindError!net.Socket {
3712 if (!have_networking) return error.NetworkDown;4340 if (!have_networking) return error.NetworkDown;
3713 const t: *Threaded = @ptrCast(@alignCast(userdata));4341 const t: *Threaded = @ptrCast(@alignCast(userdata));
4342 const current_thread = Thread.getCurrent(t);
3714 const family = posixAddressFamily(address);4343 const family = posixAddressFamily(address);
3715 const socket_fd = try openSocketPosix(t, family, options);4344 const socket_fd = try openSocketPosix(current_thread, family, options);
3716 errdefer posix.close(socket_fd);4345 errdefer posix.close(socket_fd);
3717 var storage: PosixAddress = undefined;4346 var storage: PosixAddress = undefined;
3718 var addr_len = addressToPosix(address, &storage);4347 var addr_len = addressToPosix(address, &storage);
3719 try posixBind(t, socket_fd, &storage.any, addr_len);4348 try posixBind(current_thread, socket_fd, &storage.any, addr_len);
3720 try posixGetSockName(t, socket_fd, &storage.any, &addr_len);4349 try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
3721 return .{4350 return .{
3722 .handle = socket_fd,4351 .handle = socket_fd,
3723 .address = addressFromPosix(&storage),4352 .address = addressFromPosix(&storage),
...@@ -3731,8 +4360,9 @@ fn netBindIpWindows(...@@ -3731,8 +4360,9 @@ fn netBindIpWindows(
3731) IpAddress.BindError!net.Socket {4360) IpAddress.BindError!net.Socket {
3732 if (!have_networking) return error.NetworkDown;4361 if (!have_networking) return error.NetworkDown;
3733 const t: *Threaded = @ptrCast(@alignCast(userdata));4362 const t: *Threaded = @ptrCast(@alignCast(userdata));
4363 const current_thread = Thread.getCurrent(t);
3734 const family = posixAddressFamily(address);4364 const family = posixAddressFamily(address);
3735 const socket_handle = try openSocketWsa(t, family, .{4365 const socket_handle = try openSocketWsa(t, current_thread, family, .{
3736 .mode = options.mode,4366 .mode = options.mode,
3737 .protocol = options.protocol,4367 .protocol = options.protocol,
3738 });4368 });
...@@ -3741,29 +4371,41 @@ fn netBindIpWindows(...@@ -3741,29 +4371,41 @@ fn netBindIpWindows(
3741 var storage: WsaAddress = undefined;4371 var storage: WsaAddress = undefined;
3742 var addr_len = addressToWsa(address, &storage);4372 var addr_len = addressToWsa(address, &storage);
37434373
4374 try current_thread.beginSyscall();
3744 while (true) {4375 while (true) {
3745 try t.checkCancel();
3746 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);4376 const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
3747 if (rc != ws2_32.SOCKET_ERROR) break;4377 if (rc != ws2_32.SOCKET_ERROR) {
4378 current_thread.endSyscall();
4379 break;
4380 }
3748 switch (ws2_32.WSAGetLastError()) {4381 switch (ws2_32.WSAGetLastError()) {
3749 .EINTR => continue,4382 .EINTR => {
3750 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4383 try current_thread.checkCancel();
4384 continue;
4385 },
3751 .NOTINITIALISED => {4386 .NOTINITIALISED => {
3752 try initializeWsa(t);4387 try initializeWsa(t);
4388 try current_thread.checkCancel();
3753 continue;4389 continue;
3754 },4390 },
3755 .EADDRINUSE => return error.AddressInUse,4391 else => |e| {
3756 .EADDRNOTAVAIL => return error.AddressUnavailable,4392 current_thread.endSyscall();
3757 .ENOTSOCK => |err| return wsaErrorBug(err),4393 switch (e) {
3758 .EFAULT => |err| return wsaErrorBug(err),4394 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3759 .EINVAL => |err| return wsaErrorBug(err),4395 .EADDRINUSE => return error.AddressInUse,
3760 .ENOBUFS => return error.SystemResources,4396 .EADDRNOTAVAIL => return error.AddressUnavailable,
3761 .ENETDOWN => return error.NetworkDown,4397 .ENOTSOCK => |err| return wsaErrorBug(err),
3762 else => |err| return windows.unexpectedWSAError(err),4398 .EFAULT => |err| return wsaErrorBug(err),
4399 .EINVAL => |err| return wsaErrorBug(err),
4400 .ENOBUFS => return error.SystemResources,
4401 .ENETDOWN => return error.NetworkDown,
4402 else => |err| return windows.unexpectedWSAError(err),
4403 }
4404 },
3763 }4405 }
3764 }4406 }
37654407
3766 try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);4408 try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
37674409
3768 return .{4410 return .{
3769 .handle = socket_handle,4411 .handle = socket_handle,
...@@ -3783,7 +4425,7 @@ fn netBindIpUnavailable(...@@ -3783,7 +4425,7 @@ fn netBindIpUnavailable(
3783}4425}
37844426
3785fn openSocketPosix(4427fn openSocketPosix(
3786 t: *Threaded,4428 current_thread: *Thread,
3787 family: posix.sa_family_t,4429 family: posix.sa_family_t,
3788 options: IpAddress.BindOptions,4430 options: IpAddress.BindOptions,
3789) error{4431) error{
...@@ -3800,8 +4442,8 @@ fn openSocketPosix(...@@ -3800,8 +4442,8 @@ fn openSocketPosix(
3800}!posix.socket_t {4442}!posix.socket_t {
3801 const mode = posixSocketMode(options.mode);4443 const mode = posixSocketMode(options.mode);
3802 const protocol = posixProtocol(options.protocol);4444 const protocol = posixProtocol(options.protocol);
4445 try current_thread.beginSyscall();
3803 const socket_fd = while (true) {4446 const socket_fd = while (true) {
3804 try t.checkCancel();
3805 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;4447 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
3806 const socket_rc = posix.system.socket(family, flags, protocol);4448 const socket_rc = posix.system.socket(family, flags, protocol);
3807 switch (posix.errno(socket_rc)) {4449 switch (posix.errno(socket_rc)) {
...@@ -3809,60 +4451,90 @@ fn openSocketPosix(...@@ -3809,60 +4451,90 @@ fn openSocketPosix(
3809 const fd: posix.fd_t = @intCast(socket_rc);4451 const fd: posix.fd_t = @intCast(socket_rc);
3810 errdefer posix.close(fd);4452 errdefer posix.close(fd);
3811 if (socket_flags_unsupported) while (true) {4453 if (socket_flags_unsupported) while (true) {
3812 try t.checkCancel();4454 try current_thread.checkCancel();
3813 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {4455 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
3814 .SUCCESS => break,4456 .SUCCESS => break,
3815 .INTR => continue,4457 .INTR => continue,
3816 .CANCELED => return error.Canceled,4458 else => |e| {
3817 else => |err| return posix.unexpectedErrno(err),4459 current_thread.endSyscall();
4460 switch (e) {
4461 .CANCELED => return error.Canceled,
4462 else => |err| return posix.unexpectedErrno(err),
4463 }
4464 },
3818 }4465 }
3819 };4466 };
4467 current_thread.endSyscall();
3820 break fd;4468 break fd;
3821 },4469 },
3822 .INTR => continue,4470 .INTR => {
3823 .CANCELED => return error.Canceled,4471 try current_thread.checkCancel();
38244472 continue;
3825 .AFNOSUPPORT => return error.AddressFamilyUnsupported,4473 },
3826 .INVAL => return error.ProtocolUnsupportedBySystem,4474 else => |e| {
3827 .MFILE => return error.ProcessFdQuotaExceeded,4475 current_thread.endSyscall();
3828 .NFILE => return error.SystemFdQuotaExceeded,4476 switch (e) {
3829 .NOBUFS => return error.SystemResources,4477 .CANCELED => return error.Canceled,
3830 .NOMEM => return error.SystemResources,4478 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
3831 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,4479 .INVAL => return error.ProtocolUnsupportedBySystem,
3832 .PROTOTYPE => return error.SocketModeUnsupported,4480 .MFILE => return error.ProcessFdQuotaExceeded,
3833 else => |err| return posix.unexpectedErrno(err),4481 .NFILE => return error.SystemFdQuotaExceeded,
4482 .NOBUFS => return error.SystemResources,
4483 .NOMEM => return error.SystemResources,
4484 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
4485 .PROTOTYPE => return error.SocketModeUnsupported,
4486 else => |err| return posix.unexpectedErrno(err),
4487 }
4488 },
3834 }4489 }
3835 };4490 };
3836 errdefer posix.close(socket_fd);4491 errdefer posix.close(socket_fd);
38374492
3838 if (options.ip6_only) {4493 if (options.ip6_only) {
3839 if (posix.IPV6 == void) return error.OptionUnsupported;4494 if (posix.IPV6 == void) return error.OptionUnsupported;
3840 try setSocketOption(t, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);4495 try setSocketOption(current_thread, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
3841 }4496 }
38424497
3843 return socket_fd;4498 return socket_fd;
3844}4499}
38454500
3846fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.BindOptions) !ws2_32.SOCKET {4501fn openSocketWsa(
4502 t: *Threaded,
4503 current_thread: *Thread,
4504 family: posix.sa_family_t,
4505 options: IpAddress.BindOptions,
4506) !ws2_32.SOCKET {
3847 const mode = posixSocketMode(options.mode);4507 const mode = posixSocketMode(options.mode);
3848 const protocol = posixProtocol(options.protocol);4508 const protocol = posixProtocol(options.protocol);
3849 const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;4509 const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
4510 try current_thread.beginSyscall();
3850 while (true) {4511 while (true) {
3851 try t.checkCancel();
3852 const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);4512 const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);
3853 if (rc != ws2_32.INVALID_SOCKET) return rc;4513 if (rc != ws2_32.INVALID_SOCKET) {
4514 current_thread.endSyscall();
4515 return rc;
4516 }
3854 switch (ws2_32.WSAGetLastError()) {4517 switch (ws2_32.WSAGetLastError()) {
3855 .EINTR => continue,4518 .EINTR => {
3856 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4519 try current_thread.checkCancel();
4520 continue;
4521 },
3857 .NOTINITIALISED => {4522 .NOTINITIALISED => {
3858 try initializeWsa(t);4523 try initializeWsa(t);
4524 try current_thread.checkCancel();
3859 continue;4525 continue;
3860 },4526 },
3861 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,4527 else => |e| {
3862 .EMFILE => return error.ProcessFdQuotaExceeded,4528 current_thread.endSyscall();
3863 .ENOBUFS => return error.SystemResources,4529 switch (e) {
3864 .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,4530 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3865 else => |err| return windows.unexpectedWSAError(err),4531 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4532 .EMFILE => return error.ProcessFdQuotaExceeded,
4533 .ENOBUFS => return error.SystemResources,
4534 .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
4535 else => |err| return windows.unexpectedWSAError(err),
4536 }
4537 },
3866 }4538 }
3867 }4539 }
3868}4540}
...@@ -3870,10 +4542,11 @@ fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.Bin...@@ -3870,10 +4542,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 {4542fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {
3871 if (!have_networking) return error.NetworkDown;4543 if (!have_networking) return error.NetworkDown;
3872 const t: *Threaded = @ptrCast(@alignCast(userdata));4544 const t: *Threaded = @ptrCast(@alignCast(userdata));
4545 const current_thread = Thread.getCurrent(t);
3873 var storage: PosixAddress = undefined;4546 var storage: PosixAddress = undefined;
3874 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);4547 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);
4548 try current_thread.beginSyscall();
3875 const fd = while (true) {4549 const fd = while (true) {
3876 try t.checkCancel();
3877 const rc = if (have_accept4)4550 const rc = if (have_accept4)
3878 posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC)4551 posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC)
3879 else4552 else
...@@ -3883,33 +4556,43 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve...@@ -3883,33 +4556,43 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
3883 const fd: posix.fd_t = @intCast(rc);4556 const fd: posix.fd_t = @intCast(rc);
3884 errdefer posix.close(fd);4557 errdefer posix.close(fd);
3885 if (!have_accept4) while (true) {4558 if (!have_accept4) while (true) {
3886 try t.checkCancel();4559 try current_thread.checkCancel();
3887 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {4560 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
3888 .SUCCESS => break,4561 .SUCCESS => break,
3889 .INTR => continue,4562 .INTR => continue,
3890 .CANCELED => return error.Canceled,4563 else => |err| {
3891 else => |err| return posix.unexpectedErrno(err),4564 current_thread.endSyscall();
4565 return posix.unexpectedErrno(err);
4566 },
3892 }4567 }
3893 };4568 };
4569 current_thread.endSyscall();
3894 break fd;4570 break fd;
3895 },4571 },
3896 .INTR => continue,4572 .INTR => {
3897 .CANCELED => return error.Canceled,4573 try current_thread.checkCancel();
38984574 continue;
3899 .AGAIN => |err| return errnoBug(err),4575 },
3900 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4576 else => |e| {
3901 .CONNABORTED => return error.ConnectionAborted,4577 current_thread.endSyscall();
3902 .FAULT => |err| return errnoBug(err),4578 switch (e) {
3903 .INVAL => return error.SocketNotListening,4579 .CANCELED => return error.Canceled,
3904 .NOTSOCK => |err| return errnoBug(err),4580 .AGAIN => |err| return errnoBug(err),
3905 .MFILE => return error.ProcessFdQuotaExceeded,4581 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
3906 .NFILE => return error.SystemFdQuotaExceeded,4582 .CONNABORTED => return error.ConnectionAborted,
3907 .NOBUFS => return error.SystemResources,4583 .FAULT => |err| return errnoBug(err),
3908 .NOMEM => return error.SystemResources,4584 .INVAL => return error.SocketNotListening,
3909 .OPNOTSUPP => |err| return errnoBug(err),4585 .NOTSOCK => |err| return errnoBug(err),
3910 .PROTO => return error.ProtocolFailure,4586 .MFILE => return error.ProcessFdQuotaExceeded,
3911 .PERM => return error.BlockedByFirewall,4587 .NFILE => return error.SystemFdQuotaExceeded,
3912 else => |err| return posix.unexpectedErrno(err),4588 .NOBUFS => return error.SystemResources,
4589 .NOMEM => return error.SystemResources,
4590 .OPNOTSUPP => |err| return errnoBug(err),
4591 .PROTO => return error.ProtocolFailure,
4592 .PERM => return error.BlockedByFirewall,
4593 else => |err| return posix.unexpectedErrno(err),
4594 }
4595 },
3913 }4596 }
3914 };4597 };
3915 return .{ .socket = .{4598 return .{ .socket = .{
...@@ -3921,31 +4604,44 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve...@@ -3921,31 +4604,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 {4604fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream {
3922 if (!have_networking) return error.NetworkDown;4605 if (!have_networking) return error.NetworkDown;
3923 const t: *Threaded = @ptrCast(@alignCast(userdata));4606 const t: *Threaded = @ptrCast(@alignCast(userdata));
4607 const current_thread = Thread.getCurrent(t);
3924 var storage: WsaAddress = undefined;4608 var storage: WsaAddress = undefined;
3925 var addr_len: i32 = @sizeOf(WsaAddress);4609 var addr_len: i32 = @sizeOf(WsaAddress);
4610 try current_thread.beginSyscall();
3926 while (true) {4611 while (true) {
3927 try t.checkCancel();
3928 const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);4612 const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);
3929 if (rc != ws2_32.INVALID_SOCKET) return .{ .socket = .{4613 if (rc != ws2_32.INVALID_SOCKET) {
3930 .handle = rc,4614 current_thread.endSyscall();
3931 .address = addressFromWsa(&storage),4615 return .{ .socket = .{
3932 } };4616 .handle = rc,
4617 .address = addressFromWsa(&storage),
4618 } };
4619 }
3933 switch (ws2_32.WSAGetLastError()) {4620 switch (ws2_32.WSAGetLastError()) {
3934 .EINTR => continue,4621 .EINTR => {
3935 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,4622 try current_thread.checkCancel();
4623 continue;
4624 },
3936 .NOTINITIALISED => {4625 .NOTINITIALISED => {
3937 try initializeWsa(t);4626 try initializeWsa(t);
4627 try current_thread.checkCancel();
3938 continue;4628 continue;
3939 },4629 },
3940 .ECONNRESET => return error.ConnectionAborted,4630 else => |e| {
3941 .EFAULT => |err| return wsaErrorBug(err),4631 current_thread.endSyscall();
3942 .ENOTSOCK => |err| return wsaErrorBug(err),4632 switch (e) {
3943 .EINVAL => |err| return wsaErrorBug(err),4633 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
3944 .EMFILE => return error.ProcessFdQuotaExceeded,4634 .ECONNRESET => return error.ConnectionAborted,
3945 .ENETDOWN => return error.NetworkDown,4635 .EFAULT => |err| return wsaErrorBug(err),
3946 .ENOBUFS => return error.SystemResources,4636 .ENOTSOCK => |err| return wsaErrorBug(err),
3947 .EOPNOTSUPP => |err| return wsaErrorBug(err),4637 .EINVAL => |err| return wsaErrorBug(err),
3948 else => |err| return windows.unexpectedWSAError(err),4638 .EMFILE => return error.ProcessFdQuotaExceeded,
4639 .ENETDOWN => return error.NetworkDown,
4640 .ENOBUFS => return error.SystemResources,
4641 .EOPNOTSUPP => |err| return wsaErrorBug(err),
4642 else => |err| return windows.unexpectedWSAError(err),
4643 }
4644 },
3949 }4645 }
3950 }4646 }
3951}4647}
...@@ -3959,6 +4655,7 @@ fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle)...@@ -3959,6 +4655,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 {4655fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
3960 if (!have_networking) return error.NetworkDown;4656 if (!have_networking) return error.NetworkDown;
3961 const t: *Threaded = @ptrCast(@alignCast(userdata));4657 const t: *Threaded = @ptrCast(@alignCast(userdata));
4658 const current_thread = Thread.getCurrent(t);
39624659
3963 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;4660 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
3964 var i: usize = 0;4661 var i: usize = 0;
...@@ -3972,48 +4669,70 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net....@@ -3972,48 +4669,70 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
3972 const dest = iovecs_buffer[0..i];4669 const dest = iovecs_buffer[0..i];
3973 assert(dest[0].len > 0);4670 assert(dest[0].len > 0);
39744671
3975 if (native_os == .wasi and !builtin.link_libc) while (true) {4672 if (native_os == .wasi and !builtin.link_libc) {
3976 try t.checkCancel();4673 try current_thread.beginSyscall();
3977 var n: usize = undefined;4674 while (true) {
3978 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {4675 var n: usize = undefined;
3979 .SUCCESS => return n,4676 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
3980 .INTR => continue,4677 .SUCCESS => {
3981 .CANCELED => return error.Canceled,4678 current_thread.endSyscall();
39824679 return n;
3983 .INVAL => |err| return errnoBug(err),4680 },
3984 .FAULT => |err| return errnoBug(err),4681 .INTR => {
3985 .AGAIN => |err| return errnoBug(err),4682 try current_thread.checkCancel();
3986 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4683 continue;
3987 .NOBUFS => return error.SystemResources,4684 },
3988 .NOMEM => return error.SystemResources,4685 else => |e| {
3989 .NOTCONN => return error.SocketUnconnected,4686 current_thread.endSyscall();
3990 .CONNRESET => return error.ConnectionResetByPeer,4687 switch (e) {
3991 .TIMEDOUT => return error.Timeout,4688 .CANCELED => return error.Canceled,
3992 .NOTCAPABLE => return error.AccessDenied,4689 .INVAL => |err| return errnoBug(err),
3993 else => |err| return posix.unexpectedErrno(err),4690 .FAULT => |err| return errnoBug(err),
4691 .AGAIN => |err| return errnoBug(err),
4692 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4693 .NOBUFS => return error.SystemResources,
4694 .NOMEM => return error.SystemResources,
4695 .NOTCONN => return error.SocketUnconnected,
4696 .CONNRESET => return error.ConnectionResetByPeer,
4697 .TIMEDOUT => return error.Timeout,
4698 .NOTCAPABLE => return error.AccessDenied,
4699 else => |err| return posix.unexpectedErrno(err),
4700 }
4701 },
4702 }
3994 }4703 }
3995 };4704 }
39964705
4706 try current_thread.beginSyscall();
3997 while (true) {4707 while (true) {
3998 try t.checkCancel();
3999 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));4708 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
4000 switch (posix.errno(rc)) {4709 switch (posix.errno(rc)) {
4001 .SUCCESS => return @intCast(rc),4710 .SUCCESS => {
4002 .INTR => continue,4711 current_thread.endSyscall();
4003 .CANCELED => return error.Canceled,4712 return @intCast(rc);
40044713 },
4005 .INVAL => |err| return errnoBug(err),4714 .INTR => {
4006 .FAULT => |err| return errnoBug(err),4715 try current_thread.checkCancel();
4007 .AGAIN => |err| return errnoBug(err),4716 continue;
4008 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4717 },
4009 .NOBUFS => return error.SystemResources,4718 else => |e| {
4010 .NOMEM => return error.SystemResources,4719 current_thread.endSyscall();
4011 .NOTCONN => return error.SocketUnconnected,4720 switch (e) {
4012 .CONNRESET => return error.ConnectionResetByPeer,4721 .CANCELED => return error.Canceled,
4013 .TIMEDOUT => return error.Timeout,4722 .INVAL => |err| return errnoBug(err),
4014 .PIPE => return error.SocketUnconnected,4723 .FAULT => |err| return errnoBug(err),
4015 .NETDOWN => return error.NetworkDown,4724 .AGAIN => |err| return errnoBug(err),
4016 else => |err| return posix.unexpectedErrno(err),4725 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4726 .NOBUFS => return error.SystemResources,
4727 .NOMEM => return error.SystemResources,
4728 .NOTCONN => return error.SocketUnconnected,
4729 .CONNRESET => return error.ConnectionResetByPeer,
4730 .TIMEDOUT => return error.Timeout,
4731 .PIPE => return error.SocketUnconnected,
4732 .NETDOWN => return error.NetworkDown,
4733 else => |err| return posix.unexpectedErrno(err),
4734 }
4735 },
4017 }4736 }
4018 }4737 }
4019}4738}
...@@ -4021,6 +4740,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net....@@ -4021,6 +4740,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 {4740fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
4022 if (!have_networking) return error.NetworkDown;4741 if (!have_networking) return error.NetworkDown;
4023 const t: *Threaded = @ptrCast(@alignCast(userdata));4742 const t: *Threaded = @ptrCast(@alignCast(userdata));
4743 const current_thread = Thread.getCurrent(t);
40244744
4025 const bufs = b: {4745 const bufs = b: {
4026 var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined;4746 var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined;
...@@ -4048,7 +4768,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8...@@ -4048,7 +4768,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8
4048 };4768 };
40494769
4050 while (true) {4770 while (true) {
4051 try t.checkCancel();4771 try current_thread.checkCancel();
40524772
4053 var flags: u32 = 0;4773 var flags: u32 = 0;
4054 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);4774 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
...@@ -4108,6 +4828,7 @@ fn netSendPosix(...@@ -4108,6 +4828,7 @@ fn netSendPosix(
4108) struct { ?net.Socket.SendError, usize } {4828) struct { ?net.Socket.SendError, usize } {
4109 if (!have_networking) return .{ error.NetworkDown, 0 };4829 if (!have_networking) return .{ error.NetworkDown, 0 };
4110 const t: *Threaded = @ptrCast(@alignCast(userdata));4830 const t: *Threaded = @ptrCast(@alignCast(userdata));
4831 const current_thread = Thread.getCurrent(t);
41114832
4112 const posix_flags: u32 =4833 const posix_flags: u32 =
4113 @as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |4834 @as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |
...@@ -4120,10 +4841,10 @@ fn netSendPosix(...@@ -4120,10 +4841,10 @@ fn netSendPosix(
4120 var i: usize = 0;4841 var i: usize = 0;
4121 while (messages.len - i != 0) {4842 while (messages.len - i != 0) {
4122 if (have_sendmmsg) {4843 if (have_sendmmsg) {
4123 i += netSendMany(t, handle, messages[i..], posix_flags) catch |err| return .{ err, i };4844 i += netSendMany(current_thread, handle, messages[i..], posix_flags) catch |err| return .{ err, i };
4124 continue;4845 continue;
4125 }4846 }
4126 netSendOne(t, handle, &messages[i], posix_flags) catch |err| return .{ err, i };4847 netSendOne(t, current_thread, handle, &messages[i], posix_flags) catch |err| return .{ err, i };
4127 i += 1;4848 i += 1;
4128 }4849 }
4129 return .{ null, i };4850 return .{ null, i };
...@@ -4159,6 +4880,7 @@ fn netSendUnavailable(...@@ -4159,6 +4880,7 @@ fn netSendUnavailable(
41594880
4160fn netSendOne(4881fn netSendOne(
4161 t: *Threaded,4882 t: *Threaded,
4883 current_thread: *Thread,
4162 handle: net.Socket.Handle,4884 handle: net.Socket.Handle,
4163 message: *net.OutgoingMessage,4885 message: *net.OutgoingMessage,
4164 flags: u32,4886 flags: u32,
...@@ -4175,75 +4897,92 @@ fn netSendOne(...@@ -4175,75 +4897,92 @@ fn netSendOne(
4175 .controllen = @intCast(message.control.len),4897 .controllen = @intCast(message.control.len),
4176 .flags = 0,4898 .flags = 0,
4177 };4899 };
4900 try current_thread.beginSyscall();
4178 while (true) {4901 while (true) {
4179 try t.checkCancel();
4180 const rc = posix.system.sendmsg(handle, &msg, flags);4902 const rc = posix.system.sendmsg(handle, &msg, flags);
4181 if (is_windows) {4903 if (is_windows) {
4182 if (rc == ws2_32.SOCKET_ERROR) {4904 if (rc != ws2_32.SOCKET_ERROR) {
4183 switch (ws2_32.WSAGetLastError()) {4905 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);4906 message.data_len = @intCast(rc);
4210 return;4907 return;
4211 }4908 }
4909 switch (ws2_32.WSAGetLastError()) {
4910 .EINTR => {
4911 try current_thread.checkCancel();
4912 continue;
4913 },
4914 .NOTINITIALISED => {
4915 try initializeWsa(t);
4916 try current_thread.checkCancel();
4917 continue;
4918 },
4919 else => |e| {
4920 current_thread.endSyscall();
4921 switch (e) {
4922 .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
4923 .EACCES => return error.AccessDenied,
4924 .EADDRNOTAVAIL => return error.AddressUnavailable,
4925 .ECONNRESET => return error.ConnectionResetByPeer,
4926 .EMSGSIZE => return error.MessageOversize,
4927 .ENOBUFS => return error.SystemResources,
4928 .ENOTSOCK => return error.FileDescriptorNotASocket,
4929 .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
4930 .EDESTADDRREQ => unreachable, // A destination address is required.
4931 .EFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small.
4932 .EHOSTUNREACH => return error.NetworkUnreachable,
4933 .EINVAL => unreachable,
4934 .ENETDOWN => return error.NetworkDown,
4935 .ENETRESET => return error.ConnectionResetByPeer,
4936 .ENETUNREACH => return error.NetworkUnreachable,
4937 .ENOTCONN => return error.SocketUnconnected,
4938 .ESHUTDOWN => |err| return wsaErrorBug(err),
4939 else => |err| return windows.unexpectedWSAError(err),
4940 }
4941 },
4942 }
4212 }4943 }
4213 switch (posix.errno(rc)) {4944 switch (posix.errno(rc)) {
4214 .SUCCESS => {4945 .SUCCESS => {
4946 current_thread.endSyscall();
4215 message.data_len = @intCast(rc);4947 message.data_len = @intCast(rc);
4216 return;4948 return;
4217 },4949 },
4218 .INTR => continue,4950 .INTR => {
4219 .CANCELED => return error.Canceled,4951 try current_thread.checkCancel();
42204952 continue;
4221 .ACCES => return error.AccessDenied,4953 },
4222 .ALREADY => return error.FastOpenAlreadyInProgress,4954 else => |e| {
4223 .BADF => |err| return errnoBug(err), // File descriptor used after closed.4955 current_thread.endSyscall();
4224 .CONNRESET => return error.ConnectionResetByPeer,4956 switch (e) {
4225 .DESTADDRREQ => |err| return errnoBug(err),4957 .CANCELED => return error.Canceled,
4226 .FAULT => |err| return errnoBug(err),4958 .ACCES => return error.AccessDenied,
4227 .INVAL => |err| return errnoBug(err),4959 .ALREADY => return error.FastOpenAlreadyInProgress,
4228 .ISCONN => |err| return errnoBug(err),4960 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4229 .MSGSIZE => return error.MessageOversize,4961 .CONNRESET => return error.ConnectionResetByPeer,
4230 .NOBUFS => return error.SystemResources,4962 .DESTADDRREQ => |err| return errnoBug(err),
4231 .NOMEM => return error.SystemResources,4963 .FAULT => |err| return errnoBug(err),
4232 .NOTSOCK => |err| return errnoBug(err),4964 .INVAL => |err| return errnoBug(err),
4233 .OPNOTSUPP => |err| return errnoBug(err),4965 .ISCONN => |err| return errnoBug(err),
4234 .PIPE => return error.SocketUnconnected,4966 .MSGSIZE => return error.MessageOversize,
4235 .AFNOSUPPORT => return error.AddressFamilyUnsupported,4967 .NOBUFS => return error.SystemResources,
4236 .HOSTUNREACH => return error.HostUnreachable,4968 .NOMEM => return error.SystemResources,
4237 .NETUNREACH => return error.NetworkUnreachable,4969 .NOTSOCK => |err| return errnoBug(err),
4238 .NOTCONN => return error.SocketUnconnected,4970 .OPNOTSUPP => |err| return errnoBug(err),
4239 .NETDOWN => return error.NetworkDown,4971 .PIPE => return error.SocketUnconnected,
4240 else => |err| return posix.unexpectedErrno(err),4972 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
4973 .HOSTUNREACH => return error.HostUnreachable,
4974 .NETUNREACH => return error.NetworkUnreachable,
4975 .NOTCONN => return error.SocketUnconnected,
4976 .NETDOWN => return error.NetworkDown,
4977 else => |err| return posix.unexpectedErrno(err),
4978 }
4979 },
4241 }4980 }
4242 }4981 }
4243}4982}
42444983
4245fn netSendMany(4984fn netSendMany(
4246 t: *Threaded,4985 current_thread: *Thread,
4247 handle: net.Socket.Handle,4986 handle: net.Socket.Handle,
4248 messages: []net.OutgoingMessage,4987 messages: []net.OutgoingMessage,
4249 flags: u32,4988 flags: u32,
...@@ -4273,40 +5012,48 @@ fn netSendMany(...@@ -4273,40 +5012,48 @@ fn netSendMany(
4273 };5012 };
4274 }5013 }
42755014
5015 try current_thread.beginSyscall();
4276 while (true) {5016 while (true) {
4277 try t.checkCancel();
4278 const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags);5017 const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags);
4279 switch (posix.errno(rc)) {5018 switch (posix.errno(rc)) {
4280 .SUCCESS => {5019 .SUCCESS => {
5020 current_thread.endSyscall();
4281 const n: usize = @intCast(rc);5021 const n: usize = @intCast(rc);
4282 for (clamped_messages[0..n], clamped_msgs[0..n]) |*message, *msg| {5022 for (clamped_messages[0..n], clamped_msgs[0..n]) |*message, *msg| {
4283 message.data_len = msg.len;5023 message.data_len = msg.len;
4284 }5024 }
4285 return n;5025 return n;
4286 },5026 },
4287 .INTR => continue,5027 .INTR => {
4288 .CANCELED => return error.Canceled,5028 try current_thread.checkCancel();
42895029 continue;
4290 .AGAIN => |err| return errnoBug(err),5030 },
4291 .ALREADY => return error.FastOpenAlreadyInProgress,5031 else => |e| {
4292 .BADF => |err| return errnoBug(err), // File descriptor used after closed.5032 current_thread.endSyscall();
4293 .CONNRESET => return error.ConnectionResetByPeer,5033 switch (e) {
4294 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.5034 .CANCELED => return error.Canceled,
4295 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.5035 .AGAIN => |err| return errnoBug(err),
4296 .INVAL => |err| return errnoBug(err), // Invalid argument passed.5036 .ALREADY => return error.FastOpenAlreadyInProgress,
4297 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified5037 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
4298 .MSGSIZE => return error.MessageOversize,5038 .CONNRESET => return error.ConnectionResetByPeer,
4299 .NOBUFS => return error.SystemResources,5039 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
4300 .NOMEM => return error.SystemResources,5040 .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.5041 .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.5042 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
4303 .PIPE => return error.SocketUnconnected,5043 .MSGSIZE => return error.MessageOversize,
4304 .AFNOSUPPORT => return error.AddressFamilyUnsupported,5044 .NOBUFS => return error.SystemResources,
4305 .HOSTUNREACH => return error.HostUnreachable,5045 .NOMEM => return error.SystemResources,
4306 .NETUNREACH => return error.NetworkUnreachable,5046 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
4307 .NOTCONN => return error.SocketUnconnected,5047 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
4308 .NETDOWN => return error.NetworkDown,5048 .PIPE => return error.SocketUnconnected,
4309 else => |err| return posix.unexpectedErrno(err),5049 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
5050 .HOSTUNREACH => return error.HostUnreachable,
5051 .NETUNREACH => return error.NetworkUnreachable,
5052 .NOTCONN => return error.SocketUnconnected,
5053 .NETDOWN => return error.NetworkDown,
5054 else => |err| return posix.unexpectedErrno(err),
5055 }
5056 },
4310 }5057 }
4311 }5058 }
4312}5059}
...@@ -4321,6 +5068,7 @@ fn netReceivePosix(...@@ -4321,6 +5068,7 @@ fn netReceivePosix(
4321) struct { ?net.Socket.ReceiveTimeoutError, usize } {5068) struct { ?net.Socket.ReceiveTimeoutError, usize } {
4322 if (!have_networking) return .{ error.NetworkDown, 0 };5069 if (!have_networking) return .{ error.NetworkDown, 0 };
4323 const t: *Threaded = @ptrCast(@alignCast(userdata));5070 const t: *Threaded = @ptrCast(@alignCast(userdata));
5071 const current_thread = Thread.getCurrent(t);
4324 const t_io = io(t);5072 const t_io = io(t);
43255073
4326 // recvmmsg is useless, here's why:5074 // recvmmsg is useless, here's why:
...@@ -4351,8 +5099,6 @@ fn netReceivePosix(...@@ -4351,8 +5099,6 @@ fn netReceivePosix(
4351 const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i };5099 const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i };
43525100
4353 recv: while (true) {5101 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 };5102 if (message_buffer.len - message_i == 0) return .{ null, message_i };
4357 const message = &message_buffer[message_i];5103 const message = &message_buffer[message_i];
4358 const remaining_data_buffer = data_buffer[data_i..];5104 const remaining_data_buffer = data_buffer[data_i..];
...@@ -4368,7 +5114,9 @@ fn netReceivePosix(...@@ -4368,7 +5114,9 @@ fn netReceivePosix(
4368 .flags = undefined,5114 .flags = undefined,
4369 };5115 };
43705116
5117 current_thread.beginSyscall() catch |err| return .{ err, message_i };
4371 const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags);5118 const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags);
5119 current_thread.endSyscall();
4372 switch (posix.errno(recv_rc)) {5120 switch (posix.errno(recv_rc)) {
4373 .SUCCESS => {5121 .SUCCESS => {
4374 const data = remaining_data_buffer[0..@intCast(recv_rc)];5122 const data = remaining_data_buffer[0..@intCast(recv_rc)];
...@@ -4389,7 +5137,6 @@ fn netReceivePosix(...@@ -4389,7 +5137,6 @@ fn netReceivePosix(
4389 continue;5137 continue;
4390 },5138 },
4391 .AGAIN => while (true) {5139 .AGAIN => while (true) {
4392 t.checkCancel() catch |err| return .{ err, message_i };
4393 if (message_i != 0) return .{ null, message_i };5140 if (message_i != 0) return .{ null, message_i };
43945141
4395 const max_poll_ms = std.math.maxInt(u31);5142 const max_poll_ms = std.math.maxInt(u31);
...@@ -4399,7 +5146,10 @@ fn netReceivePosix(...@@ -4399,7 +5146,10 @@ fn netReceivePosix(
4399 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));5146 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
4400 } else max_poll_ms;5147 } else max_poll_ms;
44015148
5149 current_thread.beginSyscall() catch |err| return .{ err, message_i };
4402 const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);5150 const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
5151 current_thread.endSyscall();
5152
4403 switch (posix.errno(poll_rc)) {5153 switch (posix.errno(poll_rc)) {
4404 .SUCCESS => {5154 .SUCCESS => {
4405 if (poll_rc == 0) {5155 if (poll_rc == 0) {
...@@ -4486,6 +5236,7 @@ fn netWritePosix(...@@ -4486,6 +5236,7 @@ fn netWritePosix(
4486) net.Stream.Writer.Error!usize {5236) net.Stream.Writer.Error!usize {
4487 if (!have_networking) return error.NetworkDown;5237 if (!have_networking) return error.NetworkDown;
4488 const t: *Threaded = @ptrCast(@alignCast(userdata));5238 const t: *Threaded = @ptrCast(@alignCast(userdata));
5239 const current_thread = Thread.getCurrent(t);
44895240
4490 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;5241 var iovecs: [max_iovecs_len]posix.iovec_const = undefined;
4491 var msg: posix.msghdr_const = .{5242 var msg: posix.msghdr_const = .{
...@@ -4526,35 +5277,45 @@ fn netWritePosix(...@@ -4526,35 +5277,45 @@ fn netWritePosix(
4526 },5277 },
4527 };5278 };
4528 const flags = posix.MSG.NOSIGNAL;5279 const flags = posix.MSG.NOSIGNAL;
5280 try current_thread.beginSyscall();
4529 while (true) {5281 while (true) {
4530 try t.checkCancel();
4531 const rc = posix.system.sendmsg(fd, &msg, flags);5282 const rc = posix.system.sendmsg(fd, &msg, flags);
4532 switch (posix.errno(rc)) {5283 switch (posix.errno(rc)) {
4533 .SUCCESS => return @intCast(rc),5284 .SUCCESS => {
4534 .INTR => continue,5285 current_thread.endSyscall();
4535 .CANCELED => return error.Canceled,5286 return @intCast(rc);
45365287 },
4537 .ACCES => |err| return errnoBug(err),5288 .INTR => {
4538 .AGAIN => |err| return errnoBug(err),5289 try current_thread.checkCancel();
4539 .ALREADY => return error.FastOpenAlreadyInProgress,5290 continue;
4540 .BADF => |err| return errnoBug(err), // File descriptor used after closed.5291 },
4541 .CONNRESET => return error.ConnectionResetByPeer,5292 else => |e| {
4542 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.5293 current_thread.endSyscall();
4543 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.5294 switch (e) {
4544 .INVAL => |err| return errnoBug(err), // Invalid argument passed.5295 .CANCELED => return error.Canceled,
4545 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified5296 .ACCES => |err| return errnoBug(err),
4546 .MSGSIZE => |err| return errnoBug(err),5297 .AGAIN => |err| return errnoBug(err),
4547 .NOBUFS => return error.SystemResources,5298 .ALREADY => return error.FastOpenAlreadyInProgress,
4548 .NOMEM => return error.SystemResources,5299 .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.5300 .CONNRESET => return error.ConnectionResetByPeer,
4550 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.5301 .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
4551 .PIPE => return error.SocketUnconnected,5302 .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
4552 .AFNOSUPPORT => return error.AddressFamilyUnsupported,5303 .INVAL => |err| return errnoBug(err), // Invalid argument passed.
4553 .HOSTUNREACH => return error.HostUnreachable,5304 .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
4554 .NETUNREACH => return error.NetworkUnreachable,5305 .MSGSIZE => |err| return errnoBug(err),
4555 .NOTCONN => return error.SocketUnconnected,5306 .NOBUFS => return error.SystemResources,
4556 .NETDOWN => return error.NetworkDown,5307 .NOMEM => return error.SystemResources,
4557 else => |err| return posix.unexpectedErrno(err),5308 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
5309 .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
5310 .PIPE => return error.SocketUnconnected,
5311 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
5312 .HOSTUNREACH => return error.HostUnreachable,
5313 .NETUNREACH => return error.NetworkUnreachable,
5314 .NOTCONN => return error.SocketUnconnected,
5315 .NETDOWN => return error.NetworkDown,
5316 else => |err| return posix.unexpectedErrno(err),
5317 }
5318 },
4558 }5319 }
4559 }5320 }
4560}5321}
...@@ -4567,6 +5328,7 @@ fn netWriteWindows(...@@ -4567,6 +5328,7 @@ fn netWriteWindows(
4567 splat: usize,5328 splat: usize,
4568) net.Stream.Writer.Error!usize {5329) net.Stream.Writer.Error!usize {
4569 const t: *Threaded = @ptrCast(@alignCast(userdata));5330 const t: *Threaded = @ptrCast(@alignCast(userdata));
5331 const current_thread = Thread.getCurrent(t);
4570 comptime assert(native_os == .windows);5332 comptime assert(native_os == .windows);
45715333
4572 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;5334 var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;
...@@ -4600,7 +5362,7 @@ fn netWriteWindows(...@@ -4600,7 +5362,7 @@ fn netWriteWindows(
4600 };5362 };
46015363
4602 while (true) {5364 while (true) {
4603 try t.checkCancel();5365 try current_thread.checkCancel();
46045366
4605 var n: u32 = undefined;5367 var n: u32 = undefined;
4606 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);5368 var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
...@@ -4707,9 +5469,10 @@ fn netInterfaceNameResolve(...@@ -4707,9 +5469,10 @@ fn netInterfaceNameResolve(
4707) net.Interface.Name.ResolveError!net.Interface {5469) net.Interface.Name.ResolveError!net.Interface {
4708 if (!have_networking) return error.InterfaceNotFound;5470 if (!have_networking) return error.InterfaceNotFound;
4709 const t: *Threaded = @ptrCast(@alignCast(userdata));5471 const t: *Threaded = @ptrCast(@alignCast(userdata));
5472 const current_thread = Thread.getCurrent(t);
47105473
4711 if (native_os == .linux) {5474 if (native_os == .linux) {
4712 const sock_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {5475 const sock_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
4713 error.ProcessFdQuotaExceeded => return error.SystemResources,5476 error.ProcessFdQuotaExceeded => return error.SystemResources,
4714 error.SystemFdQuotaExceeded => return error.SystemResources,5477 error.SystemFdQuotaExceeded => return error.SystemResources,
4715 error.AddressFamilyUnsupported => return error.Unexpected,5478 error.AddressFamilyUnsupported => return error.Unexpected,
...@@ -4726,32 +5489,42 @@ fn netInterfaceNameResolve(...@@ -4726,32 +5489,42 @@ fn netInterfaceNameResolve(
4726 .ifru = undefined,5489 .ifru = undefined,
4727 };5490 };
47285491
5492 try current_thread.beginSyscall();
4729 while (true) {5493 while (true) {
4730 try t.checkCancel();
4731 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {5494 switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {
4732 .SUCCESS => return .{ .index = @bitCast(ifr.ifru.ivalue) },5495 .SUCCESS => {
4733 .INTR => continue,5496 current_thread.endSyscall();
4734 .CANCELED => return error.Canceled,5497 return .{ .index = @bitCast(ifr.ifru.ivalue) };
47355498 },
4736 .INVAL => |err| return errnoBug(err), // Bad parameters.5499 .INTR => {
4737 .NOTTY => |err| return errnoBug(err),5500 try current_thread.checkCancel();
4738 .NXIO => |err| return errnoBug(err),5501 continue;
4739 .BADF => |err| return errnoBug(err), // File descriptor used after closed.5502 },
4740 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.5503 else => |e| {
4741 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor5504 current_thread.endSyscall();
4742 .NODEV => return error.InterfaceNotFound,5505 switch (e) {
4743 else => |err| return posix.unexpectedErrno(err),5506 .CANCELED => return error.Canceled,
5507 .INVAL => |err| return errnoBug(err), // Bad parameters.
5508 .NOTTY => |err| return errnoBug(err),
5509 .NXIO => |err| return errnoBug(err),
5510 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
5511 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
5512 .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
5513 .NODEV => return error.InterfaceNotFound,
5514 else => |err| return posix.unexpectedErrno(err),
5515 }
5516 },
4744 }5517 }
4745 }5518 }
4746 }5519 }
47475520
4748 if (native_os == .windows) {5521 if (native_os == .windows) {
4749 try t.checkCancel();5522 try current_thread.checkCancel();
4750 @panic("TODO implement netInterfaceNameResolve for Windows");5523 @panic("TODO implement netInterfaceNameResolve for Windows");
4751 }5524 }
47525525
4753 if (builtin.link_libc) {5526 if (builtin.link_libc) {
4754 try t.checkCancel();5527 try current_thread.checkCancel();
4755 const index = std.c.if_nametoindex(&name.bytes);5528 const index = std.c.if_nametoindex(&name.bytes);
4756 if (index == 0) return error.InterfaceNotFound;5529 if (index == 0) return error.InterfaceNotFound;
4757 return .{ .index = @bitCast(index) };5530 return .{ .index = @bitCast(index) };
...@@ -4771,7 +5544,8 @@ fn netInterfaceNameResolveUnavailable(...@@ -4771,7 +5544,8 @@ fn netInterfaceNameResolveUnavailable(
47715544
4772fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {5545fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
4773 const t: *Threaded = @ptrCast(@alignCast(userdata));5546 const t: *Threaded = @ptrCast(@alignCast(userdata));
4774 try t.checkCancel();5547 const current_thread = Thread.getCurrent(t);
5548 try current_thread.checkCancel();
47755549
4776 if (native_os == .linux) {5550 if (native_os == .linux) {
4777 _ = interface;5551 _ = interface;
...@@ -4802,8 +5576,9 @@ fn netLookup(...@@ -4802,8 +5576,9 @@ fn netLookup(
4802 options: HostName.LookupOptions,5576 options: HostName.LookupOptions,
4803) void {5577) void {
4804 const t: *Threaded = @ptrCast(@alignCast(userdata));5578 const t: *Threaded = @ptrCast(@alignCast(userdata));
5579 const current_thread = Thread.getCurrent(t);
4805 const t_io = io(t);5580 const t_io = io(t);
4806 resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, host_name, resolved, options) });5581 resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, current_thread, host_name, resolved, options) });
4807}5582}
48085583
4809fn netLookupUnavailable(5584fn netLookupUnavailable(
...@@ -4821,6 +5596,7 @@ fn netLookupUnavailable(...@@ -4821,6 +5596,7 @@ fn netLookupUnavailable(
48215596
4822fn netLookupFallible(5597fn netLookupFallible(
4823 t: *Threaded,5598 t: *Threaded,
5599 current_thread: *Thread,
4824 host_name: HostName,5600 host_name: HostName,
4825 resolved: *Io.Queue(HostName.LookupResult),5601 resolved: *Io.Queue(HostName.LookupResult),
4826 options: HostName.LookupOptions,5602 options: HostName.LookupOptions,
...@@ -4866,7 +5642,7 @@ fn netLookupFallible(...@@ -4866,7 +5642,7 @@ fn netLookupFallible(
4866 var res: *ws2_32.ADDRINFOEXW = undefined;5642 var res: *ws2_32.ADDRINFOEXW = undefined;
4867 const timeout: ?*ws2_32.timeval = null;5643 const timeout: ?*ws2_32.timeval = null;
4868 while (true) {5644 while (true) {
4869 try t.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel5645 try current_thread.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
4870 // TODO make this append to the queue eagerly rather than blocking until5646 // TODO make this append to the queue eagerly rather than blocking until
4871 // the whole thing finishes5647 // 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));5648 const rc: ws2_32.WinsockError = @enumFromInt(ws2_32.GetAddrInfoExW(name_w, port_w, .DNS, null, &hints, &res, timeout, null, null, cancel_handle));
...@@ -5013,23 +5789,39 @@ fn netLookupFallible(...@@ -5013,23 +5789,39 @@ fn netLookupFallible(
5013 .next = null,5789 .next = null,
5014 };5790 };
5015 var res: ?*posix.addrinfo = null;5791 var res: ?*posix.addrinfo = null;
5792 try current_thread.beginSyscall();
5016 while (true) {5793 while (true) {
5017 try t.checkCancel();
5018 switch (posix.system.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {5794 switch (posix.system.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
5019 @as(posix.system.EAI, @enumFromInt(0)) => break,5795 @as(posix.system.EAI, @enumFromInt(0)) => {
5020 .ADDRFAMILY => return error.AddressFamilyUnsupported,5796 current_thread.endSyscall();
5021 .AGAIN => return error.NameServerFailure,5797 break;
5022 .FAIL => return error.NameServerFailure,5798 },
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)) {5799 .SYSTEM => switch (posix.errno(-1)) {
5028 .INTR => continue,5800 .INTR => {
5029 .CANCELED => return error.Canceled,5801 try current_thread.checkCancel();
5030 else => |e| return posix.unexpectedErrno(e),5802 continue;
5803 },
5804 else => |e| {
5805 current_thread.endSyscall();
5806 switch (e) {
5807 .CANCELED => return error.Canceled,
5808 else => |inner| return posix.unexpectedErrno(inner),
5809 }
5810 },
5811 },
5812 else => |e| {
5813 current_thread.endSyscall();
5814 switch (e) {
5815 .ADDRFAMILY => return error.AddressFamilyUnsupported,
5816 .AGAIN => return error.NameServerFailure,
5817 .FAIL => return error.NameServerFailure,
5818 .FAMILY => return error.AddressFamilyUnsupported,
5819 .MEMORY => return error.SystemResources,
5820 .NODATA => return error.UnknownHostName,
5821 .NONAME => return error.UnknownHostName,
5822 else => return error.Unexpected,
5823 }
5031 },5824 },
5032 else => return error.Unexpected,
5033 }5825 }
5034 }5826 }
5035 defer if (res) |some| posix.system.freeaddrinfo(some);5827 defer if (res) |some| posix.system.freeaddrinfo(some);
...@@ -5726,12 +6518,12 @@ fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) Hos...@@ -5726,12 +6518,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)6518/// 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;6519const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11;
57286520
5729fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {6521fn futexWait(current_thread: *Thread, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {
5730 @branchHint(.cold);6522 @branchHint(.cold);
57316523
5732 if (builtin.cpu.arch.isWasm()) {6524 if (builtin.cpu.arch.isWasm()) {
5733 comptime assert(builtin.cpu.has(.wasm, .atomics));6525 comptime assert(builtin.cpu.has(.wasm, .atomics));
5734 try t.checkCancel();6526 try current_thread.checkCancel();
5735 const timeout: i64 = -1;6527 const timeout: i64 = -1;
5736 const signed_expect: i32 = @bitCast(expect);6528 const signed_expect: i32 = @bitCast(expect);
5737 const result = asm volatile (6529 const result = asm volatile (
...@@ -5754,8 +6546,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5754,8 +6546,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5754 } else switch (native_os) {6546 } else switch (native_os) {
5755 .linux => {6547 .linux => {
5756 const linux = std.os.linux;6548 const linux = std.os.linux;
5757 try t.checkCancel();6549 try current_thread.beginSyscall();
5758 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);6550 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
6551 current_thread.endSyscall();
5759 if (is_debug) switch (linux.errno(rc)) {6552 if (is_debug) switch (linux.errno(rc)) {
5760 .SUCCESS => {}, // notified by `wake()`6553 .SUCCESS => {}, // notified by `wake()`
5761 .INTR => {}, // gives caller a chance to check cancellation6554 .INTR => {}, // gives caller a chance to check cancellation
...@@ -5772,11 +6565,12 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5772,11 +6565,12 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5772 .op = .COMPARE_AND_WAIT,6565 .op = .COMPARE_AND_WAIT,
5773 .NO_ERRNO = true,6566 .NO_ERRNO = true,
5774 };6567 };
5775 try t.checkCancel();6568 try current_thread.beginSyscall();
5776 const status = if (darwin_supports_ulock_wait2)6569 const status = if (darwin_supports_ulock_wait2)
5777 c.__ulock_wait2(flags, ptr, expect, 0, 0)6570 c.__ulock_wait2(flags, ptr, expect, 0, 0)
5778 else6571 else
5779 c.__ulock_wait(flags, ptr, expect, 0);6572 c.__ulock_wait(flags, ptr, expect, 0);
6573 current_thread.endSyscall();
57806574
5781 if (status >= 0) return;6575 if (status >= 0) return;
57826576
...@@ -5791,7 +6585,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5791,7 +6585,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5791 };6585 };
5792 },6586 },
5793 .windows => {6587 .windows => {
5794 try t.checkCancel();6588 try current_thread.checkCancel();
5795 switch (windows.ntdll.RtlWaitOnAddress(ptr, &expect, @sizeOf(@TypeOf(expect)), null)) {6589 switch (windows.ntdll.RtlWaitOnAddress(ptr, &expect, @sizeOf(@TypeOf(expect)), null)) {
5796 .SUCCESS => {},6590 .SUCCESS => {},
5797 .CANCELLED => return error.Canceled,6591 .CANCELLED => return error.Canceled,
...@@ -5800,8 +6594,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca...@@ -5800,8 +6594,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
5800 },6594 },
5801 .freebsd => {6595 .freebsd => {
5802 const flags = @intFromEnum(std.c.UMTX_OP.WAIT_UINT_PRIVATE);6596 const flags = @intFromEnum(std.c.UMTX_OP.WAIT_UINT_PRIVATE);
5803 try t.checkCancel();6597 try current_thread.beginSyscall();
5804 const rc = std.c._umtx_op(@intFromPtr(&ptr.raw), flags, @as(c_ulong, expect), 0, 0);6598 const rc = std.c._umtx_op(@intFromPtr(&ptr.raw), flags, @as(c_ulong, expect), 0, 0);
6599 current_thread.endSyscall();
5805 if (is_debug) switch (posix.errno(rc)) {6600 if (is_debug) switch (posix.errno(rc)) {
5806 .SUCCESS => {},6601 .SUCCESS => {},
5807 .FAULT => unreachable, // one of the args points to invalid memory6602 .FAULT => unreachable, // one of the args points to invalid memory
...@@ -6050,8 +6845,9 @@ const ResetEventFutex = enum(u32) {...@@ -6050,8 +6845,9 @@ const ResetEventFutex = enum(u32) {
6050 if (state == .unset) {6845 if (state == .unset) {
6051 state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting;6846 state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting;
6052 }6847 }
6848 const current_thread = Thread.getCurrent(t);
6053 while (state == .waiting) {6849 while (state == .waiting) {
6054 try futexWait(t, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));6850 try futexWait(current_thread, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
6055 state = @atomicLoad(ResetEventFutex, ref, .acquire);6851 state = @atomicLoad(ResetEventFutex, ref, .acquire);
6056 }6852 }
6057 assert(state == .is_set);6853 assert(state == .is_set);
...@@ -6140,6 +6936,7 @@ const ResetEventPosix = struct {...@@ -6140,6 +6936,7 @@ const ResetEventPosix = struct {
6140 .waiting => unreachable, // Invalid state.6936 .waiting => unreachable, // Invalid state.
6141 .is_set => return,6937 .is_set => return,
6142 };6938 };
6939 const current_thread = Thread.getCurrent(t);
6143 assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS);6940 assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS);
6144 defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS);6941 defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS);
6145 sw: switch (rep.state) {6942 sw: switch (rep.state) {
...@@ -6148,8 +6945,9 @@ const ResetEventPosix = struct {...@@ -6148,8 +6945,9 @@ const ResetEventPosix = struct {
6148 continue :sw .waiting;6945 continue :sw .waiting;
6149 },6946 },
6150 .waiting => {6947 .waiting => {
6151 try t.checkCancel();6948 try current_thread.beginSyscall();
6152 assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS);6949 assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS);
6950 current_thread.endSyscall();
6153 continue :sw rep.state;6951 continue :sw rep.state;
6154 },6952 },
6155 .is_set => return,6953 .is_set => return,
...@@ -6222,10 +7020,10 @@ const Wsa = struct {...@@ -6222,10 +7020,10 @@ const Wsa = struct {
6222 } || Io.UnexpectedError;7020 } || Io.UnexpectedError;
6223};7021};
62247022
6225fn initializeWsa(t: *Threaded) error{NetworkDown}!void {7023fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
6226 const t_io = io(t);7024 const t_io = io(t);
6227 const wsa = &t.wsa;7025 const wsa = &t.wsa;
6228 wsa.mutex.lockUncancelable(t_io);7026 try wsa.mutex.lock(t_io);
6229 defer wsa.mutex.unlock(t_io);7027 defer wsa.mutex.unlock(t_io);
6230 switch (wsa.status) {7028 switch (wsa.status) {
6231 .uninitialized => {7029 .uninitialized => {
...@@ -6237,12 +7035,15 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {...@@ -6237,12 +7035,15 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
6237 wsa.status = .initialized;7035 wsa.status = .initialized;
6238 return;7036 return;
6239 },7037 },
6240 else => |err_int| switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {7038 else => |err_int| {
6241 .SYSNOTREADY => wsa.init_error = error.NetworkDown,7039 wsa.status = .failure;
6242 .VERNOTSUPPORTED => wsa.init_error = error.VersionUnsupported,7040 wsa.init_error = switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
6243 .EINPROGRESS => wsa.init_error = error.BlockingOperationInProgress,7041 .SYSNOTREADY => error.NetworkDown,
6244 .EPROCLIM => wsa.init_error = error.ProcessFdQuotaExceeded,7042 .VERNOTSUPPORTED => error.VersionUnsupported,
6245 else => |err| wsa.init_error = windows.unexpectedWSAError(err),7043 .EINPROGRESS => error.BlockingOperationInProgress,
7044 .EPROCLIM => error.ProcessFdQuotaExceeded,
7045 else => |err| windows.unexpectedWSAError(err),
7046 };
6246 },7047 },
6247 }7048 }
6248 },7049 },