commit 29e418cbfb3d5e5800ac2ad267b21cf2b8942c2c (tree)
parent 95f93a0b281e32583edef36808231a5f61fb7de1
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 27 Nov 2025 08:42:06 -0800
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
Diffstat:
2 files changed, 1910 insertions(+), 1114 deletions(-)
diff --git a/lib/std/Io.zig b/lib/std/Io.zig
@@ -620,11 +620,6 @@ pub const VTable = struct {
result: []u8,
result_alignment: std.mem.Alignment,
) void,
- /// Returns whether the current thread of execution is known to have
- /// been requested to cancel.
- ///
- /// Thread-safe.
- cancelRequested: *const fn (?*anyopaque) bool,
/// When this function returns, implementation guarantees that `start` has
/// either already been called, or a unit of concurrency has been assigned
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -50,6 +50,8 @@ cpu_count_error: ?std.Thread.CpuCountError,
/// available count, subtract this from either `async_limit` or
/// `concurrent_limit`.
busy_count: usize = 0,
+main_thread: Thread,
+pid: Pid = .unknown,
wsa: if (is_windows) Wsa else struct {} = .{},
@@ -57,7 +59,79 @@ have_signal_handler: bool,
old_sig_io: if (have_sig_io) posix.Sigaction else void,
old_sig_pipe: if (have_sig_pipe) posix.Sigaction else void,
-threadlocal var current_closure: ?*Closure = null;
+pub const Pid = if (native_os == .linux) enum(posix.pid_t) {
+ unknown = 0,
+ _,
+} else enum(u0) { unknown = 0 };
+
+const Thread = struct {
+ /// The value that needs to be passed to pthread_kill or tgkill in order to
+ /// send a signal.
+ signal_id: SignalId,
+ current_closure: ?*Closure = null,
+
+ const SignalId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;
+
+ threadlocal var current: ?*Thread = null;
+
+ fn getCurrent(t: *Threaded) *Thread {
+ return current orelse return &t.main_thread;
+ }
+
+ fn checkCancel(thread: *Thread) error{Canceled}!void {
+ const closure = thread.current_closure orelse return;
+ switch (@cmpxchgStrong(
+ CancelStatus,
+ &closure.cancel_status,
+ .requested,
+ .acknowledged,
+ .acq_rel,
+ .acquire,
+ ) orelse return error.Canceled) {
+ .none => return,
+ .requested => unreachable,
+ .acknowledged => unreachable,
+ _ => return,
+ }
+ }
+
+ fn beginSyscall(thread: *Thread) error{Canceled}!void {
+ const closure = thread.current_closure orelse return;
+
+ switch (@cmpxchgStrong(
+ CancelStatus,
+ &closure.cancel_status,
+ .none,
+ .fromSignalId(thread.signal_id),
+ .acq_rel,
+ .acquire,
+ ) orelse return) {
+ .none => unreachable,
+ .requested => {
+ @atomicStore(CancelStatus, &closure.cancel_status, .acknowledged, .release);
+ return error.Canceled;
+ },
+ .acknowledged => unreachable,
+ _ => unreachable,
+ }
+ }
+
+ fn endSyscall(thread: *Thread) void {
+ const closure = thread.current_closure orelse return;
+ _ = @cmpxchgStrong(
+ CancelStatus,
+ &closure.cancel_status,
+ .fromSignalId(thread.signal_id),
+ .none,
+ .acq_rel,
+ .acquire,
+ );
+ }
+
+ fn currentSignalId() SignalId {
+ return if (std.Thread.use_pthreads) std.c.pthread_self() else std.Thread.getCurrentId();
+ }
+};
const max_iovecs_len = 8;
const splat_buffer_size = 64;
@@ -66,48 +140,93 @@ comptime {
if (@TypeOf(posix.IOV_MAX) != void) assert(max_iovecs_len <= posix.IOV_MAX);
}
-const CancelId = enum(usize) {
+const CancelStatus = enum(usize) {
+ /// Cancellation has neither been requested, nor checked. The async
+ /// operation will check status before entering a blocking syscall.
+ /// This is also the status used for uninteruptible tasks.
none = 0,
- canceling = std.math.maxInt(usize),
+ /// Cancellation has been requested and the status will be checked before
+ /// entering a blocking syscall.
+ requested = std.math.maxInt(usize) - 1,
+ /// Cancellation has been acknowledged and is in progress. Signals should
+ /// not be sent.
+ acknowledged = std.math.maxInt(usize),
+ /// Stores a `Thread.SignalId` and indicates that sending a signal to this thread
+ /// is needed in order to cancel. This state is set before going into
+ /// a blocking operation that needs to get unblocked via signal.
_,
- const ThreadId = if (std.Thread.use_pthreads) std.c.pthread_t else std.Thread.Id;
+ const Unpacked = union(enum) {
+ none,
+ requested,
+ acknowledged,
+ signal_id: Thread.SignalId,
+ };
- fn currentThread() CancelId {
- if (std.Thread.use_pthreads) {
- return @enumFromInt(@intFromPtr(std.c.pthread_self()));
- } else {
- return @enumFromInt(std.Thread.getCurrentId());
- }
+ fn unpack(cs: CancelStatus) Unpacked {
+ return switch (cs) {
+ .none => .none,
+ .requested => .requested,
+ .acknowledged => .acknowledged,
+ _ => |signal_id| .{
+ .signal_id = if (std.Thread.use_pthreads)
+ @ptrFromInt(@intFromEnum(signal_id))
+ else
+ @truncate(@intFromEnum(signal_id)),
+ },
+ };
}
- fn toThreadId(cancel_id: CancelId) ThreadId {
- if (std.Thread.use_pthreads) {
- return @ptrFromInt(@intFromEnum(cancel_id));
- } else {
- return @intCast(@intFromEnum(cancel_id));
- }
+ fn fromSignalId(signal_id: Thread.SignalId) CancelStatus {
+ return if (std.Thread.use_pthreads)
+ @enumFromInt(@intFromPtr(signal_id))
+ else
+ @enumFromInt(signal_id);
}
};
const Closure = struct {
start: Start,
node: std.SinglyLinkedList.Node = .{},
- cancel_tid: CancelId,
-
- const Start = *const fn (*Closure) void;
-
- fn requestCancel(closure: *Closure) void {
- switch (@atomicRmw(CancelId, &closure.cancel_tid, .Xchg, .canceling, .acq_rel)) {
- .none, .canceling => {},
- else => |tid| {
- if (std.Thread.use_pthreads) {
- const rc = std.c.pthread_kill(tid.toThreadId(), .IO);
- if (is_debug) assert(rc == 0);
- } else if (native_os == .linux) {
- _ = std.os.linux.tgkill(std.os.linux.getpid(), @bitCast(tid.toThreadId()), .IO);
- }
- },
+ cancel_status: CancelStatus,
+
+ const Start = *const fn (*Closure, *Threaded) void;
+
+ fn requestCancel(closure: *Closure, t: *Threaded) void {
+ var signal_id = switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
+ .none, .acknowledged, .requested => return,
+ .signal_id => |signal_id| signal_id,
+ };
+ // The task will enter a blocking syscall before checking for cancellation again.
+ // We can send a signal to interrupt the syscall, but if it arrives before
+ // the syscall instruction, it will be missed. Therefore, this code tries
+ // again until the cancellation request is acknowledged.
+ const max_attempts = 3;
+ for (0..max_attempts) |_| {
+ if (std.Thread.use_pthreads) {
+ const rc = std.c.pthread_kill(signal_id, .IO);
+ if (is_debug) assert(rc == 0);
+ } else if (native_os == .linux) {
+ const pid: posix.pid_t = p: {
+ const cached_pid = @atomicLoad(Pid, &t.pid, .monotonic);
+ if (cached_pid != .unknown) break :p @intFromEnum(cached_pid);
+ const pid = std.os.linux.getpid();
+ @atomicStore(Pid, &t.pid, @enumFromInt(pid), .monotonic);
+ break :p pid;
+ };
+ _ = std.os.linux.tgkill(pid, @bitCast(signal_id), .IO);
+ } else {
+ return;
+ }
+
+ // TODO make this a nanosleep with 1 << attempt duration
+ std.Thread.yield() catch {};
+
+ switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
+ .requested => continue,
+ .none, .acknowledged => return,
+ .signal_id => |new_signal_id| signal_id = new_signal_id,
+ }
}
}
};
@@ -136,6 +255,9 @@ pub fn init(
.old_sig_io = undefined,
.old_sig_pipe = undefined,
.have_signal_handler = false,
+ .main_thread = .{
+ .signal_id = Thread.currentSignalId(),
+ },
};
if (posix.Sigaction != void) {
@@ -169,6 +291,7 @@ pub const init_single_threaded: Threaded = .{
.old_sig_io = undefined,
.old_sig_pipe = undefined,
.have_signal_handler = false,
+ .main_thread = .{ .signal_id = undefined },
};
pub fn setAsyncLimit(t: *Threaded, new_limit: Io.Limit) void {
@@ -201,6 +324,11 @@ fn join(t: *Threaded) void {
}
fn worker(t: *Threaded) void {
+ var thread: Thread = .{
+ .signal_id = Thread.currentSignalId(),
+ };
+ Thread.current = &thread;
+
defer t.wait_group.finish();
t.mutex.lock();
@@ -210,7 +338,7 @@ fn worker(t: *Threaded) void {
while (t.run_queue.popFirst()) |closure_node| {
t.mutex.unlock();
const closure: *Closure = @fieldParentPtr("node", closure_node);
- closure.start(closure);
+ closure.start(closure, t);
t.mutex.lock();
t.busy_count -= 1;
}
@@ -227,7 +355,6 @@ pub fn io(t: *Threaded) Io {
.concurrent = concurrent,
.await = await,
.cancel = cancel,
- .cancelRequested = cancelRequested,
.select = select,
.groupAsync = groupAsync,
@@ -324,7 +451,6 @@ pub fn ioBasic(t: *Threaded) Io {
.concurrent = concurrent,
.await = await,
.cancel = cancel,
- .cancelRequested = cancelRequested,
.select = select,
.groupAsync = groupAsync,
@@ -418,24 +544,12 @@ const AsyncClosure = struct {
const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent));
- fn start(closure: *Closure) void {
+ fn start(closure: *Closure, t: *Threaded) void {
const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure));
- const tid: CancelId = .currentThread();
- if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {
- assert(cancel_tid == .canceling);
- // Even though we already know the task is canceled, we must still
- // run the closure in order to make the return value valid and in
- // case there are side effects.
- }
- current_closure = closure;
+ const current_thread = Thread.getCurrent(t);
+ current_thread.current_closure = closure;
ac.func(ac.contextPointer(), ac.resultPointer());
- current_closure = null;
-
- // In case a cancel happens after successful task completion, prevents
- // signal from being delivered to the thread in `requestCancel`.
- if (@cmpxchgStrong(CancelId, &closure.cancel_tid, tid, .none, .acq_rel, .acquire)) |cancel_tid| {
- assert(cancel_tid == .canceling);
- }
+ current_thread.current_closure = null;
if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| {
assert(select_reset != done_reset_event);
@@ -476,7 +590,7 @@ const AsyncClosure = struct {
const actual_result_offset = actual_result_addr - @intFromPtr(ac);
ac.* = .{
.closure = .{
- .cancel_tid = .none,
+ .cancel_status = .none,
.start = start,
},
.func = func,
@@ -493,7 +607,7 @@ const AsyncClosure = struct {
fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void {
ac.reset_event.wait(t) catch |err| switch (err) {
error.Canceled => {
- ac.closure.requestCancel();
+ ac.closure.requestCancel(t);
ac.reset_event.waitUncancelable();
},
};
@@ -604,7 +718,6 @@ fn concurrent(
const GroupClosure = struct {
closure: Closure,
- t: *Threaded,
group: *Io.Group,
/// Points to sibling `GroupClosure`. Used for walking the group to cancel all.
node: std.SinglyLinkedList.Node,
@@ -612,26 +725,15 @@ const GroupClosure = struct {
context_alignment: Alignment,
alloc_len: usize,
- fn start(closure: *Closure) void {
+ fn start(closure: *Closure, t: *Threaded) void {
const gc: *GroupClosure = @alignCast(@fieldParentPtr("closure", closure));
- const tid: CancelId = .currentThread();
+ const current_thread = Thread.getCurrent(t);
const group = gc.group;
const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state);
const reset_event: *ResetEvent = @ptrCast(&group.context);
- if (@cmpxchgStrong(CancelId, &closure.cancel_tid, .none, tid, .acq_rel, .acquire)) |cancel_tid| {
- assert(cancel_tid == .canceling);
- // Even though we already know the task is canceled, we must still
- // run the closure in case there are side effects.
- }
- current_closure = closure;
+ current_thread.current_closure = closure;
gc.func(group, gc.contextPointer());
- current_closure = null;
-
- // In case a cancel happens after successful task completion, prevents
- // signal from being delivered to the thread in `requestCancel`.
- if (@cmpxchgStrong(CancelId, &closure.cancel_tid, tid, .none, .acq_rel, .acquire)) |cancel_tid| {
- assert(cancel_tid == .canceling);
- }
+ current_thread.current_closure = null;
const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel);
assert((prev_state / sync_one_pending) > 0);
@@ -647,7 +749,6 @@ const GroupClosure = struct {
/// Does not initialize the `node` field.
fn init(
gpa: Allocator,
- t: *Threaded,
group: *Io.Group,
context: []const u8,
context_alignment: Alignment,
@@ -662,10 +763,9 @@ const GroupClosure = struct {
gc.* = .{
.closure = .{
- .cancel_tid = .none,
+ .cancel_status = .none,
.start = start,
},
- .t = t,
.group = group,
.node = undefined,
.func = func,
@@ -696,7 +796,7 @@ fn groupAsync(
if (builtin.single_threaded) return start(group, context.ptr);
const gpa = t.allocator;
- const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch
+ const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
return start(group, context.ptr);
t.mutex.lock();
@@ -752,7 +852,7 @@ fn groupConcurrent(
const t: *Threaded = @ptrCast(@alignCast(userdata));
const gpa = t.allocator;
- const gc = GroupClosure.init(gpa, t, group, context, context_alignment, start) catch
+ const gc = GroupClosure.init(gpa, group, context, context_alignment, start) catch
return error.ConcurrencyUnavailable;
t.mutex.lock();
@@ -806,7 +906,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
while (true) {
const gc: *GroupClosure = @fieldParentPtr("node", node);
- gc.closure.requestCancel();
+ gc.closure.requestCancel(t);
node = node.next orelse break;
}
reset_event.waitUncancelable();
@@ -832,7 +932,7 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void
var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token));
while (true) {
const gc: *GroupClosure = @fieldParentPtr("node", node);
- gc.closure.requestCancel();
+ gc.closure.requestCancel(t);
node = node.next orelse break;
}
}
@@ -875,30 +975,20 @@ fn cancel(
_ = result_alignment;
const t: *Threaded = @ptrCast(@alignCast(userdata));
const ac: *AsyncClosure = @ptrCast(@alignCast(any_future));
- ac.closure.requestCancel();
+ ac.closure.requestCancel(t);
ac.waitAndDeinit(t, result);
}
-fn cancelRequested(userdata: ?*anyopaque) bool {
- const t: *Threaded = @ptrCast(@alignCast(userdata));
- _ = t;
- const closure = current_closure orelse return false;
- return @atomicLoad(CancelId, &closure.cancel_tid, .acquire) == .canceling;
-}
-
-fn checkCancel(t: *Threaded) error{Canceled}!void {
- if (cancelRequested(t)) return error.Canceled;
-}
-
fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {
if (builtin.single_threaded) unreachable; // Interface should have prevented this.
if (native_os == .netbsd) @panic("TODO");
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
if (prev_state == .contended) {
- try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
+ try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
}
while (@atomicRmw(Io.Mutex.State, &mutex.state, .Xchg, .contended, .acquire) != .unlocked) {
- try futexWait(t, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
+ try futexWait(current_thread, @ptrCast(&mutex.state), @intFromEnum(Io.Mutex.State.contended));
}
}
@@ -960,6 +1050,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I
if (builtin.single_threaded) unreachable; // Deadlock.
if (native_os == .netbsd) @panic("TODO");
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const t_io = ioBasic(t);
comptime assert(@TypeOf(cond.state) == u64);
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
defer mutex.lockUncancelable(t_io);
while (true) {
- try futexWait(t, cond_epoch, epoch);
+ try futexWait(current_thread, cond_epoch, epoch);
epoch = cond_epoch.load(.acquire);
state = cond_state.load(.monotonic);
@@ -1074,35 +1165,46 @@ const dirMake = switch (native_os) {
fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var path_buffer: [posix.PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.mkdirat(dir.handle, sub_path_posix, mode))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ACCES => return error.AccessDenied,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .PERM => return error.PermissionDenied,
- .DQUOT => return error.DiskQuota,
- .EXIST => return error.PathAlreadyExists,
- .FAULT => |err| return errnoBug(err),
- .LOOP => return error.SymLinkLoop,
- .MLINK => return error.LinkQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOSPC => return error.NoSpaceLeft,
- .NOTDIR => return error.NotDir,
- .ROFS => return error.ReadOnlyFileSystem,
- // dragonfly: when dir_fd is unlinked from filesystem
- .NOTCONN => return error.FileNotFound,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ACCES => return error.AccessDenied,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .PERM => return error.PermissionDenied,
+ .DQUOT => return error.DiskQuota,
+ .EXIST => return error.PathAlreadyExists,
+ .FAULT => |err| return errnoBug(err),
+ .LOOP => return error.SymLinkLoop,
+ .MLINK => return error.LinkQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NOENT => return error.FileNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOSPC => return error.NoSpaceLeft,
+ .NOTDIR => return error.NotDir,
+ .ROFS => return error.ReadOnlyFileSystem,
+ // dragonfly: when dir_fd is unlinked from filesystem
+ .NOTCONN => return error.FileNotFound,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -1110,11 +1212,18 @@ fn dirMakePosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode:
fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
if (builtin.link_libc) return dirMakePosix(userdata, dir, sub_path, mode);
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (std.os.wasi.path_create_directory(dir.handle, sub_path.ptr, sub_path.len)) {
- .SUCCESS => return,
- .INTR => continue,
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.CANCELED => return error.Canceled,
.ACCES => return error.AccessDenied,
@@ -1140,7 +1249,8 @@ fn dirMakeWasi(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: I
fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
- try t.checkCancel();
+ const current_thread = Thread.getCurrent(t);
+ try current_thread.checkCancel();
const sub_path_w = try windows.sliceToPrefixedFileW(dir.handle, sub_path);
_ = mode;
@@ -1213,6 +1323,7 @@ fn dirMakeOpenPathWindows(
options: Io.Dir.OpenOptions,
) Io.Dir.MakeOpenPathError!Io.Dir {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const w = windows;
const access_mask = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
w.SYNCHRONIZE | w.FILE_TRAVERSE |
@@ -1226,7 +1337,7 @@ fn dirMakeOpenPathWindows(
};
while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, component.path);
const sub_path_w = sub_path_w_array.span();
@@ -1328,8 +1439,7 @@ fn dirMakeOpenPathWasi(
fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
- try t.checkCancel();
-
+ _ = t;
_ = dir;
@panic("TODO implement dirStat");
}
@@ -1348,6 +1458,7 @@ fn dirStatPathLinux(
options: Io.Dir.StatPathOptions,
) Io.Dir.StatPathError!Io.File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const linux = std.os.linux;
var path_buffer: [posix.PATH_MAX]u8 = undefined;
@@ -1356,8 +1467,8 @@ fn dirStatPathLinux(
const flags: u32 = linux.AT.NO_AUTOMOUNT |
@as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
var statx = std.mem.zeroes(linux.Statx);
const rc = linux.statx(
dir.handle,
@@ -1367,20 +1478,30 @@ fn dirStatPathLinux(
&statx,
);
switch (linux.errno(rc)) {
- .SUCCESS => return statFromLinux(&statx),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ACCES => return error.AccessDenied,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .FAULT => |err| return errnoBug(err),
- .INVAL => |err| return errnoBug(err),
- .LOOP => return error.SymLinkLoop,
- .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.
- .NOENT => return error.FileNotFound,
- .NOTDIR => return error.NotDir,
- .NOMEM => return error.SystemResources,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return statFromLinux(&statx);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ACCES => return error.AccessDenied,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => |err| return errnoBug(err),
+ .LOOP => return error.SymLinkLoop,
+ .NAMETOOLONG => |err| return errnoBug(err), // Handled by pathToPosix() above.
+ .NOENT => return error.FileNotFound,
+ .NOTDIR => return error.NotDir,
+ .NOMEM => return error.SystemResources,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -1392,32 +1513,43 @@ fn dirStatPathPosix(
options: Io.Dir.StatPathOptions,
) Io.Dir.StatPathError!Io.File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var path_buffer: [posix.PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
var stat = std.mem.zeroes(posix.Stat);
switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) {
- .SUCCESS => return statFromPosix(&stat),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOMEM => return error.SystemResources,
- .ACCES => return error.AccessDenied,
- .PERM => return error.PermissionDenied,
- .FAULT => |err| return errnoBug(err),
- .NAMETOOLONG => return error.NameTooLong,
- .LOOP => return error.SymLinkLoop,
- .NOENT => return error.FileNotFound,
- .NOTDIR => return error.FileNotFound,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return statFromPosix(&stat);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ .PERM => return error.PermissionDenied,
+ .FAULT => |err| return errnoBug(err),
+ .NAMETOOLONG => return error.NameTooLong,
+ .LOOP => return error.SymLinkLoop,
+ .NOENT => return error.FileNotFound,
+ .NOTDIR => return error.FileNotFound,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -1444,29 +1576,40 @@ fn dirStatPathWasi(
) Io.Dir.StatPathError!Io.File.Stat {
if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options);
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const wasi = std.os.wasi;
const flags: wasi.lookupflags_t = .{
.SYMLINK_FOLLOW = options.follow_symlinks,
};
var stat: wasi.filestat_t = undefined;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
- .SUCCESS => return statFromWasi(&stat),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOMEM => return error.SystemResources,
- .ACCES => return error.AccessDenied,
- .FAULT => |err| return errnoBug(err),
- .NAMETOOLONG => return error.NameTooLong,
- .NOENT => return error.FileNotFound,
- .NOTDIR => return error.FileNotFound,
- .NOTCAPABLE => return error.AccessDenied,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return statFromWasi(&stat);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ .FAULT => |err| return errnoBug(err),
+ .NAMETOOLONG => return error.NameTooLong,
+ .NOENT => return error.FileNotFound,
+ .NOTDIR => return error.FileNotFound,
+ .NOTCAPABLE => return error.AccessDenied,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -1480,31 +1623,44 @@ const fileStat = switch (native_os) {
fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
if (posix.Stat == void) return error.Streaming;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
var stat = std.mem.zeroes(posix.Stat);
switch (posix.errno(fstat_sym(file.handle, &stat))) {
- .SUCCESS => return statFromPosix(&stat),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOMEM => return error.SystemResources,
- .ACCES => return error.AccessDenied,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return statFromPosix(&stat);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const linux = std.os.linux;
+
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
var statx = std.mem.zeroes(linux.Statx);
const rc = linux.statx(
file.handle,
@@ -1514,27 +1670,38 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
&statx,
);
switch (linux.errno(rc)) {
- .SUCCESS => return statFromLinux(&statx),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ACCES => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .FAULT => |err| return errnoBug(err),
- .INVAL => |err| return errnoBug(err),
- .LOOP => |err| return errnoBug(err),
- .NAMETOOLONG => |err| return errnoBug(err),
- .NOENT => |err| return errnoBug(err),
- .NOMEM => return error.SystemResources,
- .NOTDIR => |err| return errnoBug(err),
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return statFromLinux(&statx);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ACCES => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => |err| return errnoBug(err),
+ .LOOP => |err| return errnoBug(err),
+ .NAMETOOLONG => |err| return errnoBug(err),
+ .NOENT => |err| return errnoBug(err),
+ .NOMEM => return error.SystemResources,
+ .NOTDIR => |err| return errnoBug(err),
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata));
- try t.checkCancel();
+ const current_thread = Thread.getCurrent(t);
+ try current_thread.checkCancel();
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
var info: windows.FILE_ALL_INFORMATION = undefined;
@@ -1581,21 +1748,34 @@ fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.Fi
fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
if (builtin.link_libc) return fileStatPosix(userdata, file);
+
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
+
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
var stat: std.os.wasi.filestat_t = undefined;
switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {
- .SUCCESS => return statFromWasi(&stat),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOMEM => return error.SystemResources,
- .ACCES => return error.AccessDenied,
- .NOTCAPABLE => return error.AccessDenied,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return statFromWasi(&stat);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ .NOTCAPABLE => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -1613,6 +1793,7 @@ fn dirAccessPosix(
options: Io.Dir.AccessOptions,
) Io.Dir.AccessError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var path_buffer: [posix.PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
@@ -1624,27 +1805,37 @@ fn dirAccessPosix(
@as(u32, if (options.write) posix.W_OK else 0) |
@as(u32, if (options.execute) posix.X_OK else 0);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, flags))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ACCES => return error.AccessDenied,
- .PERM => return error.PermissionDenied,
- .ROFS => return error.ReadOnlyFileSystem,
- .LOOP => return error.SymLinkLoop,
- .TXTBSY => return error.FileBusy,
- .NOTDIR => return error.FileNotFound,
- .NOENT => return error.FileNotFound,
- .NAMETOOLONG => return error.NameTooLong,
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .IO => return error.InputOutput,
- .NOMEM => return error.SystemResources,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ACCES => return error.AccessDenied,
+ .PERM => return error.PermissionDenied,
+ .ROFS => return error.ReadOnlyFileSystem,
+ .LOOP => return error.SymLinkLoop,
+ .TXTBSY => return error.FileBusy,
+ .NOTDIR => return error.FileNotFound,
+ .NOENT => return error.FileNotFound,
+ .NAMETOOLONG => return error.NameTooLong,
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .IO => return error.InputOutput,
+ .NOMEM => return error.SystemResources,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -1657,29 +1848,41 @@ fn dirAccessWasi(
) Io.Dir.AccessError!void {
if (builtin.link_libc) return dirAccessPosix(userdata, dir, sub_path, options);
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const wasi = std.os.wasi;
const flags: wasi.lookupflags_t = .{
.SYMLINK_FOLLOW = options.follow_symlinks,
};
var stat: wasi.filestat_t = undefined;
+
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (wasi.path_filestat_get(dir.handle, flags, sub_path.ptr, sub_path.len, &stat)) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOMEM => return error.SystemResources,
- .ACCES => return error.AccessDenied,
- .FAULT => |err| return errnoBug(err),
- .NAMETOOLONG => return error.NameTooLong,
- .NOENT => return error.FileNotFound,
- .NOTDIR => return error.FileNotFound,
- .NOTCAPABLE => return error.AccessDenied,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ .FAULT => |err| return errnoBug(err),
+ .NAMETOOLONG => return error.NameTooLong,
+ .NOENT => return error.FileNotFound,
+ .NOTDIR => return error.FileNotFound,
+ .NOTCAPABLE => return error.AccessDenied,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
@@ -1717,7 +1920,8 @@ fn dirAccessWindows(
options: Io.Dir.AccessOptions,
) Io.Dir.AccessError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
- try t.checkCancel();
+ const current_thread = Thread.getCurrent(t);
+ try current_thread.checkCancel();
_ = options; // TODO
@@ -1768,6 +1972,7 @@ fn dirCreateFilePosix(
flags: Io.File.CreateFlags,
) Io.File.OpenError!Io.File {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var path_buffer: [posix.PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
@@ -1796,40 +2001,50 @@ fn dirCreateFilePosix(
},
};
+ try current_thread.beginSyscall();
const fd: posix.fd_t = while (true) {
- try t.checkCancel();
const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
switch (posix.errno(rc)) {
- .SUCCESS => break @intCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .FAULT => |err| return errnoBug(err),
- .INVAL => return error.BadPathName,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .ACCES => return error.AccessDenied,
- .FBIG => return error.FileTooBig,
- .OVERFLOW => return error.FileTooBig,
- .ISDIR => return error.IsDir,
- .LOOP => return error.SymLinkLoop,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NODEV => return error.NoDevice,
- .NOENT => return error.FileNotFound,
- .SRCH => return error.ProcessNotFound,
- .NOMEM => return error.SystemResources,
- .NOSPC => return error.NoSpaceLeft,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .EXIST => return error.PathAlreadyExists,
- .BUSY => return error.DeviceBusy,
- .OPNOTSUPP => return error.FileLocksNotSupported,
- .AGAIN => return error.WouldBlock,
- .TXTBSY => return error.FileBusy,
- .NXIO => return error.NoDevice,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break @intCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => return error.BadPathName,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .ACCES => return error.AccessDenied,
+ .FBIG => return error.FileTooBig,
+ .OVERFLOW => return error.FileTooBig,
+ .ISDIR => return error.IsDir,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .SRCH => return error.ProcessNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOSPC => return error.NoSpaceLeft,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.PermissionDenied,
+ .EXIST => return error.PathAlreadyExists,
+ .BUSY => return error.DeviceBusy,
+ .OPNOTSUPP => return error.FileLocksNotSupported,
+ .AGAIN => return error.WouldBlock,
+ .TXTBSY => return error.FileBusy,
+ .NXIO => return error.NoDevice,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
};
errdefer posix.close(fd);
@@ -1841,42 +2056,71 @@ fn dirCreateFilePosix(
.shared => posix.LOCK.SH | lock_nonblocking,
.exclusive => posix.LOCK.EX | lock_nonblocking,
};
+
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.flock(fd, lock_flags))) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .INVAL => |err| return errnoBug(err), // invalid parameters
- .NOLCK => return error.SystemResources,
- .AGAIN => return error.WouldBlock,
- .OPNOTSUPP => return error.FileLocksNotSupported,
- else => |err| return posix.unexpectedErrno(err),
- }
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .INVAL => |err| return errnoBug(err), // invalid parameters
+ .NOLCK => return error.SystemResources,
+ .AGAIN => return error.WouldBlock,
+ .OPNOTSUPP => return error.FileLocksNotSupported,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
+ }
}
}
if (have_flock_open_flags and flags.lock_nonblocking) {
+ try current_thread.beginSyscall();
var fl_flags: usize = while (true) {
- try t.checkCancel();
const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
switch (posix.errno(rc)) {
- .SUCCESS => break @intCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break @intCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |err| {
+ current_thread.endSyscall();
+ return posix.unexpectedErrno(err);
+ },
}
};
+
fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
+
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |err| {
+ current_thread.endSyscall();
+ return posix.unexpectedErrno(err);
+ },
}
}
}
@@ -1892,7 +2136,8 @@ fn dirCreateFileWindows(
) Io.File.OpenError!Io.File {
const w = windows;
const t: *Threaded = @ptrCast(@alignCast(userdata));
- try t.checkCancel();
+ const current_thread = Thread.getCurrent(t);
+ try current_thread.checkCancel();
const sub_path_w_array = try w.sliceToPrefixedFileW(dir.handle, sub_path);
const sub_path_w = sub_path_w_array.span();
@@ -1939,6 +2184,7 @@ fn dirCreateFileWasi(
flags: Io.File.CreateFlags,
) Io.File.OpenError!Io.File {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const wasi = std.os.wasi;
const lookup_flags: wasi.lookupflags_t = .{};
const oflags: wasi.oflags_t = .{
@@ -1966,35 +2212,45 @@ fn dirCreateFileWasi(
};
const inheriting: wasi.rights_t = .{};
var fd: posix.fd_t = undefined;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
- .SUCCESS => return .{ .handle = fd },
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .FAULT => |err| return errnoBug(err),
- .INVAL => return error.BadPathName,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .ACCES => return error.AccessDenied,
- .FBIG => return error.FileTooBig,
- .OVERFLOW => return error.FileTooBig,
- .ISDIR => return error.IsDir,
- .LOOP => return error.SymLinkLoop,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NODEV => return error.NoDevice,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOSPC => return error.NoSpaceLeft,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .EXIST => return error.PathAlreadyExists,
- .BUSY => return error.DeviceBusy,
- .NOTCAPABLE => return error.AccessDenied,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return .{ .handle = fd };
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => return error.BadPathName,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .ACCES => return error.AccessDenied,
+ .FBIG => return error.FileTooBig,
+ .OVERFLOW => return error.FileTooBig,
+ .ISDIR => return error.IsDir,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOSPC => return error.NoSpaceLeft,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.PermissionDenied,
+ .EXIST => return error.PathAlreadyExists,
+ .BUSY => return error.DeviceBusy,
+ .NOTCAPABLE => return error.AccessDenied,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -2012,6 +2268,7 @@ fn dirOpenFilePosix(
flags: Io.File.OpenFlags,
) Io.File.OpenError!Io.File {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var path_buffer: [posix.PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
@@ -2048,40 +2305,50 @@ fn dirOpenFilePosix(
},
};
+ try current_thread.beginSyscall();
const fd: posix.fd_t = while (true) {
- try t.checkCancel();
const rc = openat_sym(dir.handle, sub_path_posix, os_flags, @as(posix.mode_t, 0));
switch (posix.errno(rc)) {
- .SUCCESS => break @intCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .FAULT => |err| return errnoBug(err),
- .INVAL => return error.BadPathName,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .ACCES => return error.AccessDenied,
- .FBIG => return error.FileTooBig,
- .OVERFLOW => return error.FileTooBig,
- .ISDIR => return error.IsDir,
- .LOOP => return error.SymLinkLoop,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NODEV => return error.NoDevice,
- .NOENT => return error.FileNotFound,
- .SRCH => return error.ProcessNotFound,
- .NOMEM => return error.SystemResources,
- .NOSPC => return error.NoSpaceLeft,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .EXIST => return error.PathAlreadyExists,
- .BUSY => return error.DeviceBusy,
- .OPNOTSUPP => return error.FileLocksNotSupported,
- .AGAIN => return error.WouldBlock,
- .TXTBSY => return error.FileBusy,
- .NXIO => return error.NoDevice,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break @intCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => return error.BadPathName,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .ACCES => return error.AccessDenied,
+ .FBIG => return error.FileTooBig,
+ .OVERFLOW => return error.FileTooBig,
+ .ISDIR => return error.IsDir,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .SRCH => return error.ProcessNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOSPC => return error.NoSpaceLeft,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.PermissionDenied,
+ .EXIST => return error.PathAlreadyExists,
+ .BUSY => return error.DeviceBusy,
+ .OPNOTSUPP => return error.FileLocksNotSupported,
+ .AGAIN => return error.WouldBlock,
+ .TXTBSY => return error.FileBusy,
+ .NXIO => return error.NoDevice,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
};
errdefer posix.close(fd);
@@ -2093,42 +2360,70 @@ fn dirOpenFilePosix(
.shared => posix.LOCK.SH | lock_nonblocking,
.exclusive => posix.LOCK.EX | lock_nonblocking,
};
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.flock(fd, lock_flags))) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .INVAL => |err| return errnoBug(err), // invalid parameters
- .NOLCK => return error.SystemResources,
- .AGAIN => return error.WouldBlock,
- .OPNOTSUPP => return error.FileLocksNotSupported,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .INVAL => |err| return errnoBug(err), // invalid parameters
+ .NOLCK => return error.SystemResources,
+ .AGAIN => return error.WouldBlock,
+ .OPNOTSUPP => return error.FileLocksNotSupported,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
if (have_flock_open_flags and flags.lock_nonblocking) {
+ try current_thread.beginSyscall();
var fl_flags: usize = while (true) {
- try t.checkCancel();
const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
switch (posix.errno(rc)) {
- .SUCCESS => break @intCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break @intCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |err| {
+ current_thread.endSyscall();
+ return posix.unexpectedErrno(err);
+ },
}
};
+
fl_flags |= @as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
+
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |err| {
+ current_thread.endSyscall();
+ return posix.unexpectedErrno(err);
+ },
}
}
}
@@ -2158,7 +2453,7 @@ pub fn dirOpenFileWtf16(
if (std.mem.eql(u16, sub_path_w, &.{'.'})) return error.IsDir;
if (std.mem.eql(u16, sub_path_w, &.{ '.', '.' })) return error.IsDir;
const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
-
+ const current_thread = Thread.getCurrent(t);
const w = windows;
var nt_name: w.UNICODE_STRING = .{
@@ -2187,7 +2482,7 @@ pub fn dirOpenFileWtf16(
var attempt: u5 = 0;
const handle = while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
var result: w.HANDLE = undefined;
const rc = w.ntdll.NtCreateFile(
@@ -2281,6 +2576,7 @@ fn dirOpenFileWasi(
) Io.File.OpenError!Io.File {
if (builtin.link_libc) return dirOpenFilePosix(userdata, dir, sub_path, flags);
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const wasi = std.os.wasi;
var base: std.os.wasi.rights_t = .{};
// POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE
@@ -2310,33 +2606,44 @@ fn dirOpenFileWasi(
const inheriting: wasi.rights_t = .{};
const fdflags: wasi.fdflags_t = .{};
var fd: posix.fd_t = undefined;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, inheriting, fdflags, &fd)) {
- .SUCCESS => return .{ .handle = fd },
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .FAULT => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .ACCES => return error.AccessDenied,
- .FBIG => return error.FileTooBig,
- .OVERFLOW => return error.FileTooBig,
- .ISDIR => return error.IsDir,
- .LOOP => return error.SymLinkLoop,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NODEV => return error.NoDevice,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .BUSY => return error.DeviceBusy,
- .NOTCAPABLE => return error.AccessDenied,
- .NAMETOOLONG => return error.NameTooLong,
- .INVAL => return error.BadPathName,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ errdefer posix.close(fd);
+ current_thread.endSyscall();
+ return .{ .handle = fd };
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .FAULT => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .ACCES => return error.AccessDenied,
+ .FBIG => return error.FileTooBig,
+ .OVERFLOW => return error.FileTooBig,
+ .ISDIR => return error.IsDir,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.PermissionDenied,
+ .BUSY => return error.DeviceBusy,
+ .NOTCAPABLE => return error.AccessDenied,
+ .NAMETOOLONG => return error.NameTooLong,
+ .INVAL => return error.BadPathName,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -2361,6 +2668,8 @@ fn dirOpenDirPosix(
return dirOpenDirWindows(t, dir, sub_path_w.span(), options);
}
+ const current_thread = Thread.getCurrent(t);
+
var path_buffer: [posix.PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
@@ -2381,31 +2690,41 @@ fn dirOpenDirPosix(
if (@hasField(posix.O, "PATH") and !options.iterate)
flags.PATH = true;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = openat_sym(dir.handle, sub_path_posix, flags, @as(usize, 0));
switch (posix.errno(rc)) {
- .SUCCESS => return .{ .handle = @intCast(rc) },
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .FAULT => |err| return errnoBug(err),
- .INVAL => return error.BadPathName,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .ACCES => return error.AccessDenied,
- .LOOP => return error.SymLinkLoop,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NODEV => return error.NoDevice,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .BUSY => return error.DeviceBusy,
- .NXIO => return error.NoDevice,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return .{ .handle = @intCast(rc) };
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => return error.BadPathName,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .ACCES => return error.AccessDenied,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.PermissionDenied,
+ .BUSY => return error.DeviceBusy,
+ .NXIO => return error.NoDevice,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -2417,34 +2736,46 @@ fn dirOpenDirHaiku(
options: Io.Dir.OpenOptions,
) Io.Dir.OpenError!Io.Dir {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var path_buffer: [posix.PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
_ = options;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = posix.system._kern_open_dir(dir.handle, sub_path_posix);
- if (rc >= 0) return .{ .handle = rc };
+ if (rc >= 0) {
+ current_thread.endSyscall();
+ return .{ .handle = rc };
+ }
switch (@as(posix.E, @enumFromInt(rc))) {
- .INTR => continue,
- .CANCELED => return error.Canceled,
- .FAULT => |err| return errnoBug(err),
- .INVAL => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .ACCES => return error.AccessDenied,
- .LOOP => return error.SymLinkLoop,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NODEV => return error.NoDevice,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .BUSY => return error.DeviceBusy,
- else => |err| return posix.unexpectedErrno(err),
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .ACCES => return error.AccessDenied,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.PermissionDenied,
+ .BUSY => return error.DeviceBusy,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -2455,6 +2786,7 @@ pub fn dirOpenDirWindows(
sub_path_w: [:0]const u16,
options: Io.Dir.OpenOptions,
) Io.Dir.OpenError!Io.Dir {
+ const current_thread = Thread.getCurrent(t);
const w = windows;
// TODO remove some of these flags if options.access_sub_paths is false
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
@@ -2478,7 +2810,7 @@ pub fn dirOpenDirWindows(
const open_reparse_point: w.DWORD = if (!options.follow_symlinks) w.FILE_OPEN_REPARSE_POINT else 0x0;
var io_status_block: w.IO_STATUS_BLOCK = undefined;
var result: Io.Dir = .{ .handle = undefined };
- try t.checkCancel();
+ try current_thread.checkCancel();
const rc = w.ntdll.NtCreateFile(
&result.handle,
access_mask,
@@ -2527,6 +2859,7 @@ fn dirOpenDirWasi(
) Io.Dir.OpenError!Io.Dir {
if (builtin.link_libc) return dirOpenDirPosix(userdata, dir, sub_path, options);
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const wasi = std.os.wasi;
var base: std.os.wasi.rights_t = .{
@@ -2556,31 +2889,40 @@ fn dirOpenDirWasi(
const oflags: wasi.oflags_t = .{ .DIRECTORY = true };
const fdflags: wasi.fdflags_t = .{};
var fd: posix.fd_t = undefined;
-
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (wasi.path_open(dir.handle, lookup_flags, sub_path.ptr, sub_path.len, oflags, base, base, fdflags, &fd)) {
- .SUCCESS => return .{ .handle = fd },
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .FAULT => |err| return errnoBug(err),
- .INVAL => return error.BadPathName,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .ACCES => return error.AccessDenied,
- .LOOP => return error.SymLinkLoop,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NAMETOOLONG => return error.NameTooLong,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NODEV => return error.NoDevice,
- .NOENT => return error.FileNotFound,
- .NOMEM => return error.SystemResources,
- .NOTDIR => return error.NotDir,
- .PERM => return error.PermissionDenied,
- .BUSY => return error.DeviceBusy,
- .NOTCAPABLE => return error.AccessDenied,
- .ILSEQ => return error.BadPathName,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return .{ .handle = fd };
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => return error.BadPathName,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .ACCES => return error.AccessDenied,
+ .LOOP => return error.SymLinkLoop,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NAMETOOLONG => return error.NameTooLong,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NODEV => return error.NoDevice,
+ .NOENT => return error.FileNotFound,
+ .NOMEM => return error.SystemResources,
+ .NOTDIR => return error.NotDir,
+ .PERM => return error.PermissionDenied,
+ .BUSY => return error.DeviceBusy,
+ .NOTCAPABLE => return error.AccessDenied,
+ .ILSEQ => return error.BadPathName,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -2598,6 +2940,7 @@ const fileReadStreaming = switch (native_os) {
fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
var i: usize = 0;
@@ -2611,59 +2954,82 @@ fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io
const dest = iovecs_buffer[0..i];
assert(dest[0].len > 0);
- if (native_os == .wasi and !builtin.link_libc) while (true) {
- try t.checkCancel();
- var nread: usize = undefined;
- switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {
- .SUCCESS => return nread,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .BADF => return error.NotOpenForReading, // File operation on directory.
- .IO => return error.InputOutput,
- .ISDIR => return error.IsDir,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTCONN => return error.SocketUnconnected,
- .CONNRESET => return error.ConnectionResetByPeer,
- .TIMEDOUT => return error.Timeout,
- .NOTCAPABLE => return error.AccessDenied,
- else => |err| return posix.unexpectedErrno(err),
+ if (native_os == .wasi and !builtin.link_libc) {
+ try current_thread.beginSyscall();
+ while (true) {
+ var nread: usize = undefined;
+ switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) {
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return nread;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .BADF => return error.NotOpenForReading, // File operation on directory.
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTCONN => return error.SocketUnconnected,
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .TIMEDOUT => return error.Timeout,
+ .NOTCAPABLE => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
+ }
}
- };
+ }
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = posix.system.readv(file.handle, dest.ptr, @intCast(dest.len));
switch (posix.errno(rc)) {
- .SUCCESS => return @intCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .SRCH => return error.ProcessNotFound,
- .AGAIN => return error.WouldBlock,
- .BADF => |err| {
- if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
- return errnoBug(err); // File descriptor used after closed.
- },
- .IO => return error.InputOutput,
- .ISDIR => return error.IsDir,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTCONN => return error.SocketUnconnected,
- .CONNRESET => return error.ConnectionResetByPeer,
- .TIMEDOUT => return error.Timeout,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return @intCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .SRCH => return error.ProcessNotFound,
+ .AGAIN => return error.WouldBlock,
+ .BADF => |err| {
+ if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
+ return errnoBug(err); // File descriptor used after closed.
+ },
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTCONN => return error.SocketUnconnected,
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .TIMEDOUT => return error.Timeout,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.Reader.Error!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const DWORD = windows.DWORD;
var index: usize = 0;
@@ -2672,7 +3038,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
const want_read_count: DWORD = @min(std.math.maxInt(DWORD), buffer.len);
while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
var n: DWORD = undefined;
if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, null) != 0)
return n;
@@ -2692,6 +3058,7 @@ fn fileReadStreamingWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8)
fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
if (!have_preadv) @compileError("TODO");
@@ -2707,60 +3074,82 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o
const dest = iovecs_buffer[0..i];
assert(dest[0].len > 0);
- if (native_os == .wasi and !builtin.link_libc) while (true) {
- try t.checkCancel();
- var nread: usize = undefined;
- switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {
- .SUCCESS => return nread,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .AGAIN => |err| return errnoBug(err),
- .BADF => return error.NotOpenForReading, // File operation on directory.
- .IO => return error.InputOutput,
- .ISDIR => return error.IsDir,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTCONN => return error.SocketUnconnected,
- .CONNRESET => return error.ConnectionResetByPeer,
- .TIMEDOUT => return error.Timeout,
- .NXIO => return error.Unseekable,
- .SPIPE => return error.Unseekable,
- .OVERFLOW => return error.Unseekable,
- .NOTCAPABLE => return error.AccessDenied,
- else => |err| return posix.unexpectedErrno(err),
+ if (native_os == .wasi and !builtin.link_libc) {
+ try current_thread.beginSyscall();
+ while (true) {
+ var nread: usize = undefined;
+ switch (std.os.wasi.fd_pread(file.handle, dest.ptr, dest.len, offset, &nread)) {
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return nread;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .AGAIN => |err| return errnoBug(err),
+ .BADF => return error.NotOpenForReading, // File operation on directory.
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTCONN => return error.SocketUnconnected,
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .TIMEDOUT => return error.Timeout,
+ .NXIO => return error.Unseekable,
+ .SPIPE => return error.Unseekable,
+ .OVERFLOW => return error.Unseekable,
+ .NOTCAPABLE => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
+ }
}
- };
+ }
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset));
switch (posix.errno(rc)) {
- .SUCCESS => return @bitCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .SRCH => return error.ProcessNotFound,
- .AGAIN => return error.WouldBlock,
- .BADF => |err| {
- if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
- return errnoBug(err); // File descriptor used after closed.
- },
- .IO => return error.InputOutput,
- .ISDIR => return error.IsDir,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTCONN => return error.SocketUnconnected,
- .CONNRESET => return error.ConnectionResetByPeer,
- .TIMEDOUT => return error.Timeout,
- .NXIO => return error.Unseekable,
- .SPIPE => return error.Unseekable,
- .OVERFLOW => return error.Unseekable,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return @bitCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .SRCH => return error.ProcessNotFound,
+ .AGAIN => return error.WouldBlock,
+ .BADF => |err| {
+ if (native_os == .wasi) return error.NotOpenForReading; // File operation on directory.
+ return errnoBug(err); // File descriptor used after closed.
+ },
+ .IO => return error.InputOutput,
+ .ISDIR => return error.IsDir,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTCONN => return error.SocketUnconnected,
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .TIMEDOUT => return error.Timeout,
+ .NXIO => return error.Unseekable,
+ .SPIPE => return error.Unseekable,
+ .OVERFLOW => return error.Unseekable,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -2772,6 +3161,7 @@ const fileReadPositional = switch (native_os) {
fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const DWORD = windows.DWORD;
@@ -2793,7 +3183,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
};
while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
var n: DWORD = undefined;
if (windows.kernel32.ReadFile(file.handle, buffer.ptr, want_read_count, &n, &overlapped) != 0)
return n;
@@ -2813,8 +3203,7 @@ fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8,
fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
- try t.checkCancel();
-
+ _ = t;
_ = file;
_ = offset;
@panic("TODO implement fileSeekBy");
@@ -2822,63 +3211,96 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr
fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const fd = file.handle;
- if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) while (true) {
- try t.checkCancel();
- var result: u64 = undefined;
- switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .INVAL => return error.Unseekable,
- .OVERFLOW => return error.Unseekable,
- .SPIPE => return error.Unseekable,
- .NXIO => return error.Unseekable,
- else => |err| return posix.unexpectedErrno(err),
+ if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) {
+ try current_thread.beginSyscall();
+ while (true) {
+ var result: u64 = undefined;
+ switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) {
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .INVAL => return error.Unseekable,
+ .OVERFLOW => return error.Unseekable,
+ .SPIPE => return error.Unseekable,
+ .NXIO => return error.Unseekable,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
+ }
}
- };
+ }
if (native_os == .windows) {
- try t.checkCancel();
+ try current_thread.checkCancel();
return windows.SetFilePointerEx_BEGIN(fd, offset);
}
if (native_os == .wasi and !builtin.link_libc) while (true) {
- try t.checkCancel();
var new_offset: std.os.wasi.filesize_t = undefined;
+ try current_thread.beginSyscall();
switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .INVAL => return error.Unseekable,
- .OVERFLOW => return error.Unseekable,
- .SPIPE => return error.Unseekable,
- .NXIO => return error.Unseekable,
- .NOTCAPABLE => return error.AccessDenied,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .INVAL => return error.Unseekable,
+ .OVERFLOW => return error.Unseekable,
+ .SPIPE => return error.Unseekable,
+ .NXIO => return error.Unseekable,
+ .NOTCAPABLE => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
};
if (posix.SEEK == void) return error.Unseekable;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(lseek_sym(fd, @bitCast(offset), posix.SEEK.SET))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .INVAL => return error.Unseekable,
- .OVERFLOW => return error.Unseekable,
- .SPIPE => return error.Unseekable,
- .NXIO => return error.Unseekable,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .INVAL => return error.Unseekable,
+ .OVERFLOW => return error.Unseekable,
+ .SPIPE => return error.Unseekable,
+ .NXIO => return error.Unseekable,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -2907,8 +3329,8 @@ fn fileWritePositional(
offset: u64,
) Io.File.WritePositionalError!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ _ = t;
while (true) {
- try t.checkCancel();
_ = file;
_ = buffer;
_ = offset;
@@ -2918,8 +3340,8 @@ fn fileWritePositional(
fn fileWriteStreaming(userdata: ?*anyopaque, file: Io.File, buffer: [][]const u8) Io.File.WriteStreamingError!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ _ = t;
while (true) {
- try t.checkCancel();
_ = file;
_ = buffer;
@panic("TODO implement fileWriteStreaming");
@@ -2997,6 +3419,7 @@ const sleep = switch (native_os) {
fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const clock_id: posix.clockid_t = clockToPosix(switch (timeout) {
.none => .awake,
.duration => |d| d.clock,
@@ -3008,25 +3431,37 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
.deadline => |deadline| deadline.raw.nanoseconds,
};
var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
.none, .duration => false,
.deadline => true,
} }, ×pec, ×pec))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
- .INVAL => return error.UnsupportedClock,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => return error.UnsupportedClock,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const t_io = ioBasic(t);
- try t.checkCancel();
+ try current_thread.checkCancel();
const ms = ms: {
const d = (try timeout.toDurationFromNow(t_io)) orelse
break :ms std.math.maxInt(windows.DWORD);
@@ -3038,9 +3473,8 @@ fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const t_io = ioBasic(t);
- try t.checkCancel();
-
const w = std.os.wasi;
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 {
};
var event: w.event_t = undefined;
var nevents: usize = undefined;
+ try current_thread.beginSyscall();
_ = w.poll_oneoff(&in, &event, 1, &nevents);
+ current_thread.endSyscall();
}
fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const t_io = ioBasic(t);
const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
@@ -3079,12 +3516,18 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
};
break :t timestampToPosix(d.raw.toNanoseconds());
};
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.nanosleep(×pec, ×pec))) {
- .INTR => continue,
- .CANCELED => return error.Canceled,
- else => return, // This prong handles success as well as unexpected errors.
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => {
+ // This prong handles success as well as unexpected errors.
+ current_thread.endSyscall();
+ return;
+ },
}
}
}
@@ -3127,34 +3570,48 @@ fn netListenIpPosix(
) IpAddress.ListenError!net.Server {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const family = posixAddressFamily(&address);
- const socket_fd = try openSocketPosix(t, family, .{
+ const socket_fd = try openSocketPosix(current_thread, family, .{
.mode = options.mode,
.protocol = options.protocol,
});
errdefer posix.close(socket_fd);
if (options.reuse_address) {
- try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
+ try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
if (@hasDecl(posix.SO, "REUSEPORT"))
- try setSocketOption(t, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);
+ try setSocketOption(current_thread, socket_fd, posix.SOL.SOCKET, posix.SO.REUSEPORT, 1);
}
var storage: PosixAddress = undefined;
var addr_len = addressToPosix(&address, &storage);
- try posixBind(t, socket_fd, &storage.any, addr_len);
+ try posixBind(current_thread, socket_fd, &storage.any, addr_len);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
- .SUCCESS => break,
- .ADDRINUSE => return error.AddressInUse,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ADDRINUSE => return error.AddressInUse,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
- try posixGetSockName(t, socket_fd, &storage.any, &addr_len);
+ try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
return .{
.socket = .{
.handle = socket_fd,
@@ -3170,8 +3627,9 @@ fn netListenIpWindows(
) IpAddress.ListenError!net.Server {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const family = posixAddressFamily(&address);
- const socket_handle = try openSocketWsa(t, family, .{
+ const socket_handle = try openSocketWsa(t, current_thread, family, .{
.mode = options.mode,
.protocol = options.protocol,
});
@@ -3183,52 +3641,73 @@ fn netListenIpWindows(
var storage: WsaAddress = undefined;
var addr_len = addressToWsa(&address, &storage);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
if (rc != ws2_32.SOCKET_ERROR) break;
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
- .EADDRINUSE => return error.AddressInUse,
- .EADDRNOTAVAIL => return error.AddressUnavailable,
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EFAULT => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- .ENOBUFS => return error.SystemResources,
- .ENETDOWN => return error.NetworkDown,
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EADDRINUSE => return error.AddressInUse,
+ .EADDRNOTAVAIL => return error.AddressUnavailable,
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EFAULT => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ .ENOBUFS => return error.SystemResources,
+ .ENETDOWN => return error.NetworkDown,
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
+ try current_thread.checkCancel();
while (true) {
- try t.checkCancel();
const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
- if (rc != ws2_32.SOCKET_ERROR) break;
+ if (rc != ws2_32.SOCKET_ERROR) {
+ current_thread.endSyscall();
+ break;
+ }
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
- .ENETDOWN => return error.NetworkDown,
- .EADDRINUSE => return error.AddressInUse,
- .EISCONN => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- .EMFILE, .ENOBUFS => return error.SystemResources,
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EOPNOTSUPP => |err| return wsaErrorBug(err),
- .EINPROGRESS => |err| return wsaErrorBug(err),
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .ENETDOWN => return error.NetworkDown,
+ .EADDRINUSE => return error.AddressInUse,
+ .EISCONN => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ .EMFILE, .ENOBUFS => return error.SystemResources,
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EOPNOTSUPP => |err| return wsaErrorBug(err),
+ .EINPROGRESS => |err| return wsaErrorBug(err),
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
- try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
+ try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
return .{
.socket = .{
@@ -3256,7 +3735,8 @@ fn netListenUnixPosix(
) net.UnixAddress.ListenError!net.Socket.Handle {
if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
const t: *Threaded = @ptrCast(@alignCast(userdata));
- const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
+ const current_thread = Thread.getCurrent(t);
+ const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
error.ProtocolUnsupportedBySystem => return error.AddressFamilyUnsupported,
error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
error.SocketModeUnsupported => return error.AddressFamilyUnsupported,
@@ -3267,15 +3747,28 @@ fn netListenUnixPosix(
var storage: UnixAddress = undefined;
const addr_len = addressUnixToPosix(address, &storage);
- try posixBindUnix(t, socket_fd, &storage.any, addr_len);
+ try posixBindUnix(current_thread, socket_fd, &storage.any, addr_len);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.listen(socket_fd, options.kernel_backlog))) {
- .SUCCESS => break,
- .ADDRINUSE => return error.AddressInUse,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ADDRINUSE => return error.AddressInUse,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
@@ -3289,8 +3782,9 @@ fn netListenUnixWindows(
) net.UnixAddress.ListenError!net.Socket.Handle {
if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
- const socket_handle = openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
+ const socket_handle = openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
error.ProtocolUnsupportedByAddressFamily => return error.AddressFamilyUnsupported,
else => |e| return e,
};
@@ -3299,52 +3793,67 @@ fn netListenUnixWindows(
var storage: WsaAddress = undefined;
const addr_len = addressUnixToWsa(address, &storage);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
if (rc != ws2_32.SOCKET_ERROR) break;
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
- .EADDRINUSE => return error.AddressInUse,
- .EADDRNOTAVAIL => return error.AddressUnavailable,
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EFAULT => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- .ENOBUFS => return error.SystemResources,
- .ENETDOWN => return error.NetworkDown,
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EADDRINUSE => return error.AddressInUse,
+ .EADDRNOTAVAIL => return error.AddressUnavailable,
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EFAULT => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ .ENOBUFS => return error.SystemResources,
+ .ENETDOWN => return error.NetworkDown,
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
const rc = ws2_32.listen(socket_handle, options.kernel_backlog);
- if (rc != ws2_32.SOCKET_ERROR) break;
+ if (rc != ws2_32.SOCKET_ERROR) {
+ current_thread.endSyscall();
+ return socket_handle;
+ }
switch (ws2_32.WSAGetLastError()) {
.EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
.NOTINITIALISED => {
try initializeWsa(t);
continue;
},
- .ENETDOWN => return error.NetworkDown,
- .EADDRINUSE => return error.AddressInUse,
- .EISCONN => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- .EMFILE, .ENOBUFS => return error.SystemResources,
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EOPNOTSUPP => |err| return wsaErrorBug(err),
- .EINPROGRESS => |err| return wsaErrorBug(err),
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .ENETDOWN => return error.NetworkDown,
+ .EADDRINUSE => return error.AddressInUse,
+ .EISCONN => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ .EMFILE, .ENOBUFS => return error.SystemResources,
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EOPNOTSUPP => |err| return wsaErrorBug(err),
+ .EINPROGRESS => |err| return wsaErrorBug(err),
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
-
- return socket_handle;
}
fn netListenUnixUnavailable(
@@ -3358,172 +3867,275 @@ fn netListenUnixUnavailable(
return error.AddressFamilyUnsupported;
}
-fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
+fn posixBindUnix(
+ current_thread: *Thread,
+ fd: posix.socket_t,
+ addr: *const posix.sockaddr,
+ addr_len: posix.socklen_t,
+) !void {
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.bind(fd, addr, addr_len))) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ACCES => return error.AccessDenied,
- .ADDRINUSE => return error.AddressInUse,
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .ADDRNOTAVAIL => return error.AddressUnavailable,
- .NOMEM => return error.SystemResources,
-
- .LOOP => return error.SymLinkLoop,
- .NOENT => return error.FileNotFound,
- .NOTDIR => return error.NotDir,
- .ROFS => return error.ReadOnlyFileSystem,
- .PERM => return error.PermissionDenied,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .INVAL => |err| return errnoBug(err), // invalid parameters
- .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
- .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
- .NAMETOOLONG => |err| return errnoBug(err),
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ACCES => return error.AccessDenied,
+ .ADDRINUSE => return error.AddressInUse,
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .ADDRNOTAVAIL => return error.AddressUnavailable,
+ .NOMEM => return error.SystemResources,
+
+ .LOOP => return error.SymLinkLoop,
+ .NOENT => return error.FileNotFound,
+ .NOTDIR => return error.NotDir,
+ .ROFS => return error.ReadOnlyFileSystem,
+ .PERM => return error.PermissionDenied,
+
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .INVAL => |err| return errnoBug(err), // invalid parameters
+ .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
+ .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
+ .NAMETOOLONG => |err| return errnoBug(err),
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
-fn posixBind(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
+fn posixBind(
+ current_thread: *Thread,
+ socket_fd: posix.socket_t,
+ addr: *const posix.sockaddr,
+ addr_len: posix.socklen_t,
+) !void {
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ADDRINUSE => return error.AddressInUse,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .INVAL => |err| return errnoBug(err), // invalid parameters
- .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .ADDRNOTAVAIL => return error.AddressUnavailable,
- .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
- .NOMEM => return error.SystemResources,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ADDRINUSE => return error.AddressInUse,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .INVAL => |err| return errnoBug(err), // invalid parameters
+ .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .ADDRNOTAVAIL => return error.AddressUnavailable,
+ .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
+ .NOMEM => return error.SystemResources,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
-fn posixConnect(t: *Threaded, socket_fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
+fn posixConnect(
+ current_thread: *Thread,
+ socket_fd: posix.socket_t,
+ addr: *const posix.sockaddr,
+ addr_len: posix.socklen_t,
+) !void {
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ADDRNOTAVAIL => return error.AddressUnavailable,
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .AGAIN, .INPROGRESS => return error.WouldBlock,
- .ALREADY => return error.ConnectionPending,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .CONNREFUSED => return error.ConnectionRefused,
- .CONNRESET => return error.ConnectionResetByPeer,
- .FAULT => |err| return errnoBug(err),
- .ISCONN => |err| return errnoBug(err),
- .HOSTUNREACH => return error.HostUnreachable,
- .NETUNREACH => return error.NetworkUnreachable,
- .NOTSOCK => |err| return errnoBug(err),
- .PROTOTYPE => |err| return errnoBug(err),
- .TIMEDOUT => return error.Timeout,
- .CONNABORTED => |err| return errnoBug(err),
- .ACCES => return error.AccessDenied,
- .PERM => |err| return errnoBug(err),
- .NOENT => |err| return errnoBug(err),
- .NETDOWN => return error.NetworkDown,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ADDRNOTAVAIL => return error.AddressUnavailable,
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .AGAIN, .INPROGRESS => return error.WouldBlock,
+ .ALREADY => return error.ConnectionPending,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .CONNREFUSED => return error.ConnectionRefused,
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .FAULT => |err| return errnoBug(err),
+ .ISCONN => |err| return errnoBug(err),
+ .HOSTUNREACH => return error.HostUnreachable,
+ .NETUNREACH => return error.NetworkUnreachable,
+ .NOTSOCK => |err| return errnoBug(err),
+ .PROTOTYPE => |err| return errnoBug(err),
+ .TIMEDOUT => return error.Timeout,
+ .CONNABORTED => |err| return errnoBug(err),
+ .ACCES => return error.AccessDenied,
+ .PERM => |err| return errnoBug(err),
+ .NOENT => |err| return errnoBug(err),
+ .NETDOWN => return error.NetworkDown,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
-fn posixConnectUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
+fn posixConnectUnix(
+ current_thread: *Thread,
+ fd: posix.socket_t,
+ addr: *const posix.sockaddr,
+ addr_len: posix.socklen_t,
+) !void {
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.connect(fd, addr, addr_len))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .AGAIN => return error.WouldBlock,
- .INPROGRESS => return error.WouldBlock,
- .ACCES => return error.AccessDenied,
-
- .LOOP => return error.SymLinkLoop,
- .NOENT => return error.FileNotFound,
- .NOTDIR => return error.NotDir,
- .ROFS => return error.ReadOnlyFileSystem,
- .PERM => return error.PermissionDenied,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .CONNABORTED => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .ISCONN => |err| return errnoBug(err),
- .NOTSOCK => |err| return errnoBug(err),
- .PROTOTYPE => |err| return errnoBug(err),
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .AGAIN => return error.WouldBlock,
+ .INPROGRESS => return error.WouldBlock,
+ .ACCES => return error.AccessDenied,
+
+ .LOOP => return error.SymLinkLoop,
+ .NOENT => return error.FileNotFound,
+ .NOTDIR => return error.NotDir,
+ .ROFS => return error.ReadOnlyFileSystem,
+ .PERM => return error.PermissionDenied,
+
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .CONNABORTED => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .ISCONN => |err| return errnoBug(err),
+ .NOTSOCK => |err| return errnoBug(err),
+ .PROTOTYPE => |err| return errnoBug(err),
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
-fn posixGetSockName(t: *Threaded, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void {
+fn posixGetSockName(
+ current_thread: *Thread,
+ socket_fd: posix.fd_t,
+ addr: *posix.sockaddr,
+ addr_len: *posix.socklen_t,
+) !void {
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) {
- .SUCCESS => break,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .FAULT => |err| return errnoBug(err),
- .INVAL => |err| return errnoBug(err), // invalid parameters
- .NOTSOCK => |err| return errnoBug(err), // always a race condition
- .NOBUFS => return error.SystemResources,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ break;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => |err| return errnoBug(err), // invalid parameters
+ .NOTSOCK => |err| return errnoBug(err), // always a race condition
+ .NOBUFS => return error.SystemResources,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
-fn wsaGetSockName(t: *Threaded, handle: ws2_32.SOCKET, addr: *ws2_32.sockaddr, addr_len: *i32) !void {
+fn wsaGetSockName(
+ t: *Threaded,
+ current_thread: *Thread,
+ handle: ws2_32.SOCKET,
+ addr: *ws2_32.sockaddr,
+ addr_len: *i32,
+) !void {
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = ws2_32.getsockname(handle, addr, addr_len);
- if (rc != ws2_32.SOCKET_ERROR) break;
+ if (rc != ws2_32.SOCKET_ERROR) {
+ current_thread.endSyscall();
+ return;
+ }
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
- .ENETDOWN => return error.NetworkDown,
- .EFAULT => |err| return wsaErrorBug(err),
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .ENETDOWN => return error.NetworkDown,
+ .EFAULT => |err| return wsaErrorBug(err),
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
}
-fn setSocketOption(t: *Threaded, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
+fn setSocketOption(current_thread: *Thread, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
const o: []const u8 = @ptrCast(&option);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) {
- .SUCCESS => return,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOTSOCK => |err| return errnoBug(err),
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOTSOCK => |err| return errnoBug(err),
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -3557,16 +4169,17 @@ fn netConnectIpPosix(
if (!have_networking) return error.NetworkDown;
if (options.timeout != .none) @panic("TODO implement netConnectIpPosix with timeout");
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const family = posixAddressFamily(address);
- const socket_fd = try openSocketPosix(t, family, .{
+ const socket_fd = try openSocketPosix(current_thread, family, .{
.mode = options.mode,
.protocol = options.protocol,
});
errdefer posix.close(socket_fd);
var storage: PosixAddress = undefined;
var addr_len = addressToPosix(address, &storage);
- try posixConnect(t, socket_fd, &storage.any, addr_len);
- try posixGetSockName(t, socket_fd, &storage.any, &addr_len);
+ try posixConnect(current_thread, socket_fd, &storage.any, addr_len);
+ try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
return .{ .socket = .{
.handle = socket_fd,
.address = addressFromPosix(&storage),
@@ -3581,8 +4194,9 @@ fn netConnectIpWindows(
if (!have_networking) return error.NetworkDown;
if (options.timeout != .none) @panic("TODO implement netConnectIpWindows with timeout");
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const family = posixAddressFamily(address);
- const socket_handle = try openSocketWsa(t, family, .{
+ const socket_handle = try openSocketWsa(t, current_thread, family, .{
.mode = options.mode,
.protocol = options.protocol,
});
@@ -3591,36 +4205,48 @@ fn netConnectIpWindows(
var storage: WsaAddress = undefined;
var addr_len = addressToWsa(address, &storage);
+ try current_thread.beginSyscall();
while (true) {
const rc = ws2_32.connect(socket_handle, &storage.any, addr_len);
- if (rc != ws2_32.SOCKET_ERROR) break;
+ if (rc != ws2_32.SOCKET_ERROR) {
+ current_thread.endSyscall();
+ break;
+ }
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
-
- .EADDRNOTAVAIL => return error.AddressUnavailable,
- .ECONNREFUSED => return error.ConnectionRefused,
- .ECONNRESET => return error.ConnectionResetByPeer,
- .ETIMEDOUT => return error.Timeout,
- .EHOSTUNREACH => return error.HostUnreachable,
- .ENETUNREACH => return error.NetworkUnreachable,
- .EFAULT => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- .EISCONN => |err| return wsaErrorBug(err),
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EWOULDBLOCK => return error.WouldBlock,
- .EACCES => return error.AccessDenied,
- .ENOBUFS => return error.SystemResources,
- .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EADDRNOTAVAIL => return error.AddressUnavailable,
+ .ECONNREFUSED => return error.ConnectionRefused,
+ .ECONNRESET => return error.ConnectionResetByPeer,
+ .ETIMEDOUT => return error.Timeout,
+ .EHOSTUNREACH => return error.HostUnreachable,
+ .ENETUNREACH => return error.NetworkUnreachable,
+ .EFAULT => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ .EISCONN => |err| return wsaErrorBug(err),
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EWOULDBLOCK => return error.WouldBlock,
+ .EACCES => return error.AccessDenied,
+ .ENOBUFS => return error.SystemResources,
+ .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
- try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
+ try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
return .{ .socket = .{
.handle = socket_handle,
@@ -3645,14 +4271,15 @@ fn netConnectUnixPosix(
) net.UnixAddress.ConnectError!net.Socket.Handle {
if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
const t: *Threaded = @ptrCast(@alignCast(userdata));
- const socket_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
+ const current_thread = Thread.getCurrent(t);
+ const socket_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .stream }) catch |err| switch (err) {
error.OptionUnsupported => return error.Unexpected,
else => |e| return e,
};
errdefer posix.close(socket_fd);
var storage: UnixAddress = undefined;
const addr_len = addressUnixToPosix(address, &storage);
- try posixConnectUnix(t, socket_fd, &storage.any, addr_len);
+ try posixConnectUnix(current_thread, socket_fd, &storage.any, addr_len);
return socket_fd;
}
@@ -3662,8 +4289,9 @@ fn netConnectUnixWindows(
) net.UnixAddress.ConnectError!net.Socket.Handle {
if (!net.has_unix_sockets) return error.AddressFamilyUnsupported;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
- const socket_handle = try openSocketWsa(t, posix.AF.UNIX, .{ .mode = .stream });
+ const socket_handle = try openSocketWsa(t, current_thread, posix.AF.UNIX, .{ .mode = .stream });
errdefer closeSocketWindows(socket_handle);
var storage: WsaAddress = undefined;
const addr_len = addressUnixToWsa(address, &storage);
@@ -3711,13 +4339,14 @@ fn netBindIpPosix(
) IpAddress.BindError!net.Socket {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const family = posixAddressFamily(address);
- const socket_fd = try openSocketPosix(t, family, options);
+ const socket_fd = try openSocketPosix(current_thread, family, options);
errdefer posix.close(socket_fd);
var storage: PosixAddress = undefined;
var addr_len = addressToPosix(address, &storage);
- try posixBind(t, socket_fd, &storage.any, addr_len);
- try posixGetSockName(t, socket_fd, &storage.any, &addr_len);
+ try posixBind(current_thread, socket_fd, &storage.any, addr_len);
+ try posixGetSockName(current_thread, socket_fd, &storage.any, &addr_len);
return .{
.handle = socket_fd,
.address = addressFromPosix(&storage),
@@ -3731,8 +4360,9 @@ fn netBindIpWindows(
) IpAddress.BindError!net.Socket {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const family = posixAddressFamily(address);
- const socket_handle = try openSocketWsa(t, family, .{
+ const socket_handle = try openSocketWsa(t, current_thread, family, .{
.mode = options.mode,
.protocol = options.protocol,
});
@@ -3741,29 +4371,41 @@ fn netBindIpWindows(
var storage: WsaAddress = undefined;
var addr_len = addressToWsa(address, &storage);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = ws2_32.bind(socket_handle, &storage.any, addr_len);
- if (rc != ws2_32.SOCKET_ERROR) break;
+ if (rc != ws2_32.SOCKET_ERROR) {
+ current_thread.endSyscall();
+ break;
+ }
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
- .EADDRINUSE => return error.AddressInUse,
- .EADDRNOTAVAIL => return error.AddressUnavailable,
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EFAULT => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- .ENOBUFS => return error.SystemResources,
- .ENETDOWN => return error.NetworkDown,
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EADDRINUSE => return error.AddressInUse,
+ .EADDRNOTAVAIL => return error.AddressUnavailable,
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EFAULT => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ .ENOBUFS => return error.SystemResources,
+ .ENETDOWN => return error.NetworkDown,
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
- try wsaGetSockName(t, socket_handle, &storage.any, &addr_len);
+ try wsaGetSockName(t, current_thread, socket_handle, &storage.any, &addr_len);
return .{
.handle = socket_handle,
@@ -3783,7 +4425,7 @@ fn netBindIpUnavailable(
}
fn openSocketPosix(
- t: *Threaded,
+ current_thread: *Thread,
family: posix.sa_family_t,
options: IpAddress.BindOptions,
) error{
@@ -3800,8 +4442,8 @@ fn openSocketPosix(
}!posix.socket_t {
const mode = posixSocketMode(options.mode);
const protocol = posixProtocol(options.protocol);
+ try current_thread.beginSyscall();
const socket_fd = while (true) {
- try t.checkCancel();
const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
const socket_rc = posix.system.socket(family, flags, protocol);
switch (posix.errno(socket_rc)) {
@@ -3809,60 +4451,90 @@ fn openSocketPosix(
const fd: posix.fd_t = @intCast(socket_rc);
errdefer posix.close(fd);
if (socket_flags_unsupported) while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
.SUCCESS => break,
.INTR => continue,
- .CANCELED => return error.Canceled,
- else => |err| return posix.unexpectedErrno(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
};
+ current_thread.endSyscall();
break fd;
},
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .INVAL => return error.ProtocolUnsupportedBySystem,
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
- .PROTOTYPE => return error.SocketModeUnsupported,
- else => |err| return posix.unexpectedErrno(err),
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .INVAL => return error.ProtocolUnsupportedBySystem,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
+ .PROTOTYPE => return error.SocketModeUnsupported,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
};
errdefer posix.close(socket_fd);
if (options.ip6_only) {
if (posix.IPV6 == void) return error.OptionUnsupported;
- try setSocketOption(t, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
+ try setSocketOption(current_thread, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
}
return socket_fd;
}
-fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.BindOptions) !ws2_32.SOCKET {
+fn openSocketWsa(
+ t: *Threaded,
+ current_thread: *Thread,
+ family: posix.sa_family_t,
+ options: IpAddress.BindOptions,
+) !ws2_32.SOCKET {
const mode = posixSocketMode(options.mode);
const protocol = posixProtocol(options.protocol);
const flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED | ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = ws2_32.WSASocketW(family, @bitCast(mode), @bitCast(protocol), null, 0, flags);
- if (rc != ws2_32.INVALID_SOCKET) return rc;
+ if (rc != ws2_32.INVALID_SOCKET) {
+ current_thread.endSyscall();
+ return rc;
+ }
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
- .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
- .EMFILE => return error.ProcessFdQuotaExceeded,
- .ENOBUFS => return error.SystemResources,
- .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .EMFILE => return error.ProcessFdQuotaExceeded,
+ .ENOBUFS => return error.SystemResources,
+ .EPROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
}
@@ -3870,10 +4542,11 @@ fn openSocketWsa(t: *Threaded, family: posix.sa_family_t, options: IpAddress.Bin
fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Stream {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var storage: PosixAddress = undefined;
var addr_len: posix.socklen_t = @sizeOf(PosixAddress);
+ try current_thread.beginSyscall();
const fd = while (true) {
- try t.checkCancel();
const rc = if (have_accept4)
posix.system.accept4(listen_fd, &storage.any, &addr_len, posix.SOCK.CLOEXEC)
else
@@ -3883,33 +4556,43 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
const fd: posix.fd_t = @intCast(rc);
errdefer posix.close(fd);
if (!have_accept4) while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
.SUCCESS => break,
.INTR => continue,
- .CANCELED => return error.Canceled,
- else => |err| return posix.unexpectedErrno(err),
+ else => |err| {
+ current_thread.endSyscall();
+ return posix.unexpectedErrno(err);
+ },
}
};
+ current_thread.endSyscall();
break fd;
},
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .AGAIN => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .CONNABORTED => return error.ConnectionAborted,
- .FAULT => |err| return errnoBug(err),
- .INVAL => return error.SocketNotListening,
- .NOTSOCK => |err| return errnoBug(err),
- .MFILE => return error.ProcessFdQuotaExceeded,
- .NFILE => return error.SystemFdQuotaExceeded,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .OPNOTSUPP => |err| return errnoBug(err),
- .PROTO => return error.ProtocolFailure,
- .PERM => return error.BlockedByFirewall,
- else => |err| return posix.unexpectedErrno(err),
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .AGAIN => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .CONNABORTED => return error.ConnectionAborted,
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => return error.SocketNotListening,
+ .NOTSOCK => |err| return errnoBug(err),
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .OPNOTSUPP => |err| return errnoBug(err),
+ .PROTO => return error.ProtocolFailure,
+ .PERM => return error.BlockedByFirewall,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
};
return .{ .socket = .{
@@ -3921,31 +4604,44 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var storage: WsaAddress = undefined;
var addr_len: i32 = @sizeOf(WsaAddress);
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = ws2_32.accept(listen_handle, &storage.any, &addr_len);
- if (rc != ws2_32.INVALID_SOCKET) return .{ .socket = .{
- .handle = rc,
- .address = addressFromWsa(&storage),
- } };
+ if (rc != ws2_32.INVALID_SOCKET) {
+ current_thread.endSyscall();
+ return .{ .socket = .{
+ .handle = rc,
+ .address = addressFromWsa(&storage),
+ } };
+ }
switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
.NOTINITIALISED => {
try initializeWsa(t);
+ try current_thread.checkCancel();
continue;
},
- .ECONNRESET => return error.ConnectionAborted,
- .EFAULT => |err| return wsaErrorBug(err),
- .ENOTSOCK => |err| return wsaErrorBug(err),
- .EINVAL => |err| return wsaErrorBug(err),
- .EMFILE => return error.ProcessFdQuotaExceeded,
- .ENETDOWN => return error.NetworkDown,
- .ENOBUFS => return error.SystemResources,
- .EOPNOTSUPP => |err| return wsaErrorBug(err),
- else => |err| return windows.unexpectedWSAError(err),
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .ECONNRESET => return error.ConnectionAborted,
+ .EFAULT => |err| return wsaErrorBug(err),
+ .ENOTSOCK => |err| return wsaErrorBug(err),
+ .EINVAL => |err| return wsaErrorBug(err),
+ .EMFILE => return error.ProcessFdQuotaExceeded,
+ .ENETDOWN => return error.NetworkDown,
+ .ENOBUFS => return error.SystemResources,
+ .EOPNOTSUPP => |err| return wsaErrorBug(err),
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
}
}
}
@@ -3959,6 +4655,7 @@ fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle)
fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
var i: usize = 0;
@@ -3972,48 +4669,70 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
const dest = iovecs_buffer[0..i];
assert(dest[0].len > 0);
- if (native_os == .wasi and !builtin.link_libc) while (true) {
- try t.checkCancel();
- var n: usize = undefined;
- switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
- .SUCCESS => return n,
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .AGAIN => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTCONN => return error.SocketUnconnected,
- .CONNRESET => return error.ConnectionResetByPeer,
- .TIMEDOUT => return error.Timeout,
- .NOTCAPABLE => return error.AccessDenied,
- else => |err| return posix.unexpectedErrno(err),
+ if (native_os == .wasi and !builtin.link_libc) {
+ try current_thread.beginSyscall();
+ while (true) {
+ var n: usize = undefined;
+ switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return n;
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .AGAIN => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTCONN => return error.SocketUnconnected,
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .TIMEDOUT => return error.Timeout,
+ .NOTCAPABLE => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
+ }
}
- };
+ }
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
switch (posix.errno(rc)) {
- .SUCCESS => return @intCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .AGAIN => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTCONN => return error.SocketUnconnected,
- .CONNRESET => return error.ConnectionResetByPeer,
- .TIMEDOUT => return error.Timeout,
- .PIPE => return error.SocketUnconnected,
- .NETDOWN => return error.NetworkDown,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return @intCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .AGAIN => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTCONN => return error.SocketUnconnected,
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .TIMEDOUT => return error.Timeout,
+ .PIPE => return error.SocketUnconnected,
+ .NETDOWN => return error.NetworkDown,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -4021,6 +4740,7 @@ fn netReadPosix(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.
fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const bufs = b: {
var iovec_buffer: [max_iovecs_len]ws2_32.WSABUF = undefined;
@@ -4048,7 +4768,7 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8
};
while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
var flags: u32 = 0;
var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
@@ -4108,6 +4828,7 @@ fn netSendPosix(
) struct { ?net.Socket.SendError, usize } {
if (!have_networking) return .{ error.NetworkDown, 0 };
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const posix_flags: u32 =
@as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |
@@ -4120,10 +4841,10 @@ fn netSendPosix(
var i: usize = 0;
while (messages.len - i != 0) {
if (have_sendmmsg) {
- i += netSendMany(t, handle, messages[i..], posix_flags) catch |err| return .{ err, i };
+ i += netSendMany(current_thread, handle, messages[i..], posix_flags) catch |err| return .{ err, i };
continue;
}
- netSendOne(t, handle, &messages[i], posix_flags) catch |err| return .{ err, i };
+ netSendOne(t, current_thread, handle, &messages[i], posix_flags) catch |err| return .{ err, i };
i += 1;
}
return .{ null, i };
@@ -4159,6 +4880,7 @@ fn netSendUnavailable(
fn netSendOne(
t: *Threaded,
+ current_thread: *Thread,
handle: net.Socket.Handle,
message: *net.OutgoingMessage,
flags: u32,
@@ -4175,75 +4897,92 @@ fn netSendOne(
.controllen = @intCast(message.control.len),
.flags = 0,
};
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = posix.system.sendmsg(handle, &msg, flags);
if (is_windows) {
- if (rc == ws2_32.SOCKET_ERROR) {
- switch (ws2_32.WSAGetLastError()) {
- .EINTR => continue,
- .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
- .NOTINITIALISED => {
- try initializeWsa(t);
- continue;
- },
- .EACCES => return error.AccessDenied,
- .EADDRNOTAVAIL => return error.AddressUnavailable,
- .ECONNRESET => return error.ConnectionResetByPeer,
- .EMSGSIZE => return error.MessageOversize,
- .ENOBUFS => return error.SystemResources,
- .ENOTSOCK => return error.FileDescriptorNotASocket,
- .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
- .EDESTADDRREQ => unreachable, // A destination address is required.
- .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.
- .EHOSTUNREACH => return error.NetworkUnreachable,
- .EINVAL => unreachable,
- .ENETDOWN => return error.NetworkDown,
- .ENETRESET => return error.ConnectionResetByPeer,
- .ENETUNREACH => return error.NetworkUnreachable,
- .ENOTCONN => return error.SocketUnconnected,
- .ESHUTDOWN => |err| return wsaErrorBug(err),
- else => |err| return windows.unexpectedWSAError(err),
- }
- } else {
+ if (rc != ws2_32.SOCKET_ERROR) {
+ current_thread.endSyscall();
message.data_len = @intCast(rc);
return;
}
+ switch (ws2_32.WSAGetLastError()) {
+ .EINTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ .NOTINITIALISED => {
+ try initializeWsa(t);
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ECANCELLED, .E_CANCELLED, .OPERATION_ABORTED => return error.Canceled,
+ .EACCES => return error.AccessDenied,
+ .EADDRNOTAVAIL => return error.AddressUnavailable,
+ .ECONNRESET => return error.ConnectionResetByPeer,
+ .EMSGSIZE => return error.MessageOversize,
+ .ENOBUFS => return error.SystemResources,
+ .ENOTSOCK => return error.FileDescriptorNotASocket,
+ .EAFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .EDESTADDRREQ => unreachable, // A destination address is required.
+ .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.
+ .EHOSTUNREACH => return error.NetworkUnreachable,
+ .EINVAL => unreachable,
+ .ENETDOWN => return error.NetworkDown,
+ .ENETRESET => return error.ConnectionResetByPeer,
+ .ENETUNREACH => return error.NetworkUnreachable,
+ .ENOTCONN => return error.SocketUnconnected,
+ .ESHUTDOWN => |err| return wsaErrorBug(err),
+ else => |err| return windows.unexpectedWSAError(err),
+ }
+ },
+ }
}
switch (posix.errno(rc)) {
.SUCCESS => {
+ current_thread.endSyscall();
message.data_len = @intCast(rc);
return;
},
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ACCES => return error.AccessDenied,
- .ALREADY => return error.FastOpenAlreadyInProgress,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .CONNRESET => return error.ConnectionResetByPeer,
- .DESTADDRREQ => |err| return errnoBug(err),
- .FAULT => |err| return errnoBug(err),
- .INVAL => |err| return errnoBug(err),
- .ISCONN => |err| return errnoBug(err),
- .MSGSIZE => return error.MessageOversize,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTSOCK => |err| return errnoBug(err),
- .OPNOTSUPP => |err| return errnoBug(err),
- .PIPE => return error.SocketUnconnected,
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .HOSTUNREACH => return error.HostUnreachable,
- .NETUNREACH => return error.NetworkUnreachable,
- .NOTCONN => return error.SocketUnconnected,
- .NETDOWN => return error.NetworkDown,
- else => |err| return posix.unexpectedErrno(err),
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ACCES => return error.AccessDenied,
+ .ALREADY => return error.FastOpenAlreadyInProgress,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .DESTADDRREQ => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => |err| return errnoBug(err),
+ .ISCONN => |err| return errnoBug(err),
+ .MSGSIZE => return error.MessageOversize,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTSOCK => |err| return errnoBug(err),
+ .OPNOTSUPP => |err| return errnoBug(err),
+ .PIPE => return error.SocketUnconnected,
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .HOSTUNREACH => return error.HostUnreachable,
+ .NETUNREACH => return error.NetworkUnreachable,
+ .NOTCONN => return error.SocketUnconnected,
+ .NETDOWN => return error.NetworkDown,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
fn netSendMany(
- t: *Threaded,
+ current_thread: *Thread,
handle: net.Socket.Handle,
messages: []net.OutgoingMessage,
flags: u32,
@@ -4273,40 +5012,48 @@ fn netSendMany(
};
}
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = posix.system.sendmmsg(handle, clamped_msgs.ptr, @intCast(clamped_msgs.len), flags);
switch (posix.errno(rc)) {
.SUCCESS => {
+ current_thread.endSyscall();
const n: usize = @intCast(rc);
for (clamped_messages[0..n], clamped_msgs[0..n]) |*message, *msg| {
message.data_len = msg.len;
}
return n;
},
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .AGAIN => |err| return errnoBug(err),
- .ALREADY => return error.FastOpenAlreadyInProgress,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .CONNRESET => return error.ConnectionResetByPeer,
- .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
- .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
- .INVAL => |err| return errnoBug(err), // Invalid argument passed.
- .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
- .MSGSIZE => return error.MessageOversize,
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
- .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
- .PIPE => return error.SocketUnconnected,
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .HOSTUNREACH => return error.HostUnreachable,
- .NETUNREACH => return error.NetworkUnreachable,
- .NOTCONN => return error.SocketUnconnected,
- .NETDOWN => return error.NetworkDown,
- else => |err| return posix.unexpectedErrno(err),
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .AGAIN => |err| return errnoBug(err),
+ .ALREADY => return error.FastOpenAlreadyInProgress,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
+ .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
+ .INVAL => |err| return errnoBug(err), // Invalid argument passed.
+ .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
+ .MSGSIZE => return error.MessageOversize,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
+ .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
+ .PIPE => return error.SocketUnconnected,
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .HOSTUNREACH => return error.HostUnreachable,
+ .NETUNREACH => return error.NetworkUnreachable,
+ .NOTCONN => return error.SocketUnconnected,
+ .NETDOWN => return error.NetworkDown,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -4321,6 +5068,7 @@ fn netReceivePosix(
) struct { ?net.Socket.ReceiveTimeoutError, usize } {
if (!have_networking) return .{ error.NetworkDown, 0 };
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const t_io = io(t);
// recvmmsg is useless, here's why:
@@ -4351,8 +5099,6 @@ fn netReceivePosix(
const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i };
recv: while (true) {
- t.checkCancel() catch |err| return .{ err, message_i };
-
if (message_buffer.len - message_i == 0) return .{ null, message_i };
const message = &message_buffer[message_i];
const remaining_data_buffer = data_buffer[data_i..];
@@ -4368,7 +5114,9 @@ fn netReceivePosix(
.flags = undefined,
};
+ current_thread.beginSyscall() catch |err| return .{ err, message_i };
const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags);
+ current_thread.endSyscall();
switch (posix.errno(recv_rc)) {
.SUCCESS => {
const data = remaining_data_buffer[0..@intCast(recv_rc)];
@@ -4389,7 +5137,6 @@ fn netReceivePosix(
continue;
},
.AGAIN => while (true) {
- t.checkCancel() catch |err| return .{ err, message_i };
if (message_i != 0) return .{ null, message_i };
const max_poll_ms = std.math.maxInt(u31);
@@ -4399,7 +5146,10 @@ fn netReceivePosix(
break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
} else max_poll_ms;
+ current_thread.beginSyscall() catch |err| return .{ err, message_i };
const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms);
+ current_thread.endSyscall();
+
switch (posix.errno(poll_rc)) {
.SUCCESS => {
if (poll_rc == 0) {
@@ -4486,6 +5236,7 @@ fn netWritePosix(
) net.Stream.Writer.Error!usize {
if (!have_networking) return error.NetworkDown;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
var iovecs: [max_iovecs_len]posix.iovec_const = undefined;
var msg: posix.msghdr_const = .{
@@ -4526,35 +5277,45 @@ fn netWritePosix(
},
};
const flags = posix.MSG.NOSIGNAL;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
const rc = posix.system.sendmsg(fd, &msg, flags);
switch (posix.errno(rc)) {
- .SUCCESS => return @intCast(rc),
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .ACCES => |err| return errnoBug(err),
- .AGAIN => |err| return errnoBug(err),
- .ALREADY => return error.FastOpenAlreadyInProgress,
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .CONNRESET => return error.ConnectionResetByPeer,
- .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
- .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
- .INVAL => |err| return errnoBug(err), // Invalid argument passed.
- .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
- .MSGSIZE => |err| return errnoBug(err),
- .NOBUFS => return error.SystemResources,
- .NOMEM => return error.SystemResources,
- .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
- .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
- .PIPE => return error.SocketUnconnected,
- .AFNOSUPPORT => return error.AddressFamilyUnsupported,
- .HOSTUNREACH => return error.HostUnreachable,
- .NETUNREACH => return error.NetworkUnreachable,
- .NOTCONN => return error.SocketUnconnected,
- .NETDOWN => return error.NetworkDown,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return @intCast(rc);
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .ACCES => |err| return errnoBug(err),
+ .AGAIN => |err| return errnoBug(err),
+ .ALREADY => return error.FastOpenAlreadyInProgress,
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .CONNRESET => return error.ConnectionResetByPeer,
+ .DESTADDRREQ => |err| return errnoBug(err), // The socket is not connection-mode, and no peer address is set.
+ .FAULT => |err| return errnoBug(err), // An invalid user space address was specified for an argument.
+ .INVAL => |err| return errnoBug(err), // Invalid argument passed.
+ .ISCONN => |err| return errnoBug(err), // connection-mode socket was connected already but a recipient was specified
+ .MSGSIZE => |err| return errnoBug(err),
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
+ .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type.
+ .PIPE => return error.SocketUnconnected,
+ .AFNOSUPPORT => return error.AddressFamilyUnsupported,
+ .HOSTUNREACH => return error.HostUnreachable,
+ .NETUNREACH => return error.NetworkUnreachable,
+ .NOTCONN => return error.SocketUnconnected,
+ .NETDOWN => return error.NetworkDown,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
@@ -4567,6 +5328,7 @@ fn netWriteWindows(
splat: usize,
) net.Stream.Writer.Error!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
comptime assert(native_os == .windows);
var iovecs: [max_iovecs_len]ws2_32.WSABUF = undefined;
@@ -4600,7 +5362,7 @@ fn netWriteWindows(
};
while (true) {
- try t.checkCancel();
+ try current_thread.checkCancel();
var n: u32 = undefined;
var overlapped: windows.OVERLAPPED = std.mem.zeroes(windows.OVERLAPPED);
@@ -4707,9 +5469,10 @@ fn netInterfaceNameResolve(
) net.Interface.Name.ResolveError!net.Interface {
if (!have_networking) return error.InterfaceNotFound;
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
if (native_os == .linux) {
- const sock_fd = openSocketPosix(t, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
+ const sock_fd = openSocketPosix(current_thread, posix.AF.UNIX, .{ .mode = .dgram }) catch |err| switch (err) {
error.ProcessFdQuotaExceeded => return error.SystemResources,
error.SystemFdQuotaExceeded => return error.SystemResources,
error.AddressFamilyUnsupported => return error.Unexpected,
@@ -4726,32 +5489,42 @@ fn netInterfaceNameResolve(
.ifru = undefined,
};
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.errno(posix.system.ioctl(sock_fd, posix.SIOCGIFINDEX, @intFromPtr(&ifr)))) {
- .SUCCESS => return .{ .index = @bitCast(ifr.ifru.ivalue) },
- .INTR => continue,
- .CANCELED => return error.Canceled,
-
- .INVAL => |err| return errnoBug(err), // Bad parameters.
- .NOTTY => |err| return errnoBug(err),
- .NXIO => |err| return errnoBug(err),
- .BADF => |err| return errnoBug(err), // File descriptor used after closed.
- .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
- .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
- .NODEV => return error.InterfaceNotFound,
- else => |err| return posix.unexpectedErrno(err),
+ .SUCCESS => {
+ current_thread.endSyscall();
+ return .{ .index = @bitCast(ifr.ifru.ivalue) };
+ },
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ .INVAL => |err| return errnoBug(err), // Bad parameters.
+ .NOTTY => |err| return errnoBug(err),
+ .NXIO => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err), // File descriptor used after closed.
+ .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
+ .IO => |err| return errnoBug(err), // sock_fd is not a file descriptor
+ .NODEV => return error.InterfaceNotFound,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ },
}
}
}
if (native_os == .windows) {
- try t.checkCancel();
+ try current_thread.checkCancel();
@panic("TODO implement netInterfaceNameResolve for Windows");
}
if (builtin.link_libc) {
- try t.checkCancel();
+ try current_thread.checkCancel();
const index = std.c.if_nametoindex(&name.bytes);
if (index == 0) return error.InterfaceNotFound;
return .{ .index = @bitCast(index) };
@@ -4771,7 +5544,8 @@ fn netInterfaceNameResolveUnavailable(
fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
const t: *Threaded = @ptrCast(@alignCast(userdata));
- try t.checkCancel();
+ const current_thread = Thread.getCurrent(t);
+ try current_thread.checkCancel();
if (native_os == .linux) {
_ = interface;
@@ -4802,8 +5576,9 @@ fn netLookup(
options: HostName.LookupOptions,
) void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
+ const current_thread = Thread.getCurrent(t);
const t_io = io(t);
- resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, host_name, resolved, options) });
+ resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, current_thread, host_name, resolved, options) });
}
fn netLookupUnavailable(
@@ -4821,6 +5596,7 @@ fn netLookupUnavailable(
fn netLookupFallible(
t: *Threaded,
+ current_thread: *Thread,
host_name: HostName,
resolved: *Io.Queue(HostName.LookupResult),
options: HostName.LookupOptions,
@@ -4866,7 +5642,7 @@ fn netLookupFallible(
var res: *ws2_32.ADDRINFOEXW = undefined;
const timeout: ?*ws2_32.timeval = null;
while (true) {
- try t.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
+ try current_thread.checkCancel(); // TODO make requestCancel call GetAddrInfoExCancel
// TODO make this append to the queue eagerly rather than blocking until
// the whole thing finishes
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(
.next = null,
};
var res: ?*posix.addrinfo = null;
+ try current_thread.beginSyscall();
while (true) {
- try t.checkCancel();
switch (posix.system.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
- @as(posix.system.EAI, @enumFromInt(0)) => break,
- .ADDRFAMILY => return error.AddressFamilyUnsupported,
- .AGAIN => return error.NameServerFailure,
- .FAIL => return error.NameServerFailure,
- .FAMILY => return error.AddressFamilyUnsupported,
- .MEMORY => return error.SystemResources,
- .NODATA => return error.UnknownHostName,
- .NONAME => return error.UnknownHostName,
+ @as(posix.system.EAI, @enumFromInt(0)) => {
+ current_thread.endSyscall();
+ break;
+ },
.SYSTEM => switch (posix.errno(-1)) {
- .INTR => continue,
- .CANCELED => return error.Canceled,
- else => |e| return posix.unexpectedErrno(e),
+ .INTR => {
+ try current_thread.checkCancel();
+ continue;
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .CANCELED => return error.Canceled,
+ else => |inner| return posix.unexpectedErrno(inner),
+ }
+ },
+ },
+ else => |e| {
+ current_thread.endSyscall();
+ switch (e) {
+ .ADDRFAMILY => return error.AddressFamilyUnsupported,
+ .AGAIN => return error.NameServerFailure,
+ .FAIL => return error.NameServerFailure,
+ .FAMILY => return error.AddressFamilyUnsupported,
+ .MEMORY => return error.SystemResources,
+ .NODATA => return error.UnknownHostName,
+ .NONAME => return error.UnknownHostName,
+ else => return error.Unexpected,
+ }
},
- else => return error.Unexpected,
}
}
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
/// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention)
const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11;
-fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {
+fn futexWait(current_thread: *Thread, ptr: *const std.atomic.Value(u32), expect: u32) Io.Cancelable!void {
@branchHint(.cold);
if (builtin.cpu.arch.isWasm()) {
comptime assert(builtin.cpu.has(.wasm, .atomics));
- try t.checkCancel();
+ try current_thread.checkCancel();
const timeout: i64 = -1;
const signed_expect: i32 = @bitCast(expect);
const result = asm volatile (
@@ -5754,8 +6546,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
} else switch (native_os) {
.linux => {
const linux = std.os.linux;
- try t.checkCancel();
+ try current_thread.beginSyscall();
const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
+ current_thread.endSyscall();
if (is_debug) switch (linux.errno(rc)) {
.SUCCESS => {}, // notified by `wake()`
.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
.op = .COMPARE_AND_WAIT,
.NO_ERRNO = true,
};
- try t.checkCancel();
+ try current_thread.beginSyscall();
const status = if (darwin_supports_ulock_wait2)
c.__ulock_wait2(flags, ptr, expect, 0, 0)
else
c.__ulock_wait(flags, ptr, expect, 0);
+ current_thread.endSyscall();
if (status >= 0) return;
@@ -5791,7 +6585,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
};
},
.windows => {
- try t.checkCancel();
+ try current_thread.checkCancel();
switch (windows.ntdll.RtlWaitOnAddress(ptr, &expect, @sizeOf(@TypeOf(expect)), null)) {
.SUCCESS => {},
.CANCELLED => return error.Canceled,
@@ -5800,8 +6594,9 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
},
.freebsd => {
const flags = @intFromEnum(std.c.UMTX_OP.WAIT_UINT_PRIVATE);
- try t.checkCancel();
+ try current_thread.beginSyscall();
const rc = std.c._umtx_op(@intFromPtr(&ptr.raw), flags, @as(c_ulong, expect), 0, 0);
+ current_thread.endSyscall();
if (is_debug) switch (posix.errno(rc)) {
.SUCCESS => {},
.FAULT => unreachable, // one of the args points to invalid memory
@@ -6050,8 +6845,9 @@ const ResetEventFutex = enum(u32) {
if (state == .unset) {
state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting;
}
+ const current_thread = Thread.getCurrent(t);
while (state == .waiting) {
- try futexWait(t, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
+ try futexWait(current_thread, @ptrCast(ref), @intFromEnum(ResetEventFutex.waiting));
state = @atomicLoad(ResetEventFutex, ref, .acquire);
}
assert(state == .is_set);
@@ -6140,6 +6936,7 @@ const ResetEventPosix = struct {
.waiting => unreachable, // Invalid state.
.is_set => return,
};
+ const current_thread = Thread.getCurrent(t);
assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS);
defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS);
sw: switch (rep.state) {
@@ -6148,8 +6945,9 @@ const ResetEventPosix = struct {
continue :sw .waiting;
},
.waiting => {
- try t.checkCancel();
+ try current_thread.beginSyscall();
assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS);
+ current_thread.endSyscall();
continue :sw rep.state;
},
.is_set => return,
@@ -6222,10 +7020,10 @@ const Wsa = struct {
} || Io.UnexpectedError;
};
-fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
+fn initializeWsa(t: *Threaded) error{ NetworkDown, Canceled }!void {
const t_io = io(t);
const wsa = &t.wsa;
- wsa.mutex.lockUncancelable(t_io);
+ try wsa.mutex.lock(t_io);
defer wsa.mutex.unlock(t_io);
switch (wsa.status) {
.uninitialized => {
@@ -6237,12 +7035,15 @@ fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
wsa.status = .initialized;
return;
},
- else => |err_int| switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
- .SYSNOTREADY => wsa.init_error = error.NetworkDown,
- .VERNOTSUPPORTED => wsa.init_error = error.VersionUnsupported,
- .EINPROGRESS => wsa.init_error = error.BlockingOperationInProgress,
- .EPROCLIM => wsa.init_error = error.ProcessFdQuotaExceeded,
- else => |err| wsa.init_error = windows.unexpectedWSAError(err),
+ else => |err_int| {
+ wsa.status = .failure;
+ wsa.init_error = switch (@as(ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(err_int))))) {
+ .SYSNOTREADY => error.NetworkDown,
+ .VERNOTSUPPORTED => error.VersionUnsupported,
+ .EINPROGRESS => error.BlockingOperationInProgress,
+ .EPROCLIM => error.ProcessFdQuotaExceeded,
+ else => |err| windows.unexpectedWSAError(err),
+ };
},
}
},