mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
system specific errno
This commit is contained in:
parent
4b5351bc0d
commit
6b4f45f782
15 changed files with 91 additions and 98 deletions
|
|
@ -1302,7 +1302,7 @@ fn dirStatPathLinux(
|
|||
linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
|
||||
&statx,
|
||||
);
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => return statFromLinux(&statx),
|
||||
.INTR => continue,
|
||||
.CANCELED => return error.Canceled,
|
||||
|
|
@ -1449,7 +1449,7 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
|
|||
linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
|
||||
&statx,
|
||||
);
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => return statFromLinux(&statx),
|
||||
.INTR => continue,
|
||||
.CANCELED => return error.Canceled,
|
||||
|
|
@ -2931,7 +2931,7 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
|
|||
var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
|
||||
while (true) {
|
||||
try t.checkCancel();
|
||||
switch (std.os.linux.E.init(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
|
||||
switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
|
||||
.none, .duration => false,
|
||||
.deadline => true,
|
||||
} }, ×pec, ×pec))) {
|
||||
|
|
@ -5677,7 +5677,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
|
|||
const linux = std.os.linux;
|
||||
try t.checkCancel();
|
||||
const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
|
||||
if (is_debug) switch (linux.E.init(rc)) {
|
||||
if (is_debug) switch (linux.errno(rc)) {
|
||||
.SUCCESS => {}, // notified by `wake()`
|
||||
.INTR => {}, // gives caller a chance to check cancellation
|
||||
.AGAIN => {}, // ptr.* != expect
|
||||
|
|
@ -5764,7 +5764,7 @@ pub fn futexWaitUncancelable(ptr: *const std.atomic.Value(u32), expect: u32) voi
|
|||
.linux => {
|
||||
const linux = std.os.linux;
|
||||
const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => {}, // notified by `wake()`
|
||||
.INTR => {}, // gives caller a chance to check cancellation
|
||||
.AGAIN => {}, // ptr.* != expect
|
||||
|
|
@ -5827,7 +5827,7 @@ pub fn futexWaitDurationUncancelable(ptr: *const std.atomic.Value(u32), expect:
|
|||
const linux = std.os.linux;
|
||||
var ts = timestampToPosix(timeout.toNanoseconds());
|
||||
const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, &ts);
|
||||
if (is_debug) switch (linux.E.init(rc)) {
|
||||
if (is_debug) switch (linux.errno(rc)) {
|
||||
.SUCCESS => {}, // notified by `wake()`
|
||||
.INTR => {}, // gives caller a chance to check cancellation
|
||||
.AGAIN => {}, // ptr.* != expect
|
||||
|
|
@ -5861,7 +5861,7 @@ pub fn futexWake(ptr: *const std.atomic.Value(u32), max_waiters: u32) void {
|
|||
} else switch (native_os) {
|
||||
.linux => {
|
||||
const linux = std.os.linux;
|
||||
switch (linux.E.init(linux.futex_3arg(
|
||||
switch (linux.errno(linux.futex_3arg(
|
||||
&ptr.raw,
|
||||
.{ .cmd = .WAKE, .private = true },
|
||||
@min(max_waiters, std.math.maxInt(i32)),
|
||||
|
|
|
|||
|
|
@ -1622,7 +1622,7 @@ const LinuxThreadImpl = struct {
|
|||
linux.CLONE.PARENT_SETTID | linux.CLONE.CHILD_CLEARTID |
|
||||
linux.CLONE.SIGHAND | linux.CLONE.SYSVSEM | linux.CLONE.SETTLS;
|
||||
|
||||
switch (linux.E.init(linux.clone(
|
||||
switch (linux.errno(linux.clone(
|
||||
Instance.entryFn,
|
||||
@intFromPtr(&mapped[stack_offset]),
|
||||
flags,
|
||||
|
|
@ -1661,7 +1661,7 @@ const LinuxThreadImpl = struct {
|
|||
const tid = self.thread.child_tid.load(.seq_cst);
|
||||
if (tid == 0) break;
|
||||
|
||||
switch (linux.E.init(linux.futex_4arg(
|
||||
switch (linux.errno(linux.futex_4arg(
|
||||
&self.thread.child_tid.raw,
|
||||
.{ .cmd = .WAIT, .private = false },
|
||||
@bitCast(tid),
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ const LinuxImpl = struct {
|
|||
if (timeout != null) &ts else null,
|
||||
);
|
||||
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => {}, // notified by `wake()`
|
||||
.INTR => {}, // spurious wakeup
|
||||
.AGAIN => {}, // ptr.* != expect
|
||||
|
|
@ -290,7 +290,7 @@ const LinuxImpl = struct {
|
|||
@min(max_waiters, std.math.maxInt(i32)),
|
||||
);
|
||||
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => {}, // successful wake up
|
||||
.INVAL => {}, // invalid futex_wait() on ptr done elsewhere
|
||||
.FAULT => {}, // pointer became invalid while doing the wake
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ pub inline fn versionCheck(comptime version: std.SemanticVersion) bool {
|
|||
};
|
||||
}
|
||||
|
||||
/// Get the errno if rc is -1 and SUCCESS if rc is not -1.
|
||||
pub fn errno(rc: anytype) E {
|
||||
return if (rc == -1) @enumFromInt(_errno().*) else .SUCCESS;
|
||||
}
|
||||
|
||||
pub const ino_t = switch (native_os) {
|
||||
.linux => linux.ino_t,
|
||||
.emscripten => emscripten.ino_t,
|
||||
|
|
@ -11580,6 +11585,6 @@ const private = struct {
|
|||
extern threadlocal var errno: c_int;
|
||||
|
||||
fn errnoFromThreadLocal() *c_int {
|
||||
return &errno;
|
||||
return &private.errno;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ pub const Iterator = switch (native_os) {
|
|||
self.first_iter = false;
|
||||
}
|
||||
const rc = linux.getdents64(self.dir.fd, &self.buf, self.buf.len);
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => {},
|
||||
.BADF => unreachable, // Dir is invalid or was opened without iteration ability
|
||||
.FAULT => unreachable,
|
||||
|
|
|
|||
|
|
@ -568,9 +568,8 @@ fn splitValue64(val: i64) [2]u32 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the errno from a syscall return value, or 0 for no error.
|
||||
/// The public API is exposed via the `E` namespace.
|
||||
fn errnoFromSyscall(r: usize) E {
|
||||
/// Get the errno from a syscall return value. SUCCESS means no error.
|
||||
pub fn errno(r: usize) E {
|
||||
const signed_r: isize = @bitCast(r);
|
||||
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
||||
return @enumFromInt(int);
|
||||
|
|
@ -1961,7 +1960,7 @@ pub fn sigaction(sig: SIG, noalias act: ?*const Sigaction, noalias oact: ?*Sigac
|
|||
.sparc, .sparc64 => syscall5(.rt_sigaction, @intFromEnum(sig), ksa_arg, oldksa_arg, @intFromPtr(ksa.restorer), mask_size),
|
||||
else => syscall4(.rt_sigaction, @intFromEnum(sig), ksa_arg, oldksa_arg, mask_size),
|
||||
};
|
||||
if (E.init(result) != .SUCCESS) return result;
|
||||
if (errno(result) != .SUCCESS) return result;
|
||||
|
||||
if (oact) |old| {
|
||||
old.handler.handler = oldksa.handler;
|
||||
|
|
@ -2402,7 +2401,7 @@ pub fn sched_setaffinity(pid: pid_t, set: *const cpu_set_t) !void {
|
|||
const size = @sizeOf(cpu_set_t);
|
||||
const rc = syscall3(.sched_setaffinity, @as(usize, @bitCast(@as(isize, pid))), size, @intFromPtr(set));
|
||||
|
||||
switch (E.init(rc)) {
|
||||
switch (errno(rc)) {
|
||||
.SUCCESS => return,
|
||||
else => |err| return std.posix.unexpectedErrno(err),
|
||||
}
|
||||
|
|
@ -3003,8 +3002,6 @@ pub const E = switch (native_arch) {
|
|||
HWPOISON = 168,
|
||||
DQUOT = 1133,
|
||||
_,
|
||||
|
||||
pub const init = errnoFromSyscall;
|
||||
},
|
||||
.sparc, .sparc64 => enum(u16) {
|
||||
/// No error occurred.
|
||||
|
|
@ -3148,8 +3145,6 @@ pub const E = switch (native_arch) {
|
|||
RFKILL = 134,
|
||||
HWPOISON = 135,
|
||||
_,
|
||||
|
||||
pub const init = errnoFromSyscall;
|
||||
},
|
||||
else => enum(u16) {
|
||||
/// No error occurred.
|
||||
|
|
@ -3459,8 +3454,6 @@ pub const E = switch (native_arch) {
|
|||
NSRCNAMELOOP = 177,
|
||||
|
||||
_,
|
||||
|
||||
pub const init = errnoFromSyscall;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -9892,7 +9885,7 @@ pub const wrapped = struct {
|
|||
const adjusted_len = @min(in_len, 0x7ffff000); // Prevents EOVERFLOW.
|
||||
const sendfileSymbol = if (lfs64_abi) system.sendfile64 else system.sendfile;
|
||||
const rc = sendfileSymbol(out_fd, in_fd, in_offset, adjusted_len);
|
||||
switch (errno(rc)) {
|
||||
switch (system.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.BADF => return invalidApiUsage(), // Always a race condition.
|
||||
.FAULT => return invalidApiUsage(), // Segmentation fault.
|
||||
|
|
@ -9958,7 +9951,7 @@ pub const wrapped = struct {
|
|||
const use_c = std.c.versionCheck(if (builtin.abi.isAndroid()) .{ .major = 34, .minor = 0, .patch = 0 } else .{ .major = 2, .minor = 27, .patch = 0 });
|
||||
const sys = if (use_c) std.c else std.os.linux;
|
||||
const rc = sys.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
|
||||
switch (errno(rc)) {
|
||||
switch (sys.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.BADF => return error.BadFileFlags,
|
||||
.FBIG => return error.FileTooBig,
|
||||
|
|
@ -9982,12 +9975,4 @@ pub const wrapped = struct {
|
|||
if (builtin.mode == .Debug) @panic("invalid API usage");
|
||||
return error.Unexpected;
|
||||
}
|
||||
|
||||
fn errno(rc: anytype) E {
|
||||
if (builtin.link_libc) {
|
||||
return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
|
||||
} else {
|
||||
return errnoFromSyscall(rc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ pub fn init_params(entries: u16, p: *linux.io_uring_params) !IoUring {
|
|||
assert(p.resv[2] == 0);
|
||||
|
||||
const res = linux.io_uring_setup(entries, p);
|
||||
switch (linux.E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => {},
|
||||
.FAULT => return error.ParamsOutsideAccessibleAddressSpace,
|
||||
// The resv array contains non-zero data, p.flags contains an unsupported flag,
|
||||
|
|
@ -175,7 +175,7 @@ pub fn submit_and_wait(self: *IoUring, wait_nr: u32) !u32 {
|
|||
pub fn enter(self: *IoUring, to_submit: u32, min_complete: u32, flags: u32) !u32 {
|
||||
assert(self.fd >= 0);
|
||||
const res = linux.io_uring_enter(self.fd, to_submit, min_complete, flags, null);
|
||||
switch (linux.E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => {},
|
||||
// The kernel was unable to allocate memory or ran out of resources for the request.
|
||||
// The application should wait for some completions and try again:
|
||||
|
|
@ -1298,7 +1298,7 @@ pub fn register_buffers(self: *IoUring, buffers: []const posix.iovec) !void {
|
|||
pub fn unregister_buffers(self: *IoUring) !void {
|
||||
assert(self.fd >= 0);
|
||||
const res = linux.io_uring_register(self.fd, .UNREGISTER_BUFFERS, null, 0);
|
||||
switch (linux.E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => {},
|
||||
.NXIO => return error.BuffersNotRegistered,
|
||||
else => |errno| return posix.unexpectedErrno(errno),
|
||||
|
|
@ -1316,7 +1316,7 @@ pub fn get_probe(self: *IoUring) !linux.io_uring_probe {
|
|||
}
|
||||
|
||||
fn handle_registration_result(res: usize) !void {
|
||||
switch (linux.E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => {},
|
||||
// One or more fds in the array are invalid, or the kernel does not support sparse sets:
|
||||
.BADF => return error.FileDescriptorInvalid,
|
||||
|
|
@ -1341,7 +1341,7 @@ fn handle_registration_result(res: usize) !void {
|
|||
pub fn unregister_files(self: *IoUring) !void {
|
||||
assert(self.fd >= 0);
|
||||
const res = linux.io_uring_register(self.fd, .UNREGISTER_FILES, null, 0);
|
||||
switch (linux.E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => {},
|
||||
.NXIO => return error.FilesNotRegistered,
|
||||
else => |errno| return posix.unexpectedErrno(errno),
|
||||
|
|
@ -1771,7 +1771,7 @@ fn register_buf_ring(
|
|||
.flags = flags,
|
||||
});
|
||||
var res = linux.io_uring_register(fd, .REGISTER_PBUF_RING, @as(*const anyopaque, @ptrCast(®)), 1);
|
||||
if (linux.E.init(res) == .INVAL and reg.flags.inc) {
|
||||
if (linux.errno(res) == .INVAL and reg.flags.inc) {
|
||||
// Retry without incremental buffer consumption.
|
||||
// It is available since kernel 6.12. returns INVAL on older.
|
||||
reg.flags.inc = false;
|
||||
|
|
@ -1794,7 +1794,7 @@ fn unregister_buf_ring(fd: linux.fd_t, group_id: u16) !void {
|
|||
}
|
||||
|
||||
fn handle_register_buf_ring_result(res: usize) !void {
|
||||
switch (linux.E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => {},
|
||||
.INVAL => return error.ArgumentsInvalid,
|
||||
else => |errno| return posix.unexpectedErrno(errno),
|
||||
|
|
@ -4085,7 +4085,7 @@ inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
|
|||
|
||||
var uts: linux.utsname = undefined;
|
||||
const res = linux.uname(&uts);
|
||||
switch (linux.E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => {},
|
||||
else => |errno| return posix.unexpectedErrno(errno),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const std = @import("../../std.zig");
|
||||
const errno = linux.E.init;
|
||||
const errno = linux.errno;
|
||||
const unexpectedErrno = std.posix.unexpectedErrno;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const expectError = std.testing.expectError;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ test "fallocate" {
|
|||
try expect((try file.stat()).size == 0);
|
||||
|
||||
const len: i64 = 65536;
|
||||
switch (linux.E.init(linux.fallocate(file.handle, 0, 0, len))) {
|
||||
switch (linux.errno(linux.fallocate(file.handle, 0, 0, len))) {
|
||||
.SUCCESS => {},
|
||||
.NOSYS => return error.SkipZigTest,
|
||||
.OPNOTSUPP => return error.SkipZigTest,
|
||||
|
|
@ -42,11 +42,11 @@ test "getppid" {
|
|||
|
||||
test "timer" {
|
||||
const epoll_fd = linux.epoll_create();
|
||||
var err: linux.E = linux.E.init(epoll_fd);
|
||||
var err: linux.E = linux.errno(epoll_fd);
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
const timer_fd = linux.timerfd_create(linux.TIMERFD_CLOCK.MONOTONIC, .{});
|
||||
try expect(linux.E.init(timer_fd) == .SUCCESS);
|
||||
try expect(linux.errno(timer_fd) == .SUCCESS);
|
||||
|
||||
const time_interval = linux.timespec{
|
||||
.sec = 0,
|
||||
|
|
@ -58,7 +58,7 @@ test "timer" {
|
|||
.it_value = time_interval,
|
||||
};
|
||||
|
||||
err = linux.E.init(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
|
||||
err = linux.errno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
var event = linux.epoll_event{
|
||||
|
|
@ -66,13 +66,13 @@ test "timer" {
|
|||
.data = linux.epoll_data{ .ptr = 0 },
|
||||
};
|
||||
|
||||
err = linux.E.init(linux.epoll_ctl(@as(i32, @intCast(epoll_fd)), linux.EPOLL.CTL_ADD, @as(i32, @intCast(timer_fd)), &event));
|
||||
err = linux.errno(linux.epoll_ctl(@as(i32, @intCast(epoll_fd)), linux.EPOLL.CTL_ADD, @as(i32, @intCast(timer_fd)), &event));
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
const events_one: linux.epoll_event = undefined;
|
||||
var events = [_]linux.epoll_event{events_one} ** 8;
|
||||
|
||||
err = linux.E.init(linux.epoll_wait(@as(i32, @intCast(epoll_fd)), &events, 8, -1));
|
||||
err = linux.errno(linux.epoll_wait(@as(i32, @intCast(epoll_fd)), &events, 8, -1));
|
||||
try expect(err == .SUCCESS);
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ test "statx" {
|
|||
defer file.close();
|
||||
|
||||
var statx_buf: linux.Statx = undefined;
|
||||
switch (linux.E.init(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
|
||||
switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
|
||||
.SUCCESS => {},
|
||||
else => unreachable,
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ test "statx" {
|
|||
if (builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; // No fstatat, so the rest of the test is meaningless.
|
||||
|
||||
var stat_buf: linux.Stat = undefined;
|
||||
switch (linux.E.init(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
|
||||
switch (linux.errno(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
|
||||
.SUCCESS => {},
|
||||
else => unreachable,
|
||||
}
|
||||
|
|
@ -179,7 +179,7 @@ test "sigemptyset" {
|
|||
test "sysinfo" {
|
||||
var info: linux.Sysinfo = undefined;
|
||||
const result: usize = linux.sysinfo(&info);
|
||||
try expect(std.os.linux.E.init(result) == .SUCCESS);
|
||||
try expect(std.os.linux.errno(result) == .SUCCESS);
|
||||
|
||||
try expect(info.mem_unit > 0);
|
||||
try expect(info.mem_unit <= std.heap.page_size_max);
|
||||
|
|
@ -202,17 +202,17 @@ test "futex v1" {
|
|||
|
||||
// No-op wait, lock value is not expected value
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
try expectEqual(.AGAIN, linux.E.init(rc));
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
rc = linux.futex_4arg(&lock.raw, .{ .cmd = .WAIT, .private = true }, 2, null);
|
||||
try expectEqual(.AGAIN, linux.E.init(rc));
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// Short-fuse wait, timeout kicks in
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT, .private = true }, 1, .{ .timeout = &.{ .sec = 0, .nsec = 2 } }, null, 0);
|
||||
try expectEqual(.TIMEDOUT, linux.E.init(rc));
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
|
||||
rc = linux.futex_4arg(&lock.raw, .{ .cmd = .WAIT, .private = true }, 1, &.{ .sec = 0, .nsec = 2 });
|
||||
try expectEqual(.TIMEDOUT, linux.E.init(rc));
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
|
||||
// Wakeup (no waiters)
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAKE, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
|
|
@ -223,7 +223,7 @@ test "futex v1" {
|
|||
|
||||
// CMP_REQUEUE - val3 mismatch
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .CMP_REQUEUE, .private = true }, 2, .{ .val2 = 0 }, null, 99);
|
||||
try expectEqual(.AGAIN, linux.E.init(rc));
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// CMP_REQUEUE - requeue (but no waiters, so ... not much)
|
||||
{
|
||||
|
|
@ -256,12 +256,12 @@ test "futex v1" {
|
|||
{
|
||||
// val1 return early
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0xfff);
|
||||
try expectEqual(.AGAIN, linux.E.init(rc));
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// timeout wait
|
||||
const timeout: linux.timespec = .{ .sec = 0, .nsec = 2 };
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT_BITSET, .private = true }, 1, .{ .timeout = &timeout }, null, 0xfff);
|
||||
try expectEqual(.TIMEDOUT, linux.E.init(rc));
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
}
|
||||
|
||||
// WAKE_BITSET
|
||||
|
|
@ -271,7 +271,7 @@ test "futex v1" {
|
|||
|
||||
// bitmask must have at least 1 bit set:
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAKE_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
try expectEqual(.INVAL, linux.E.init(rc));
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +307,7 @@ test "futex2_waitv" {
|
|||
|
||||
const timeout = linux.kernel_timespec{ .sec = 0, .nsec = 2 }; // absolute timeout, so this is 1970...
|
||||
const rc = linux.futex2_waitv(&futexes, futexes.len, .{}, &timeout, .MONOTONIC);
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.NOSYS => return error.SkipZigTest, // futex2_waitv added in kernel v5.16
|
||||
else => |err| try expectEqual(.TIMEDOUT, err),
|
||||
}
|
||||
|
|
@ -318,7 +318,7 @@ test "futex2_waitv" {
|
|||
fn futex2_skip_if_unsupported() !void {
|
||||
const lock: u32 = 0;
|
||||
const rc = linux.futex2_wake(&lock, 0, 1, .{ .size = .U32, .private = true });
|
||||
if (linux.E.init(rc) == .NOSYS) {
|
||||
if (linux.errno(rc) == .NOSYS) {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
}
|
||||
|
|
@ -334,23 +334,23 @@ test "futex2_wait" {
|
|||
// (at least) they're not implemented.
|
||||
if (false) {
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U8, .private = true }, null, .MONOTONIC);
|
||||
try expectEqual(.INVAL, linux.E.init(rc));
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U16, .private = true }, null, .MONOTONIC);
|
||||
try expectEqual(.INVAL, linux.E.init(rc));
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U64, .private = true }, null, .MONOTONIC);
|
||||
try expectEqual(.INVAL, linux.E.init(rc));
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
}
|
||||
|
||||
const flags = linux.FUTEX2_FLAGS{ .size = .U32, .private = true };
|
||||
// no-wait, lock state mismatch
|
||||
rc = linux.futex2_wait(&lock.raw, 2, mask, flags, null, .MONOTONIC);
|
||||
try expectEqual(.AGAIN, linux.E.init(rc));
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// hit timeout on wait
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .MONOTONIC);
|
||||
try expectEqual(.TIMEDOUT, linux.E.init(rc));
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
|
||||
// timeout is absolute
|
||||
{
|
||||
|
|
@ -364,11 +364,11 @@ test "futex2_wait" {
|
|||
.nsec = curr.nsec + 2,
|
||||
};
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &timeout, .MONOTONIC);
|
||||
try expectEqual(.TIMEDOUT, linux.E.init(rc));
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
}
|
||||
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .REALTIME);
|
||||
try expectEqual(.TIMEDOUT, linux.E.init(rc));
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
}
|
||||
|
||||
test "futex2_wake" {
|
||||
|
|
@ -405,6 +405,14 @@ test "futex2_requeue" {
|
|||
try expectEqual(0, rc);
|
||||
}
|
||||
|
||||
test "copy_file_range error" {
|
||||
const fds = try std.posix.pipe();
|
||||
defer std.posix.close(fds[0]);
|
||||
defer std.posix.close(fds[1]);
|
||||
|
||||
try std.testing.expectError(error.InvalidArguments, linux.wrapped.copy_file_range(fds[0], null, fds[1], null, 1, 0));
|
||||
}
|
||||
|
||||
test {
|
||||
_ = linux.IoUring;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void {
|
|||
}
|
||||
|
||||
const begin_addr = mmap_tls(area_desc.size + area_desc.alignment - 1);
|
||||
if (@call(.always_inline, linux.E.init, .{begin_addr}) != .SUCCESS) @trap();
|
||||
if (@call(.always_inline, linux.errno, .{begin_addr}) != .SUCCESS) @trap();
|
||||
|
||||
const area_ptr: [*]align(page_size_min) u8 = @ptrFromInt(begin_addr);
|
||||
|
||||
|
|
|
|||
|
|
@ -94,13 +94,15 @@ pub const E = enum(u16) {
|
|||
OVERFLOW,
|
||||
LOOP,
|
||||
TXTBSY,
|
||||
|
||||
pub fn init(r: usize) E {
|
||||
const signed_r: isize = @bitCast(r);
|
||||
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
||||
return @enumFromInt(int);
|
||||
}
|
||||
};
|
||||
|
||||
/// Get the errno from a syscall return value. SUCCESS means no error.
|
||||
pub fn errno(r: usize) E {
|
||||
const signed_r: isize = @bitCast(r);
|
||||
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
||||
return @enumFromInt(int);
|
||||
}
|
||||
|
||||
// The max bytes that can be in the errstr buff
|
||||
pub const ERRMAX = 128;
|
||||
var errstr_buf: [ERRMAX]u8 = undefined;
|
||||
|
|
|
|||
|
|
@ -272,14 +272,7 @@ pub const socket_t = if (native_os == .windows) windows.ws2_32.SOCKET else fd_t;
|
|||
/// for others it will use a thread-local errno variable. Therefore, this
|
||||
/// function only returns a well-defined value when it is called directly after
|
||||
/// the system function call whose errno value is intended to be observed.
|
||||
pub fn errno(rc: anytype) E {
|
||||
if (use_libc) {
|
||||
return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
|
||||
}
|
||||
const signed: isize = @bitCast(rc);
|
||||
const int = if (signed > -4096 and signed < 0) -signed else 0;
|
||||
return @enumFromInt(int);
|
||||
}
|
||||
pub const errno = system.errno;
|
||||
|
||||
/// Closes the file descriptor.
|
||||
///
|
||||
|
|
@ -433,7 +426,7 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
|
|||
// Later on this should be changed to `system.fchmodat2`
|
||||
// when the musl/glibc add a wrapper.
|
||||
const res = linux.fchmodat2(dirfd, &path_c, mode, flags);
|
||||
switch (E.init(res)) {
|
||||
switch (linux.errno(res)) {
|
||||
.SUCCESS => return,
|
||||
.INTR => continue,
|
||||
.BADF => unreachable,
|
||||
|
|
@ -588,7 +581,7 @@ pub const RebootCommand = switch (native_os) {
|
|||
pub fn reboot(cmd: RebootCommand) RebootError!void {
|
||||
switch (native_os) {
|
||||
.linux => {
|
||||
switch (linux.E.init(linux.reboot(
|
||||
switch (linux.errno(linux.reboot(
|
||||
.MAGIC1,
|
||||
.MAGIC2,
|
||||
cmd,
|
||||
|
|
@ -647,7 +640,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
|
|||
break :res .{ @bitCast(rc), errno(rc) };
|
||||
} else res: {
|
||||
const rc = linux.getrandom(buf.ptr, buf.len, 0);
|
||||
break :res .{ rc, linux.E.init(rc) };
|
||||
break :res .{ rc, linux.errno(rc) };
|
||||
};
|
||||
|
||||
switch (err) {
|
||||
|
|
@ -3298,7 +3291,7 @@ pub fn isatty(handle: fd_t) bool {
|
|||
var wsz: winsize = undefined;
|
||||
const fd: usize = @bitCast(@as(isize, handle));
|
||||
const rc = linux.syscall3(.ioctl, fd, linux.T.IOCGWINSZ, @intFromPtr(&wsz));
|
||||
switch (linux.E.init(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => return true,
|
||||
.INTR => continue,
|
||||
else => return false,
|
||||
|
|
@ -5762,7 +5755,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
|
|||
while (true) {
|
||||
const rc = sys.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
|
||||
if (native_os == .freebsd) {
|
||||
switch (errno(rc)) {
|
||||
switch (sys.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.BADF => return error.FilesOpenedWithWrongFlags,
|
||||
.FBIG => return error.FileTooBig,
|
||||
|
|
@ -5775,7 +5768,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
|
|||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
} else { // assume linux
|
||||
switch (errno(rc)) {
|
||||
switch (sys.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.BADF => return error.FilesOpenedWithWrongFlags,
|
||||
.FBIG => return error.FileTooBig,
|
||||
|
|
@ -6070,7 +6063,7 @@ pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t {
|
|||
const use_c = std.c.versionCheck(if (builtin.abi.isAndroid()) .{ .major = 30, .minor = 0, .patch = 0 } else .{ .major = 2, .minor = 27, .patch = 0 });
|
||||
const sys = if (use_c) std.c else linux;
|
||||
const rc = sys.memfd_create(name, flags);
|
||||
switch (errno(rc)) {
|
||||
switch (sys.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.FAULT => unreachable, // name has invalid memory
|
||||
.INVAL => return error.NameTooLong, // or, program has a bug and flags are faulty
|
||||
|
|
@ -6494,7 +6487,7 @@ pub fn perf_event_open(
|
|||
if (native_os == .linux) {
|
||||
// There is no syscall wrapper for this function exposed by libcs
|
||||
const rc = linux.perf_event_open(attr, pid, cpu, group_fd, flags);
|
||||
switch (errno(rc)) {
|
||||
switch (linux.errno(rc)) {
|
||||
.SUCCESS => return @intCast(rc),
|
||||
.@"2BIG" => return error.TooBig,
|
||||
.ACCES => return error.PermissionDenied,
|
||||
|
|
|
|||
|
|
@ -1772,7 +1772,7 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
|
|||
.linux => {
|
||||
var info: std.os.linux.Sysinfo = undefined;
|
||||
const result: usize = std.os.linux.sysinfo(&info);
|
||||
if (std.os.linux.E.init(result) != .SUCCESS) {
|
||||
if (std.os.linux.errno(result) != .SUCCESS) {
|
||||
return error.UnknownTotalSystemMemory;
|
||||
}
|
||||
// Promote to u64 to avoid overflow on systems where info.totalram is a 32-bit usize
|
||||
|
|
|
|||
|
|
@ -1437,7 +1437,7 @@ fn updateNavCode(
|
|||
.len = code.len,
|
||||
}};
|
||||
const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
|
||||
switch (std.os.linux.E.init(rc)) {
|
||||
switch (std.os.linux.errno(rc)) {
|
||||
.SUCCESS => assert(rc == code.len),
|
||||
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
||||
}
|
||||
|
|
@ -2026,7 +2026,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
|
|||
.len = out.len,
|
||||
}};
|
||||
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
|
||||
switch (std.os.linux.E.init(rc)) {
|
||||
switch (std.os.linux.errno(rc)) {
|
||||
.SUCCESS => assert(rc == out.len),
|
||||
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -645,7 +645,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
|
|||
@intCast(requested_size +| requested_size / growth_factor),
|
||||
) - old_size;
|
||||
_, const file_size = Node.Index.root.location(mf).resolve(mf);
|
||||
while (true) switch (linux.E.init(switch (std.math.order(range_file_offset, file_size)) {
|
||||
while (true) switch (linux.errno(switch (std.math.order(range_file_offset, file_size)) {
|
||||
.lt => linux.fallocate(
|
||||
mf.file.handle,
|
||||
linux.FALLOC.FL_INSERT_RANGE,
|
||||
|
|
@ -858,7 +858,7 @@ fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:
|
|||
// delete the copy of this node at the old location
|
||||
if (is_linux and !mf.flags.fallocate_punch_hole_unsupported and
|
||||
size >= mf.flags.block_size.toByteUnits() * 2 - 1) while (true)
|
||||
switch (linux.E.init(linux.fallocate(
|
||||
switch (linux.errno(linux.fallocate(
|
||||
mf.file.handle,
|
||||
linux.FALLOC.FL_PUNCH_HOLE | linux.FALLOC.FL_KEEP_SIZE,
|
||||
@intCast(old_file_offset),
|
||||
|
|
@ -910,7 +910,7 @@ fn copyFileRange(
|
|||
@intCast(remaining_size),
|
||||
0,
|
||||
);
|
||||
switch (linux.E.init(copy_len)) {
|
||||
switch (linux.errno(copy_len)) {
|
||||
.SUCCESS => {
|
||||
if (copy_len == 0) break;
|
||||
remaining_size -= copy_len;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue