std.Io.Threaded: add ioBasic which disables networking

This commit is contained in:
Andrew Kelley 2025-10-23 13:58:49 -07:00
parent 701d4bc80b
commit 46f7e3ea9f
11 changed files with 375 additions and 118 deletions

View file

@ -168,80 +168,28 @@ pub fn io(t: *Threaded) Io {
.conditionWaitUncancelable = conditionWaitUncancelable, .conditionWaitUncancelable = conditionWaitUncancelable,
.conditionWake = conditionWake, .conditionWake = conditionWake,
.dirMake = switch (native_os) { .dirMake = dirMake,
.windows => dirMakeWindows, .dirMakePath = dirMakePath,
.wasi => dirMakeWasi, .dirMakeOpenPath = dirMakeOpenPath,
else => dirMakePosix,
},
.dirMakePath = switch (native_os) {
.windows => dirMakePathWindows,
else => dirMakePathPosix,
},
.dirMakeOpenPath = switch (native_os) {
.windows => dirMakeOpenPathWindows,
.wasi => dirMakeOpenPathWasi,
else => dirMakeOpenPathPosix,
},
.dirStat = dirStat, .dirStat = dirStat,
.dirStatPath = switch (native_os) { .dirStatPath = dirStatPath,
.linux => dirStatPathLinux, .fileStat = fileStat,
.windows => dirStatPathWindows, .dirAccess = dirAccess,
.wasi => dirStatPathWasi, .dirCreateFile = dirCreateFile,
else => dirStatPathPosix, .dirOpenFile = dirOpenFile,
}, .dirOpenDir = dirOpenDir,
.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,
},
.dirClose = dirClose, .dirClose = dirClose,
.fileClose = fileClose, .fileClose = fileClose,
.fileWriteStreaming = fileWriteStreaming, .fileWriteStreaming = fileWriteStreaming,
.fileWritePositional = fileWritePositional, .fileWritePositional = fileWritePositional,
.fileReadStreaming = switch (native_os) { .fileReadStreaming = fileReadStreaming,
.windows => fileReadStreamingWindows, .fileReadPositional = fileReadPositional,
else => fileReadStreamingPosix,
},
.fileReadPositional = switch (native_os) {
.windows => fileReadPositionalWindows,
else => fileReadPositionalPosix,
},
.fileSeekBy = fileSeekBy, .fileSeekBy = fileSeekBy,
.fileSeekTo = fileSeekTo, .fileSeekTo = fileSeekTo,
.openSelfExe = openSelfExe, .openSelfExe = openSelfExe,
.now = switch (native_os) { .now = now,
.windows => nowWindows, .sleep = sleep,
.wasi => nowWasi,
else => nowPosix,
},
.sleep = switch (native_os) {
.windows => sleepWindows,
.wasi => sleepWasi,
.linux => sleepLinux,
else => sleepPosix,
},
.netListenIp = switch (native_os) { .netListenIp = switch (native_os) {
.windows => netListenIpWindows, .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; // 💩💩 pub const socket_flags_unsupported = native_os.isDarwin() or native_os == .haiku; // 💩💩
const have_accept4 = !socket_flags_unsupported; const have_accept4 = !socket_flags_unsupported;
const have_flock_open_flags = @hasField(posix.O, "EXLOCK"); 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 { fn conditionWaitUncancelable(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) void {
if (builtin.single_threaded) unreachable; // Deadlock. if (builtin.single_threaded) unreachable; // Deadlock.
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = t.io(); const t_io = ioBasic(t);
comptime assert(@TypeOf(cond.state) == u64); comptime assert(@TypeOf(cond.state) == u64);
const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state);
const cond_state = &ints[0]; 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 { fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) Io.Cancelable!void {
if (builtin.single_threaded) unreachable; // Deadlock. if (builtin.single_threaded) unreachable; // Deadlock.
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
comptime assert(@TypeOf(cond.state) == u64); comptime assert(@TypeOf(cond.state) == u64);
const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state);
const cond_state = &ints[0]; 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); assert(state & waiter_mask != waiter_mask);
state += one_waiter; state += one_waiter;
mutex.unlock(t.io()); mutex.unlock(t_io);
defer mutex.lockUncancelable(t.io()); defer mutex.lockUncancelable(t_io);
while (true) { while (true) {
try futexWait(t, cond_epoch, epoch); 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 { 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 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); 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 { 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)); const t: *Threaded = @ptrCast(@alignCast(userdata));
_ = t; _ = t;
@ -1045,6 +1072,12 @@ fn dirMakePathWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8,
@panic("TODO implement dirMakePathWindows"); @panic("TODO implement dirMakePathWindows");
} }
const dirMakeOpenPath = switch (native_os) {
.windows => dirMakeOpenPathWindows,
.wasi => dirMakeOpenPathWasi,
else => dirMakeOpenPathPosix,
};
fn dirMakeOpenPathPosix( fn dirMakeOpenPathPosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
dir: Io.Dir, dir: Io.Dir,
@ -1052,11 +1085,11 @@ fn dirMakeOpenPathPosix(
options: Io.Dir.OpenOptions, options: Io.Dir.OpenOptions,
) Io.Dir.MakeOpenPathError!Io.Dir { ) Io.Dir.MakeOpenPathError!Io.Dir {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = t.io(); const t_io = ioBasic(t);
return dir.openDir(t_io, sub_path, options) catch |err| switch (err) { return dirOpenDirPosix(t, dir, sub_path, options) catch |err| switch (err) {
error.FileNotFound => { error.FileNotFound => {
try dir.makePath(t_io, sub_path); 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, else => |e| return e,
}; };
@ -1135,7 +1168,7 @@ fn dirMakeOpenPathWindows(
// could cause an infinite loop // could cause an infinite loop
check_dir: { check_dir: {
// workaround for windows, see https://github.com/ziglang/zig/issues/16738 // 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, .follow_symlinks = options.follow_symlinks,
}) catch |stat_err| switch (stat_err) { }) catch |stat_err| switch (stat_err) {
error.IsDir => break :check_dir, 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"); @panic("TODO implement dirStat");
} }
const dirStatPath = switch (native_os) {
.linux => dirStatPathLinux,
.windows => dirStatPathWindows,
.wasi => dirStatPathWasi,
else => dirStatPathPosix,
};
fn dirStatPathLinux( fn dirStatPathLinux(
userdata: ?*anyopaque, userdata: ?*anyopaque,
dir: Io.Dir, dir: Io.Dir,
@ -1275,12 +1315,11 @@ fn dirStatPathWindows(
options: Io.Dir.StatPathOptions, options: Io.Dir.StatPathOptions,
) Io.Dir.StatPathError!Io.File.Stat { ) Io.Dir.StatPathError!Io.File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = t.io(); const file = try dirOpenFileWindows(t, dir, sub_path, .{
var file = try dir.openFile(t_io, sub_path, .{
.follow_symlinks = options.follow_symlinks, .follow_symlinks = options.follow_symlinks,
}); });
defer file.close(t_io); defer windows.CloseHandle(file.handle);
return file.stat(t_io); return fileStatWindows(t, file);
} }
fn dirStatPathWasi( 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 { fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
const t: *Threaded = @ptrCast(@alignCast(userdata)); 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( fn dirAccessPosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
dir: Io.Dir, dir: Io.Dir,
@ -1589,6 +1641,12 @@ fn dirAccessWindows(
} }
} }
const dirCreateFile = switch (native_os) {
.windows => dirCreateFileWindows,
.wasi => dirCreateFileWasi,
else => dirCreateFilePosix,
};
fn dirCreateFilePosix( fn dirCreateFilePosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
dir: Io.Dir, dir: Io.Dir,
@ -1827,6 +1885,12 @@ fn dirCreateFileWasi(
} }
} }
const dirOpenFile = switch (native_os) {
.windows => dirOpenFileWindows,
.wasi => dirOpenFileWasi,
else => dirOpenFilePosix,
};
fn dirOpenFilePosix( fn dirOpenFilePosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
dir: Io.Dir, dir: Io.Dir,
@ -2077,6 +2141,12 @@ fn dirOpenFileWasi(
} }
} }
const dirOpenDir = switch (native_os) {
.wasi => dirOpenDirWasi,
.haiku => dirOpenDirHaiku,
else => dirOpenDirPosix,
};
fn dirOpenDirPosix( fn dirOpenDirPosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
dir: Io.Dir, dir: Io.Dir,
@ -2320,6 +2390,11 @@ fn fileClose(userdata: ?*anyopaque, file: Io.File) void {
posix.close(file.handle); 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 { fn fileReadStreamingPosix(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata)); 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 { fn fileReadPositionalWindows(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset: u64) Io.File.ReadPositionalError!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
try t.checkCancel(); 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 { fn nowWindows(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
_ = t; _ = t;
@ -2680,6 +2766,13 @@ fn nowWasi(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
return .fromNanoseconds(ns); 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 { fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const clock_id: posix.clockid_t = clockToPosix(switch (timeout) { 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 { fn sleepWindows(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
try t.checkCancel(); try t.checkCancel();
const ms = ms: { 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.maxInt(windows.DWORD);
break :ms std.math.lossyCast(windows.DWORD, d.raw.toMilliseconds()); 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 { fn sleepWasi(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
try t.checkCancel(); try t.checkCancel();
const w = std.os.wasi; 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), .id = clockToWasi(d.clock),
.timeout = std.math.lossyCast(u64, d.raw.nanoseconds), .timeout = std.math.lossyCast(u64, d.raw.nanoseconds),
.precision = 0, .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 { fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = ioBasic(t);
const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type; const sec_type = @typeInfo(posix.timespec).@"struct".fields[0].type;
const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type; const nsec_type = @typeInfo(posix.timespec).@"struct".fields[1].type;
var timespec: posix.timespec = t: { 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), .sec = std.math.maxInt(sec_type),
.nsec = std.math.maxInt(nsec_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( fn netListenUnixPosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
address: *const net.UnixAddress, address: *const net.UnixAddress,
@ -2965,6 +3072,17 @@ fn netListenUnixWindows(
@panic("TODO implement 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 { fn posixBindUnix(t: *Threaded, fd: posix.socket_t, addr: *const posix.sockaddr, addr_len: posix.socklen_t) !void {
while (true) { while (true) {
try t.checkCancel(); 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( fn netConnectUnixPosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
address: *const net.UnixAddress, address: *const net.UnixAddress,
@ -3263,6 +3392,15 @@ fn netConnectUnixWindows(
@panic("TODO implement 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( fn netBindIpPosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
address: *const IpAddress, 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( fn openSocketPosix(
t: *Threaded, t: *Threaded,
family: posix.sa_family_t, 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 { 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 t: *Threaded = @ptrCast(@alignCast(userdata));
var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; 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 { 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)); const t: *Threaded = @ptrCast(@alignCast(userdata));
_ = t; _ = t;
_ = handle; _ = handle;
@ -3568,6 +3724,13 @@ fn netReadWindows(userdata: ?*anyopaque, handle: net.Socket.Handle, data: [][]u8
@panic("TODO implement netReadWindows"); @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( fn netSendPosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
handle: net.Socket.Handle, handle: net.Socket.Handle,
@ -3612,6 +3775,19 @@ fn netSendWindows(
@panic("TODO 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( fn netSendOne(
t: *Threaded, t: *Threaded,
handle: net.Socket.Handle, handle: net.Socket.Handle,
@ -3777,6 +3953,7 @@ fn netReceivePosix(
) struct { ?net.Socket.ReceiveTimeoutError, usize } { ) struct { ?net.Socket.ReceiveTimeoutError, usize } {
if (!have_networking) return .{ error.NetworkDown, 0 }; if (!have_networking) return .{ error.NetworkDown, 0 };
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
const t_io = io(t);
// recvmmsg is useless, here's why: // recvmmsg is useless, here's why:
// * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371) // * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371)
@ -3803,7 +3980,7 @@ fn netReceivePosix(
var message_i: usize = 0; var message_i: usize = 0;
var data_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) { recv: while (true) {
t.checkCancel() catch |err| return .{ err, message_i }; t.checkCancel() catch |err| return .{ err, message_i };
@ -3849,7 +4026,7 @@ fn netReceivePosix(
const max_poll_ms = std.math.maxInt(u31); const max_poll_ms = std.math.maxInt(u31);
const timeout_ms: u31 = if (deadline) |d| t: { 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 }; if (duration.raw.nanoseconds <= 0) return .{ error.Timeout, message_i };
break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds())); break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
} else max_poll_ms; } else max_poll_ms;
@ -3915,6 +4092,23 @@ fn netReceiveWindows(
@panic("TODO implement 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( fn netWritePosix(
userdata: ?*anyopaque, userdata: ?*anyopaque,
fd: net.Socket.Handle, fd: net.Socket.Handle,
@ -4013,6 +4207,21 @@ fn netWriteWindows(
@panic("TODO implement 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 { 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. // OS checks ptr addr before length so zero length vectors must be omitted.
if (bytes.len == 0) return; 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( fn netInterfaceNameResolve(
userdata: ?*anyopaque, userdata: ?*anyopaque,
name: *const net.Interface.Name, name: *const net.Interface.Name,
@ -4089,6 +4304,15 @@ fn netInterfaceNameResolve(
@panic("unimplemented"); @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 { fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
const t: *Threaded = @ptrCast(@alignCast(userdata)); const t: *Threaded = @ptrCast(@alignCast(userdata));
try t.checkCancel(); try t.checkCancel();
@ -4109,6 +4333,12 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa
@panic("unimplemented"); @panic("unimplemented");
} }
fn netInterfaceNameUnavailable(userdata: ?*anyopaque, interface: net.Interface) net.Interface.NameError!net.Interface.Name {
_ = userdata;
_ = interface;
return error.Unexpected;
}
fn netLookup( fn netLookup(
userdata: ?*anyopaque, userdata: ?*anyopaque,
host_name: HostName, host_name: HostName,
@ -4116,17 +4346,31 @@ fn netLookup(
options: HostName.LookupOptions, options: HostName.LookupOptions,
) void { ) void {
const t: *Threaded = @ptrCast(@alignCast(userdata)); 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) }); 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( fn netLookupFallible(
t: *Threaded, t: *Threaded,
host_name: HostName, host_name: HostName,
resolved: *Io.Queue(HostName.LookupResult), resolved: *Io.Queue(HostName.LookupResult),
options: HostName.LookupOptions, options: HostName.LookupOptions,
) !void { ) !void {
const t_io = t.io(); if (!have_networking) return error.NetworkDown;
const t_io = io(t);
const name = host_name.bytes; const name = host_name.bytes;
assert(name.len <= HostName.max_len); assert(name.len <= HostName.max_len);
@ -4637,7 +4881,7 @@ fn lookupDnsSearch(
resolved: *Io.Queue(HostName.LookupResult), resolved: *Io.Queue(HostName.LookupResult),
options: HostName.LookupOptions, options: HostName.LookupOptions,
) HostName.LookupError!void { ) HostName.LookupError!void {
const t_io = t.io(); const t_io = io(t);
const rc = HostName.ResolvConf.init(t_io) catch return error.ResolvConfParseFailed; const rc = HostName.ResolvConf.init(t_io) catch return error.ResolvConfParseFailed;
// Count dots, suppress search when >=ndots or name ends in // Count dots, suppress search when >=ndots or name ends in
@ -4681,7 +4925,7 @@ fn lookupDns(
resolved: *Io.Queue(HostName.LookupResult), resolved: *Io.Queue(HostName.LookupResult),
options: HostName.LookupOptions, options: HostName.LookupOptions,
) HostName.LookupError!void { ) HostName.LookupError!void {
const t_io = t.io(); const t_io = io(t);
const family_records: [2]struct { af: IpAddress.Family, rr: HostName.DnsRecord } = .{ const family_records: [2]struct { af: IpAddress.Family, rr: HostName.DnsRecord } = .{
.{ .af = .ip6, .rr = .A }, .{ .af = .ip6, .rr = .A },
.{ .af = .ip4, .rr = .AAAA }, .{ .af = .ip4, .rr = .AAAA },
@ -4868,7 +5112,7 @@ fn lookupHosts(
resolved: *Io.Queue(HostName.LookupResult), resolved: *Io.Queue(HostName.LookupResult),
options: HostName.LookupOptions, options: HostName.LookupOptions,
) !void { ) !void {
const t_io = t.io(); const t_io = io(t);
const file = Io.File.openAbsolute(t_io, "/etc/hosts", .{}) catch |err| switch (err) { const file = Io.File.openAbsolute(t_io, "/etc/hosts", .{}) catch |err| switch (err) {
error.FileNotFound, error.FileNotFound,
error.NotDir, error.NotDir,
@ -4906,7 +5150,7 @@ fn lookupHostsReader(
options: HostName.LookupOptions, options: HostName.LookupOptions,
reader: *Io.Reader, reader: *Io.Reader,
) error{ ReadFailed, Canceled, UnknownHostName }!void { ) error{ ReadFailed, Canceled, UnknownHostName }!void {
const t_io = t.io(); const t_io = io(t);
var addresses_len: usize = 0; var addresses_len: usize = 0;
var canonical_name: ?HostName = null; var canonical_name: ?HostName = null;
while (true) { while (true) {
@ -5374,7 +5618,7 @@ const Wsa = struct {
}; };
fn initializeWsa(t: *Threaded) error{NetworkDown}!void { fn initializeWsa(t: *Threaded) error{NetworkDown}!void {
const t_io = t.io(); const t_io = io(t);
const wsa = &t.wsa; const wsa = &t.wsa;
wsa.mutex.lockUncancelable(t_io); wsa.mutex.lockUncancelable(t_io);
defer wsa.mutex.unlock(t_io); defer wsa.mutex.unlock(t_io);

View file

@ -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()}); const path = try std.fmt.bufPrint(&buf, "/proc/self/task/{d}/comm", .{self.getHandle()});
var threaded: std.Io.Threaded = .init_single_threaded; var threaded: std.Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
const file = try std.fs.cwd().openFile(path, .{}); const file = try std.fs.cwd().openFile(path, .{});
defer file.close(); defer file.close();

View file

@ -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. /// 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 { pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void {
var threaded: Io.Threaded = .init_single_threaded; var threaded: Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
if (!std.options.allow_stack_tracing) { if (!std.options.allow_stack_tracing) {
tty_config.setColor(writer, .dim) catch {}; 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 // We use an independent Io implementation here in case there was a problem
// with the application's Io implementation itself. // with the application's Io implementation itself.
var threaded: Io.Threaded = .init_single_threaded; 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 // 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. // `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; const gpa = std.testing.allocator;
var threaded: Io.Threaded = .init_single_threaded; var threaded: Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
var discarding: Io.Writer.Discarding = .init(&.{}); var discarding: Io.Writer.Discarding = .init(&.{});
var di: SelfInfo = .init; var di: SelfInfo = .init;
defer di.deinit(gpa); defer di.deinit(gpa);

View file

@ -340,7 +340,7 @@ pub const OpenSelfExeError = Io.File.OpenSelfExeError;
pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
if (native_os == .linux or native_os == .serenity or native_os == .windows) { if (native_os == .linux or native_os == .serenity or native_os == .windows) {
var threaded: Io.Threaded = .init_single_threaded; var threaded: Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
return .adaptFromNewApi(try Io.File.openSelfExe(io, flags)); return .adaptFromNewApi(try Io.File.openSelfExe(io, flags));
} }
// Use of max_path_bytes here is valid as the resulting path is immediately // Use of max_path_bytes here is valid as the resulting path is immediately

View file

@ -849,14 +849,14 @@ pub fn close(self: *Dir) void {
/// Deprecated in favor of `Io.Dir.openFile`. /// Deprecated in favor of `Io.Dir.openFile`.
pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
var threaded: Io.Threaded = .init_single_threaded; 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)); return .adaptFromNewApi(try Io.Dir.openFile(self.adaptToNewApi(), io, sub_path, flags));
} }
/// Deprecated in favor of `Io.Dir.createFile`. /// Deprecated in favor of `Io.Dir.createFile`.
pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
var threaded: Io.Threaded = .init_single_threaded; 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); const new_file = try Io.Dir.createFile(self.adaptToNewApi(), io, sub_path, flags);
return .adaptFromNewApi(new_file); return .adaptFromNewApi(new_file);
} }
@ -867,7 +867,7 @@ pub const MakeError = Io.Dir.MakeError;
/// Deprecated in favor of `Io.Dir.makeDir`. /// Deprecated in favor of `Io.Dir.makeDir`.
pub fn makeDir(self: Dir, sub_path: []const u8) MakeError!void { pub fn makeDir(self: Dir, sub_path: []const u8) MakeError!void {
var threaded: Io.Threaded = .init_single_threaded; 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); 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`. /// Deprecated in favor of `Io.Dir.makePathStatus`.
pub fn makePathStatus(self: Dir, sub_path: []const u8) MakePathError!MakePathStatus { pub fn makePathStatus(self: Dir, sub_path: []const u8) MakePathError!MakePathStatus {
var threaded: Io.Threaded = .init_single_threaded; 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); return Io.Dir.makePathStatus(.{ .handle = self.fd }, io, sub_path);
} }
/// Deprecated in favor of `Io.Dir.makeOpenPath`. /// Deprecated in favor of `Io.Dir.makeOpenPath`.
pub fn makeOpenPath(dir: Dir, sub_path: []const u8, options: OpenOptions) Io.Dir.MakeOpenPathError!Dir { pub fn makeOpenPath(dir: Dir, sub_path: []const u8, options: OpenOptions) Io.Dir.MakeOpenPathError!Dir {
var threaded: Io.Threaded = .init_single_threaded; 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)); 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`. /// Deprecated in favor of `Io.Dir.openDir`.
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenOptions) OpenError!Dir { pub fn openDir(self: Dir, sub_path: []const u8, args: OpenOptions) OpenError!Dir {
var threaded: Io.Threaded = .init_single_threaded; 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)); 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`. /// Deprecated in favor of `Io.Dir.readFile`.
pub fn readFile(self: Dir, file_path: []const u8, buffer: []u8) ![]u8 { pub fn readFile(self: Dir, file_path: []const u8, buffer: []u8) ![]u8 {
var threaded: Io.Threaded = .init_single_threaded; 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); return Io.Dir.readFile(.{ .handle = self.fd }, io, file_path, buffer);
} }
@ -1437,7 +1437,7 @@ pub fn readFileAllocOptions(
comptime sentinel: ?u8, comptime sentinel: ?u8,
) ReadFileAllocError!(if (sentinel) |s| [:s]align(alignment.toByteUnits()) u8 else []align(alignment.toByteUnits()) u8) { ) ReadFileAllocError!(if (sentinel) |s| [:s]align(alignment.toByteUnits()) u8 else []align(alignment.toByteUnits()) u8) {
var threaded: Io.Threaded = .init_single_threaded; var threaded: Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
var file = try dir.openFile(sub_path, .{}); var file = try dir.openFile(sub_path, .{});
defer file.close(); defer file.close();
@ -1892,7 +1892,7 @@ pub const AccessError = Io.Dir.AccessError;
/// Deprecated in favor of `Io.Dir.access`. /// Deprecated in favor of `Io.Dir.access`.
pub fn access(self: Dir, sub_path: []const u8, options: Io.Dir.AccessOptions) AccessError!void { pub fn access(self: Dir, sub_path: []const u8, options: Io.Dir.AccessOptions) AccessError!void {
var threaded: Io.Threaded = .init_single_threaded; 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); return Io.Dir.access(self.adaptToNewApi(), io, sub_path, options);
} }
@ -1928,7 +1928,7 @@ pub fn copyFile(
options: CopyFileOptions, options: CopyFileOptions,
) CopyFileError!void { ) CopyFileError!void {
var threaded: Io.Threaded = .init_single_threaded; var threaded: Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
const file = try source_dir.openFile(source_path, .{}); const file = try source_dir.openFile(source_path, .{});
var file_reader: File.Reader = .init(.{ .handle = file.handle }, io, &.{}); 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`. /// Deprecated in favor of `Io.Dir.statPath`.
pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat { pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
var threaded: Io.Threaded = .init_single_threaded; 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, .{}); return Io.Dir.statPath(.{ .handle = self.fd }, io, sub_path, .{});
} }

View file

@ -313,7 +313,7 @@ pub const StatError = posix.FStatError;
/// Returns `Stat` containing basic information about the `File`. /// Returns `Stat` containing basic information about the `File`.
pub fn stat(self: File) StatError!Stat { pub fn stat(self: File) StatError!Stat {
var threaded: Io.Threaded = .init_single_threaded; var threaded: Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
return Io.File.stat(.{ .handle = self.handle }, io); return Io.File.stat(.{ .handle = self.handle }, io);
} }

View file

@ -1089,7 +1089,7 @@ fn windowsCreateProcessPathExt(
// opening function knowing which implementation we are in. Here, we imitate // opening function knowing which implementation we are in. Here, we imitate
// that scenario. // that scenario.
var threaded: std.Io.Threaded = .init_single_threaded; var threaded: std.Io.Threaded = .init_single_threaded;
const io = threaded.io(); const io = threaded.ioBasic();
var dir = dir: { var dir = dir: {
// needs to be null-terminated // needs to be null-terminated

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const Io = std.Io;
// 42 is expected by parent; other values result in test failure // 42 is expected by parent; other values result in test failure
var exit_code: u8 = 42; var exit_code: u8 = 42;
@ -6,12 +7,17 @@ var exit_code: u8 = 42;
pub fn main() !void { pub fn main() !void {
var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const arena = arena_state.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(); arena_state.deinit();
std.process.exit(exit_code); 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); var args = try std.process.argsWithAllocator(allocator);
defer args.deinit(); defer args.deinit();
_ = args.next() orelse unreachable; // skip binary name _ = args.next() orelse unreachable; // skip binary name
@ -33,7 +39,8 @@ fn run(allocator: std.mem.Allocator) !void {
const hello_stdin = "hello from stdin"; const hello_stdin = "hello from stdin";
var buf: [hello_stdin.len]u8 = undefined; var buf: [hello_stdin.len]u8 = undefined;
const stdin: std.fs.File = .stdin(); 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)) { if (!std.mem.eql(u8, buf[0..n], hello_stdin)) {
testError("stdin: '{s}'; want '{s}'", .{ buf[0..n], hello_stdin }); testError("stdin: '{s}'; want '{s}'", .{ buf[0..n], hello_stdin });
} }

View file

@ -9,6 +9,10 @@ pub fn main() !void {
defer arena_instance.deinit(); defer arena_instance.deinit();
const arena = arena_instance.allocator(); 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 args = try std.process.argsAlloc(arena);
const exe = args[0]; const exe = args[0];
@ -16,7 +20,7 @@ pub fn main() !void {
var stdout_buffer: [4096]u8 = undefined; var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer); var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
const stdout = &stdout_writer.interface; const stdout = &stdout_writer.interface;
var stdin_reader = fs.File.stdin().readerStreaming(&.{}); var stdin_reader = fs.File.stdin().readerStreaming(io, &.{});
const cwd = fs.cwd(); const cwd = fs.cwd();
@ -32,7 +36,7 @@ pub fn main() !void {
defer file.close(); defer file.close();
catted_anything = true; catted_anything = true;
var file_reader = file.reader(&.{}); var file_reader = file.reader(io, &.{});
_ = try stdout.sendFileAll(&file_reader, .unlimited); _ = try stdout.sendFileAll(&file_reader, .unlimited);
try stdout.flush(); try stdout.flush();
} }

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const Io = std.Io;
const fs = std.fs; const fs = std.fs;
const mem = std.mem; const mem = std.mem;
const process = std.process; const process = std.process;
@ -85,7 +86,7 @@ pub fn main() anyerror!void {
} else try argv.append(arg); } else try argv.append(arg);
} }
var threaded: std.Io.Threaded = .init(gpa); var threaded: Io.Threaded = .init(gpa);
defer threaded.deinit(); defer threaded.deinit();
const io = threaded.io(); const io = threaded.io();
@ -118,12 +119,13 @@ pub fn main() anyerror!void {
.arch = arch, .arch = arch,
.os_ver = os_ver, .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( fn fetchTarget(
arena: Allocator, arena: Allocator,
io: Io,
args: []const []const u8, args: []const []const u8,
sysroot: []const u8, sysroot: []const u8,
target: Target, target: Target,
@ -194,7 +196,7 @@ fn fetchTarget(
var dirs = std.StringHashMap(fs.Dir).init(arena); var dirs = std.StringHashMap(fs.Dir).init(arena);
try dirs.putNoClobber(".", dest_dir); 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 headers_list_str = try headers_list_file_reader.interface.allocRemaining(arena, .unlimited);
const prefix = "/usr/include"; const prefix = "/usr/include";
@ -267,8 +269,8 @@ const Version = struct {
pub fn format( pub fn format(
v: Version, v: Version,
writer: *std.Io.Writer, writer: *Io.Writer,
) std.Io.Writer.Error!void { ) Io.Writer.Error!void {
try writer.print("{d}.{d}.{d}", .{ v.major, v.minor, v.patch }); try writer.print("{d}.{d}.{d}", .{ v.major, v.minor, v.patch });
} }
}; };

View file

@ -73,7 +73,7 @@ fn findHeaders(
switch (entry.kind) { switch (entry.kind) {
.directory => { .directory => {
const path = try std.fs.path.join(arena, &.{ prefix, entry.name }); 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(); defer subdir.close();
try findHeaders(arena, subdir, path, paths); try findHeaders(arena, subdir, path, paths);
}, },