diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index b2daa35bcb..be9803adbf 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -168,80 +168,28 @@ pub fn io(t: *Threaded) Io { .conditionWaitUncancelable = conditionWaitUncancelable, .conditionWake = conditionWake, - .dirMake = switch (native_os) { - .windows => dirMakeWindows, - .wasi => dirMakeWasi, - else => dirMakePosix, - }, - .dirMakePath = switch (native_os) { - .windows => dirMakePathWindows, - else => dirMakePathPosix, - }, - .dirMakeOpenPath = switch (native_os) { - .windows => dirMakeOpenPathWindows, - .wasi => dirMakeOpenPathWasi, - else => dirMakeOpenPathPosix, - }, + .dirMake = dirMake, + .dirMakePath = dirMakePath, + .dirMakeOpenPath = dirMakeOpenPath, .dirStat = dirStat, - .dirStatPath = switch (native_os) { - .linux => dirStatPathLinux, - .windows => dirStatPathWindows, - .wasi => dirStatPathWasi, - else => dirStatPathPosix, - }, - .fileStat = switch (native_os) { - .linux => fileStatLinux, - .windows => fileStatWindows, - .wasi => fileStatWasi, - else => fileStatPosix, - }, - .dirAccess = switch (native_os) { - .windows => dirAccessWindows, - .wasi => dirAccessWasi, - else => dirAccessPosix, - }, - .dirCreateFile = switch (native_os) { - .windows => dirCreateFileWindows, - .wasi => dirCreateFileWasi, - else => dirCreateFilePosix, - }, - .dirOpenFile = switch (native_os) { - .windows => dirOpenFileWindows, - .wasi => dirOpenFileWasi, - else => dirOpenFilePosix, - }, - .dirOpenDir = switch (native_os) { - .wasi => dirOpenDirWasi, - .haiku => dirOpenDirHaiku, - else => dirOpenDirPosix, - }, + .dirStatPath = dirStatPath, + .fileStat = fileStat, + .dirAccess = dirAccess, + .dirCreateFile = dirCreateFile, + .dirOpenFile = dirOpenFile, + .dirOpenDir = dirOpenDir, .dirClose = dirClose, .fileClose = fileClose, .fileWriteStreaming = fileWriteStreaming, .fileWritePositional = fileWritePositional, - .fileReadStreaming = switch (native_os) { - .windows => fileReadStreamingWindows, - else => fileReadStreamingPosix, - }, - .fileReadPositional = switch (native_os) { - .windows => fileReadPositionalWindows, - else => fileReadPositionalPosix, - }, + .fileReadStreaming = fileReadStreaming, + .fileReadPositional = fileReadPositional, .fileSeekBy = fileSeekBy, .fileSeekTo = fileSeekTo, .openSelfExe = openSelfExe, - .now = switch (native_os) { - .windows => nowWindows, - .wasi => nowWasi, - else => nowPosix, - }, - .sleep = switch (native_os) { - .windows => sleepWindows, - .wasi => sleepWasi, - .linux => sleepLinux, - else => sleepPosix, - }, + .now = now, + .sleep = sleep, .netListenIp = switch (native_os) { .windows => netListenIpWindows, @@ -291,6 +239,73 @@ pub fn io(t: *Threaded) Io { }; } +/// Same as `io` but disables all networking functionality, which has +/// an additional dependency on Windows (ws2_32). +pub fn ioBasic(t: *Threaded) Io { + return .{ + .userdata = t, + .vtable = &.{ + .async = async, + .concurrent = concurrent, + .await = await, + .cancel = cancel, + .cancelRequested = cancelRequested, + .select = select, + + .groupAsync = groupAsync, + .groupWait = groupWait, + .groupWaitUncancelable = groupWaitUncancelable, + .groupCancel = groupCancel, + + .mutexLock = mutexLock, + .mutexLockUncancelable = mutexLockUncancelable, + .mutexUnlock = mutexUnlock, + + .conditionWait = conditionWait, + .conditionWaitUncancelable = conditionWaitUncancelable, + .conditionWake = conditionWake, + + .dirMake = dirMake, + .dirMakePath = dirMakePath, + .dirMakeOpenPath = dirMakeOpenPath, + .dirStat = dirStat, + .dirStatPath = dirStatPath, + .fileStat = fileStat, + .dirAccess = dirAccess, + .dirCreateFile = dirCreateFile, + .dirOpenFile = dirOpenFile, + .dirOpenDir = dirOpenDir, + .dirClose = dirClose, + .fileClose = fileClose, + .fileWriteStreaming = fileWriteStreaming, + .fileWritePositional = fileWritePositional, + .fileReadStreaming = fileReadStreaming, + .fileReadPositional = fileReadPositional, + .fileSeekBy = fileSeekBy, + .fileSeekTo = fileSeekTo, + .openSelfExe = openSelfExe, + + .now = now, + .sleep = sleep, + + .netListenIp = netListenIpUnavailable, + .netListenUnix = netListenUnixUnavailable, + .netAccept = netAcceptUnavailable, + .netBindIp = netBindIpUnavailable, + .netConnectIp = netConnectIpUnavailable, + .netConnectUnix = netConnectUnixUnavailable, + .netClose = netCloseUnavailable, + .netRead = netReadUnavailable, + .netWrite = netWriteUnavailable, + .netSend = netSendUnavailable, + .netReceive = netReceiveUnavailable, + .netInterfaceNameResolve = netInterfaceNameResolveUnavailable, + .netInterfaceName = netInterfaceNameUnavailable, + .netLookup = netLookupUnavailable, + }, + }; +} + pub const socket_flags_unsupported = native_os.isDarwin() or native_os == .haiku; // 💩💩 const have_accept4 = !socket_flags_unsupported; const have_flock_open_flags = @hasField(posix.O, "EXLOCK"); @@ -804,7 +819,7 @@ fn mutexUnlock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mut fn conditionWaitUncancelable(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) void { if (builtin.single_threaded) unreachable; // Deadlock. const t: *Threaded = @ptrCast(@alignCast(userdata)); - const t_io = t.io(); + const t_io = ioBasic(t); comptime assert(@TypeOf(cond.state) == u64); const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); const cond_state = &ints[0]; @@ -835,6 +850,7 @@ fn conditionWaitUncancelable(userdata: ?*anyopaque, cond: *Io.Condition, mutex: fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) Io.Cancelable!void { if (builtin.single_threaded) unreachable; // Deadlock. const t: *Threaded = @ptrCast(@alignCast(userdata)); + const t_io = ioBasic(t); comptime assert(@TypeOf(cond.state) == u64); const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); const cond_state = &ints[0]; @@ -858,8 +874,8 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I assert(state & waiter_mask != waiter_mask); state += one_waiter; - mutex.unlock(t.io()); - defer mutex.lockUncancelable(t.io()); + mutex.unlock(t_io); + defer mutex.lockUncancelable(t_io); while (true) { try futexWait(t, cond_epoch, epoch); @@ -939,6 +955,12 @@ fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition. } } +const dirMake = switch (native_os) { + .windows => dirMakeWindows, + .wasi => dirMakeWasi, + else => dirMakePosix, +}; + 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)); @@ -1027,6 +1049,11 @@ fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode windows.CloseHandle(sub_dir_handle); } +const dirMakePath = switch (native_os) { + .windows => dirMakePathWindows, + else => dirMakePathPosix, +}; + fn dirMakePathPosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; @@ -1045,6 +1072,12 @@ fn dirMakePathWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, @panic("TODO implement dirMakePathWindows"); } +const dirMakeOpenPath = switch (native_os) { + .windows => dirMakeOpenPathWindows, + .wasi => dirMakeOpenPathWasi, + else => dirMakeOpenPathPosix, +}; + fn dirMakeOpenPathPosix( userdata: ?*anyopaque, dir: Io.Dir, @@ -1052,11 +1085,11 @@ fn dirMakeOpenPathPosix( options: Io.Dir.OpenOptions, ) Io.Dir.MakeOpenPathError!Io.Dir { const t: *Threaded = @ptrCast(@alignCast(userdata)); - const t_io = t.io(); - return dir.openDir(t_io, sub_path, options) catch |err| switch (err) { + const t_io = ioBasic(t); + return dirOpenDirPosix(t, dir, sub_path, options) catch |err| switch (err) { error.FileNotFound => { try dir.makePath(t_io, sub_path); - return dir.openDir(t_io, sub_path, options); + return dirOpenDirPosix(t, dir, sub_path, options); }, else => |e| return e, }; @@ -1135,7 +1168,7 @@ fn dirMakeOpenPathWindows( // could cause an infinite loop check_dir: { // workaround for windows, see https://github.com/ziglang/zig/issues/16738 - const fstat = dir.statPath(t.io(), component.path, .{ + const fstat = dirStatPathWindows(t, dir, component.path, .{ .follow_symlinks = options.follow_symlinks, }) catch |stat_err| switch (stat_err) { error.IsDir => break :check_dir, @@ -1187,6 +1220,13 @@ fn dirStat(userdata: ?*anyopaque, dir: Io.Dir) Io.Dir.StatError!Io.Dir.Stat { @panic("TODO implement dirStat"); } +const dirStatPath = switch (native_os) { + .linux => dirStatPathLinux, + .windows => dirStatPathWindows, + .wasi => dirStatPathWasi, + else => dirStatPathPosix, +}; + fn dirStatPathLinux( userdata: ?*anyopaque, dir: Io.Dir, @@ -1275,12 +1315,11 @@ fn dirStatPathWindows( options: Io.Dir.StatPathOptions, ) Io.Dir.StatPathError!Io.File.Stat { const t: *Threaded = @ptrCast(@alignCast(userdata)); - const t_io = t.io(); - var file = try dir.openFile(t_io, sub_path, .{ + const file = try dirOpenFileWindows(t, dir, sub_path, .{ .follow_symlinks = options.follow_symlinks, }); - defer file.close(t_io); - return file.stat(t_io); + defer windows.CloseHandle(file.handle); + return fileStatWindows(t, file); } fn dirStatPathWasi( @@ -1318,6 +1357,13 @@ fn dirStatPathWasi( } } +const fileStat = switch (native_os) { + .linux => fileStatLinux, + .windows => fileStatWindows, + .wasi => fileStatWasi, + else => fileStatPosix, +}; + fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat { const t: *Threaded = @ptrCast(@alignCast(userdata)); @@ -1440,6 +1486,12 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. } } +const dirAccess = switch (native_os) { + .windows => dirAccessWindows, + .wasi => dirAccessWasi, + else => dirAccessPosix, +}; + fn dirAccessPosix( userdata: ?*anyopaque, dir: Io.Dir, @@ -1589,6 +1641,12 @@ fn dirAccessWindows( } } +const dirCreateFile = switch (native_os) { + .windows => dirCreateFileWindows, + .wasi => dirCreateFileWasi, + else => dirCreateFilePosix, +}; + fn dirCreateFilePosix( userdata: ?*anyopaque, dir: Io.Dir, @@ -1827,6 +1885,12 @@ fn dirCreateFileWasi( } } +const dirOpenFile = switch (native_os) { + .windows => dirOpenFileWindows, + .wasi => dirOpenFileWasi, + else => dirOpenFilePosix, +}; + fn dirOpenFilePosix( userdata: ?*anyopaque, dir: Io.Dir, @@ -2077,6 +2141,12 @@ fn dirOpenFileWasi( } } +const dirOpenDir = switch (native_os) { + .wasi => dirOpenDirWasi, + .haiku => dirOpenDirHaiku, + else => dirOpenDirPosix, +}; + fn dirOpenDirPosix( userdata: ?*anyopaque, dir: Io.Dir, @@ -2320,6 +2390,11 @@ fn fileClose(userdata: ?*anyopaque, file: Io.File) void { posix.close(file.handle); } +const fileReadStreaming = switch (native_os) { + .windows => fileReadStreamingWindows, + else => fileReadStreamingPosix, +}; + fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize { const t: *Threaded = @ptrCast(@alignCast(userdata)); @@ -2482,6 +2557,11 @@ fn fileReadPositionalPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8, o } } +const fileReadPositional = switch (native_os) { + .windows => fileReadPositionalWindows, + else => fileReadPositionalPosix, +}; + fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize { const t: *Threaded = @ptrCast(@alignCast(userdata)); try t.checkCancel(); @@ -2652,6 +2732,12 @@ fn nowPosix(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp } } +const now = switch (native_os) { + .windows => nowWindows, + .wasi => nowWasi, + else => nowPosix, +}; + fn nowWindows(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; @@ -2680,6 +2766,13 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp { return .fromNanoseconds(ns); } +const sleep = switch (native_os) { + .windows => sleepWindows, + .wasi => sleepWasi, + .linux => sleepLinux, + else => sleepPosix, +}; + fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); const clock_id: posix.clockid_t = clockToPosix(switch (timeout) { @@ -2710,9 +2803,10 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); + const t_io = ioBasic(t); try t.checkCancel(); const ms = ms: { - const d = (try timeout.toDurationFromNow(t.io())) orelse + const d = (try timeout.toDurationFromNow(t_io)) orelse break :ms std.math.maxInt(windows.DWORD); break :ms std.math.lossyCast(windows.DWORD, d.raw.toMilliseconds()); }; @@ -2721,11 +2815,12 @@ 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 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| .{ + const clock: w.subscription_clock_t = if (try timeout.toDurationFromNow(t_io)) |d| .{ .id = clockToWasi(d.clock), .timeout = std.math.lossyCast(u64, d.raw.nanoseconds), .precision = 0, @@ -2750,11 +2845,12 @@ fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); + 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; var timespec: posix.timespec = t: { - const d = (try timeout.toDurationFromNow(t.io())) orelse break :t .{ + const d = (try timeout.toDurationFromNow(t_io)) orelse break :t .{ .sec = std.math.maxInt(sec_type), .nsec = std.math.maxInt(nsec_type), }; @@ -2919,6 +3015,17 @@ fn netListenIpWindows( }; } +fn netListenIpUnavailable( + userdata: ?*anyopaque, + address: IpAddress, + options: IpAddress.ListenOptions, +) IpAddress.ListenError!net.Server { + _ = userdata; + _ = address; + _ = options; + return error.NetworkDown; +} + fn netListenUnixPosix( userdata: ?*anyopaque, address: *const net.UnixAddress, @@ -2965,6 +3072,17 @@ fn netListenUnixWindows( @panic("TODO implement netListenUnixWindows"); } +fn netListenUnixUnavailable( + userdata: ?*anyopaque, + address: *const net.UnixAddress, + options: net.UnixAddress.ListenOptions, +) net.UnixAddress.ListenError!net.Socket.Handle { + _ = userdata; + _ = address; + _ = options; + return error.AddressFamilyUnsupported; +} + fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void { while (true) { try t.checkCancel(); @@ -3235,6 +3353,17 @@ fn netConnectIpWindows( } }; } +fn netConnectIpUnavailable( + userdata: ?*anyopaque, + address: *const IpAddress, + options: IpAddress.ConnectOptions, +) IpAddress.ConnectError!net.Stream { + _ = userdata; + _ = address; + _ = options; + return error.NetworkDown; +} + fn netConnectUnixPosix( userdata: ?*anyopaque, address: *const net.UnixAddress, @@ -3263,6 +3392,15 @@ fn netConnectUnixWindows( @panic("TODO implement netConnectUnixWindows"); } +fn netConnectUnixUnavailable( + userdata: ?*anyopaque, + address: *const net.UnixAddress, +) net.UnixAddress.ConnectError!net.Socket.Handle { + _ = userdata; + _ = address; + return error.AddressFamilyUnsupported; +} + fn netBindIpPosix( userdata: ?*anyopaque, address: *const IpAddress, @@ -3330,6 +3468,17 @@ fn netBindIpWindows( }; } +fn netBindIpUnavailable( + userdata: ?*anyopaque, + address: *const IpAddress, + options: IpAddress.BindOptions, +) IpAddress.BindError!net.Socket { + _ = userdata; + _ = address; + _ = options; + return error.NetworkDown; +} + fn openSocketPosix( t: *Threaded, family: posix.sa_family_t, @@ -3498,7 +3647,14 @@ fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net } } +fn netAcceptUnavailable(userdata: ?*anyopaque, listen_handle: net.Socket.Handle) net.Server.AcceptError!net.Stream { + _ = userdata; + _ = listen_handle; + return error.NetworkDown; +} + 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)); var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; @@ -3560,7 +3716,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, 0 }; + if (!have_networking) return error.NetworkDown; const t: *Threaded = @ptrCast(@alignCast(userdata)); _ = t; _ = handle; @@ -3568,6 +3724,13 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8 @panic("TODO implement netReadWindows"); } +fn netReadUnavailable(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Stream.Reader.Error!usize { + _ = userdata; + _ = fd; + _ = data; + return error.NetworkDown; +} + fn netSendPosix( userdata: ?*anyopaque, handle: net.Socket.Handle, @@ -3612,6 +3775,19 @@ fn netSendWindows( @panic("TODO netSendWindows"); } +fn netSendUnavailable( + userdata: ?*anyopaque, + handle: net.Socket.Handle, + messages: []net.OutgoingMessage, + flags: net.SendFlags, +) struct { ?net.Socket.SendError, usize } { + _ = userdata; + _ = handle; + _ = messages; + _ = flags; + return .{ error.NetworkDown, 0 }; +} + fn netSendOne( t: *Threaded, handle: net.Socket.Handle, @@ -3777,6 +3953,7 @@ fn netReceivePosix( ) struct { ?net.Socket.ReceiveTimeoutError, usize } { if (!have_networking) return .{ error.NetworkDown, 0 }; const t: *Threaded = @ptrCast(@alignCast(userdata)); + const t_io = io(t); // recvmmsg is useless, here's why: // * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371) @@ -3803,7 +3980,7 @@ fn netReceivePosix( var message_i: usize = 0; var data_i: usize = 0; - const deadline = timeout.toDeadline(t.io()) catch |err| return .{ err, message_i }; + const deadline = timeout.toDeadline(t_io) catch |err| return .{ err, message_i }; recv: while (true) { t.checkCancel() catch |err| return .{ err, message_i }; @@ -3849,7 +4026,7 @@ fn netReceivePosix( const max_poll_ms = std.math.maxInt(u31); const timeout_ms: u31 = if (deadline) |d| t: { - const duration = d.durationFromNow(t.io()) catch |err| return .{ err, message_i }; + const duration = d.durationFromNow(t_io) catch |err| return .{ err, message_i }; if (duration.raw.nanoseconds <= 0) return .{ error.Timeout, message_i }; break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds())); } else max_poll_ms; @@ -3915,6 +4092,23 @@ fn netReceiveWindows( @panic("TODO implement netReceiveWindows"); } +fn netReceiveUnavailable( + userdata: ?*anyopaque, + handle: net.Socket.Handle, + message_buffer: []net.IncomingMessage, + data_buffer: []u8, + flags: net.ReceiveFlags, + timeout: Io.Timeout, +) struct { ?net.Socket.ReceiveTimeoutError, usize } { + _ = userdata; + _ = handle; + _ = message_buffer; + _ = data_buffer; + _ = flags; + _ = timeout; + return .{ error.NetworkDown, 0 }; +} + fn netWritePosix( userdata: ?*anyopaque, fd: net.Socket.Handle, @@ -4013,6 +4207,21 @@ fn netWriteWindows( @panic("TODO implement netWriteWindows"); } +fn netWriteUnavailable( + userdata: ?*anyopaque, + handle: net.Socket.Handle, + header: []const u8, + data: []const []const u8, + splat: usize, +) net.Stream.Writer.Error!usize { + _ = userdata; + _ = handle; + _ = header; + _ = data; + _ = splat; + return error.NetworkDown; +} + fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), bytes: []const u8) void { // OS checks ptr addr before length so zero length vectors must be omitted. if (bytes.len == 0) return; @@ -4030,6 +4239,12 @@ fn netClose(userdata: ?*anyopaque, handle: net.Socket.Handle) void { } } +fn netCloseUnavailable(userdata: ?*anyopaque, handle: net.Socket.Handle) void { + _ = userdata; + _ = handle; + unreachable; // How you gonna close something that was impossible to open? +} + fn netInterfaceNameResolve( userdata: ?*anyopaque, name: *const net.Interface.Name, @@ -4089,6 +4304,15 @@ fn netInterfaceNameResolve( @panic("unimplemented"); } +fn netInterfaceNameResolveUnavailable( + userdata: ?*anyopaque, + name: *const net.Interface.Name, +) net.Interface.Name.ResolveError!net.Interface { + _ = userdata; + _ = name; + return error.InterfaceNotFound; +} + fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { const t: *Threaded = @ptrCast(@alignCast(userdata)); try t.checkCancel(); @@ -4109,6 +4333,12 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa @panic("unimplemented"); } +fn netInterfaceNameUnavailable(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name { + _ = userdata; + _ = interface; + return error.Unexpected; +} + fn netLookup( userdata: ?*anyopaque, host_name: HostName, @@ -4116,17 +4346,31 @@ fn netLookup( options: HostName.LookupOptions, ) void { const t: *Threaded = @ptrCast(@alignCast(userdata)); - const t_io = t.io(); + const t_io = io(t); resolved.putOneUncancelable(t_io, .{ .end = netLookupFallible(t, host_name, resolved, options) }); } +fn netLookupUnavailable( + userdata: ?*anyopaque, + host_name: HostName, + resolved: *Io.Queue(HostName.LookupResult), + options: HostName.LookupOptions, +) void { + _ = host_name; + _ = options; + const t: *Threaded = @ptrCast(@alignCast(userdata)); + const t_io = ioBasic(t); + resolved.putOneUncancelable(t_io, .{ .end = error.NetworkDown }); +} + fn netLookupFallible( t: *Threaded, host_name: HostName, resolved: *Io.Queue(HostName.LookupResult), options: HostName.LookupOptions, ) !void { - const t_io = t.io(); + if (!have_networking) return error.NetworkDown; + const t_io = io(t); const name = host_name.bytes; assert(name.len <= HostName.max_len); @@ -4637,7 +4881,7 @@ fn lookupDnsSearch( resolved: *Io.Queue(HostName.LookupResult), options: HostName.LookupOptions, ) HostName.LookupError!void { - const t_io = t.io(); + const t_io = io(t); const rc = HostName.ResolvConf.init(t_io) catch return error.ResolvConfParseFailed; // Count dots, suppress search when >=ndots or name ends in @@ -4681,7 +4925,7 @@ fn lookupDns( resolved: *Io.Queue(HostName.LookupResult), options: HostName.LookupOptions, ) HostName.LookupError!void { - const t_io = t.io(); + const t_io = io(t); const family_records: [2]struct { af: IpAddress.Family, rr: HostName.DnsRecord } = .{ .{ .af = .ip6, .rr = .A }, .{ .af = .ip4, .rr = .AAAA }, @@ -4868,7 +5112,7 @@ fn lookupHosts( resolved: *Io.Queue(HostName.LookupResult), options: HostName.LookupOptions, ) !void { - const t_io = t.io(); + const t_io = io(t); const file = Io.File.openAbsolute(t_io, "/etc/hosts", .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, @@ -4906,7 +5150,7 @@ fn lookupHostsReader( options: HostName.LookupOptions, reader: *Io.Reader, ) error{ ReadFailed, Canceled, UnknownHostName }!void { - const t_io = t.io(); + const t_io = io(t); var addresses_len: usize = 0; var canonical_name: ?HostName = null; while (true) { @@ -5374,7 +5618,7 @@ const Wsa = struct { }; fn initializeWsa(t: *Threaded) error{NetworkDown}!void { - const t_io = t.io(); + const t_io = io(t); const wsa = &t.wsa; wsa.mutex.lockUncancelable(t_io); defer wsa.mutex.unlock(t_io); diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 7e1ce45a46..f3abe1e6cf 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -320,7 +320,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()}); var threaded: std.Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); const file = try std.fs.cwd().openFile(path, .{}); defer file.close(); diff --git a/lib/std/debug.zig b/lib/std/debug.zig index a92a4b360f..616a524011 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -649,7 +649,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: /// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing. pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); if (!std.options.allow_stack_tracing) { tty_config.setColor(writer, .dim) catch {}; @@ -780,7 +780,7 @@ pub fn writeStackTrace(st: *const StackTrace, writer: *Writer, tty_config: tty.C // We use an independent Io implementation here in case there was a problem // with the application's Io implementation itself. var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. @@ -1602,7 +1602,7 @@ test "manage resources correctly" { }; const gpa = std.testing.allocator; var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); var discarding: Io.Writer.Discarding = .init(&.{}); var di: SelfInfo = .init; defer di.deinit(gpa); diff --git a/lib/std/fs.zig b/lib/std/fs.zig index ea39ce8e33..6db63b6e2b 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -340,7 +340,7 @@ pub const OpenSelfExeError = Io.File.OpenSelfExeError; pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { if (native_os == .linux or native_os == .serenity or native_os == .windows) { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return .adaptFromNewApi(try Io.File.openSelfExe(io, flags)); } // Use of max_path_bytes here is valid as the resulting path is immediately diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig index 15f3a6c45a..c90eeef508 100644 --- a/lib/std/fs/Dir.zig +++ b/lib/std/fs/Dir.zig @@ -849,14 +849,14 @@ pub fn close(self: *Dir) void { /// Deprecated in favor of `Io.Dir.openFile`. pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return .adaptFromNewApi(try Io.Dir.openFile(self.adaptToNewApi(), io, sub_path, flags)); } /// Deprecated in favor of `Io.Dir.createFile`. pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); const new_file = try Io.Dir.createFile(self.adaptToNewApi(), io, sub_path, flags); return .adaptFromNewApi(new_file); } @@ -867,7 +867,7 @@ pub const MakeError = Io.Dir.MakeError; /// Deprecated in favor of `Io.Dir.makeDir`. pub fn makeDir(self: Dir, sub_path: []const u8) MakeError!void { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return Io.Dir.makeDir(.{ .handle = self.fd }, io, sub_path); } @@ -894,14 +894,14 @@ pub const MakePathError = Io.Dir.MakePathError; /// Deprecated in favor of `Io.Dir.makePathStatus`. pub fn makePathStatus(self: Dir, sub_path: []const u8) MakePathError!MakePathStatus { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return Io.Dir.makePathStatus(.{ .handle = self.fd }, io, sub_path); } /// Deprecated in favor of `Io.Dir.makeOpenPath`. pub fn makeOpenPath(dir: Dir, sub_path: []const u8, options: OpenOptions) Io.Dir.MakeOpenPathError!Dir { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return .adaptFromNewApi(try Io.Dir.makeOpenPath(dir.adaptToNewApi(), io, sub_path, options)); } @@ -1070,7 +1070,7 @@ pub const OpenOptions = Io.Dir.OpenOptions; /// Deprecated in favor of `Io.Dir.openDir`. pub fn openDir(self: Dir, sub_path: []const u8, args: OpenOptions) OpenError!Dir { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return .adaptFromNewApi(try Io.Dir.openDir(.{ .handle = self.fd }, io, sub_path, args)); } @@ -1384,7 +1384,7 @@ pub fn readLinkW(self: Dir, sub_path_w: []const u16, buffer: []u8) ![]u8 { /// Deprecated in favor of `Io.Dir.readFile`. pub fn readFile(self: Dir, file_path: []const u8, buffer: []u8) ![]u8 { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return Io.Dir.readFile(.{ .handle = self.fd }, io, file_path, buffer); } @@ -1437,7 +1437,7 @@ pub fn readFileAllocOptions( comptime sentinel: ?u8, ) ReadFileAllocError!(if (sentinel) |s| [:s]align(alignment.toByteUnits()) u8 else []align(alignment.toByteUnits()) u8) { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); var file = try dir.openFile(sub_path, .{}); defer file.close(); @@ -1892,7 +1892,7 @@ pub const AccessError = Io.Dir.AccessError; /// Deprecated in favor of `Io.Dir.access`. pub fn access(self: Dir, sub_path: []const u8, options: Io.Dir.AccessOptions) AccessError!void { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return Io.Dir.access(self.adaptToNewApi(), io, sub_path, options); } @@ -1928,7 +1928,7 @@ pub fn copyFile( options: CopyFileOptions, ) CopyFileError!void { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); const file = try source_dir.openFile(source_path, .{}); var file_reader: File.Reader = .init(.{ .handle = file.handle }, io, &.{}); @@ -1996,7 +1996,7 @@ pub const StatFileError = File.OpenError || File.StatError || posix.FStatAtError /// Deprecated in favor of `Io.Dir.statPath`. pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return Io.Dir.statPath(.{ .handle = self.fd }, io, sub_path, .{}); } diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index d6c5e9f969..11d8e7471b 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -313,7 +313,7 @@ pub const StatError = posix.FStatError; /// Returns `Stat` containing basic information about the `File`. pub fn stat(self: File) StatError!Stat { var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); return Io.File.stat(.{ .handle = self.handle }, io); } diff --git a/lib/std/process/Child.zig b/lib/std/process/Child.zig index e49c5c4532..c84c878972 100644 --- a/lib/std/process/Child.zig +++ b/lib/std/process/Child.zig @@ -1089,7 +1089,7 @@ fn windowsCreateProcessPathExt( // opening function knowing which implementation we are in. Here, we imitate // that scenario. var threaded: std.Io.Threaded = .init_single_threaded; - const io = threaded.io(); + const io = threaded.ioBasic(); var dir = dir: { // needs to be null-terminated diff --git a/test/standalone/child_process/child.zig b/test/standalone/child_process/child.zig index b02bec3500..2e74f30882 100644 --- a/test/standalone/child_process/child.zig +++ b/test/standalone/child_process/child.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Io = std.Io; // 42 is expected by parent; other values result in test failure var exit_code: u8 = 42; @@ -6,12 +7,17 @@ var exit_code: u8 = 42; pub fn main() !void { var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); const arena = arena_state.allocator(); - try run(arena); + + var threaded: std.Io.Threaded = .init(arena); + defer threaded.deinit(); + const io = threaded.io(); + + try run(arena, io); arena_state.deinit(); std.process.exit(exit_code); } -fn run(allocator: std.mem.Allocator) !void { +fn run(allocator: std.mem.Allocator, io: Io) !void { var args = try std.process.argsWithAllocator(allocator); defer args.deinit(); _ = args.next() orelse unreachable; // skip binary name @@ -33,7 +39,8 @@ fn run(allocator: std.mem.Allocator) !void { const hello_stdin = "hello from stdin"; var buf: [hello_stdin.len]u8 = undefined; const stdin: std.fs.File = .stdin(); - const n = try stdin.readAll(&buf); + var reader = stdin.reader(io, &.{}); + const n = try reader.interface.readSliceShort(&buf); if (!std.mem.eql(u8, buf[0..n], hello_stdin)) { testError("stdin: '{s}'; want '{s}'", .{ buf[0..n], hello_stdin }); } diff --git a/test/standalone/simple/cat/main.zig b/test/standalone/simple/cat/main.zig index 61b7fbe7ce..9ea980aecc 100644 --- a/test/standalone/simple/cat/main.zig +++ b/test/standalone/simple/cat/main.zig @@ -9,6 +9,10 @@ pub fn main() !void { defer arena_instance.deinit(); const arena = arena_instance.allocator(); + var threaded: std.Io.Threaded = .init(arena); + defer threaded.deinit(); + const io = threaded.io(); + const args = try std.process.argsAlloc(arena); const exe = args[0]; @@ -16,7 +20,7 @@ pub fn main() !void { var stdout_buffer: [4096]u8 = undefined; var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer); const stdout = &stdout_writer.interface; - var stdin_reader = fs.File.stdin().readerStreaming(&.{}); + var stdin_reader = fs.File.stdin().readerStreaming(io, &.{}); const cwd = fs.cwd(); @@ -32,7 +36,7 @@ pub fn main() !void { defer file.close(); catted_anything = true; - var file_reader = file.reader(&.{}); + var file_reader = file.reader(io, &.{}); _ = try stdout.sendFileAll(&file_reader, .unlimited); try stdout.flush(); } diff --git a/tools/fetch_them_macos_headers.zig b/tools/fetch_them_macos_headers.zig index d91235fee9..2a2a2452e7 100644 --- a/tools/fetch_them_macos_headers.zig +++ b/tools/fetch_them_macos_headers.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Io = std.Io; const fs = std.fs; const mem = std.mem; const process = std.process; @@ -85,7 +86,7 @@ pub fn main() anyerror!void { } else try argv.append(arg); } - var threaded: std.Io.Threaded = .init(gpa); + var threaded: Io.Threaded = .init(gpa); defer threaded.deinit(); const io = threaded.io(); @@ -118,12 +119,13 @@ pub fn main() anyerror!void { .arch = arch, .os_ver = os_ver, }; - try fetchTarget(allocator, argv.items, sysroot_path, target, version, tmp); + try fetchTarget(allocator, io, argv.items, sysroot_path, target, version, tmp); } } fn fetchTarget( arena: Allocator, + io: Io, args: []const []const u8, sysroot: []const u8, target: Target, @@ -194,7 +196,7 @@ fn fetchTarget( var dirs = std.StringHashMap(fs.Dir).init(arena); try dirs.putNoClobber(".", dest_dir); - var headers_list_file_reader = headers_list_file.reader(&.{}); + var headers_list_file_reader = headers_list_file.reader(io, &.{}); const headers_list_str = try headers_list_file_reader.interface.allocRemaining(arena, .unlimited); const prefix = "/usr/include"; @@ -267,8 +269,8 @@ const Version = struct { pub fn format( v: Version, - writer: *std.Io.Writer, - ) std.Io.Writer.Error!void { + writer: *Io.Writer, + ) Io.Writer.Error!void { try writer.print("{d}.{d}.{d}", .{ v.major, v.minor, v.patch }); } }; diff --git a/tools/gen_macos_headers_c.zig b/tools/gen_macos_headers_c.zig index a5d865bf03..fe036cf6b7 100644 --- a/tools/gen_macos_headers_c.zig +++ b/tools/gen_macos_headers_c.zig @@ -73,7 +73,7 @@ fn findHeaders( switch (entry.kind) { .directory => { const path = try std.fs.path.join(arena, &.{ prefix, entry.name }); - var subdir = try dir.openDir(entry.name, .{ .no_follow = true }); + var subdir = try dir.openDir(entry.name, .{ .follow_symlinks = false }); defer subdir.close(); try findHeaders(arena, subdir, path, paths); },