authorgravatar for rpkak@noreply.codeberg.orgrpkak <rpkak@noreply.codeberg.org> 2025-11-14 23:16:55+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-11-20 15:03:23-08:00
log6b4f45f782fb9c8906d3fcbfca9e21fc3771c2dd
treeee11cca9b35e72958e2dc66576b4cb8e4a82d6f5
parent4b5351bc0ddc248d6935d7d160a57cb4dfe4dedd

system specific errno


15 files changed, 91 insertions(+), 98 deletions(-)

lib/std/Io/Threaded.zig+7-7
......@@ -1302,7 +1302,7 @@ fn dirStatPathLinux(
13021302 linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
13031303 &statx,
13041304 );
1305 switch (linux.E.init(rc)) {
1305 switch (linux.errno(rc)) {
13061306 .SUCCESS => return statFromLinux(&statx),
13071307 .INTR => continue,
13081308 .CANCELED => return error.Canceled,
......@@ -1449,7 +1449,7 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
14491449 linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
14501450 &statx,
14511451 );
1452 switch (linux.E.init(rc)) {
1452 switch (linux.errno(rc)) {
14531453 .SUCCESS => return statFromLinux(&statx),
14541454 .INTR => continue,
14551455 .CANCELED => return error.Canceled,
......@@ -2931,7 +2931,7 @@ fn sleepLinux(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void {
29312931 var timespec: posix.timespec = timestampToPosix(deadline_nanoseconds);
29322932 while (true) {
29332933 try t.checkCancel();
2934 switch (std.os.linux.E.init(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
2934 switch (std.os.linux.errno(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) {
29352935 .none, .duration => false,
29362936 .deadline => true,
29372937 } }, &timespec, &timespec))) {
......@@ -5677,7 +5677,7 @@ fn futexWait(t: *Threaded, ptr: *const std.atomic.Value(u32), expect: u32) Io.Ca
56775677 const linux = std.os.linux;
56785678 try t.checkCancel();
56795679 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
5680 if (is_debug) switch (linux.E.init(rc)) {
5680 if (is_debug) switch (linux.errno(rc)) {
56815681 .SUCCESS => {}, // notified by `wake()`
56825682 .INTR => {}, // gives caller a chance to check cancellation
56835683 .AGAIN => {}, // ptr.* != expect
......@@ -5764,7 +5764,7 @@ pub fn futexWaitUncancelable(ptr: *const std.atomic.Value(u32), expect: u32) voi
57645764 .linux => {
57655765 const linux = std.os.linux;
57665766 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, null);
5767 switch (linux.E.init(rc)) {
5767 switch (linux.errno(rc)) {
57685768 .SUCCESS => {}, // notified by `wake()`
57695769 .INTR => {}, // gives caller a chance to check cancellation
57705770 .AGAIN => {}, // ptr.* != expect
......@@ -5827,7 +5827,7 @@ pub fn futexWaitDurationUncancelable(ptr: *const std.atomic.Value(u32), expect:
58275827 const linux = std.os.linux;
58285828 var ts = timestampToPosix(timeout.toNanoseconds());
58295829 const rc = linux.futex_4arg(ptr, .{ .cmd = .WAIT, .private = true }, expect, &ts);
5830 if (is_debug) switch (linux.E.init(rc)) {
5830 if (is_debug) switch (linux.errno(rc)) {
58315831 .SUCCESS => {}, // notified by `wake()`
58325832 .INTR => {}, // gives caller a chance to check cancellation
58335833 .AGAIN => {}, // ptr.* != expect
......@@ -5861,7 +5861,7 @@ pub fn futexWake(ptr: *const std.atomic.Value(u32), max_waiters: u32) void {
58615861 } else switch (native_os) {
58625862 .linux => {
58635863 const linux = std.os.linux;
5864 switch (linux.E.init(linux.futex_3arg(
5864 switch (linux.errno(linux.futex_3arg(
58655865 &ptr.raw,
58665866 .{ .cmd = .WAKE, .private = true },
58675867 @min(max_waiters, std.math.maxInt(i32)),
lib/std/Thread.zig+2-2
......@@ -1622,7 +1622,7 @@ const LinuxThreadImpl = struct {
16221622 linux.CLONE.PARENT_SETTID | linux.CLONE.CHILD_CLEARTID |
16231623 linux.CLONE.SIGHAND | linux.CLONE.SYSVSEM | linux.CLONE.SETTLS;
16241624
1625 switch (linux.E.init(linux.clone(
1625 switch (linux.errno(linux.clone(
16261626 Instance.entryFn,
16271627 @intFromPtr(&mapped[stack_offset]),
16281628 flags,
......@@ -1661,7 +1661,7 @@ const LinuxThreadImpl = struct {
16611661 const tid = self.thread.child_tid.load(.seq_cst);
16621662 if (tid == 0) break;
16631663
1664 switch (linux.E.init(linux.futex_4arg(
1664 switch (linux.errno(linux.futex_4arg(
16651665 &self.thread.child_tid.raw,
16661666 .{ .cmd = .WAIT, .private = false },
16671667 @bitCast(tid),
lib/std/Thread/Futex.zig+2-2
......@@ -269,7 +269,7 @@ const LinuxImpl = struct {
269269 if (timeout != null) &ts else null,
270270 );
271271
272 switch (linux.E.init(rc)) {
272 switch (linux.errno(rc)) {
273273 .SUCCESS => {}, // notified by `wake()`
274274 .INTR => {}, // spurious wakeup
275275 .AGAIN => {}, // ptr.* != expect
......@@ -290,7 +290,7 @@ const LinuxImpl = struct {
290290 @min(max_waiters, std.math.maxInt(i32)),
291291 );
292292
293 switch (linux.E.init(rc)) {
293 switch (linux.errno(rc)) {
294294 .SUCCESS => {}, // successful wake up
295295 .INVAL => {}, // invalid futex_wait() on ptr done elsewhere
296296 .FAULT => {}, // pointer became invalid while doing the wake
lib/std/c.zig+6-1
......@@ -72,6 +72,11 @@ pub inline fn versionCheck(comptime version: std.SemanticVersion) bool {
7272 };
7373}
7474
75/// Get the errno if rc is -1 and SUCCESS if rc is not -1.
76pub fn errno(rc: anytype) E {
77 return if (rc == -1) @enumFromInt(_errno().*) else .SUCCESS;
78}
79
7580pub const ino_t = switch (native_os) {
7681 .linux => linux.ino_t,
7782 .emscripten => emscripten.ino_t,
......@@ -11580,6 +11585,6 @@ const private = struct {
1158011585 extern threadlocal var errno: c_int;
1158111586
1158211587 fn errnoFromThreadLocal() *c_int {
11583 return &errno;
11588 return &private.errno;
1158411589 }
1158511590};
lib/std/fs/Dir.zig+1-1
......@@ -378,7 +378,7 @@ pub const Iterator = switch (native_os) {
378378 self.first_iter = false;
379379 }
380380 const rc = linux.getdents64(self.dir.fd, &self.buf, self.buf.len);
381 switch (linux.E.init(rc)) {
381 switch (linux.errno(rc)) {
382382 .SUCCESS => {},
383383 .BADF => unreachable, // Dir is invalid or was opened without iteration ability
384384 .FAULT => unreachable,
lib/std/os/linux.zig+6-21
......@@ -568,9 +568,8 @@ fn splitValue64(val: i64) [2]u32 {
568568 }
569569}
570570
571/// Get the errno from a syscall return value, or 0 for no error.
572/// The public API is exposed via the `E` namespace.
573fn errnoFromSyscall(r: usize) E {
571/// Get the errno from a syscall return value. SUCCESS means no error.
572pub fn errno(r: usize) E {
574573 const signed_r: isize = @bitCast(r);
575574 const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
576575 return @enumFromInt(int);
......@@ -1961,7 +1960,7 @@ pub fn sigaction(sig: SIG, noalias act: ?*const Sigaction, noalias oact: ?*Sigac
19611960 .sparc, .sparc64 => syscall5(.rt_sigaction, @intFromEnum(sig), ksa_arg, oldksa_arg, @intFromPtr(ksa.restorer), mask_size),
19621961 else => syscall4(.rt_sigaction, @intFromEnum(sig), ksa_arg, oldksa_arg, mask_size),
19631962 };
1964 if (E.init(result) != .SUCCESS) return result;
1963 if (errno(result) != .SUCCESS) return result;
19651964
19661965 if (oact) |old| {
19671966 old.handler.handler = oldksa.handler;
......@@ -2402,7 +2401,7 @@ pub fn sched_setaffinity(pid: pid_t, set: *const cpu_set_t) !void {
24022401 const size = @sizeOf(cpu_set_t);
24032402 const rc = syscall3(.sched_setaffinity, @as(usize, @bitCast(@as(isize, pid))), size, @intFromPtr(set));
24042403
2405 switch (E.init(rc)) {
2404 switch (errno(rc)) {
24062405 .SUCCESS => return,
24072406 else => |err| return std.posix.unexpectedErrno(err),
24082407 }
......@@ -3003,8 +3002,6 @@ pub const E = switch (native_arch) {
30033002 HWPOISON = 168,
30043003 DQUOT = 1133,
30053004 _,
3006
3007 pub const init = errnoFromSyscall;
30083005 },
30093006 .sparc, .sparc64 => enum(u16) {
30103007 /// No error occurred.
......@@ -3148,8 +3145,6 @@ pub const E = switch (native_arch) {
31483145 RFKILL = 134,
31493146 HWPOISON = 135,
31503147 _,
3151
3152 pub const init = errnoFromSyscall;
31533148 },
31543149 else => enum(u16) {
31553150 /// No error occurred.
......@@ -3459,8 +3454,6 @@ pub const E = switch (native_arch) {
34593454 NSRCNAMELOOP = 177,
34603455
34613456 _,
3462
3463 pub const init = errnoFromSyscall;
34643457 },
34653458};
34663459
......@@ -9892,7 +9885,7 @@ pub const wrapped = struct {
98929885 const adjusted_len = @min(in_len, 0x7ffff000); // Prevents EOVERFLOW.
98939886 const sendfileSymbol = if (lfs64_abi) system.sendfile64 else system.sendfile;
98949887 const rc = sendfileSymbol(out_fd, in_fd, in_offset, adjusted_len);
9895 switch (errno(rc)) {
9888 switch (system.errno(rc)) {
98969889 .SUCCESS => return @intCast(rc),
98979890 .BADF => return invalidApiUsage(), // Always a race condition.
98989891 .FAULT => return invalidApiUsage(), // Segmentation fault.
......@@ -9958,7 +9951,7 @@ pub const wrapped = struct {
99589951 const use_c = std.c.versionCheck(if (builtin.abi.isAndroid()) .{ .major = 34, .minor = 0, .patch = 0 } else .{ .major = 2, .minor = 27, .patch = 0 });
99599952 const sys = if (use_c) std.c else std.os.linux;
99609953 const rc = sys.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
9961 switch (errno(rc)) {
9954 switch (sys.errno(rc)) {
99629955 .SUCCESS => return @intCast(rc),
99639956 .BADF => return error.BadFileFlags,
99649957 .FBIG => return error.FileTooBig,
......@@ -9982,12 +9975,4 @@ pub const wrapped = struct {
99829975 if (builtin.mode == .Debug) @panic("invalid API usage");
99839976 return error.Unexpected;
99849977 }
9985
9986 fn errno(rc: anytype) E {
9987 if (builtin.link_libc) {
9988 return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
9989 } else {
9990 return errnoFromSyscall(rc);
9991 }
9992 }
99939978};
lib/std/os/linux/IoUring.zig+8-8
......@@ -46,7 +46,7 @@ pub fn init_params(entries: u16, p: *linux.io_uring_params) !IoUring {
4646 assert(p.resv[2] == 0);
4747
4848 const res = linux.io_uring_setup(entries, p);
49 switch (linux.E.init(res)) {
49 switch (linux.errno(res)) {
5050 .SUCCESS => {},
5151 .FAULT => return error.ParamsOutsideAccessibleAddressSpace,
5252 // 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 {
175175pub fn enter(self: *IoUring, to_submit: u32, min_complete: u32, flags: u32) !u32 {
176176 assert(self.fd >= 0);
177177 const res = linux.io_uring_enter(self.fd, to_submit, min_complete, flags, null);
178 switch (linux.E.init(res)) {
178 switch (linux.errno(res)) {
179179 .SUCCESS => {},
180180 // The kernel was unable to allocate memory or ran out of resources for the request.
181181 // 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 {
12981298pub fn unregister_buffers(self: *IoUring) !void {
12991299 assert(self.fd >= 0);
13001300 const res = linux.io_uring_register(self.fd, .UNREGISTER_BUFFERS, null, 0);
1301 switch (linux.E.init(res)) {
1301 switch (linux.errno(res)) {
13021302 .SUCCESS => {},
13031303 .NXIO => return error.BuffersNotRegistered,
13041304 else => |errno| return posix.unexpectedErrno(errno),
......@@ -1316,7 +1316,7 @@ pub fn get_probe(self: *IoUring) !linux.io_uring_probe {
13161316}
13171317
13181318fn handle_registration_result(res: usize) !void {
1319 switch (linux.E.init(res)) {
1319 switch (linux.errno(res)) {
13201320 .SUCCESS => {},
13211321 // One or more fds in the array are invalid, or the kernel does not support sparse sets:
13221322 .BADF => return error.FileDescriptorInvalid,
......@@ -1341,7 +1341,7 @@ fn handle_registration_result(res: usize) !void {
13411341pub fn unregister_files(self: *IoUring) !void {
13421342 assert(self.fd >= 0);
13431343 const res = linux.io_uring_register(self.fd, .UNREGISTER_FILES, null, 0);
1344 switch (linux.E.init(res)) {
1344 switch (linux.errno(res)) {
13451345 .SUCCESS => {},
13461346 .NXIO => return error.FilesNotRegistered,
13471347 else => |errno| return posix.unexpectedErrno(errno),
......@@ -1771,7 +1771,7 @@ fn register_buf_ring(
17711771 .flags = flags,
17721772 });
17731773 var res = linux.io_uring_register(fd, .REGISTER_PBUF_RING, @as(*const anyopaque, @ptrCast(&reg)), 1);
1774 if (linux.E.init(res) == .INVAL and reg.flags.inc) {
1774 if (linux.errno(res) == .INVAL and reg.flags.inc) {
17751775 // Retry without incremental buffer consumption.
17761776 // It is available since kernel 6.12. returns INVAL on older.
17771777 reg.flags.inc = false;
......@@ -1794,7 +1794,7 @@ fn unregister_buf_ring(fd: linux.fd_t, group_id: u16) !void {
17941794}
17951795
17961796fn handle_register_buf_ring_result(res: usize) !void {
1797 switch (linux.E.init(res)) {
1797 switch (linux.errno(res)) {
17981798 .SUCCESS => {},
17991799 .INVAL => return error.ArgumentsInvalid,
18001800 else => |errno| return posix.unexpectedErrno(errno),
......@@ -4085,7 +4085,7 @@ inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
40854085
40864086 var uts: linux.utsname = undefined;
40874087 const res = linux.uname(&uts);
4088 switch (linux.E.init(res)) {
4088 switch (linux.errno(res)) {
40894089 .SUCCESS => {},
40904090 else => |errno| return posix.unexpectedErrno(errno),
40914091 }
lib/std/os/linux/bpf.zig+1-1
......@@ -1,5 +1,5 @@
11const std = @import("../../std.zig");
2const errno = linux.E.init;
2const errno = linux.errno;
33const unexpectedErrno = std.posix.unexpectedErrno;
44const expectEqual = std.testing.expectEqual;
55const expectError = std.testing.expectError;
lib/std/os/linux/test.zig+34-26
......@@ -22,7 +22,7 @@ test "fallocate" {
2222 try expect((try file.stat()).size == 0);
2323
2424 const len: i64 = 65536;
25 switch (linux.E.init(linux.fallocate(file.handle, 0, 0, len))) {
25 switch (linux.errno(linux.fallocate(file.handle, 0, 0, len))) {
2626 .SUCCESS => {},
2727 .NOSYS => return error.SkipZigTest,
2828 .OPNOTSUPP => return error.SkipZigTest,
......@@ -42,11 +42,11 @@ test "getppid" {
4242
4343test "timer" {
4444 const epoll_fd = linux.epoll_create();
45 var err: linux.E = linux.E.init(epoll_fd);
45 var err: linux.E = linux.errno(epoll_fd);
4646 try expect(err == .SUCCESS);
4747
4848 const timer_fd = linux.timerfd_create(linux.TIMERFD_CLOCK.MONOTONIC, .{});
49 try expect(linux.E.init(timer_fd) == .SUCCESS);
49 try expect(linux.errno(timer_fd) == .SUCCESS);
5050
5151 const time_interval = linux.timespec{
5252 .sec = 0,
......@@ -58,7 +58,7 @@ test "timer" {
5858 .it_value = time_interval,
5959 };
6060
61 err = linux.E.init(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
61 err = linux.errno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
6262 try expect(err == .SUCCESS);
6363
6464 var event = linux.epoll_event{
......@@ -66,13 +66,13 @@ test "timer" {
6666 .data = linux.epoll_data{ .ptr = 0 },
6767 };
6868
69 err = linux.E.init(linux.epoll_ctl(@as(i32, @intCast(epoll_fd)), linux.EPOLL.CTL_ADD, @as(i32, @intCast(timer_fd)), &event));
69 err = linux.errno(linux.epoll_ctl(@as(i32, @intCast(epoll_fd)), linux.EPOLL.CTL_ADD, @as(i32, @intCast(timer_fd)), &event));
7070 try expect(err == .SUCCESS);
7171
7272 const events_one: linux.epoll_event = undefined;
7373 var events = [_]linux.epoll_event{events_one} ** 8;
7474
75 err = linux.E.init(linux.epoll_wait(@as(i32, @intCast(epoll_fd)), &events, 8, -1));
75 err = linux.errno(linux.epoll_wait(@as(i32, @intCast(epoll_fd)), &events, 8, -1));
7676 try expect(err == .SUCCESS);
7777}
7878
......@@ -85,7 +85,7 @@ test "statx" {
8585 defer file.close();
8686
8787 var statx_buf: linux.Statx = undefined;
88 switch (linux.E.init(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
88 switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
8989 .SUCCESS => {},
9090 else => unreachable,
9191 }
......@@ -93,7 +93,7 @@ test "statx" {
9393 if (builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; // No fstatat, so the rest of the test is meaningless.
9494
9595 var stat_buf: linux.Stat = undefined;
96 switch (linux.E.init(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
96 switch (linux.errno(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
9797 .SUCCESS => {},
9898 else => unreachable,
9999 }
......@@ -179,7 +179,7 @@ test "sigemptyset" {
179179test "sysinfo" {
180180 var info: linux.Sysinfo = undefined;
181181 const result: usize = linux.sysinfo(&info);
182 try expect(std.os.linux.E.init(result) == .SUCCESS);
182 try expect(std.os.linux.errno(result) == .SUCCESS);
183183
184184 try expect(info.mem_unit > 0);
185185 try expect(info.mem_unit <= std.heap.page_size_max);
......@@ -202,17 +202,17 @@ test "futex v1" {
202202
203203 // No-op wait, lock value is not expected value
204204 rc = linux.futex(&lock.raw, .{ .cmd = .WAIT, .private = true }, 2, .{ .timeout = null }, null, 0);
205 try expectEqual(.AGAIN, linux.E.init(rc));
205 try expectEqual(.AGAIN, linux.errno(rc));
206206
207207 rc = linux.futex_4arg(&lock.raw, .{ .cmd = .WAIT, .private = true }, 2, null);
208 try expectEqual(.AGAIN, linux.E.init(rc));
208 try expectEqual(.AGAIN, linux.errno(rc));
209209
210210 // Short-fuse wait, timeout kicks in
211211 rc = linux.futex(&lock.raw, .{ .cmd = .WAIT, .private = true }, 1, .{ .timeout = &.{ .sec = 0, .nsec = 2 } }, null, 0);
212 try expectEqual(.TIMEDOUT, linux.E.init(rc));
212 try expectEqual(.TIMEDOUT, linux.errno(rc));
213213
214214 rc = linux.futex_4arg(&lock.raw, .{ .cmd = .WAIT, .private = true }, 1, &.{ .sec = 0, .nsec = 2 });
215 try expectEqual(.TIMEDOUT, linux.E.init(rc));
215 try expectEqual(.TIMEDOUT, linux.errno(rc));
216216
217217 // Wakeup (no waiters)
218218 rc = linux.futex(&lock.raw, .{ .cmd = .WAKE, .private = true }, 2, .{ .timeout = null }, null, 0);
......@@ -223,7 +223,7 @@ test "futex v1" {
223223
224224 // CMP_REQUEUE - val3 mismatch
225225 rc = linux.futex(&lock.raw, .{ .cmd = .CMP_REQUEUE, .private = true }, 2, .{ .val2 = 0 }, null, 99);
226 try expectEqual(.AGAIN, linux.E.init(rc));
226 try expectEqual(.AGAIN, linux.errno(rc));
227227
228228 // CMP_REQUEUE - requeue (but no waiters, so ... not much)
229229 {
......@@ -256,12 +256,12 @@ test "futex v1" {
256256 {
257257 // val1 return early
258258 rc = linux.futex(&lock.raw, .{ .cmd = .WAIT_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0xfff);
259 try expectEqual(.AGAIN, linux.E.init(rc));
259 try expectEqual(.AGAIN, linux.errno(rc));
260260
261261 // timeout wait
262262 const timeout: linux.timespec = .{ .sec = 0, .nsec = 2 };
263263 rc = linux.futex(&lock.raw, .{ .cmd = .WAIT_BITSET, .private = true }, 1, .{ .timeout = &timeout }, null, 0xfff);
264 try expectEqual(.TIMEDOUT, linux.E.init(rc));
264 try expectEqual(.TIMEDOUT, linux.errno(rc));
265265 }
266266
267267 // WAKE_BITSET
......@@ -271,7 +271,7 @@ test "futex v1" {
271271
272272 // bitmask must have at least 1 bit set:
273273 rc = linux.futex(&lock.raw, .{ .cmd = .WAKE_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0);
274 try expectEqual(.INVAL, linux.E.init(rc));
274 try expectEqual(.INVAL, linux.errno(rc));
275275 }
276276}
277277
......@@ -307,7 +307,7 @@ test "futex2_waitv" {
307307
308308 const timeout = linux.kernel_timespec{ .sec = 0, .nsec = 2 }; // absolute timeout, so this is 1970...
309309 const rc = linux.futex2_waitv(&futexes, futexes.len, .{}, &timeout, .MONOTONIC);
310 switch (linux.E.init(rc)) {
310 switch (linux.errno(rc)) {
311311 .NOSYS => return error.SkipZigTest, // futex2_waitv added in kernel v5.16
312312 else => |err| try expectEqual(.TIMEDOUT, err),
313313 }
......@@ -318,7 +318,7 @@ test "futex2_waitv" {
318318fn futex2_skip_if_unsupported() !void {
319319 const lock: u32 = 0;
320320 const rc = linux.futex2_wake(&lock, 0, 1, .{ .size = .U32, .private = true });
321 if (linux.E.init(rc) == .NOSYS) {
321 if (linux.errno(rc) == .NOSYS) {
322322 return error.SkipZigTest;
323323 }
324324}
......@@ -334,23 +334,23 @@ test "futex2_wait" {
334334 // (at least) they're not implemented.
335335 if (false) {
336336 rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U8, .private = true }, null, .MONOTONIC);
337 try expectEqual(.INVAL, linux.E.init(rc));
337 try expectEqual(.INVAL, linux.errno(rc));
338338
339339 rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U16, .private = true }, null, .MONOTONIC);
340 try expectEqual(.INVAL, linux.E.init(rc));
340 try expectEqual(.INVAL, linux.errno(rc));
341341
342342 rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U64, .private = true }, null, .MONOTONIC);
343 try expectEqual(.INVAL, linux.E.init(rc));
343 try expectEqual(.INVAL, linux.errno(rc));
344344 }
345345
346346 const flags = linux.FUTEX2_FLAGS{ .size = .U32, .private = true };
347347 // no-wait, lock state mismatch
348348 rc = linux.futex2_wait(&lock.raw, 2, mask, flags, null, .MONOTONIC);
349 try expectEqual(.AGAIN, linux.E.init(rc));
349 try expectEqual(.AGAIN, linux.errno(rc));
350350
351351 // hit timeout on wait
352352 rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .MONOTONIC);
353 try expectEqual(.TIMEDOUT, linux.E.init(rc));
353 try expectEqual(.TIMEDOUT, linux.errno(rc));
354354
355355 // timeout is absolute
356356 {
......@@ -364,11 +364,11 @@ test "futex2_wait" {
364364 .nsec = curr.nsec + 2,
365365 };
366366 rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &timeout, .MONOTONIC);
367 try expectEqual(.TIMEDOUT, linux.E.init(rc));
367 try expectEqual(.TIMEDOUT, linux.errno(rc));
368368 }
369369
370370 rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .REALTIME);
371 try expectEqual(.TIMEDOUT, linux.E.init(rc));
371 try expectEqual(.TIMEDOUT, linux.errno(rc));
372372}
373373
374374test "futex2_wake" {
......@@ -405,6 +405,14 @@ test "futex2_requeue" {
405405 try expectEqual(0, rc);
406406}
407407
408test "copy_file_range error" {
409 const fds = try std.posix.pipe();
410 defer std.posix.close(fds[0]);
411 defer std.posix.close(fds[1]);
412
413 try std.testing.expectError(error.InvalidArguments, linux.wrapped.copy_file_range(fds[0], null, fds[1], null, 1, 0));
414}
415
408416test {
409417 _ = linux.IoUring;
410418}
lib/std/os/linux/tls.zig+1-1
......@@ -555,7 +555,7 @@ pub fn initStatic(phdrs: []elf.Phdr) void {
555555 }
556556
557557 const begin_addr = mmap_tls(area_desc.size + area_desc.alignment - 1);
558 if (@call(.always_inline, linux.E.init, .{begin_addr}) != .SUCCESS) @trap();
558 if (@call(.always_inline, linux.errno, .{begin_addr}) != .SUCCESS) @trap();
559559
560560 const area_ptr: [*]align(page_size_min) u8 = @ptrFromInt(begin_addr);
561561
lib/std/os/plan9.zig+8-6
......@@ -94,13 +94,15 @@ pub const E = enum(u16) {
9494 OVERFLOW,
9595 LOOP,
9696 TXTBSY,
97
98 pub fn init(r: usize) E {
99 const signed_r: isize = @bitCast(r);
100 const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
101 return @enumFromInt(int);
102 }
10397};
98
99/// Get the errno from a syscall return value. SUCCESS means no error.
100pub fn errno(r: usize) E {
101 const signed_r: isize = @bitCast(r);
102 const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
103 return @enumFromInt(int);
104}
105
104106// The max bytes that can be in the errstr buff
105107pub const ERRMAX = 128;
106108var errstr_buf: [ERRMAX]u8 = undefined;
lib/std/posix.zig+9-16
......@@ -272,14 +272,7 @@ pub const socket_t = if (native_os == .windows) windows.ws2_32.SOCKET else fd_t;
272272/// for others it will use a thread-local errno variable. Therefore, this
273273/// function only returns a well-defined value when it is called directly after
274274/// the system function call whose errno value is intended to be observed.
275pub fn errno(rc: anytype) E {
276 if (use_libc) {
277 return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
278 }
279 const signed: isize = @bitCast(rc);
280 const int = if (signed > -4096 and signed < 0) -signed else 0;
281 return @enumFromInt(int);
282}
275pub const errno = system.errno;
283276
284277/// Closes the file descriptor.
285278///
......@@ -433,7 +426,7 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
433426 // Later on this should be changed to `system.fchmodat2`
434427 // when the musl/glibc add a wrapper.
435428 const res = linux.fchmodat2(dirfd, &path_c, mode, flags);
436 switch (E.init(res)) {
429 switch (linux.errno(res)) {
437430 .SUCCESS => return,
438431 .INTR => continue,
439432 .BADF => unreachable,
......@@ -588,7 +581,7 @@ pub const RebootCommand = switch (native_os) {
588581pub fn reboot(cmd: RebootCommand) RebootError!void {
589582 switch (native_os) {
590583 .linux => {
591 switch (linux.E.init(linux.reboot(
584 switch (linux.errno(linux.reboot(
592585 .MAGIC1,
593586 .MAGIC2,
594587 cmd,
......@@ -647,7 +640,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
647640 break :res .{ @bitCast(rc), errno(rc) };
648641 } else res: {
649642 const rc = linux.getrandom(buf.ptr, buf.len, 0);
650 break :res .{ rc, linux.E.init(rc) };
643 break :res .{ rc, linux.errno(rc) };
651644 };
652645
653646 switch (err) {
......@@ -3298,7 +3291,7 @@ pub fn isatty(handle: fd_t) bool {
32983291 var wsz: winsize = undefined;
32993292 const fd: usize = @bitCast(@as(isize, handle));
33003293 const rc = linux.syscall3(.ioctl, fd, linux.T.IOCGWINSZ, @intFromPtr(&wsz));
3301 switch (linux.E.init(rc)) {
3294 switch (linux.errno(rc)) {
33023295 .SUCCESS => return true,
33033296 .INTR => continue,
33043297 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
57625755 while (true) {
57635756 const rc = sys.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
57645757 if (native_os == .freebsd) {
5765 switch (errno(rc)) {
5758 switch (sys.errno(rc)) {
57665759 .SUCCESS => return @intCast(rc),
57675760 .BADF => return error.FilesOpenedWithWrongFlags,
57685761 .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
57755768 else => |err| return unexpectedErrno(err),
57765769 }
57775770 } else { // assume linux
5778 switch (errno(rc)) {
5771 switch (sys.errno(rc)) {
57795772 .SUCCESS => return @intCast(rc),
57805773 .BADF => return error.FilesOpenedWithWrongFlags,
57815774 .FBIG => return error.FileTooBig,
......@@ -6070,7 +6063,7 @@ pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t {
60706063 const use_c = std.c.versionCheck(if (builtin.abi.isAndroid()) .{ .major = 30, .minor = 0, .patch = 0 } else .{ .major = 2, .minor = 27, .patch = 0 });
60716064 const sys = if (use_c) std.c else linux;
60726065 const rc = sys.memfd_create(name, flags);
6073 switch (errno(rc)) {
6066 switch (sys.errno(rc)) {
60746067 .SUCCESS => return @intCast(rc),
60756068 .FAULT => unreachable, // name has invalid memory
60766069 .INVAL => return error.NameTooLong, // or, program has a bug and flags are faulty
......@@ -6494,7 +6487,7 @@ pub fn perf_event_open(
64946487 if (native_os == .linux) {
64956488 // There is no syscall wrapper for this function exposed by libcs
64966489 const rc = linux.perf_event_open(attr, pid, cpu, group_fd, flags);
6497 switch (errno(rc)) {
6490 switch (linux.errno(rc)) {
64986491 .SUCCESS => return @intCast(rc),
64996492 .@"2BIG" => return error.TooBig,
65006493 .ACCES => return error.PermissionDenied,
lib/std/process.zig+1-1
......@@ -1772,7 +1772,7 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
17721772 .linux => {
17731773 var info: std.os.linux.Sysinfo = undefined;
17741774 const result: usize = std.os.linux.sysinfo(&info);
1775 if (std.os.linux.E.init(result) != .SUCCESS) {
1775 if (std.os.linux.errno(result) != .SUCCESS) {
17761776 return error.UnknownTotalSystemMemory;
17771777 }
17781778 // Promote to u64 to avoid overflow on systems where info.totalram is a 32-bit usize
src/link/Elf/ZigObject.zig+2-2
......@@ -1437,7 +1437,7 @@ fn updateNavCode(
14371437 .len = code.len,
14381438 }};
14391439 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
1440 switch (std.os.linux.E.init(rc)) {
1440 switch (std.os.linux.errno(rc)) {
14411441 .SUCCESS => assert(rc == code.len),
14421442 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
14431443 }
......@@ -2026,7 +2026,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
20262026 .len = out.len,
20272027 }};
20282028 const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
2029 switch (std.os.linux.E.init(rc)) {
2029 switch (std.os.linux.errno(rc)) {
20302030 .SUCCESS => assert(rc == out.len),
20312031 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
20322032 }
src/link/MappedFile.zig+3-3
......@@ -645,7 +645,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested
645645 @intCast(requested_size +| requested_size / growth_factor),
646646 ) - old_size;
647647 _, const file_size = Node.Index.root.location(mf).resolve(mf);
648 while (true) switch (linux.E.init(switch (std.math.order(range_file_offset, file_size)) {
648 while (true) switch (linux.errno(switch (std.math.order(range_file_offset, file_size)) {
649649 .lt => linux.fallocate(
650650 mf.file.handle,
651651 linux.FALLOC.FL_INSERT_RANGE,
......@@ -858,7 +858,7 @@ fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size:
858858 // delete the copy of this node at the old location
859859 if (is_linux and !mf.flags.fallocate_punch_hole_unsupported and
860860 size >= mf.flags.block_size.toByteUnits() * 2 - 1) while (true)
861 switch (linux.E.init(linux.fallocate(
861 switch (linux.errno(linux.fallocate(
862862 mf.file.handle,
863863 linux.FALLOC.FL_PUNCH_HOLE | linux.FALLOC.FL_KEEP_SIZE,
864864 @intCast(old_file_offset),
......@@ -910,7 +910,7 @@ fn copyFileRange(
910910 @intCast(remaining_size),
911911 0,
912912 );
913 switch (linux.E.init(copy_len)) {
913 switch (linux.errno(copy_len)) {
914914 .SUCCESS => {
915915 if (copy_len == 0) break;
916916 remaining_size -= copy_len;