authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-10 23:31:37-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-11 23:37:31+01:00
logb600b6e5e08bc443ef9742b36d51c95715c8150a
treeff9dc624970254de1b3500858df3064095cafb87
parentea30f86113cb1ef2ea53f8d35598061ebb153c8e

std.posix: remove close function


16 files changed, 165 insertions(+), 234 deletions(-)

lib/c/unistd.zig+30
...@@ -14,6 +14,8 @@ comptime {...@@ -14,6 +14,8 @@ comptime {
14 symbol(&acctLinux, "acct");14 symbol(&acctLinux, "acct");
15 symbol(&chdirLinux, "chdir");15 symbol(&chdirLinux, "chdir");
16 symbol(&chownLinux, "chown");16 symbol(&chownLinux, "chown");
17 symbol(&close, "close");
18 symbol(&posix_close, "posix_close");
17 symbol(&fchownatLinux, "fchownat");19 symbol(&fchownatLinux, "fchownat");
18 symbol(&lchownLinux, "lchown");20 symbol(&lchownLinux, "lchown");
19 symbol(&chrootLinux, "chroot");21 symbol(&chrootLinux, "chroot");
...@@ -49,6 +51,9 @@ comptime {...@@ -49,6 +51,9 @@ comptime {
49 if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {51 if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
50 symbol(&swab, "swab");52 symbol(&swab, "swab");
51 }53 }
54 if (builtin.target.isWasiLibC()) {
55 symbol(&closeWasi, "close");
56 }
52}57}
5358
54fn _exit(exit_code: c_int) callconv(.c) noreturn {59fn _exit(exit_code: c_int) callconv(.c) noreturn {
...@@ -226,3 +231,28 @@ test swab {...@@ -226,3 +231,28 @@ test swab {
226 swab("abcd", &a, 3);231 swab("abcd", &a, 3);
227 try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a);232 try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a);
228}233}
234
235fn close(fd: std.c.fd_t) callconv(.c) c_int {
236 const signed: isize = @bitCast(linux.close(fd));
237 if (signed < 0) {
238 @branchHint(.unlikely);
239 if (-signed == @intFromEnum(linux.E.INTR)) return 0;
240 std.c._errno().* = @intCast(-signed);
241 return -1;
242 }
243 return 0;
244}
245
246fn posix_close(fd: std.c.fd_t, _: c_int) callconv(.c) c_int {
247 return close(fd);
248}
249
250fn closeWasi(fd: std.c.fd_t) callconv(.c) c_int {
251 switch (std.os.wasi.fd_close(fd)) {
252 .SUCCESS => return 0,
253 else => |e| {
254 std.c._errno().* = @intFromEnum(e);
255 return -1;
256 },
257 }
258}
lib/libc/musl/src/unistd/close.c deleted-19
...@@ -1,19 +0,0 @@
1#include <unistd.h>
2#include <errno.h>
3#include "aio_impl.h"
4#include "syscall.h"
5
6static int dummy(int fd)
7{
8 return fd;
9}
10
11weak_alias(dummy, __aio_close);
12
13int close(int fd)
14{
15 fd = __aio_close(fd);
16 int r = __syscall_cp(SYS_close, fd);
17 if (r == -EINTR) r = 0;
18 return __syscall_ret(r);
19}
lib/libc/musl/src/unistd/posix_close.c deleted-6
...@@ -1,6 +0,0 @@
1#include <unistd.h>
2
3int posix_close(int fd, int flags)
4{
5 return close(fd);
6}
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_fd_renumber.c-38
...@@ -70,41 +70,3 @@ void drop_udp_socket(udp_socket_t socket) {...@@ -70,41 +70,3 @@ void drop_udp_socket(udp_socket_t socket) {
70 udp_udp_socket_drop_own(socket.socket);70 udp_udp_socket_drop_own(socket.socket);
71}71}
72#endif // __wasilibc_use_wasip272#endif // __wasilibc_use_wasip2
73
74int close(int fd) {
75 // Scan the preopen fds before making any changes.
76 __wasilibc_populate_preopens();
77
78#ifdef __wasilibc_use_wasip2
79 descriptor_table_entry_t entry;
80 if (descriptor_table_remove(fd, &entry)) {
81
82 switch (entry.tag)
83 {
84 case DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET:
85 drop_tcp_socket(entry.tcp_socket);
86 break;
87 case DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET:
88 drop_udp_socket(entry.udp_socket);
89 break;
90 default: /* unreachable */ abort();
91 }
92
93 return 0;
94 }
95#endif // __wasilibc_use_wasip2
96
97 __wasi_errno_t error = __wasi_fd_close(fd);
98 if (error != 0) {
99 errno = error;
100 return -1;
101 }
102
103 return 0;
104}
105
106weak void __wasilibc_populate_preopens(void) {
107 // This version does nothing. It may be overridden by a version which does
108 // something if `__wasilibc_find_abspath` or `__wasilibc_find_relpath` are
109 // used.
110}
lib/std/Build/Watch.zig+2-2
...@@ -693,7 +693,7 @@ const Os = switch (builtin.os.tag) {...@@ -693,7 +693,7 @@ const Os = switch (builtin.os.tag) {
693 fatal("failed to open directory {f}: {t}", .{ path, err });693 fatal("failed to open directory {f}: {t}", .{ path, err });
694 };694 };
695 // Empirically the dir has to stay open or else no events are triggered.695 // Empirically the dir has to stay open or else no events are triggered.
696 errdefer if (!skip_open_dir) posix.close(dir_fd);696 errdefer if (!skip_open_dir) std.Io.Threaded.closeFd(dir_fd);
697 const changes = [1]posix.Kevent{.{697 const changes = [1]posix.Kevent{.{
698 .ident = @bitCast(@as(isize, dir_fd)),698 .ident = @bitCast(@as(isize, dir_fd)),
699 .filter = std.c.EVFILT.VNODE,699 .filter = std.c.EVFILT.VNODE,
...@@ -793,7 +793,7 @@ const Os = switch (builtin.os.tag) {...@@ -793,7 +793,7 @@ const Os = switch (builtin.os.tag) {
793 };793 };
794 const filtered_changes = if (i == handles.len - 1) changes[0..1] else &changes;794 const filtered_changes = if (i == handles.len - 1) changes[0..1] else &changes;
795 _ = try Io.Kqueue.kevent(w.os.kq_fd, filtered_changes, &.{}, null);795 _ = try Io.Kqueue.kevent(w.os.kq_fd, filtered_changes, &.{}, null);
796 if (path.sub_path.len != 0) posix.close(dir_fd);796 if (path.sub_path.len != 0) std.Io.Threaded.closeFd(dir_fd);
797797
798 w.dir_table.swapRemoveAt(i);798 w.dir_table.swapRemoveAt(i);
799 handles.swapRemove(i);799 handles.swapRemove(i);
lib/std/Io/IoUring.zig+1-1
...@@ -549,7 +549,7 @@ const CachedFd = struct {...@@ -549,7 +549,7 @@ const CachedFd = struct {
549 .initializing => unreachable,549 .initializing => unreachable,
550 _ => |fd| {550 _ => |fd| {
551 assert(@intFromEnum(fd) >= 0);551 assert(@intFromEnum(fd) >= 0);
552 std.posix.close(@intFromEnum(fd));552 _ = std.os.linux.close(@intFromEnum(fd));
553 cached_fd.* = .init;553 cached_fd.* = .init;
554 },554 },
555 }555 }
lib/std/Io/Kqueue.zig+8-7
...@@ -11,6 +11,7 @@ const Allocator = std.mem.Allocator;...@@ -11,6 +11,7 @@ const Allocator = std.mem.Allocator;
11const Alignment = std.mem.Alignment;11const Alignment = std.mem.Alignment;
12const IpAddress = std.Io.net.IpAddress;12const IpAddress = std.Io.net.IpAddress;
13const errnoBug = std.Io.Threaded.errnoBug;13const errnoBug = std.Io.Threaded.errnoBug;
14const closeFd = std.Io.Threaded.closeFd;
14const posix = std.posix;15const posix = std.posix;
1516
16/// Must be a thread-safe allocator.17/// Must be a thread-safe allocator.
...@@ -64,7 +65,7 @@ const Thread = struct {...@@ -64,7 +65,7 @@ const Thread = struct {
64 };65 };
6566
66 fn deinit(thread: *Thread, gpa: Allocator) void {67 fn deinit(thread: *Thread, gpa: Allocator) void {
67 posix.close(thread.kq_fd);68 closeFd(thread.kq_fd);
68 assert(thread.wait_queues.count() == 0);69 assert(thread.wait_queues.count() == 0);
69 thread.wait_queues.deinit(gpa);70 thread.wait_queues.deinit(gpa);
70 thread.* = undefined;71 thread.* = undefined;
...@@ -212,7 +213,7 @@ pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void {...@@ -212,7 +213,7 @@ pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void {
212 .steal_ready_search_index = 1,213 .steal_ready_search_index = 1,
213 .wait_queues = .empty,214 .wait_queues = .empty,
214 };215 };
215 errdefer std.posix.close(main_thread.kq_fd);216 errdefer closeFd(main_thread.kq_fd);
216 std.log.debug("created main idle {*}", .{&main_thread.idle_context});217 std.log.debug("created main idle {*}", .{&main_thread.idle_context});
217 std.log.debug("created main {*}", .{main_fiber});218 std.log.debug("created main {*}", .{main_fiber});
218}219}
...@@ -371,7 +372,7 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void {...@@ -371,7 +372,7 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void {
371 .stack_size = idle_stack_size,372 .stack_size = idle_stack_size,
372 .allocator = k.gpa,373 .allocator = k.gpa,
373 }, threadEntry, .{ k, new_thread_index }) catch |err| {374 }, threadEntry, .{ k, new_thread_index }) catch |err| {
374 posix.close(new_thread.kq_fd);375 closeFd(new_thread.kq_fd);
375 @atomicStore(u32, &k.threads.reserved, new_thread_index, .release);376 @atomicStore(u32, &k.threads.reserved, new_thread_index, .release);
376 // no more access to `thread` after giving up reservation377 // no more access to `thread` after giving up reservation
377 std.log.warn("unable to create worker thread due spawn failure: {s}", .{@errorName(err)});378 std.log.warn("unable to create worker thread due spawn failure: {s}", .{@errorName(err)});
...@@ -1234,7 +1235,7 @@ fn netBindIp(...@@ -1234,7 +1235,7 @@ fn netBindIp(
1234 const k: *Kqueue = @ptrCast(@alignCast(userdata));1235 const k: *Kqueue = @ptrCast(@alignCast(userdata));
1235 const family = Io.Threaded.posixAddressFamily(address);1236 const family = Io.Threaded.posixAddressFamily(address);
1236 const socket_fd = try openSocketPosix(k, family, options);1237 const socket_fd = try openSocketPosix(k, family, options);
1237 errdefer std.posix.close(socket_fd);1238 errdefer closeFd(socket_fd);
1238 var storage: Io.Threaded.PosixAddress = undefined;1239 var storage: Io.Threaded.PosixAddress = undefined;
1239 var addr_len = Io.Threaded.addressToPosix(address, &storage);1240 var addr_len = Io.Threaded.addressToPosix(address, &storage);
1240 try posixBind(k, socket_fd, &storage.any, addr_len);1241 try posixBind(k, socket_fd, &storage.any, addr_len);
...@@ -1252,7 +1253,7 @@ fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: n...@@ -1252,7 +1253,7 @@ fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: n
1252 .mode = options.mode,1253 .mode = options.mode,
1253 .protocol = options.protocol,1254 .protocol = options.protocol,
1254 });1255 });
1255 errdefer posix.close(socket_fd);1256 errdefer closeFd(socket_fd);
1256 var storage: Io.Threaded.PosixAddress = undefined;1257 var storage: Io.Threaded.PosixAddress = undefined;
1257 var addr_len = Io.Threaded.addressToPosix(address, &storage);1258 var addr_len = Io.Threaded.addressToPosix(address, &storage);
1258 try posixConnect(k, socket_fd, &storage.any, addr_len);1259 try posixConnect(k, socket_fd, &storage.any, addr_len);
...@@ -1565,7 +1566,7 @@ fn openSocketPosix(...@@ -1565,7 +1566,7 @@ fn openSocketPosix(
1565 switch (posix.errno(socket_rc)) {1566 switch (posix.errno(socket_rc)) {
1566 .SUCCESS => {1567 .SUCCESS => {
1567 const fd: posix.fd_t = @intCast(socket_rc);1568 const fd: posix.fd_t = @intCast(socket_rc);
1568 errdefer posix.close(fd);1569 errdefer closeFd(fd);
1569 if (Io.Threaded.socket_flags_unsupported) {1570 if (Io.Threaded.socket_flags_unsupported) {
1570 while (true) {1571 while (true) {
1571 try k.checkCancel();1572 try k.checkCancel();
...@@ -1614,7 +1615,7 @@ fn openSocketPosix(...@@ -1614,7 +1615,7 @@ fn openSocketPosix(
1614 else => |err| return posix.unexpectedErrno(err),1615 else => |err| return posix.unexpectedErrno(err),
1615 }1616 }
1616 };1617 };
1617 errdefer posix.close(socket_fd);1618 errdefer closeFd(socket_fd);
16181619
1619 if (options.ip6_only) {1620 if (options.ip6_only) {
1620 if (posix.IPV6 == void) return error.OptionUnsupported;1621 if (posix.IPV6 == void) return error.OptionUnsupported;
lib/std/Io/Threaded.zig+64-38
...@@ -303,7 +303,7 @@ pub const NullFile = switch (native_os) {...@@ -303,7 +303,7 @@ pub const NullFile = switch (native_os) {
303303
304 fn deinit(this: *@This()) void {304 fn deinit(this: *@This()) void {
305 if (this.fd >= 0) {305 if (this.fd >= 0) {
306 posix.close(this.fd);306 closeFd(this.fd);
307 this.fd = -1;307 this.fd = -1;
308 }308 }
309 }309 }
...@@ -4337,7 +4337,7 @@ fn dirCreateFilePosix(...@@ -4337,7 +4337,7 @@ fn dirCreateFilePosix(
4337 }4337 }
4338 }4338 }
4339 };4339 };
4340 errdefer posix.close(fd);4340 errdefer closeFd(fd);
43414341
4342 if (have_flock and !have_flock_open_flags and flags.lock != .none) {4342 if (have_flock and !have_flock_open_flags and flags.lock != .none) {
4343 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;4343 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
...@@ -4917,7 +4917,7 @@ fn dirOpenFilePosix(...@@ -4917,7 +4917,7 @@ fn dirOpenFilePosix(
4917 }4917 }
4918 }4918 }
4919 };4919 };
4920 errdefer posix.close(fd);4920 errdefer closeFd(fd);
49214921
4922 if (!flags.allow_directory) {4922 if (!flags.allow_directory) {
4923 const is_dir = is_dir: {4923 const is_dir = is_dir: {
...@@ -5241,7 +5241,7 @@ fn dirOpenFileWasi(...@@ -5241,7 +5241,7 @@ fn dirOpenFileWasi(
5241 },5241 },
5242 }5242 }
5243 }5243 }
5244 errdefer posix.close(fd);5244 errdefer closeFd(fd);
52455245
5246 if (!flags.allow_directory) {5246 if (!flags.allow_directory) {
5247 const is_dir = is_dir: {5247 const is_dir = is_dir: {
...@@ -5457,7 +5457,13 @@ pub fn dirOpenDirWindows(...@@ -5457,7 +5457,13 @@ pub fn dirOpenDirWindows(
5457fn dirClose(userdata: ?*anyopaque, dirs: []const Dir) void {5457fn dirClose(userdata: ?*anyopaque, dirs: []const Dir) void {
5458 const t: *Threaded = @ptrCast(@alignCast(userdata));5458 const t: *Threaded = @ptrCast(@alignCast(userdata));
5459 _ = t;5459 _ = t;
5460 for (dirs) |dir| posix.close(dir.handle);5460 for (dirs) |dir| {
5461 if (is_windows) {
5462 windows.CloseHandle(dir.handle);
5463 } else {
5464 closeFd(dir.handle);
5465 }
5466 }
5461}5467}
54625468
5463const dirRead = switch (native_os) {5469const dirRead = switch (native_os) {
...@@ -6777,7 +6783,7 @@ fn dirRealPathFilePosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, o...@@ -6777,7 +6783,7 @@ fn dirRealPathFilePosix(userdata: ?*anyopaque, dir: Dir, sub_path: []const u8, o
6777 },6783 },
6778 }6784 }
6779 };6785 };
6780 defer posix.close(fd);6786 defer closeFd(fd);
6781 return realPathPosix(fd, out_buffer);6787 return realPathPosix(fd, out_buffer);
6782}6788}
67836789
...@@ -8367,7 +8373,7 @@ fn fchmodatFallback(...@@ -8367,7 +8373,7 @@ fn fchmodatFallback(
8367 }8373 }
8368 }8374 }
8369 };8375 };
8370 defer posix.close(path_fd);8376 defer closeFd(path_fd);
83718377
8372 const path_mode = mode: {8378 const path_mode = mode: {
8373 const sys = if (statx_use_c) std.c else std.os.linux;8379 const sys = if (statx_use_c) std.c else std.os.linux;
...@@ -9592,7 +9598,13 @@ fn dirHardLink(...@@ -9592,7 +9598,13 @@ fn dirHardLink(
9592fn fileClose(userdata: ?*anyopaque, files: []const File) void {9598fn fileClose(userdata: ?*anyopaque, files: []const File) void {
9593 const t: *Threaded = @ptrCast(@alignCast(userdata));9599 const t: *Threaded = @ptrCast(@alignCast(userdata));
9594 _ = t;9600 _ = t;
9595 for (files) |file| posix.close(file.handle);9601 for (files) |file| {
9602 if (is_windows) {
9603 windows.CloseHandle(file.handle);
9604 } else {
9605 closeFd(file.handle);
9606 }
9607 }
9596}9608}
95979609
9598fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: []const []u8) File.ReadStreamingError!usize {9610fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: []const []u8) File.ReadStreamingError!usize {
...@@ -11783,7 +11795,7 @@ fn netListenIpPosix(...@@ -11783,7 +11795,7 @@ fn netListenIpPosix(
11783 .mode = options.mode,11795 .mode = options.mode,
11784 .protocol = options.protocol,11796 .protocol = options.protocol,
11785 });11797 });
11786 errdefer posix.close(socket_fd);11798 errdefer closeFd(socket_fd);
1178711799
11788 if (options.reuse_address) {11800 if (options.reuse_address) {
11789 try setSocketOption(socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);11801 try setSocketOption(socket_fd, posix.SOL.SOCKET, posix.SO.REUSEADDR, 1);
...@@ -11946,7 +11958,7 @@ fn netListenUnixPosix(...@@ -11946,7 +11958,7 @@ fn netListenUnixPosix(
11946 error.OptionUnsupported => return error.Unexpected,11958 error.OptionUnsupported => return error.Unexpected,
11947 else => |e| return e,11959 else => |e| return e,
11948 };11960 };
11949 errdefer posix.close(socket_fd);11961 errdefer closeFd(socket_fd);
1195011962
11951 var storage: UnixAddress = undefined;11963 var storage: UnixAddress = undefined;
11952 const addr_len = addressUnixToPosix(address, &storage);11964 const addr_len = addressUnixToPosix(address, &storage);
...@@ -12362,7 +12374,7 @@ fn netConnectIpPosix(...@@ -12362,7 +12374,7 @@ fn netConnectIpPosix(
12362 .mode = options.mode,12374 .mode = options.mode,
12363 .protocol = options.protocol,12375 .protocol = options.protocol,
12364 });12376 });
12365 errdefer posix.close(socket_fd);12377 errdefer closeFd(socket_fd);
12366 var storage: PosixAddress = undefined;12378 var storage: PosixAddress = undefined;
12367 var addr_len = addressToPosix(address, &storage);12379 var addr_len = addressToPosix(address, &storage);
12368 try posixConnect(socket_fd, &storage.any, addr_len);12380 try posixConnect(socket_fd, &storage.any, addr_len);
...@@ -12462,7 +12474,7 @@ fn netConnectUnixPosix(...@@ -12462,7 +12474,7 @@ fn netConnectUnixPosix(
12462 error.OptionUnsupported => return error.Unexpected,12474 error.OptionUnsupported => return error.Unexpected,
12463 else => |e| return e,12475 else => |e| return e,
12464 };12476 };
12465 errdefer posix.close(socket_fd);12477 errdefer closeFd(socket_fd);
12466 var storage: UnixAddress = undefined;12478 var storage: UnixAddress = undefined;
12467 const addr_len = addressUnixToPosix(address, &storage);12479 const addr_len = addressUnixToPosix(address, &storage);
12468 try posixConnectUnix(socket_fd, &storage.any, addr_len);12480 try posixConnectUnix(socket_fd, &storage.any, addr_len);
...@@ -12536,7 +12548,7 @@ fn netBindIpPosix(...@@ -12536,7 +12548,7 @@ fn netBindIpPosix(
12536 _ = t;12548 _ = t;
12537 const family = posixAddressFamily(address);12549 const family = posixAddressFamily(address);
12538 const socket_fd = try openSocketPosix(family, options);12550 const socket_fd = try openSocketPosix(family, options);
12539 errdefer posix.close(socket_fd);12551 errdefer closeFd(socket_fd);
12540 var storage: PosixAddress = undefined;12552 var storage: PosixAddress = undefined;
12541 var addr_len = addressToPosix(address, &storage);12553 var addr_len = addressToPosix(address, &storage);
12542 try posixBind(socket_fd, &storage.any, addr_len);12554 try posixBind(socket_fd, &storage.any, addr_len);
...@@ -12642,7 +12654,7 @@ fn openSocketPosix(...@@ -12642,7 +12654,7 @@ fn openSocketPosix(
12642 .SUCCESS => {12654 .SUCCESS => {
12643 syscall.finish();12655 syscall.finish();
12644 const fd: posix.fd_t = @intCast(rc);12656 const fd: posix.fd_t = @intCast(rc);
12645 errdefer posix.close(fd);12657 errdefer closeFd(fd);
12646 if (socket_flags_unsupported) try setCloexec(fd);12658 if (socket_flags_unsupported) try setCloexec(fd);
12647 break fd;12659 break fd;
12648 },12660 },
...@@ -12661,7 +12673,7 @@ fn openSocketPosix(...@@ -12661,7 +12673,7 @@ fn openSocketPosix(
12661 else => |err| return syscall.unexpectedErrno(err),12673 else => |err| return syscall.unexpectedErrno(err),
12662 }12674 }
12663 };12675 };
12664 errdefer posix.close(socket_fd);12676 errdefer closeFd(socket_fd);
1266512677
12666 if (options.ip6_only) {12678 if (options.ip6_only) {
12667 if (posix.IPV6 == void) return error.OptionUnsupported;12679 if (posix.IPV6 == void) return error.OptionUnsupported;
...@@ -12707,8 +12719,8 @@ fn netSocketCreatePair(...@@ -12707,8 +12719,8 @@ fn netSocketCreatePair(
12707 .SUCCESS => {12719 .SUCCESS => {
12708 syscall.finish();12720 syscall.finish();
12709 errdefer {12721 errdefer {
12710 posix.close(sockets[0]);12722 closeFd(sockets[0]);
12711 posix.close(sockets[1]);12723 closeFd(sockets[1]);
12712 }12724 }
12713 if (socket_flags_unsupported) {12725 if (socket_flags_unsupported) {
12714 try setCloexec(sockets[0]);12726 try setCloexec(sockets[0]);
...@@ -12809,7 +12821,7 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve...@@ -12809,7 +12821,7 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
12809 .SUCCESS => {12821 .SUCCESS => {
12810 syscall.finish();12822 syscall.finish();
12811 const fd: posix.fd_t = @intCast(rc);12823 const fd: posix.fd_t = @intCast(rc);
12812 errdefer posix.close(fd);12824 errdefer closeFd(fd);
12813 if (!have_accept4) try setCloexec(fd);12825 if (!have_accept4) try setCloexec(fd);
12814 break fd;12826 break fd;
12815 },12827 },
...@@ -13679,7 +13691,7 @@ fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void {...@@ -13679,7 +13691,7 @@ fn netClose(userdata: ?*anyopaque, handles: []const net.Socket.Handle) void {
13679 _ = t;13691 _ = t;
13680 switch (native_os) {13692 switch (native_os) {
13681 .windows => for (handles) |handle| closeSocketWindows(handle),13693 .windows => for (handles) |handle| closeSocketWindows(handle),
13682 else => for (handles) |handle| posix.close(handle),13694 else => for (handles) |handle| closeFd(handle),
13683 }13695 }
13684}13696}
1368513697
...@@ -13787,7 +13799,7 @@ fn netInterfaceNameResolve(...@@ -13787,7 +13799,7 @@ fn netInterfaceNameResolve(
13787 error.OptionUnsupported => return error.Unexpected,13799 error.OptionUnsupported => return error.Unexpected,
13788 else => |e| return e,13800 else => |e| return e,
13789 };13801 };
13790 defer posix.close(sock_fd);13802 defer closeFd(sock_fd);
1379113803
13792 var ifr: posix.ifreq = .{13804 var ifr: posix.ifreq = .{
13793 .ifrn = .{ .name = @bitCast(name.bytes) },13805 .ifrn = .{ .name = @bitCast(name.bytes) },
...@@ -15329,13 +15341,13 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp...@@ -15329,13 +15341,13 @@ fn spawnPosix(t: *Threaded, options: process.SpawnOptions) process.SpawnError!Sp
15329 const pid: posix.pid_t = @intCast(pid_result); // We are the parent.15341 const pid: posix.pid_t = @intCast(pid_result); // We are the parent.
15330 errdefer comptime unreachable; // The child is forked; we must not error from now on15342 errdefer comptime unreachable; // The child is forked; we must not error from now on
1533115343
15332 posix.close(err_pipe[1]); // make sure only the child holds the write end open15344 closeFd(err_pipe[1]); // make sure only the child holds the write end open
1533315345
15334 if (options.stdin == .pipe) posix.close(stdin_pipe[0]);15346 if (options.stdin == .pipe) closeFd(stdin_pipe[0]);
15335 if (options.stdout == .pipe) posix.close(stdout_pipe[1]);15347 if (options.stdout == .pipe) closeFd(stdout_pipe[1]);
15336 if (options.stderr == .pipe) posix.close(stderr_pipe[1]);15348 if (options.stderr == .pipe) closeFd(stderr_pipe[1]);
1533715349
15338 if (prog_pipe[1] != -1) posix.close(prog_pipe[1]);15350 if (prog_pipe[1] != -1) closeFd(prog_pipe[1]);
15339 options.progress_node.setIpcFile(t, .{ .handle = prog_pipe[0], .flags = .{ .nonblocking = true } });15351 options.progress_node.setIpcFile(t, .{ .handle = prog_pipe[0], .flags = .{ .nonblocking = true } });
1534015352
15341 return .{15353 return .{
...@@ -15373,7 +15385,7 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t {...@@ -15373,7 +15385,7 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t {
15373 mutexLock(&t.mutex); // Another thread might have won the race.15385 mutexLock(&t.mutex); // Another thread might have won the race.
15374 defer mutexUnlock(&t.mutex);15386 defer mutexUnlock(&t.mutex);
15375 if (t.null_file.fd != -1) {15387 if (t.null_file.fd != -1) {
15376 posix.close(fresh_fd);15388 closeFd(fresh_fd);
15377 return t.null_file.fd;15389 return t.null_file.fd;
15378 } else {15390 } else {
15379 t.null_file.fd = fresh_fd;15391 t.null_file.fd = fresh_fd;
...@@ -15399,7 +15411,7 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t {...@@ -15399,7 +15411,7 @@ fn getDevNullFd(t: *Threaded) !posix.fd_t {
15399fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child {15411fn processSpawnPosix(userdata: ?*anyopaque, options: process.SpawnOptions) process.SpawnError!process.Child {
15400 const t: *Threaded = @ptrCast(@alignCast(userdata));15412 const t: *Threaded = @ptrCast(@alignCast(userdata));
15401 const spawned = try spawnPosix(t, options);15413 const spawned = try spawnPosix(t, options);
15402 defer posix.close(spawned.err_fd);15414 defer closeFd(spawned.err_fd);
1540315415
15404 // Wait for the child to report any errors in or before `execvpe`.15416 // Wait for the child to report any errors in or before `execvpe`.
15405 if (readIntFd(spawned.err_fd)) |child_err_int| {15417 if (readIntFd(spawned.err_fd)) |child_err_int| {
...@@ -15666,15 +15678,15 @@ fn childKillPosix(child: *process.Child) !void {...@@ -15666,15 +15678,15 @@ fn childKillPosix(child: *process.Child) !void {
1566615678
15667fn childCleanupPosix(child: *process.Child) void {15679fn childCleanupPosix(child: *process.Child) void {
15668 if (child.stdin) |*stdin| {15680 if (child.stdin) |*stdin| {
15669 posix.close(stdin.handle);15681 closeFd(stdin.handle);
15670 child.stdin = null;15682 child.stdin = null;
15671 }15683 }
15672 if (child.stdout) |*stdout| {15684 if (child.stdout) |*stdout| {
15673 posix.close(stdout.handle);15685 closeFd(stdout.handle);
15674 child.stdout = null;15686 child.stdout = null;
15675 }15687 }
15676 if (child.stderr) |*stderr| {15688 if (child.stderr) |*stderr| {
15677 posix.close(stderr.handle);15689 closeFd(stderr.handle);
15678 child.stderr = null;15690 child.stderr = null;
15679 }15691 }
15680 child.id = null;15692 child.id = null;
...@@ -15743,14 +15755,14 @@ fn readIntFd(fd: posix.fd_t) !ErrInt {...@@ -15743,14 +15755,14 @@ fn readIntFd(fd: posix.fd_t) !ErrInt {
15743const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);15755const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
1574415756
15745fn destroyPipe(pipe: [2]posix.fd_t) void {15757fn destroyPipe(pipe: [2]posix.fd_t) void {
15746 if (pipe[0] != -1) posix.close(pipe[0]);15758 if (pipe[0] != -1) closeFd(pipe[0]);
15747 if (pipe[0] != pipe[1]) posix.close(pipe[1]);15759 if (pipe[0] != pipe[1]) closeFd(pipe[1]);
15748}15760}
1574915761
15750fn setUpChildIo(stdio: process.SpawnOptions.StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {15762fn setUpChildIo(stdio: process.SpawnOptions.StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
15751 switch (stdio) {15763 switch (stdio) {
15752 .pipe => try dup2(pipe_fd, std_fileno),15764 .pipe => try dup2(pipe_fd, std_fileno),
15753 .close => posix.close(std_fileno),15765 .close => closeFd(std_fileno),
15754 .inherit => {},15766 .inherit => {},
15755 .ignore => try dup2(dev_null_fd, std_fileno),15767 .ignore => try dup2(dev_null_fd, std_fileno),
15756 .file => @panic("TODO implement setUpChildIo when file is used"),15768 .file => @panic("TODO implement setUpChildIo when file is used"),
...@@ -17439,7 +17451,7 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {...@@ -17439,7 +17451,7 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {
17439 }17451 }
17440 }17452 }
17441 };17453 };
17442 errdefer posix.close(fd);17454 errdefer closeFd(fd);
1744317455
17444 switch (native_os) {17456 switch (native_os) {
17445 .linux => {17457 .linux => {
...@@ -17454,7 +17466,7 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {...@@ -17454,7 +17466,7 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {
17454 mutexLock(&t.mutex); // Another thread might have won the race.17466 mutexLock(&t.mutex); // Another thread might have won the race.
17455 defer mutexUnlock(&t.mutex);17467 defer mutexUnlock(&t.mutex);
17456 if (t.random_file.fd >= 0) {17468 if (t.random_file.fd >= 0) {
17457 posix.close(fd);17469 closeFd(fd);
17458 return t.random_file.fd;17470 return t.random_file.fd;
17459 } else if (!posix.S.ISCHR(statx.mode)) {17471 } else if (!posix.S.ISCHR(statx.mode)) {
17460 t.random_file.fd = -2;17472 t.random_file.fd = -2;
...@@ -17482,7 +17494,7 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {...@@ -17482,7 +17494,7 @@ fn getRandomFd(t: *Threaded) Io.RandomSecureError!posix.fd_t {
17482 mutexLock(&t.mutex); // Another thread might have won the race.17494 mutexLock(&t.mutex); // Another thread might have won the race.
17483 defer mutexUnlock(&t.mutex);17495 defer mutexUnlock(&t.mutex);
17484 if (t.random_file.fd >= 0) {17496 if (t.random_file.fd >= 0) {
17485 posix.close(fd);17497 closeFd(fd);
17486 return t.random_file.fd;17498 return t.random_file.fd;
17487 } else if (!posix.S.ISCHR(stat.mode)) {17499 } else if (!posix.S.ISCHR(stat.mode)) {
17488 t.random_file.fd = -2;17500 t.random_file.fd = -2;
...@@ -18170,8 +18182,8 @@ pub fn pipe2(flags: posix.O) PipeError![2]posix.fd_t {...@@ -18170,8 +18182,8 @@ pub fn pipe2(flags: posix.O) PipeError![2]posix.fd_t {
18170 else => |err| return posix.unexpectedErrno(err),18182 else => |err| return posix.unexpectedErrno(err),
18171 }18183 }
18172 errdefer {18184 errdefer {
18173 posix.close(fds[0]);18185 closeFd(fds[0]);
18174 posix.close(fds[1]);18186 closeFd(fds[1]);
18175 }18187 }
1817618188
18177 // https://github.com/ziglang/zig/issues/1888218189 // https://github.com/ziglang/zig/issues/18882
...@@ -19164,3 +19176,17 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows...@@ -19164,3 +19176,17 @@ fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!windows
19164 }19176 }
19165 }19177 }
19166}19178}
19179
19180pub fn closeFd(fd: posix.fd_t) void {
19181 if (native_os == .wasi and !builtin.link_libc) {
19182 switch (std.os.wasi.fd_close(fd)) {
19183 .SUCCESS, .INTR => {},
19184 .BADF => recoverableOsBugDetected(), // use after free
19185 else => recoverableOsBugDetected(), // unexpected failure
19186 }
19187 } else switch (posix.errno(posix.system.close(fd))) {
19188 .SUCCESS, .INTR => {}, // INTR still a success, see https://github.com/ziglang/zig/issues/2425
19189 .BADF => recoverableOsBugDetected(), // use after free
19190 else => recoverableOsBugDetected(), // unexpected failure
19191 }
19192}
lib/std/os/linux.zig+1-1
...@@ -1571,7 +1571,7 @@ pub fn clone2(flags: u32, child_stack_ptr: usize) usize {...@@ -1571,7 +1571,7 @@ pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
1571 return syscall2(.clone, flags, child_stack_ptr);1571 return syscall2(.clone, flags, child_stack_ptr);
1572}1572}
15731573
1574pub fn close(fd: i32) usize {1574pub fn close(fd: fd_t) usize {
1575 return syscall1(.close, @as(usize, @bitCast(@as(isize, fd))));1575 return syscall1(.close, @as(usize, @bitCast(@as(isize, fd))));
1576}1576}
15771577
lib/std/os/linux/IoUring.zig+2-2
...@@ -67,7 +67,7 @@ pub fn init_params(entries: u16, p: *linux.io_uring_params) !IoUring {...@@ -67,7 +67,7 @@ pub fn init_params(entries: u16, p: *linux.io_uring_params) !IoUring {
67 }67 }
68 const fd = @as(linux.fd_t, @intCast(res));68 const fd = @as(linux.fd_t, @intCast(res));
69 assert(fd >= 0);69 assert(fd >= 0);
70 errdefer posix.close(fd);70 errdefer _ = linux.close(fd);
7171
72 // Kernel versions 5.4 and up use only one mmap() for the submission and completion queues.72 // Kernel versions 5.4 and up use only one mmap() for the submission and completion queues.
73 // This is not an optional feature for us... if the kernel does it, we have to do it.73 // This is not an optional feature for us... if the kernel does it, we have to do it.
...@@ -125,7 +125,7 @@ pub fn deinit(self: *IoUring) void {...@@ -125,7 +125,7 @@ pub fn deinit(self: *IoUring) void {
125 // The mmaps depend on the fd, so the order of these calls is important:125 // The mmaps depend on the fd, so the order of these calls is important:
126 self.cq.deinit();126 self.cq.deinit();
127 self.sq.deinit();127 self.sq.deinit();
128 posix.close(self.fd);128 _ = linux.close(self.fd);
129 self.fd = -1;129 self.fd = -1;
130}130}
131131
lib/std/os/linux/IoUring/test.zig+21-21
...@@ -440,7 +440,7 @@ test "openat" {...@@ -440,7 +440,7 @@ test "openat" {
440 try testing.expect(cqe_openat.res > 0);440 try testing.expect(cqe_openat.res > 0);
441 try testing.expectEqual(@as(u32, 0), cqe_openat.flags);441 try testing.expectEqual(@as(u32, 0), cqe_openat.flags);
442442
443 posix.close(cqe_openat.res);443 _ = linux.close(cqe_openat.res);
444}444}
445445
446test "close" {446test "close" {
...@@ -530,7 +530,7 @@ test "sendmsg/recvmsg" {...@@ -530,7 +530,7 @@ test "sendmsg/recvmsg" {
530 };530 };
531531
532 const server = try socket(address_server.family, posix.SOCK.DGRAM, 0);532 const server = try socket(address_server.family, posix.SOCK.DGRAM, 0);
533 defer posix.close(server);533 defer _ = linux.close(server);
534 try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEPORT, &mem.toBytes(@as(c_int, 1)));534 try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEPORT, &mem.toBytes(@as(c_int, 1)));
535 try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));535 try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
536 try bind(server, addrAny(&address_server), @sizeOf(linux.sockaddr.in));536 try bind(server, addrAny(&address_server), @sizeOf(linux.sockaddr.in));
...@@ -540,7 +540,7 @@ test "sendmsg/recvmsg" {...@@ -540,7 +540,7 @@ test "sendmsg/recvmsg" {
540 try getsockname(server, addrAny(&address_server), &slen);540 try getsockname(server, addrAny(&address_server), &slen);
541541
542 const client = try socket(address_server.family, posix.SOCK.DGRAM, 0);542 const client = try socket(address_server.family, posix.SOCK.DGRAM, 0);
543 defer posix.close(client);543 defer _ = linux.close(client);
544544
545 const buffer_send = [_]u8{42} ** 128;545 const buffer_send = [_]u8{42} ** 128;
546 const iovecs_send = [_]iovec_const{546 const iovecs_send = [_]iovec_const{
...@@ -1034,7 +1034,7 @@ test "shutdown" {...@@ -1034,7 +1034,7 @@ test "shutdown" {
1034 // Socket bound, expect shutdown to work1034 // Socket bound, expect shutdown to work
1035 {1035 {
1036 const server = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);1036 const server = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1037 defer posix.close(server);1037 defer _ = linux.close(server);
1038 try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));1038 try posix.setsockopt(server, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
1039 try bind(server, addrAny(&address), @sizeOf(linux.sockaddr.in));1039 try bind(server, addrAny(&address), @sizeOf(linux.sockaddr.in));
1040 try listen(server, 1);1040 try listen(server, 1);
...@@ -1067,7 +1067,7 @@ test "shutdown" {...@@ -1067,7 +1067,7 @@ test "shutdown" {
1067 // Socket not bound, expect to fail with ENOTCONN1067 // Socket not bound, expect to fail with ENOTCONN
1068 {1068 {
1069 const server = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);1069 const server = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1070 defer posix.close(server);1070 defer _ = linux.close(server);
10711071
1072 const shutdown_sqe = ring.shutdown(0x445445445, server, linux.SHUT.RD) catch |err| switch (err) {1072 const shutdown_sqe = ring.shutdown(0x445445445, server, linux.SHUT.RD) catch |err| switch (err) {
1073 else => |errno| std.debug.panic("unhandled errno: {}", .{errno}),1073 else => |errno| std.debug.panic("unhandled errno: {}", .{errno}),
...@@ -1741,7 +1741,7 @@ test "accept multishot" {...@@ -1741,7 +1741,7 @@ test "accept multishot" {
1741 .addr = @bitCast([4]u8{ 127, 0, 0, 1 }),1741 .addr = @bitCast([4]u8{ 127, 0, 0, 1 }),
1742 };1742 };
1743 const listener_socket = try createListenerSocket(&address);1743 const listener_socket = try createListenerSocket(&address);
1744 defer posix.close(listener_socket);1744 defer _ = linux.close(listener_socket);
17451745
1746 // submit multishot accept operation1746 // submit multishot accept operation
1747 var addr: posix.sockaddr = undefined;1747 var addr: posix.sockaddr = undefined;
...@@ -1754,7 +1754,7 @@ test "accept multishot" {...@@ -1754,7 +1754,7 @@ test "accept multishot" {
1754 while (nr > 0) : (nr -= 1) {1754 while (nr > 0) : (nr -= 1) {
1755 // connect client1755 // connect client
1756 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);1756 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1757 errdefer posix.close(client);1757 errdefer _ = linux.close(client);
1758 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));1758 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
17591759
1760 // test accept completion1760 // test accept completion
...@@ -1764,7 +1764,7 @@ test "accept multishot" {...@@ -1764,7 +1764,7 @@ test "accept multishot" {
1764 try testing.expect(cqe.user_data == userdata);1764 try testing.expect(cqe.user_data == userdata);
1765 try testing.expect(cqe.flags & linux.IORING_CQE_F_MORE > 0); // more flag is set1765 try testing.expect(cqe.flags & linux.IORING_CQE_F_MORE > 0); // more flag is set
17661766
1767 posix.close(client);1767 _ = linux.close(client);
1768 }1768 }
1769}1769}
17701770
...@@ -1848,7 +1848,7 @@ test "accept_direct" {...@@ -1848,7 +1848,7 @@ test "accept_direct" {
1848 try ring.register_files(registered_fds[0..]);1848 try ring.register_files(registered_fds[0..]);
18491849
1850 const listener_socket = try createListenerSocket(&address);1850 const listener_socket = try createListenerSocket(&address);
1851 defer posix.close(listener_socket);1851 defer _ = linux.close(listener_socket);
18521852
1853 const accept_userdata: u64 = 0xaaaaaaaa;1853 const accept_userdata: u64 = 0xaaaaaaaa;
1854 const read_userdata: u64 = 0xbbbbbbbb;1854 const read_userdata: u64 = 0xbbbbbbbb;
...@@ -1866,7 +1866,7 @@ test "accept_direct" {...@@ -1866,7 +1866,7 @@ test "accept_direct" {
1866 // connect1866 // connect
1867 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);1867 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1868 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));1868 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1869 defer posix.close(client);1869 defer _ = linux.close(client);
18701870
1871 // accept completion1871 // accept completion
1872 const cqe_accept = try ring.copy_cqe();1872 const cqe_accept = try ring.copy_cqe();
...@@ -1900,7 +1900,7 @@ test "accept_direct" {...@@ -1900,7 +1900,7 @@ test "accept_direct" {
1900 // connect1900 // connect
1901 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);1901 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1902 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));1902 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1903 defer posix.close(client);1903 defer _ = linux.close(client);
1904 // completion with error1904 // completion with error
1905 const cqe_accept = try ring.copy_cqe();1905 const cqe_accept = try ring.copy_cqe();
1906 try testing.expect(cqe_accept.user_data == accept_userdata);1906 try testing.expect(cqe_accept.user_data == accept_userdata);
...@@ -1936,7 +1936,7 @@ test "accept_multishot_direct" {...@@ -1936,7 +1936,7 @@ test "accept_multishot_direct" {
1936 try ring.register_files(registered_fds[0..]);1936 try ring.register_files(registered_fds[0..]);
19371937
1938 const listener_socket = try createListenerSocket(&address);1938 const listener_socket = try createListenerSocket(&address);
1939 defer posix.close(listener_socket);1939 defer _ = linux.close(listener_socket);
19401940
1941 const accept_userdata: u64 = 0xaaaaaaaa;1941 const accept_userdata: u64 = 0xaaaaaaaa;
19421942
...@@ -1950,7 +1950,7 @@ test "accept_multishot_direct" {...@@ -1950,7 +1950,7 @@ test "accept_multishot_direct" {
1950 // connect1950 // connect
1951 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);1951 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1952 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));1952 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1953 defer posix.close(client);1953 defer _ = linux.close(client);
19541954
1955 // accept completion1955 // accept completion
1956 const cqe_accept = try ring.copy_cqe();1956 const cqe_accept = try ring.copy_cqe();
...@@ -1965,7 +1965,7 @@ test "accept_multishot_direct" {...@@ -1965,7 +1965,7 @@ test "accept_multishot_direct" {
1965 // connect1965 // connect
1966 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);1966 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1967 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));1967 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1968 defer posix.close(client);1968 defer _ = linux.close(client);
1969 // completion with error1969 // completion with error
1970 const cqe_accept = try ring.copy_cqe();1970 const cqe_accept = try ring.copy_cqe();
1971 try testing.expect(cqe_accept.user_data == accept_userdata);1971 try testing.expect(cqe_accept.user_data == accept_userdata);
...@@ -1998,7 +1998,7 @@ test "socket" {...@@ -1998,7 +1998,7 @@ test "socket" {
1998 const fd: linux.fd_t = @intCast(cqe.res);1998 const fd: linux.fd_t = @intCast(cqe.res);
1999 try testing.expect(fd > 2);1999 try testing.expect(fd > 2);
20002000
2001 posix.close(fd);2001 _ = linux.close(fd);
2002}2002}
20032003
2004test "socket_direct/socket_direct_alloc/close_direct" {2004test "socket_direct/socket_direct_alloc/close_direct" {
...@@ -2042,7 +2042,7 @@ test "socket_direct/socket_direct_alloc/close_direct" {...@@ -2042,7 +2042,7 @@ test "socket_direct/socket_direct_alloc/close_direct" {
2042 .addr = @bitCast([4]u8{ 127, 0, 0, 1 }),2042 .addr = @bitCast([4]u8{ 127, 0, 0, 1 }),
2043 };2043 };
2044 const listener_socket = try createListenerSocket(&address);2044 const listener_socket = try createListenerSocket(&address);
2045 defer posix.close(listener_socket);2045 defer _ = linux.close(listener_socket);
2046 const accept_userdata: u64 = 0xaaaaaaaa;2046 const accept_userdata: u64 = 0xaaaaaaaa;
2047 const connect_userdata: u64 = 0xbbbbbbbb;2047 const connect_userdata: u64 = 0xbbbbbbbb;
2048 const close_userdata: u64 = 0xcccccccc;2048 const close_userdata: u64 = 0xcccccccc;
...@@ -2599,8 +2599,8 @@ pub const SocketTestHarness = struct {...@@ -2599,8 +2599,8 @@ pub const SocketTestHarness = struct {
2599 client: posix.socket_t,2599 client: posix.socket_t,
26002600
2601 pub fn close(self: SocketTestHarness) void {2601 pub fn close(self: SocketTestHarness) void {
2602 posix.close(self.client);2602 _ = linux.close(self.client);
2603 posix.close(self.listener);2603 _ = linux.close(self.listener);
2604 }2604 }
2605};2605};
26062606
...@@ -2611,7 +2611,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {...@@ -2611,7 +2611,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {
2611 .addr = @bitCast([4]u8{ 127, 0, 0, 1 }),2611 .addr = @bitCast([4]u8{ 127, 0, 0, 1 }),
2612 };2612 };
2613 const listener_socket = try createListenerSocket(&address);2613 const listener_socket = try createListenerSocket(&address);
2614 errdefer posix.close(listener_socket);2614 errdefer _ = linux.close(listener_socket);
26152615
2616 // Submit 1 accept2616 // Submit 1 accept
2617 var accept_addr: posix.sockaddr = undefined;2617 var accept_addr: posix.sockaddr = undefined;
...@@ -2620,7 +2620,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {...@@ -2620,7 +2620,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {
26202620
2621 // Create a TCP client socket2621 // Create a TCP client socket
2622 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);2622 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
2623 errdefer posix.close(client);2623 errdefer _ = linux.close(client);
2624 _ = try ring.connect(0xcccccccc, client, addrAny(&address), @sizeOf(linux.sockaddr.in));2624 _ = try ring.connect(0xcccccccc, client, addrAny(&address), @sizeOf(linux.sockaddr.in));
26252625
2626 try testing.expectEqual(@as(u32, 2), try ring.submit());2626 try testing.expectEqual(@as(u32, 2), try ring.submit());
...@@ -2660,7 +2660,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {...@@ -2660,7 +2660,7 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness {
2660fn createListenerSocket(address: *linux.sockaddr.in) !posix.socket_t {2660fn createListenerSocket(address: *linux.sockaddr.in) !posix.socket_t {
2661 const kernel_backlog = 1;2661 const kernel_backlog = 1;
2662 const listener_socket = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);2662 const listener_socket = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
2663 errdefer posix.close(listener_socket);2663 errdefer _ = linux.close(listener_socket);
26642664
2665 try posix.setsockopt(listener_socket, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));2665 try posix.setsockopt(listener_socket, posix.SOL.SOCKET, posix.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
2666 try bind(listener_socket, addrAny(address), @sizeOf(linux.sockaddr.in));2666 try bind(listener_socket, addrAny(address), @sizeOf(linux.sockaddr.in));
lib/std/os/linux/test.zig+36
...@@ -407,6 +407,42 @@ test "futex2_requeue" {...@@ -407,6 +407,42 @@ test "futex2_requeue" {
407 try expectEqual(0, rc);407 try expectEqual(0, rc);
408}408}
409409
410test "timerfd" {
411 const tfd: linux.fd_t = rc: {
412 const rc = linux.timerfd_create(.MONOTONIC, .{ .CLOEXEC = true });
413 switch (linux.errno(rc)) {
414 .SUCCESS => break :rc @intCast(rc),
415 else => @panic("test failed"),
416 }
417 };
418 defer _ = linux.close(tfd);
419
420 // Fire event 10_000_000ns = 10ms after the posix.timerfd_settime call.
421 var sit: linux.itimerspec = .{ .it_interval = .{ .sec = 0, .nsec = 0 }, .it_value = .{ .sec = 0, .nsec = 10 * (1000 * 1000) } };
422 const flags: linux.TFD.TIMER = .{};
423 switch (linux.errno(linux.timerfd_settime(tfd, @bitCast(flags), &sit, null))) {
424 .SUCCESS => {},
425 else => @panic("test failed"),
426 }
427
428 var fds: [1]std.posix.pollfd = .{.{ .fd = tfd, .events = linux.POLL.IN, .revents = 0 }};
429 try expectEqual(@as(usize, 1), try std.posix.poll(&fds, -1)); // -1 => infinite waiting
430
431 const git = rc: {
432 var curr_value: linux.itimerspec = undefined;
433 const rc = linux.timerfd_gettime(tfd, &curr_value);
434 switch (linux.errno(rc)) {
435 .SUCCESS => break :rc curr_value,
436 else => @panic("test failed"),
437 }
438 };
439 const expect_disarmed_timer: linux.itimerspec = .{
440 .it_interval = .{ .sec = 0, .nsec = 0 },
441 .it_value = .{ .sec = 0, .nsec = 0 },
442 };
443 try expectEqual(expect_disarmed_timer, git);
444}
445
410test {446test {
411 _ = linux.IoUring;447 _ = linux.IoUring;
412}448}
lib/std/posix.zig-78
...@@ -278,30 +278,6 @@ pub const socket_t = if (native_os == .windows) windows.ws2_32.SOCKET else fd_t;...@@ -278,30 +278,6 @@ pub const socket_t = if (native_os == .windows) windows.ws2_32.SOCKET else fd_t;
278/// the system function call whose errno value is intended to be observed.278/// the system function call whose errno value is intended to be observed.
279pub const errno = system.errno;279pub const errno = system.errno;
280280
281/// Closes the file descriptor.
282///
283/// Asserts the file descriptor is open.
284///
285/// This function is not capable of returning any indication of failure. An
286/// application which wants to ensure writes have succeeded before closing must
287/// call `fsync` before `close`.
288///
289/// The Zig standard library does not support POSIX thread cancellation.
290pub fn close(fd: fd_t) void {
291 if (native_os == .windows) {
292 return windows.CloseHandle(fd);
293 }
294 if (native_os == .wasi and !builtin.link_libc) {
295 _ = std.os.wasi.fd_close(fd);
296 return;
297 }
298 switch (errno(system.close(fd))) {
299 .BADF => unreachable, // Always a race condition.
300 .INTR => return, // This is still a success. See https://github.com/ziglang/zig/issues/2425
301 else => return,
302 }
303}
304
305pub const RebootError = error{281pub const RebootError = error{
306 PermissionDenied,282 PermissionDenied,
307} || UnexpectedError;283} || UnexpectedError;
...@@ -1541,60 +1517,6 @@ pub fn perf_event_open(...@@ -1541,60 +1517,6 @@ pub fn perf_event_open(
1541 }1517 }
1542}1518}
15431519
1544pub const TimerFdCreateError = error{
1545 PermissionDenied,
1546 ProcessFdQuotaExceeded,
1547 SystemFdQuotaExceeded,
1548 NoDevice,
1549 SystemResources,
1550} || UnexpectedError;
1551
1552pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;
1553pub const TimerFdSetError = TimerFdGetError || error{Canceled};
1554
1555pub fn timerfd_create(clock_id: system.timerfd_clockid_t, flags: system.TFD) TimerFdCreateError!fd_t {
1556 const rc = system.timerfd_create(clock_id, @bitCast(flags));
1557 return switch (errno(rc)) {
1558 .SUCCESS => @intCast(rc),
1559 .INVAL => unreachable,
1560 .MFILE => return error.ProcessFdQuotaExceeded,
1561 .NFILE => return error.SystemFdQuotaExceeded,
1562 .NODEV => return error.NoDevice,
1563 .NOMEM => return error.SystemResources,
1564 .PERM => return error.PermissionDenied,
1565 else => |err| return unexpectedErrno(err),
1566 };
1567}
1568
1569pub fn timerfd_settime(
1570 fd: i32,
1571 flags: system.TFD.TIMER,
1572 new_value: *const system.itimerspec,
1573 old_value: ?*system.itimerspec,
1574) TimerFdSetError!void {
1575 const rc = system.timerfd_settime(fd, @bitCast(flags), new_value, old_value);
1576 return switch (errno(rc)) {
1577 .SUCCESS => {},
1578 .BADF => error.InvalidHandle,
1579 .FAULT => unreachable,
1580 .INVAL => unreachable,
1581 .CANCELED => error.Canceled,
1582 else => |err| return unexpectedErrno(err),
1583 };
1584}
1585
1586pub fn timerfd_gettime(fd: i32) TimerFdGetError!system.itimerspec {
1587 var curr_value: system.itimerspec = undefined;
1588 const rc = system.timerfd_gettime(fd, &curr_value);
1589 return switch (errno(rc)) {
1590 .SUCCESS => return curr_value,
1591 .BADF => error.InvalidHandle,
1592 .FAULT => unreachable,
1593 .INVAL => unreachable,
1594 else => |err| return unexpectedErrno(err),
1595 };
1596}
1597
1598pub const PtraceError = error{1520pub const PtraceError = error{
1599 DeadLock,1521 DeadLock,
1600 DeviceBusy,1522 DeviceBusy,
lib/std/posix/test.zig-18
...@@ -522,21 +522,3 @@ test "rename smoke test" {...@@ -522,21 +522,3 @@ test "rename smoke test" {
522 try expectError(error.FileNotFound, Io.Dir.cwd().openDir(io, file_path, .{}));522 try expectError(error.FileNotFound, Io.Dir.cwd().openDir(io, file_path, .{}));
523 }523 }
524}524}
525
526test "timerfd" {
527 if (native_os != .linux) return error.SkipZigTest;
528
529 const tfd = try posix.timerfd_create(.MONOTONIC, .{ .CLOEXEC = true });
530 defer posix.close(tfd);
531
532 // Fire event 10_000_000ns = 10ms after the posix.timerfd_settime call.
533 var sit: linux.itimerspec = .{ .it_interval = .{ .sec = 0, .nsec = 0 }, .it_value = .{ .sec = 0, .nsec = 10 * (1000 * 1000) } };
534 try posix.timerfd_settime(tfd, .{}, &sit, null);
535
536 var fds: [1]posix.pollfd = .{.{ .fd = tfd, .events = linux.POLL.IN, .revents = 0 }};
537 try expectEqual(@as(usize, 1), try posix.poll(&fds, -1)); // -1 => infinite waiting
538
539 const git = try posix.timerfd_gettime(tfd);
540 const expect_disarmed_timer: linux.itimerspec = .{ .it_interval = .{ .sec = 0, .nsec = 0 }, .it_value = .{ .sec = 0, .nsec = 0 } };
541 try expectEqual(expect_disarmed_timer, git);
542}
src/libs/musl.zig-2
...@@ -1830,7 +1830,6 @@ const src_files = [_][]const u8{...@@ -1830,7 +1830,6 @@ const src_files = [_][]const u8{
1830 "musl/src/time/wcsftime.c",1830 "musl/src/time/wcsftime.c",
1831 "musl/src/time/__year_to_secs.c",1831 "musl/src/time/__year_to_secs.c",
1832 "musl/src/unistd/alarm.c",1832 "musl/src/unistd/alarm.c",
1833 "musl/src/unistd/close.c",
1834 "musl/src/unistd/dup2.c",1833 "musl/src/unistd/dup2.c",
1835 "musl/src/unistd/dup3.c",1834 "musl/src/unistd/dup3.c",
1836 "musl/src/unistd/faccessat.c",1835 "musl/src/unistd/faccessat.c",
...@@ -1849,7 +1848,6 @@ const src_files = [_][]const u8{...@@ -1849,7 +1848,6 @@ const src_files = [_][]const u8{
1849 "musl/src/unistd/nice.c",1848 "musl/src/unistd/nice.c",
1850 "musl/src/unistd/pause.c",1849 "musl/src/unistd/pause.c",
1851 "musl/src/unistd/pipe2.c",1850 "musl/src/unistd/pipe2.c",
1852 "musl/src/unistd/posix_close.c",
1853 "musl/src/unistd/pread.c",1851 "musl/src/unistd/pread.c",
1854 "musl/src/unistd/preadv.c",1852 "musl/src/unistd/preadv.c",
1855 "musl/src/unistd/pwrite.c",1853 "musl/src/unistd/pwrite.c",
src/libs/wasi_libc.zig-1
...@@ -999,7 +999,6 @@ const libc_top_half_src_files = [_][]const u8{...@@ -999,7 +999,6 @@ const libc_top_half_src_files = [_][]const u8{
999 "musl/src/time/strptime.c",999 "musl/src/time/strptime.c",
1000 "musl/src/time/timespec_get.c",1000 "musl/src/time/timespec_get.c",
1001 "musl/src/time/__year_to_secs.c",1001 "musl/src/time/__year_to_secs.c",
1002 "musl/src/unistd/posix_close.c",
10031002
1004 "wasi/libc-top-half/musl/src/conf/fpathconf.c",1003 "wasi/libc-top-half/musl/src/conf/fpathconf.c",
1005 "wasi/libc-top-half/musl/src/conf/sysconf.c",1004 "wasi/libc-top-half/musl/src/conf/sysconf.c",