mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:44:43 +01:00
Merge branch "remove many std.posix functions"
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30741
This commit is contained in:
commit
6f7968f165
15 changed files with 314 additions and 1520 deletions
4
lib/compiler/aro/aro/Driver.zig
vendored
4
lib/compiler/aro/aro/Driver.zig
vendored
|
|
@ -1219,12 +1219,12 @@ pub fn getDepFileName(d: *Driver, source: Source, buf: *[std.fs.max_name_bytes]u
|
|||
fn getRandomFilename(d: *Driver, buf: *[std.fs.max_name_bytes]u8, extension: []const u8) ![]const u8 {
|
||||
const io = d.comp.io;
|
||||
const random_bytes_count = 12;
|
||||
const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count);
|
||||
const sub_path_len = comptime std.base64.url_safe.Encoder.calcSize(random_bytes_count);
|
||||
|
||||
var random_bytes: [random_bytes_count]u8 = undefined;
|
||||
io.random(&random_bytes);
|
||||
var random_name: [sub_path_len]u8 = undefined;
|
||||
_ = std.fs.base64_encoder.encode(&random_name, &random_bytes);
|
||||
_ = std.base64.url_safe.Encoder.encode(&random_name, &random_bytes);
|
||||
|
||||
const fmt_template = "/tmp/{s}{s}";
|
||||
const fmt_args = .{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
const builtin = @import("builtin");
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const Io = std.Io;
|
||||
const Step = std.Build.Step;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
|
@ -666,7 +668,7 @@ const Os = switch (builtin.os.tag) {
|
|||
.dir_table = .{},
|
||||
.dir_count = 0,
|
||||
.os = .{
|
||||
.kq_fd = try posix.kqueue(),
|
||||
.kq_fd = try Io.Kqueue.createFileDescriptor(),
|
||||
.handles = .empty,
|
||||
},
|
||||
.generation = 0,
|
||||
|
|
@ -697,7 +699,7 @@ const Os = switch (builtin.os.tag) {
|
|||
.data = 0,
|
||||
.udata = gop.index,
|
||||
}};
|
||||
_ = try posix.kevent(w.os.kq_fd, &changes, &.{}, null);
|
||||
_ = try Io.Kqueue.kevent(w.os.kq_fd, &changes, &.{}, null);
|
||||
assert(handles.len == gop.index);
|
||||
try handles.append(gpa, .{
|
||||
.rs = .{},
|
||||
|
|
@ -787,7 +789,7 @@ const Os = switch (builtin.os.tag) {
|
|||
},
|
||||
};
|
||||
const filtered_changes = if (i == handles.len - 1) changes[0..1] else &changes;
|
||||
_ = try posix.kevent(w.os.kq_fd, filtered_changes, &.{}, null);
|
||||
_ = try Io.Kqueue.kevent(w.os.kq_fd, filtered_changes, &.{}, null);
|
||||
if (path.sub_path.len != 0) posix.close(dir_fd);
|
||||
|
||||
w.dir_table.swapRemoveAt(i);
|
||||
|
|
@ -801,13 +803,13 @@ const Os = switch (builtin.os.tag) {
|
|||
fn wait(w: *Watch, gpa: Allocator, timeout: Timeout) !WaitResult {
|
||||
var timespec_buffer: posix.timespec = undefined;
|
||||
var event_buffer: [100]posix.Kevent = undefined;
|
||||
var n = try posix.kevent(w.os.kq_fd, &.{}, &event_buffer, timeout.toTimespec(×pec_buffer));
|
||||
var n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, timeout.toTimespec(×pec_buffer));
|
||||
if (n == 0) return .timeout;
|
||||
const reaction_sets = w.os.handles.items(.rs);
|
||||
var any_dirty = markDirtySteps(gpa, reaction_sets, event_buffer[0..n], false);
|
||||
timespec_buffer = .{ .sec = 0, .nsec = 0 };
|
||||
while (n == event_buffer.len) {
|
||||
n = try posix.kevent(w.os.kq_fd, &.{}, &event_buffer, ×pec_buffer);
|
||||
n = try Io.Kqueue.kevent(w.os.kq_fd, &.{}, &event_buffer, ×pec_buffer);
|
||||
if (n == 0) break;
|
||||
any_dirty = markDirtySteps(gpa, reaction_sets, event_buffer[0..n], any_dirty);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -540,18 +540,20 @@ test {
|
|||
|
||||
const Io = @This();
|
||||
|
||||
pub const Threaded = @import("Io/Threaded.zig");
|
||||
pub const Evented = switch (builtin.os.tag) {
|
||||
.linux => switch (builtin.cpu.arch) {
|
||||
.x86_64, .aarch64 => @import("Io/IoUring.zig"),
|
||||
.x86_64, .aarch64 => IoUring,
|
||||
else => void, // context-switching code not implemented yet
|
||||
},
|
||||
.dragonfly, .freebsd, .netbsd, .openbsd, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => switch (builtin.cpu.arch) {
|
||||
.x86_64, .aarch64 => @import("Io/Kqueue.zig"),
|
||||
.x86_64, .aarch64 => Kqueue,
|
||||
else => void, // context-switching code not implemented yet
|
||||
},
|
||||
else => void,
|
||||
};
|
||||
pub const Threaded = @import("Io/Threaded.zig");
|
||||
pub const Kqueue = @import("Io/Kqueue.zig");
|
||||
pub const IoUring = @import("Io/IoUring.zig");
|
||||
pub const net = @import("Io/net.zig");
|
||||
|
||||
userdata: ?*anyopaque,
|
||||
|
|
@ -1356,7 +1358,7 @@ pub const Mutex = extern struct {
|
|||
|
||||
pub const init: Mutex = .{ .state = .init(.unlocked) };
|
||||
|
||||
const State = enum(u32) {
|
||||
pub const State = enum(u32) {
|
||||
unlocked,
|
||||
locked_once,
|
||||
contended,
|
||||
|
|
|
|||
|
|
@ -157,8 +157,11 @@ pub const InitOptions = struct {
|
|||
n_threads: ?usize = null,
|
||||
};
|
||||
|
||||
pub const InitError = Allocator.Error || CreateFileDescriptorError;
|
||||
|
||||
pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void {
|
||||
assert(options.n_threads != 0);
|
||||
|
||||
const n_threads = @max(1, options.n_threads orelse std.Thread.getCpuCount() catch 1);
|
||||
const threads_size = n_threads * @sizeOf(Thread);
|
||||
const idle_stack_end_offset = std.mem.alignForward(usize, threads_size + idle_stack_size, std.heap.page_size_max);
|
||||
|
|
@ -204,7 +207,7 @@ pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void {
|
|||
},
|
||||
.current_context = &main_fiber.context,
|
||||
.ready_queue = null,
|
||||
.kq_fd = try posix.kqueue(),
|
||||
.kq_fd = try createFileDescriptor(),
|
||||
.idle_search_index = 1,
|
||||
.steal_ready_search_index = 1,
|
||||
.wait_queues = .empty,
|
||||
|
|
@ -231,6 +234,23 @@ pub fn deinit(k: *Kqueue) void {
|
|||
k.* = undefined;
|
||||
}
|
||||
|
||||
pub const CreateFileDescriptorError = error{
|
||||
/// The per-process limit on the number of open file descriptors has been reached.
|
||||
ProcessFdQuotaExceeded,
|
||||
/// The system-wide limit on the total number of open files has been reached.
|
||||
SystemFdQuotaExceeded,
|
||||
} || Io.UnexpectedError;
|
||||
|
||||
pub fn createFileDescriptor() CreateFileDescriptorError!posix.fd_t {
|
||||
const rc = posix.system.kqueue();
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.MFILE => return error.ProcessFdQuotaExceeded,
|
||||
.NFILE => return error.SystemFdQuotaExceeded,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn findReadyFiber(k: *Kqueue, thread: *Thread) ?*Fiber {
|
||||
if (@atomicRmw(?*Fiber, &thread.ready_queue, .Xchg, Fiber.finished, .acquire)) |ready_fiber| {
|
||||
@atomicStore(?*Fiber, &thread.ready_queue, ready_fiber.queue_next, .release);
|
||||
|
|
@ -314,7 +334,10 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void {
|
|||
},
|
||||
};
|
||||
// If an error occurs it only pessimises scheduling.
|
||||
_ = posix.kevent(idle_search_thread.kq_fd, &changes, &.{}, null) catch {};
|
||||
_ = kevent(idle_search_thread.kq_fd, &changes, &.{}, null) catch |err| {
|
||||
// TODO handle EINTR for cancellation purposes
|
||||
@panic(@errorName(err)); // TODO
|
||||
};
|
||||
return;
|
||||
}
|
||||
spawn_thread: {
|
||||
|
|
@ -334,7 +357,7 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void {
|
|||
.idle_context = undefined,
|
||||
.current_context = &new_thread.idle_context,
|
||||
.ready_queue = ready_queue.head,
|
||||
.kq_fd = posix.kqueue() catch |err| {
|
||||
.kq_fd = createFileDescriptor() catch |err| {
|
||||
@atomicStore(u32, &k.threads.reserved, new_thread_index, .release);
|
||||
// no more access to `thread` after giving up reservation
|
||||
std.log.warn("unable to create worker thread due to kqueue init failure: {t}", .{err});
|
||||
|
|
@ -409,9 +432,9 @@ fn idle(k: *Kqueue, thread: *Thread) void {
|
|||
k.yield(ready_fiber, .nothing);
|
||||
maybe_ready_fiber = null;
|
||||
}
|
||||
const n = posix.kevent(thread.kq_fd, &.{}, &events_buffer, null) catch |err| {
|
||||
const n = kevent(thread.kq_fd, &.{}, &events_buffer, null) catch |err| {
|
||||
// TODO handle EINTR for cancellation purposes
|
||||
@panic(@errorName(err));
|
||||
@panic(@errorName(err)); // TODO
|
||||
};
|
||||
var maybe_ready_queue: ?Fiber.Queue = null;
|
||||
for (events_buffer[0..n]) |event| switch (@as(Completion.UserData, @enumFromInt(event.udata))) {
|
||||
|
|
@ -471,14 +494,6 @@ const SwitchMessage = struct {
|
|||
recycle: *Fiber,
|
||||
register_awaiter: *?*Fiber,
|
||||
register_select: []const *Io.AnyFuture,
|
||||
mutex_lock: struct {
|
||||
prev_state: Io.Mutex.State,
|
||||
mutex: *Io.Mutex,
|
||||
},
|
||||
condition_wait: struct {
|
||||
cond: *Io.Condition,
|
||||
mutex: *Io.Mutex,
|
||||
},
|
||||
exit,
|
||||
};
|
||||
|
||||
|
|
@ -514,59 +529,6 @@ const SwitchMessage = struct {
|
|||
}
|
||||
}
|
||||
},
|
||||
.mutex_lock => |mutex_lock| {
|
||||
const prev_fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.prev));
|
||||
assert(prev_fiber.queue_next == null);
|
||||
var prev_state = mutex_lock.prev_state;
|
||||
while (switch (prev_state) {
|
||||
else => next_state: {
|
||||
prev_fiber.queue_next = @ptrFromInt(@intFromEnum(prev_state));
|
||||
break :next_state @cmpxchgWeak(
|
||||
Io.Mutex.State,
|
||||
&mutex_lock.mutex.state,
|
||||
prev_state,
|
||||
@enumFromInt(@intFromPtr(prev_fiber)),
|
||||
.release,
|
||||
.acquire,
|
||||
);
|
||||
},
|
||||
.unlocked => @cmpxchgWeak(
|
||||
Io.Mutex.State,
|
||||
&mutex_lock.mutex.state,
|
||||
.unlocked,
|
||||
.locked_once,
|
||||
.acquire,
|
||||
.acquire,
|
||||
) orelse {
|
||||
prev_fiber.queue_next = null;
|
||||
k.schedule(thread, .{ .head = prev_fiber, .tail = prev_fiber });
|
||||
return;
|
||||
},
|
||||
}) |next_state| prev_state = next_state;
|
||||
},
|
||||
.condition_wait => |condition_wait| {
|
||||
const prev_fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.prev));
|
||||
assert(prev_fiber.queue_next == null);
|
||||
const cond_impl = prev_fiber.resultPointer(Condition);
|
||||
cond_impl.* = .{
|
||||
.tail = prev_fiber,
|
||||
.event = .queued,
|
||||
};
|
||||
if (@cmpxchgStrong(
|
||||
?*Fiber,
|
||||
@as(*?*Fiber, @ptrCast(&condition_wait.cond.state)),
|
||||
null,
|
||||
prev_fiber,
|
||||
.release,
|
||||
.acquire,
|
||||
)) |waiting_fiber| {
|
||||
const waiting_cond_impl = waiting_fiber.?.resultPointer(Condition);
|
||||
assert(waiting_cond_impl.tail.queue_next == null);
|
||||
waiting_cond_impl.tail.queue_next = prev_fiber;
|
||||
waiting_cond_impl.tail = prev_fiber;
|
||||
}
|
||||
condition_wait.mutex.unlock(k.io());
|
||||
},
|
||||
.exit => for (k.threads.allocated[0..@atomicLoad(u32, &k.threads.active, .acquire)]) |*each_thread| {
|
||||
const changes = [_]posix.Kevent{
|
||||
.{
|
||||
|
|
@ -578,8 +540,9 @@ const SwitchMessage = struct {
|
|||
.udata = @intFromEnum(Completion.UserData.exit),
|
||||
},
|
||||
};
|
||||
_ = posix.kevent(each_thread.kq_fd, &changes, &.{}, null) catch |err| {
|
||||
@panic(@errorName(err));
|
||||
_ = kevent(each_thread.kq_fd, &changes, &.{}, null) catch |err| {
|
||||
// TODO handle EINTR for cancellation purposes
|
||||
@panic(@errorName(err)); // TODO
|
||||
};
|
||||
},
|
||||
}
|
||||
|
|
@ -854,21 +817,13 @@ pub fn io(k: *Kqueue) Io {
|
|||
.concurrent = concurrent,
|
||||
.await = await,
|
||||
.cancel = cancel,
|
||||
.cancelRequested = cancelRequested,
|
||||
.select = select,
|
||||
|
||||
.groupAsync = groupAsync,
|
||||
.groupWait = groupWait,
|
||||
.groupConcurrent = groupConcurrent,
|
||||
.groupAwait = groupAwait,
|
||||
.groupCancel = groupCancel,
|
||||
|
||||
.mutexLock = mutexLock,
|
||||
.mutexLockUncancelable = mutexLockUncancelable,
|
||||
.mutexUnlock = mutexUnlock,
|
||||
|
||||
.conditionWait = conditionWait,
|
||||
.conditionWaitUncancelable = conditionWaitUncancelable,
|
||||
.conditionWake = conditionWake,
|
||||
|
||||
.dirCreateDir = dirCreateDir,
|
||||
.dirCreateDirPath = dirCreateDirPath,
|
||||
.dirCreateDirPathOpen = dirCreateDirPathOpen,
|
||||
|
|
@ -888,7 +843,6 @@ pub fn io(k: *Kqueue) Io {
|
|||
.fileReadPositional = fileReadPositional,
|
||||
.fileSeekBy = fileSeekBy,
|
||||
.fileSeekTo = fileSeekTo,
|
||||
.openExecutable = openExecutable,
|
||||
|
||||
.now = now,
|
||||
.sleep = sleep,
|
||||
|
|
@ -1013,25 +967,41 @@ fn cancelRequested(userdata: ?*anyopaque) bool {
|
|||
|
||||
fn groupAsync(
|
||||
userdata: ?*anyopaque,
|
||||
group: *Io.Group,
|
||||
type_erased: *Io.Group,
|
||||
context: []const u8,
|
||||
context_alignment: std.mem.Alignment,
|
||||
start: *const fn (*Io.Group, context: *const anyopaque) void,
|
||||
context_alignment: Alignment,
|
||||
start: *const fn (context: *const anyopaque) Io.Cancelable!void,
|
||||
) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = group;
|
||||
_ = type_erased;
|
||||
_ = context;
|
||||
_ = context_alignment;
|
||||
_ = start;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void {
|
||||
fn groupConcurrent(
|
||||
userdata: ?*anyopaque,
|
||||
type_erased: *Io.Group,
|
||||
context: []const u8,
|
||||
context_alignment: Alignment,
|
||||
start: *const fn (context: *const anyopaque) Io.Cancelable!void,
|
||||
) Io.ConcurrentError!void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = group;
|
||||
_ = token;
|
||||
_ = type_erased;
|
||||
_ = context;
|
||||
_ = context_alignment;
|
||||
_ = start;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn groupAwait(userdata: ?*anyopaque, type_erased: *Io.Group, initial_token: *anyopaque) Io.Cancelable!void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = type_erased;
|
||||
_ = initial_token;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
|
|
@ -1050,102 +1020,58 @@ fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) Io.Cancelable!u
|
|||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn mutexLock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) Io.Cancelable!void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = prev_state;
|
||||
_ = mutex;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn mutexLockUncancelable(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = prev_state;
|
||||
_ = mutex;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn mutexUnlock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mutex) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = prev_state;
|
||||
_ = mutex;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) Io.Cancelable!void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
k.yield(null, .{ .condition_wait = .{ .cond = cond, .mutex = mutex } });
|
||||
const thread = Thread.current();
|
||||
const fiber = thread.currentFiber();
|
||||
const cond_impl = fiber.resultPointer(Condition);
|
||||
try mutex.lock(k.io());
|
||||
switch (cond_impl.event) {
|
||||
.queued => {},
|
||||
.wake => |wake| if (fiber.queue_next) |next_fiber| switch (wake) {
|
||||
.one => if (@cmpxchgStrong(
|
||||
?*Fiber,
|
||||
@as(*?*Fiber, @ptrCast(&cond.state)),
|
||||
null,
|
||||
next_fiber,
|
||||
.release,
|
||||
.acquire,
|
||||
)) |old_fiber| {
|
||||
const old_cond_impl = old_fiber.?.resultPointer(Condition);
|
||||
assert(old_cond_impl.tail.queue_next == null);
|
||||
old_cond_impl.tail.queue_next = next_fiber;
|
||||
old_cond_impl.tail = cond_impl.tail;
|
||||
},
|
||||
.all => k.schedule(thread, .{ .head = next_fiber, .tail = cond_impl.tail }),
|
||||
},
|
||||
}
|
||||
fiber.queue_next = null;
|
||||
}
|
||||
|
||||
fn conditionWaitUncancelable(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = cond;
|
||||
_ = mutex;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition.Wake) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
const waiting_fiber = @atomicRmw(?*Fiber, @as(*?*Fiber, @ptrCast(&cond.state)), .Xchg, null, .acquire) orelse return;
|
||||
waiting_fiber.resultPointer(Condition).event = .{ .wake = wake };
|
||||
k.yield(waiting_fiber, .reschedule);
|
||||
}
|
||||
|
||||
fn dirCreateDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.CreateDirError!void {
|
||||
fn dirCreateDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, permissions: Dir.Permissions) Dir.CreateDirError!void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = dir;
|
||||
_ = sub_path;
|
||||
_ = mode;
|
||||
_ = permissions;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn dirCreateDirPath(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, mode: Dir.Mode) Dir.CreateDirError!void {
|
||||
|
||||
fn dirCreateDirPath(
|
||||
userdata: ?*anyopaque,
|
||||
dir: Dir,
|
||||
sub_path: []const u8,
|
||||
permissions: Dir.Permissions,
|
||||
) Dir.CreateDirPathError!Dir.CreatePathStatus {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = dir;
|
||||
_ = sub_path;
|
||||
_ = mode;
|
||||
_ = permissions;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn dirCreateDirPathOpen(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.OpenOptions) Dir.CreateDirPathOpenError!Dir {
|
||||
|
||||
fn dirCreateDirPathOpen(
|
||||
userdata: ?*anyopaque,
|
||||
dir: Dir,
|
||||
sub_path: []const u8,
|
||||
permissions: Dir.Permissions,
|
||||
options: Dir.OpenOptions,
|
||||
) Dir.CreateDirPathOpenError!Dir {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = dir;
|
||||
_ = sub_path;
|
||||
_ = permissions;
|
||||
_ = options;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = dir;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn dirStatFile(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Dir.StatPathOptions) Dir.StatFileError!File.Stat {
|
||||
|
||||
fn dirStatFile(
|
||||
userdata: ?*anyopaque,
|
||||
dir: Dir,
|
||||
sub_path: []const u8,
|
||||
options: Dir.StatFileOptions,
|
||||
) Dir.StatFileError!File.Stat {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = dir;
|
||||
|
|
@ -1185,10 +1111,10 @@ fn dirOpenDir(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, options: Di
|
|||
_ = options;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn dirClose(userdata: ?*anyopaque, dir: Dir) void {
|
||||
fn dirClose(userdata: ?*anyopaque, dirs: []const Dir) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = dir;
|
||||
_ = dirs;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn fileStat(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
|
||||
|
|
@ -1197,35 +1123,57 @@ fn fileStat(userdata: ?*anyopaque, file: File) File.StatError!File.Stat {
|
|||
_ = file;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn fileClose(userdata: ?*anyopaque, file: File) void {
|
||||
|
||||
fn fileClose(userdata: ?*anyopaque, files: []const File) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = file;
|
||||
_ = files;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn fileWriteStreaming(userdata: ?*anyopaque, file: File, buffer: [][]const u8) File.WriteStreamingError!usize {
|
||||
|
||||
fn fileWriteStreaming(
|
||||
userdata: ?*anyopaque,
|
||||
file: File,
|
||||
header: []const u8,
|
||||
data: []const []const u8,
|
||||
splat: usize,
|
||||
) File.Writer.Error!usize {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = file;
|
||||
_ = buffer;
|
||||
_ = header;
|
||||
_ = data;
|
||||
_ = splat;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn fileWritePositional(userdata: ?*anyopaque, file: File, buffer: [][]const u8, offset: u64) File.WritePositionalError!usize {
|
||||
|
||||
fn fileWritePositional(
|
||||
userdata: ?*anyopaque,
|
||||
file: File,
|
||||
header: []const u8,
|
||||
data: []const []const u8,
|
||||
splat: usize,
|
||||
offset: u64,
|
||||
) File.WritePositionalError!usize {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = file;
|
||||
_ = buffer;
|
||||
_ = header;
|
||||
_ = data;
|
||||
_ = splat;
|
||||
_ = offset;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: [][]u8) File.Reader.Error!usize {
|
||||
|
||||
fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = file;
|
||||
_ = data;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn fileReadPositional(userdata: ?*anyopaque, file: File, data: [][]u8, offset: u64) File.ReadPositionalError!usize {
|
||||
|
||||
fn fileReadPositional(userdata: ?*anyopaque, file: File, data: []const []u8, offset: u64) File.ReadPositionalError!usize {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = file;
|
||||
|
|
@ -1247,12 +1195,6 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, absolute_offset: u64) File.Seek
|
|||
_ = absolute_offset;
|
||||
@panic("TODO");
|
||||
}
|
||||
fn openExecutable(userdata: ?*anyopaque, file: File.OpenFlags) File.OpenExecutableError!File {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = file;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn now(userdata: ?*anyopaque, clock: Io.Clock) Io.Clock.Error!Io.Timestamp {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
|
|
@ -1518,7 +1460,8 @@ fn netRead(userdata: ?*anyopaque, fd: net.Socket.Handle, data: [][]u8) net.Strea
|
|||
.udata = @intFromPtr(fiber),
|
||||
},
|
||||
};
|
||||
assert(0 == (posix.kevent(thread.kq_fd, &changes, &.{}, null) catch |err| {
|
||||
assert(0 == (kevent(thread.kq_fd, &changes, &.{}, null) catch |err| {
|
||||
// TODO handle EINTR for cancellation purposes
|
||||
@panic(@errorName(err)); // TODO
|
||||
}));
|
||||
}
|
||||
|
|
@ -1551,10 +1494,10 @@ fn netWrite(userdata: ?*anyopaque, dest: net.Socket.Handle, header: []const u8,
|
|||
@panic("TODO");
|
||||
}
|
||||
|
||||
fn netClose(userdata: ?*anyopaque, handle: net.Socket.Handle) void {
|
||||
fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = handle;
|
||||
_ = handles;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
|
|
@ -1586,13 +1529,13 @@ fn netInterfaceName(userdata: ?*anyopaque, interface: net.Interface) net.Interfa
|
|||
fn netLookup(
|
||||
userdata: ?*anyopaque,
|
||||
host_name: net.HostName,
|
||||
result: *Io.Queue(net.HostName.LookupResult),
|
||||
resolved: *Io.Queue(net.HostName.LookupResult),
|
||||
options: net.HostName.LookupOptions,
|
||||
) void {
|
||||
) net.HostName.LookupError!void {
|
||||
const k: *Kqueue = @ptrCast(@alignCast(userdata));
|
||||
_ = k;
|
||||
_ = host_name;
|
||||
_ = result;
|
||||
_ = resolved;
|
||||
_ = options;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
|
@ -1747,10 +1690,46 @@ fn checkCancel(k: *Kqueue) error{Canceled}!void {
|
|||
if (cancelRequested(k)) return error.Canceled;
|
||||
}
|
||||
|
||||
const Condition = struct {
|
||||
tail: *Fiber,
|
||||
event: union(enum) {
|
||||
queued,
|
||||
wake: Io.Condition.Wake,
|
||||
},
|
||||
pub const KEventError = error{
|
||||
/// The process does not have permission to register a filter.
|
||||
AccessDenied,
|
||||
/// The event could not be found to be modified or deleted.
|
||||
EventNotFound,
|
||||
/// No memory was available to register the event.
|
||||
SystemResources,
|
||||
/// The specified process to attach to does not exist.
|
||||
ProcessNotFound,
|
||||
/// changelist or eventlist had too many items on it.
|
||||
/// TODO remove this possibility
|
||||
Overflow,
|
||||
};
|
||||
|
||||
pub fn kevent(
|
||||
kq: i32,
|
||||
changelist: []const posix.Kevent,
|
||||
eventlist: []posix.Kevent,
|
||||
timeout: ?*const posix.timespec,
|
||||
) KEventError!usize {
|
||||
while (true) {
|
||||
const rc = posix.system.kevent(
|
||||
kq,
|
||||
changelist.ptr,
|
||||
std.math.cast(c_int, changelist.len) orelse return error.Overflow,
|
||||
eventlist.ptr,
|
||||
std.math.cast(c_int, eventlist.len) orelse return error.Overflow,
|
||||
timeout,
|
||||
);
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.ACCES => return error.AccessDenied,
|
||||
.FAULT => unreachable, // TODO use error.Unexpected for these
|
||||
.BADF => unreachable, // Always a race condition.
|
||||
.INTR => continue, // TODO handle cancelation
|
||||
.INVAL => unreachable,
|
||||
.NOENT => return error.EventNotFound,
|
||||
.NOMEM => return error.SystemResources,
|
||||
.SRCH => return error.ProcessNotFound,
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,11 +310,11 @@ test "listen on a unix socket, send bytes, receive bytes" {
|
|||
|
||||
fn generateFileName(io: Io, base_name: []const u8) ![]const u8 {
|
||||
const random_bytes_count = 12;
|
||||
const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count);
|
||||
const sub_path_len = comptime std.base64.url_safe.Encoder.calcSize(random_bytes_count);
|
||||
var random_bytes: [12]u8 = undefined;
|
||||
io.random(&random_bytes);
|
||||
var sub_path: [sub_path_len]u8 = undefined;
|
||||
_ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
|
||||
_ = std.base64.url_safe.Encoder.encode(&sub_path, &random_bytes);
|
||||
return std.fmt.allocPrint(testing.allocator, "{s}-{s}", .{ sub_path[0..], base_name });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ pub const SetNameError = error{
|
|||
Unsupported,
|
||||
Unexpected,
|
||||
InvalidWtf8,
|
||||
} || posix.PrctlError || posix.WriteError || Io.File.OpenError || std.fmt.BufPrintError;
|
||||
} || posix.PrctlError || Io.File.Writer.Error || Io.File.OpenError || std.fmt.BufPrintError;
|
||||
|
||||
pub fn setName(self: Thread, io: Io, name: []const u8) SetNameError!void {
|
||||
if (name.len > max_name_len) return error.NameTooLong;
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ const ElfDynLibError = error{
|
|||
ElfHashTableNotFound,
|
||||
Canceled,
|
||||
Streaming,
|
||||
} || posix.OpenError || posix.MMapError;
|
||||
} || Io.File.OpenError || posix.MMapError;
|
||||
|
||||
pub const ElfDynLib = struct {
|
||||
strings: [*:0]u8,
|
||||
|
|
@ -177,27 +177,20 @@ pub const ElfDynLib = struct {
|
|||
return parent;
|
||||
}
|
||||
|
||||
fn resolveFromSearchPath(io: Io, search_path: []const u8, file_name: []const u8, delim: u8) ?posix.fd_t {
|
||||
fn resolveFromSearchPath(io: Io, search_path: []const u8, file_name: []const u8, delim: u8) ?Io.File {
|
||||
var paths = std.mem.tokenizeScalar(u8, search_path, delim);
|
||||
while (paths.next()) |p| {
|
||||
var dir = openPath(io, p) catch continue;
|
||||
defer dir.close(io);
|
||||
const fd = posix.openat(dir.handle, file_name, .{
|
||||
.ACCMODE = .RDONLY,
|
||||
.CLOEXEC = true,
|
||||
}, 0) catch continue;
|
||||
return fd;
|
||||
return dir.openFile(io, file_name, .{}) catch continue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn resolveFromParent(io: Io, dir_path: []const u8, file_name: []const u8) ?posix.fd_t {
|
||||
fn resolveFromParent(io: Io, dir_path: []const u8, file_name: []const u8) ?Io.File {
|
||||
var dir = Io.Dir.cwd().openDir(io, dir_path, .{}) catch return null;
|
||||
defer dir.close(io);
|
||||
return posix.openat(dir.handle, file_name, .{
|
||||
.ACCMODE = .RDONLY,
|
||||
.CLOEXEC = true,
|
||||
}, 0) catch null;
|
||||
return dir.openFile(io, file_name, .{}) catch null;
|
||||
}
|
||||
|
||||
// This implements enough to be able to load system libraries in general
|
||||
|
|
@ -205,10 +198,10 @@ pub const ElfDynLib = struct {
|
|||
// - DT_RPATH of the calling binary is not used as a search path
|
||||
// - DT_RUNPATH of the calling binary is not used as a search path
|
||||
// - /etc/ld.so.cache is not read
|
||||
fn resolveFromName(io: Io, path_or_name: []const u8, LD_LIBRARY_PATH: ?[]const u8) !posix.fd_t {
|
||||
fn resolveFromName(io: Io, path_or_name: []const u8, LD_LIBRARY_PATH: ?[]const u8) !Io.File {
|
||||
// If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname
|
||||
if (std.mem.findScalarPos(u8, path_or_name, 0, '/')) |_| {
|
||||
return posix.open(path_or_name, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
return Io.Dir.cwd().openFile(io, path_or_name, .{});
|
||||
}
|
||||
|
||||
// Only read LD_LIBRARY_PATH if the binary is not setuid/setgid
|
||||
|
|
@ -216,15 +209,15 @@ pub const ElfDynLib = struct {
|
|||
std.os.linux.getegid() == std.os.linux.getgid())
|
||||
{
|
||||
if (LD_LIBRARY_PATH) |ld_library_path| {
|
||||
if (resolveFromSearchPath(io, ld_library_path, path_or_name, ':')) |fd| {
|
||||
return fd;
|
||||
if (resolveFromSearchPath(io, ld_library_path, path_or_name, ':')) |file| {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly the directories /lib and /usr/lib are searched (in this exact order)
|
||||
if (resolveFromParent(io, "/lib", path_or_name)) |fd| return fd;
|
||||
if (resolveFromParent(io, "/usr/lib", path_or_name)) |fd| return fd;
|
||||
if (resolveFromParent(io, "/lib", path_or_name)) |file| return file;
|
||||
if (resolveFromParent(io, "/usr/lib", path_or_name)) |file| return file;
|
||||
return error.FileNotFound;
|
||||
}
|
||||
|
||||
|
|
@ -232,10 +225,9 @@ pub const ElfDynLib = struct {
|
|||
pub fn open(path: []const u8, LD_LIBRARY_PATH: ?[]const u8) Error!ElfDynLib {
|
||||
const io = std.Options.debug_io;
|
||||
|
||||
const fd = try resolveFromName(io, path, LD_LIBRARY_PATH);
|
||||
defer posix.close(fd);
|
||||
const file = try resolveFromName(io, path, LD_LIBRARY_PATH);
|
||||
defer file.close(io);
|
||||
|
||||
const file: Io.File = .{ .handle = fd };
|
||||
const stat = try file.stat(io);
|
||||
const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig;
|
||||
|
||||
|
|
@ -248,7 +240,7 @@ pub const ElfDynLib = struct {
|
|||
mem.alignForward(usize, size, page_size),
|
||||
posix.PROT.READ,
|
||||
.{ .TYPE = .PRIVATE },
|
||||
fd,
|
||||
file.handle,
|
||||
0,
|
||||
);
|
||||
defer posix.munmap(file_bytes);
|
||||
|
|
@ -318,7 +310,7 @@ pub const ElfDynLib = struct {
|
|||
extended_memsz,
|
||||
prot,
|
||||
.{ .TYPE = .PRIVATE, .FIXED = true },
|
||||
fd,
|
||||
file.handle,
|
||||
ph.p_offset - extra_bytes,
|
||||
);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,15 +4,12 @@ const std = @import("std.zig");
|
|||
|
||||
/// Deprecated, use `std.Io.Dir.path`.
|
||||
pub const path = @import("fs/path.zig");
|
||||
|
||||
pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
|
||||
|
||||
/// Base64 encoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem.
|
||||
pub const base64_encoder = std.base64.Base64Encoder.init(base64_alphabet, null);
|
||||
|
||||
/// Base64 decoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem.
|
||||
pub const base64_decoder = std.base64.Base64Decoder.init(base64_alphabet, null);
|
||||
|
||||
/// Deprecated, use `std.base64.url_safe_alphabet_chars`.
|
||||
pub const base64_alphabet = std.base64.url_safe_alphabet_chars;
|
||||
/// Deprecated, use `std.base64.url_safe.Encoder`.
|
||||
pub const base64_encoder = std.base64.url_safe.Encoder;
|
||||
/// Deprecated, use `std.base64.url_safe.Decoder`.
|
||||
pub const base64_decoder = std.base64.url_safe.Decoder;
|
||||
/// Deprecated, use `std.Io.Dir.max_path_bytes`.
|
||||
pub const max_path_bytes = std.Io.Dir.max_path_bytes;
|
||||
/// Deprecated, use `std.Io.Dir.max_name_bytes`.
|
||||
|
|
|
|||
|
|
@ -1777,8 +1777,8 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
|
|||
var random_bytes: [12]u8 = undefined;
|
||||
io.random(&random_bytes);
|
||||
|
||||
var random_b64: [std.fs.base64_encoder.calcSize(random_bytes.len)]u8 = undefined;
|
||||
_ = std.fs.base64_encoder.encode(&random_b64, &random_bytes);
|
||||
var random_b64: [std.base64.url_safe.Encoder.calcSize(random_bytes.len)]u8 = undefined;
|
||||
_ = std.base64.url_safe.Encoder.encode(&random_b64, &random_bytes);
|
||||
|
||||
const sub_path = random_b64 ++ "-zig-test-absolute-paths.txt";
|
||||
|
||||
|
|
|
|||
|
|
@ -529,17 +529,17 @@ test "sendmsg/recvmsg" {
|
|||
.addr = @bitCast([4]u8{ 127, 0, 0, 1 }),
|
||||
};
|
||||
|
||||
const server = try posix.socket(address_server.family, posix.SOCK.DGRAM, 0);
|
||||
const server = try socket(address_server.family, posix.SOCK.DGRAM, 0);
|
||||
defer posix.close(server);
|
||||
try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEPORT, &mem.toBytes(@as(c_int, 1)));
|
||||
try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
|
||||
try posix.bind(server, addrAny(&address_server), @sizeOf(linux.sockaddr.in));
|
||||
try bind(server, addrAny(&address_server), @sizeOf(linux.sockaddr.in));
|
||||
|
||||
// set address_server to the OS-chosen IP/port.
|
||||
var slen: posix.socklen_t = @sizeOf(linux.sockaddr.in);
|
||||
try posix.getsockname(server, addrAny(&address_server), &slen);
|
||||
try getsockname(server, addrAny(&address_server), &slen);
|
||||
|
||||
const client = try posix.socket(address_server.family, posix.SOCK.DGRAM, 0);
|
||||
const client = try socket(address_server.family, posix.SOCK.DGRAM, 0);
|
||||
defer posix.close(client);
|
||||
|
||||
const buffer_send = [_]u8{42} ** 128;
|
||||
|
|
@ -932,6 +932,8 @@ test "accept/connect/recv/cancel" {
|
|||
}
|
||||
|
||||
test "register_files_update" {
|
||||
const io = testing.io;
|
||||
|
||||
var ring = IoUring.init(1, 0) catch |err| switch (err) {
|
||||
error.SystemOutdated => return error.SkipZigTest,
|
||||
error.PermissionDenied => return error.SkipZigTest,
|
||||
|
|
@ -939,13 +941,13 @@ test "register_files_update" {
|
|||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const fd = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer posix.close(fd);
|
||||
const file = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
|
||||
defer file.close(io);
|
||||
|
||||
var registered_fds = [_]linux.fd_t{0} ** 2;
|
||||
const fd_index = 0;
|
||||
const fd_index2 = 1;
|
||||
registered_fds[fd_index] = fd;
|
||||
registered_fds[fd_index] = file.handle;
|
||||
registered_fds[fd_index2] = -1;
|
||||
|
||||
ring.register_files(registered_fds[0..]) catch |err| switch (err) {
|
||||
|
|
@ -957,10 +959,10 @@ test "register_files_update" {
|
|||
// Test IORING_REGISTER_FILES_UPDATE
|
||||
// Only available since Linux 5.5
|
||||
|
||||
const fd2 = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer posix.close(fd2);
|
||||
const file2 = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
|
||||
defer file2.close(io);
|
||||
|
||||
registered_fds[fd_index] = fd2;
|
||||
registered_fds[fd_index] = file2.handle;
|
||||
registered_fds[fd_index2] = -1;
|
||||
try ring.register_files_update(0, registered_fds[0..]);
|
||||
|
||||
|
|
@ -1031,15 +1033,15 @@ test "shutdown" {
|
|||
|
||||
// Socket bound, expect shutdown to work
|
||||
{
|
||||
const server = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const server = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
defer posix.close(server);
|
||||
try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
|
||||
try posix.bind(server, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
try posix.listen(server, 1);
|
||||
try bind(server, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
try listen(server, 1);
|
||||
|
||||
// set address to the OS-chosen IP/port.
|
||||
var slen: posix.socklen_t = @sizeOf(linux.sockaddr.in);
|
||||
try posix.getsockname(server, addrAny(&address), &slen);
|
||||
try getsockname(server, addrAny(&address), &slen);
|
||||
|
||||
const shutdown_sqe = try ring.shutdown(0x445445445, server, linux.SHUT.RD);
|
||||
try testing.expectEqual(linux.IORING_OP.SHUTDOWN, shutdown_sqe.opcode);
|
||||
|
|
@ -1064,7 +1066,7 @@ test "shutdown" {
|
|||
|
||||
// Socket not bound, expect to fail with ENOTCONN
|
||||
{
|
||||
const server = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const server = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
defer posix.close(server);
|
||||
|
||||
const shutdown_sqe = ring.shutdown(0x445445445, server, linux.SHUT.RD) catch |err| switch (err) {
|
||||
|
|
@ -1339,6 +1341,8 @@ test "linkat" {
|
|||
}
|
||||
|
||||
test "provide_buffers: read" {
|
||||
const io = testing.io;
|
||||
|
||||
var ring = IoUring.init(1, 0) catch |err| switch (err) {
|
||||
error.SystemOutdated => return error.SkipZigTest,
|
||||
error.PermissionDenied => return error.SkipZigTest,
|
||||
|
|
@ -1346,8 +1350,8 @@ test "provide_buffers: read" {
|
|||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const fd = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer posix.close(fd);
|
||||
const file = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
|
||||
defer file.close(io);
|
||||
|
||||
const group_id = 1337;
|
||||
const buffer_id = 0;
|
||||
|
|
@ -1380,9 +1384,9 @@ test "provide_buffers: read" {
|
|||
|
||||
var i: usize = 0;
|
||||
while (i < buffers.len) : (i += 1) {
|
||||
const sqe = try ring.read(0xdededede, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
const sqe = try ring.read(0xdededede, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
|
||||
try testing.expectEqual(@as(i32, fd), sqe.fd);
|
||||
try testing.expectEqual(@as(i32, file.handle), sqe.fd);
|
||||
try testing.expectEqual(@as(u64, 0), sqe.addr);
|
||||
try testing.expectEqual(@as(u32, buffer_len), sqe.len);
|
||||
try testing.expectEqual(@as(u16, group_id), sqe.buf_index);
|
||||
|
|
@ -1406,9 +1410,9 @@ test "provide_buffers: read" {
|
|||
// This read should fail
|
||||
|
||||
{
|
||||
const sqe = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
const sqe = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
|
||||
try testing.expectEqual(@as(i32, fd), sqe.fd);
|
||||
try testing.expectEqual(@as(i32, file.handle), sqe.fd);
|
||||
try testing.expectEqual(@as(u64, 0), sqe.addr);
|
||||
try testing.expectEqual(@as(u32, buffer_len), sqe.len);
|
||||
try testing.expectEqual(@as(u16, group_id), sqe.buf_index);
|
||||
|
|
@ -1445,9 +1449,9 @@ test "provide_buffers: read" {
|
|||
// Final read which should work
|
||||
|
||||
{
|
||||
const sqe = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
const sqe = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
|
||||
try testing.expectEqual(@as(i32, fd), sqe.fd);
|
||||
try testing.expectEqual(@as(i32, file.handle), sqe.fd);
|
||||
try testing.expectEqual(@as(u64, 0), sqe.addr);
|
||||
try testing.expectEqual(@as(u32, buffer_len), sqe.len);
|
||||
try testing.expectEqual(@as(u16, group_id), sqe.buf_index);
|
||||
|
|
@ -1469,6 +1473,8 @@ test "provide_buffers: read" {
|
|||
}
|
||||
|
||||
test "remove_buffers" {
|
||||
const io = testing.io;
|
||||
|
||||
var ring = IoUring.init(1, 0) catch |err| switch (err) {
|
||||
error.SystemOutdated => return error.SkipZigTest,
|
||||
error.PermissionDenied => return error.SkipZigTest,
|
||||
|
|
@ -1476,8 +1482,8 @@ test "remove_buffers" {
|
|||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const fd = try posix.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer posix.close(fd);
|
||||
const file = try Io.Dir.openFileAbsolute(io, "/dev/zero", .{});
|
||||
defer file.close(io);
|
||||
|
||||
const group_id = 1337;
|
||||
const buffer_id = 0;
|
||||
|
|
@ -1522,7 +1528,7 @@ test "remove_buffers" {
|
|||
// This read should work
|
||||
|
||||
{
|
||||
_ = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
_ = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
try testing.expectEqual(@as(u32, 1), try ring.submit());
|
||||
|
||||
const cqe = try ring.copy_cqe();
|
||||
|
|
@ -1542,7 +1548,7 @@ test "remove_buffers" {
|
|||
// Final read should _not_ work
|
||||
|
||||
{
|
||||
_ = try ring.read(0xdfdfdfdf, fd, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
_ = try ring.read(0xdfdfdfdf, file.handle, .{ .buffer_selection = .{ .group_id = group_id, .len = buffer_len } }, 0);
|
||||
try testing.expectEqual(@as(u32, 1), try ring.submit());
|
||||
|
||||
const cqe = try ring.copy_cqe();
|
||||
|
|
@ -1747,7 +1753,7 @@ test "accept multishot" {
|
|||
var nr: usize = 4; // number of clients to connect
|
||||
while (nr > 0) : (nr -= 1) {
|
||||
// connect client
|
||||
const client = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
errdefer posix.close(client);
|
||||
try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
|
||||
|
|
@ -1856,7 +1862,7 @@ test "accept_direct" {
|
|||
try testing.expectEqual(@as(u32, 1), try ring.submit());
|
||||
|
||||
// connect
|
||||
const client = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
defer posix.close(client);
|
||||
|
||||
|
|
@ -1868,7 +1874,7 @@ test "accept_direct" {
|
|||
try testing.expect(cqe_accept.user_data == accept_userdata);
|
||||
|
||||
// send data
|
||||
_ = try posix.send(client, buffer_send, 0);
|
||||
_ = try send(client, buffer_send, 0);
|
||||
|
||||
// Example of how to use registered fd:
|
||||
// Submit receive to fixed file returned by accept (fd_index).
|
||||
|
|
@ -1890,7 +1896,7 @@ test "accept_direct" {
|
|||
_ = try ring.accept_direct(accept_userdata, listener_socket, null, null, 0);
|
||||
try testing.expectEqual(@as(u32, 1), try ring.submit());
|
||||
// connect
|
||||
const client = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
defer posix.close(client);
|
||||
// completion with error
|
||||
|
|
@ -1940,7 +1946,7 @@ test "accept_multishot_direct" {
|
|||
|
||||
for (registered_fds) |_| {
|
||||
// connect
|
||||
const client = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
defer posix.close(client);
|
||||
|
||||
|
|
@ -1955,7 +1961,7 @@ test "accept_multishot_direct" {
|
|||
// Multishot is terminated (more flag is not set).
|
||||
{
|
||||
// connect
|
||||
const client = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
defer posix.close(client);
|
||||
// completion with error
|
||||
|
|
@ -2456,7 +2462,7 @@ test "bind/listen/connect" {
|
|||
|
||||
// Read system assigned port into addr
|
||||
var addr_len: posix.socklen_t = @sizeOf(linux.sockaddr.in);
|
||||
try posix.getsockname(listen_fd, addrAny(&addr), &addr_len);
|
||||
try getsockname(listen_fd, addrAny(&addr), &addr_len);
|
||||
|
||||
break :brk listen_fd;
|
||||
};
|
||||
|
|
@ -2611,7 +2617,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {
|
|||
_ = try ring.accept(0xaaaaaaaa, listener_socket, &accept_addr, &accept_addr_len, 0);
|
||||
|
||||
// Create a TCP client socket
|
||||
const client = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
errdefer posix.close(client);
|
||||
_ = try ring.connect(0xcccccccc, client, addrAny(&address), @sizeOf(linux.sockaddr.in));
|
||||
|
||||
|
|
@ -2651,16 +2657,16 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {
|
|||
|
||||
fn createListenerSocket(address: *linux.sockaddr.in) !posix.socket_t {
|
||||
const kernel_backlog = 1;
|
||||
const listener_socket = try posix.socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
const listener_socket = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
|
||||
errdefer posix.close(listener_socket);
|
||||
|
||||
try posix.setsockopt(listener_socket, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
|
||||
try posix.bind(listener_socket, addrAny(address), @sizeOf(linux.sockaddr.in));
|
||||
try posix.listen(listener_socket, kernel_backlog);
|
||||
try bind(listener_socket, addrAny(address), @sizeOf(linux.sockaddr.in));
|
||||
try listen(listener_socket, kernel_backlog);
|
||||
|
||||
// set address to the OS-chosen IP/port.
|
||||
var slen: posix.socklen_t = @sizeOf(linux.sockaddr.in);
|
||||
try posix.getsockname(listener_socket, addrAny(address), &slen);
|
||||
try getsockname(listener_socket, addrAny(address), &slen);
|
||||
|
||||
return listener_socket;
|
||||
}
|
||||
|
|
@ -2689,3 +2695,40 @@ inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
|
|||
fn addrAny(addr: *linux.sockaddr.in) *linux.sockaddr {
|
||||
return @ptrCast(addr);
|
||||
}
|
||||
|
||||
fn socket(domain: u32, socket_type: u32, protocol: u32) !posix.socket_t {
|
||||
const rc = posix.system.socket(domain, socket_type, protocol);
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
else => return error.SocketCreationFailure,
|
||||
}
|
||||
}
|
||||
|
||||
fn bind(sock: posix.socket_t, addr: *const posix.sockaddr, len: posix.socklen_t) !void {
|
||||
switch (posix.errno(posix.system.bind(sock, addr, len))) {
|
||||
.SUCCESS => return,
|
||||
else => return error.BindFailure,
|
||||
}
|
||||
}
|
||||
|
||||
fn listen(sock: posix.socket_t, backlog: u31) !void {
|
||||
switch (posix.errno(posix.system.listen(sock, backlog))) {
|
||||
.SUCCESS => return,
|
||||
else => return error.ListenFailure,
|
||||
}
|
||||
}
|
||||
|
||||
fn getsockname(sock: posix.socket_t, addr: *posix.sockaddr, addrlen: *posix.socklen_t) !void {
|
||||
switch (posix.errno(posix.system.getsockname(sock, addr, addrlen))) {
|
||||
.SUCCESS => return,
|
||||
else => return error.GetSockNameFailure,
|
||||
}
|
||||
}
|
||||
|
||||
fn send(sockfd: posix.socket_t, buf: []const u8, flags: u32) !usize {
|
||||
const rc = posix.system.sendto(sockfd, buf.ptr, buf.len, flags, null, 0);
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
else => return error.SendFailed,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1172
lib/std/posix.zig
1172
lib/std/posix.zig
File diff suppressed because it is too large
Load diff
|
|
@ -35,14 +35,14 @@ test "check WASI CWD" {
|
|||
|
||||
test "getuid" {
|
||||
if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
|
||||
_ = posix.getuid();
|
||||
_ = posix.geteuid();
|
||||
_ = posix.system.getuid();
|
||||
_ = posix.system.geteuid();
|
||||
}
|
||||
|
||||
test "getgid" {
|
||||
if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
|
||||
_ = posix.getgid();
|
||||
_ = posix.getegid();
|
||||
_ = posix.system.getgid();
|
||||
_ = posix.system.getegid();
|
||||
}
|
||||
|
||||
test "sigaltstack" {
|
||||
|
|
@ -121,13 +121,18 @@ test "pipe" {
|
|||
if (native_os == .windows or native_os == .wasi)
|
||||
return error.SkipZigTest;
|
||||
|
||||
const io = testing.io;
|
||||
|
||||
const fds = try std.Io.Threaded.pipe2(.{});
|
||||
try expect((try posix.write(fds[1], "hello")) == 5);
|
||||
const out: Io.File = .{ .handle = fds[0] };
|
||||
const in: Io.File = .{ .handle = fds[1] };
|
||||
try in.writeStreamingAll(io, "hello");
|
||||
var buf: [16]u8 = undefined;
|
||||
try expect((try posix.read(fds[0], buf[0..])) == 5);
|
||||
try expect((try out.readStreaming(io, &.{&buf})) == 5);
|
||||
|
||||
try expectEqualSlices(u8, buf[0..5], "hello");
|
||||
posix.close(fds[1]);
|
||||
posix.close(fds[0]);
|
||||
out.close(io);
|
||||
in.close(io);
|
||||
}
|
||||
|
||||
test "memfd_create" {
|
||||
|
|
@ -458,8 +463,12 @@ test "rename smoke test" {
|
|||
// Create some file using `open`.
|
||||
const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
|
||||
defer gpa.free(file_path);
|
||||
const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
||||
posix.close(fd);
|
||||
const file = try Io.Dir.cwd().createFile(io, file_path, .{
|
||||
.read = true,
|
||||
.exclusive = true,
|
||||
.permissions = .fromMode(mode),
|
||||
});
|
||||
file.close(io);
|
||||
|
||||
// Rename the file
|
||||
const new_file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });
|
||||
|
|
@ -471,15 +480,15 @@ test "rename smoke test" {
|
|||
// Try opening renamed file
|
||||
const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_file" });
|
||||
defer gpa.free(file_path);
|
||||
const fd = try posix.open(file_path, .{ .ACCMODE = .RDWR }, mode);
|
||||
posix.close(fd);
|
||||
const file = try Io.Dir.cwd().openFile(io, file_path, .{ .mode = .read_write });
|
||||
file.close(io);
|
||||
}
|
||||
|
||||
{
|
||||
// Try opening original file - should fail with error.FileNotFound
|
||||
const file_path = try Dir.path.join(gpa, &.{ base_path, "some_file" });
|
||||
defer gpa.free(file_path);
|
||||
try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
|
||||
try expectError(error.FileNotFound, Io.Dir.cwd().openFile(io, file_path, .{ .mode = .read_write }));
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -498,15 +507,15 @@ test "rename smoke test" {
|
|||
// Try opening renamed directory
|
||||
const file_path = try Dir.path.join(gpa, &.{ base_path, "some_other_dir" });
|
||||
defer gpa.free(file_path);
|
||||
const fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
|
||||
posix.close(fd);
|
||||
const dir = try Io.Dir.cwd().openDir(io, file_path, .{});
|
||||
dir.close(io);
|
||||
}
|
||||
|
||||
{
|
||||
// Try opening original directory - should fail with error.FileNotFound
|
||||
const file_path = try Dir.path.join(gpa, &.{ base_path, "some_dir" });
|
||||
defer gpa.free(file_path);
|
||||
try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
|
||||
try expectError(error.FileNotFound, Io.Dir.cwd().openDir(io, file_path, .{}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ pub const TmpDir = struct {
|
|||
sub_path: [sub_path_len]u8,
|
||||
|
||||
const random_bytes_count = 12;
|
||||
const sub_path_len = std.fs.base64_encoder.calcSize(random_bytes_count);
|
||||
const sub_path_len = std.base64.url_safe.Encoder.calcSize(random_bytes_count);
|
||||
|
||||
pub fn cleanup(self: *TmpDir) void {
|
||||
self.dir.close(io);
|
||||
|
|
@ -633,7 +633,7 @@ pub fn tmpDir(opts: Io.Dir.OpenOptions) TmpDir {
|
|||
var random_bytes: [TmpDir.random_bytes_count]u8 = undefined;
|
||||
io.random(&random_bytes);
|
||||
var sub_path: [TmpDir.sub_path_len]u8 = undefined;
|
||||
_ = std.fs.base64_encoder.encode(&sub_path, &random_bytes);
|
||||
_ = std.base64.url_safe.Encoder.encode(&sub_path, &random_bytes);
|
||||
|
||||
const cwd = Io.Dir.cwd();
|
||||
var cache_dir = cwd.createDirPathOpen(io, ".zig-cache", .{}) catch
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
const std = @import("std");
|
||||
|
||||
const PrintFn = *const fn () void;
|
||||
|
||||
pub fn main() void {
|
||||
var printFn: PrintFn = stopSayingThat;
|
||||
var i: u32 = 0;
|
||||
while (i < 4) : (i += 1) printFn();
|
||||
|
||||
printFn = moveEveryZig;
|
||||
printFn();
|
||||
}
|
||||
|
||||
fn stopSayingThat() void {
|
||||
_ = std.posix.write(1, "Hello, my name is Inigo Montoya; you killed my father, prepare to die.\n") catch {};
|
||||
}
|
||||
|
||||
fn moveEveryZig() void {
|
||||
_ = std.posix.write(1, "All your codebase are belong to us\n") catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-macos
|
||||
//
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// Hello, my name is Inigo Montoya; you killed my father, prepare to die.
|
||||
// All your codebase are belong to us
|
||||
//
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn main() void {
|
||||
printNumberHex(0x00000000);
|
||||
printNumberHex(0xaaaaaaaa);
|
||||
printNumberHex(0xdeadbeef);
|
||||
printNumberHex(0x31415926);
|
||||
}
|
||||
|
||||
fn printNumberHex(x: u32) void {
|
||||
const digit_chars = "0123456789abcdef";
|
||||
var i: u5 = 28;
|
||||
while (true) : (i -= 4) {
|
||||
const digit = (x >> i) & 0xf;
|
||||
_ = std.posix.write(1, &.{digit_chars[digit]}) catch {};
|
||||
if (i == 0) break;
|
||||
}
|
||||
_ = std.posix.write(1, "\n") catch {};
|
||||
}
|
||||
|
||||
// run
|
||||
// target=x86_64-macos
|
||||
//
|
||||
// 00000000
|
||||
// aaaaaaaa
|
||||
// deadbeef
|
||||
// 31415926
|
||||
//
|
||||
Loading…
Add table
Add a link
Reference in a new issue