authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-30 14:30:25+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-30 14:30:25+01:00
logaa38f07c5173f9722ebfb933058a2a032c2badf3
treebc76f81dda9c9031cafa963e8fc723b6e41ce688
parentb9819fce69e0f208e9e20071071a40863fbdb8a9
parent6a3226c43cd63fd331c3f4340d4331a8875138e3

Merge pull request 'add `std.Io.net.Socket.createPair` + handful of `std.posix` removals' (#31056) from std.posix-removals into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31056

10 files changed, 221 insertions(+), 466 deletions(-)

lib/std/Io.zig+1
......@@ -688,6 +688,7 @@ pub const VTable = struct {
688688 netConnectIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Stream,
689689 netListenUnix: *const fn (?*anyopaque, *const net.UnixAddress, net.UnixAddress.ListenOptions) net.UnixAddress.ListenError!net.Socket.Handle,
690690 netConnectUnix: *const fn (?*anyopaque, *const net.UnixAddress) net.UnixAddress.ConnectError!net.Socket.Handle,
691 netSocketCreatePair: *const fn (?*anyopaque, net.Socket.CreatePairOptions) net.Socket.CreatePairError![2]net.Socket,
691692 netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) struct { ?net.Socket.SendError, usize },
692693 netReceive: *const fn (?*anyopaque, net.Socket.Handle, message_buffer: []net.IncomingMessage, data_buffer: []u8, net.ReceiveFlags, Timeout) struct { ?net.Socket.ReceiveTimeoutError, usize },
693694 /// Returns 0 on end of stream.
lib/std/Io/Threaded.zig+127-79
......@@ -1684,6 +1684,7 @@ pub fn io(t: *Threaded) Io {
16841684 .windows => netConnectUnixWindows,
16851685 else => netConnectUnixPosix,
16861686 },
1687 .netSocketCreatePair = netSocketCreatePair,
16871688 .netClose = netClose,
16881689 .netShutdown = switch (native_os) {
16891690 .windows => netShutdownWindows,
......@@ -1824,6 +1825,7 @@ pub fn ioBasic(t: *Threaded) Io {
18241825 .netAccept = netAcceptUnavailable,
18251826 .netBindIp = netBindIpUnavailable,
18261827 .netConnectIp = netConnectIpUnavailable,
1828 .netSocketCreatePair = netSocketCreatePairUnavailable,
18271829 .netConnectUnix = netConnectUnixUnavailable,
18281830 .netClose = netCloseUnavailable,
18291831 .netShutdown = netShutdownUnavailable,
......@@ -10612,43 +10614,36 @@ fn posixConnect(
1061210614 addr_len: posix.socklen_t,
1061310615) !void {
1061410616 const syscall: Syscall = try .start();
10615 while (true) {
10616 switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {
10617 .SUCCESS => {
10618 syscall.finish();
10619 return;
10620 },
10621 .INTR => {
10622 try syscall.checkCancel();
10623 continue;
10624 },
10625 else => |e| {
10626 syscall.finish();
10627 switch (e) {
10628 .ADDRNOTAVAIL => return error.AddressUnavailable,
10629 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
10630 .AGAIN, .INPROGRESS => return error.WouldBlock,
10631 .ALREADY => return error.ConnectionPending,
10632 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
10633 .CONNREFUSED => return error.ConnectionRefused,
10634 .CONNRESET => return error.ConnectionResetByPeer,
10635 .FAULT => |err| return errnoBug(err),
10636 .ISCONN => |err| return errnoBug(err),
10637 .HOSTUNREACH => return error.HostUnreachable,
10638 .NETUNREACH => return error.NetworkUnreachable,
10639 .NOTSOCK => |err| return errnoBug(err),
10640 .PROTOTYPE => |err| return errnoBug(err),
10641 .TIMEDOUT => return error.Timeout,
10642 .CONNABORTED => |err| return errnoBug(err),
10643 .ACCES => return error.AccessDenied,
10644 .PERM => |err| return errnoBug(err),
10645 .NOENT => |err| return errnoBug(err),
10646 .NETDOWN => return error.NetworkDown,
10647 else => |err| return posix.unexpectedErrno(err),
10648 }
10649 },
10650 }
10651 }
10617 while (true) switch (posix.errno(posix.system.connect(socket_fd, addr, addr_len))) {
10618 .SUCCESS => {
10619 syscall.finish();
10620 return;
10621 },
10622 .INTR => {
10623 try syscall.checkCancel();
10624 continue;
10625 },
10626 .ADDRNOTAVAIL => return syscall.fail(error.AddressUnavailable),
10627 .AFNOSUPPORT => return syscall.fail(error.AddressFamilyUnsupported),
10628 .AGAIN, .INPROGRESS => return syscall.fail(error.WouldBlock),
10629 .ALREADY => return syscall.fail(error.ConnectionPending),
10630 .CONNREFUSED => return syscall.fail(error.ConnectionRefused),
10631 .CONNRESET => return syscall.fail(error.ConnectionResetByPeer),
10632 .HOSTUNREACH => return syscall.fail(error.HostUnreachable),
10633 .NETUNREACH => return syscall.fail(error.NetworkUnreachable),
10634 .TIMEDOUT => return syscall.fail(error.Timeout),
10635 .ACCES => return syscall.fail(error.AccessDenied),
10636 .NETDOWN => return syscall.fail(error.NetworkDown),
10637 .BADF => |err| return syscall.errnoBug(err), // File descriptor used after closed.
10638 .CONNABORTED => |err| return syscall.errnoBug(err),
10639 .FAULT => |err| return syscall.errnoBug(err),
10640 .ISCONN => |err| return syscall.errnoBug(err),
10641 .NOENT => |err| return syscall.errnoBug(err),
10642 .NOTSOCK => |err| return syscall.errnoBug(err),
10643 .PERM => |err| return syscall.errnoBug(err),
10644 .PROTOTYPE => |err| return syscall.errnoBug(err),
10645 else => |err| return syscall.unexpectedErrno(err),
10646 };
1065210647}
1065310648
1065410649fn posixConnectUnix(
......@@ -11106,46 +11101,31 @@ fn openSocketPosix(
1110611101}!posix.socket_t {
1110711102 const mode = posixSocketMode(options.mode);
1110811103 const protocol = posixProtocol(options.protocol);
11104 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
1110911105 const syscall: Syscall = try .start();
1111011106 const socket_fd = while (true) {
11111 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
11112 const socket_rc = posix.system.socket(family, flags, protocol);
11113 switch (posix.errno(socket_rc)) {
11107 const rc = posix.system.socket(family, flags, protocol);
11108 switch (posix.errno(rc)) {
1111411109 .SUCCESS => {
11115 const fd: posix.fd_t = @intCast(socket_rc);
11116 errdefer posix.close(fd);
11117 if (socket_flags_unsupported) while (true) {
11118 try syscall.checkCancel();
11119 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
11120 .SUCCESS => break,
11121 .INTR => continue,
11122 else => |err| {
11123 syscall.finish();
11124 return posix.unexpectedErrno(err);
11125 },
11126 }
11127 };
1112811110 syscall.finish();
11111 const fd: posix.fd_t = @intCast(rc);
11112 errdefer posix.close(fd);
11113 if (socket_flags_unsupported) try setCloexec(fd);
1112911114 break fd;
1113011115 },
1113111116 .INTR => {
1113211117 try syscall.checkCancel();
1113311118 continue;
1113411119 },
11135 else => |e| {
11136 syscall.finish();
11137 switch (e) {
11138 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
11139 .INVAL => return error.ProtocolUnsupportedBySystem,
11140 .MFILE => return error.ProcessFdQuotaExceeded,
11141 .NFILE => return error.SystemFdQuotaExceeded,
11142 .NOBUFS => return error.SystemResources,
11143 .NOMEM => return error.SystemResources,
11144 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
11145 .PROTOTYPE => return error.SocketModeUnsupported,
11146 else => |err| return posix.unexpectedErrno(err),
11147 }
11148 },
11120 .AFNOSUPPORT => return syscall.fail(error.AddressFamilyUnsupported),
11121 .INVAL => return syscall.fail(error.ProtocolUnsupportedBySystem),
11122 .MFILE => return syscall.fail(error.ProcessFdQuotaExceeded),
11123 .NFILE => return syscall.fail(error.SystemFdQuotaExceeded),
11124 .NOBUFS => return syscall.fail(error.SystemResources),
11125 .NOMEM => return syscall.fail(error.SystemResources),
11126 .PROTONOSUPPORT => return syscall.fail(error.ProtocolUnsupportedByAddressFamily),
11127 .PROTOTYPE => return syscall.fail(error.SocketModeUnsupported),
11128 else => |err| return syscall.unexpectedErrno(err),
1114911129 }
1115011130 };
1115111131 errdefer posix.close(socket_fd);
......@@ -11158,6 +11138,84 @@ fn openSocketPosix(
1115811138 return socket_fd;
1115911139}
1116011140
11141fn setCloexec(fd: posix.fd_t) error{ Canceled, Unexpected }!void {
11142 const syscall: Syscall = try .start();
11143 while (true) switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
11144 .SUCCESS => return syscall.finish(),
11145 .INTR => {
11146 try syscall.checkCancel();
11147 continue;
11148 },
11149 else => |err| return syscall.unexpectedErrno(err),
11150 };
11151}
11152
11153fn netSocketCreatePair(
11154 userdata: ?*anyopaque,
11155 options: net.Socket.CreatePairOptions,
11156) net.Socket.CreatePairError![2]net.Socket {
11157 const t: *Threaded = @ptrCast(@alignCast(userdata));
11158 _ = t;
11159 if (!have_networking) return error.OperationUnsupported;
11160 if (@TypeOf(posix.system.socketpair) == void) return error.OperationUnsupported;
11161 if (native_os == .haiku) @panic("TODO");
11162
11163 const family: posix.sa_family_t = switch (options.family) {
11164 .ip4 => posix.AF.INET,
11165 .ip6 => posix.AF.INET6,
11166 };
11167 const mode = posixSocketMode(options.mode);
11168 const protocol = posixProtocol(options.protocol);
11169 const flags: u32 = mode | if (socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
11170
11171 var sockets: [2]posix.socket_t = undefined;
11172 const syscall: Syscall = try .start();
11173 while (true) switch (posix.errno(posix.system.socketpair(family, flags, protocol, &sockets))) {
11174 .SUCCESS => {
11175 syscall.finish();
11176 errdefer {
11177 posix.close(sockets[0]);
11178 posix.close(sockets[1]);
11179 }
11180 if (socket_flags_unsupported) {
11181 try setCloexec(sockets[0]);
11182 try setCloexec(sockets[1]);
11183 }
11184 var storages: [2]PosixAddress = undefined;
11185 var addr_lens: [2]posix.socklen_t = .{ @sizeOf(PosixAddress), @sizeOf(PosixAddress) };
11186 try posixGetSockName(sockets[0], &storages[0].any, &addr_lens[0]);
11187 try posixGetSockName(sockets[1], &storages[1].any, &addr_lens[1]);
11188 return .{
11189 .{ .handle = sockets[0], .address = addressFromPosix(&storages[0]) },
11190 .{ .handle = sockets[1], .address = addressFromPosix(&storages[1]) },
11191 };
11192 },
11193 .INTR => {
11194 try syscall.checkCancel();
11195 continue;
11196 },
11197 .ACCES => return syscall.fail(error.AccessDenied),
11198 .AFNOSUPPORT => return syscall.fail(error.AddressFamilyUnsupported),
11199 .INVAL => return syscall.fail(error.ProtocolUnsupportedBySystem),
11200 .MFILE => return syscall.fail(error.ProcessFdQuotaExceeded),
11201 .NFILE => return syscall.fail(error.SystemFdQuotaExceeded),
11202 .NOBUFS => return syscall.fail(error.SystemResources),
11203 .NOMEM => return syscall.fail(error.SystemResources),
11204 .PROTONOSUPPORT => return syscall.fail(error.ProtocolUnsupportedByAddressFamily),
11205 .PROTOTYPE => return syscall.fail(error.SocketModeUnsupported),
11206 else => |err| return syscall.unexpectedErrno(err),
11207 };
11208}
11209
11210fn netSocketCreatePairUnavailable(
11211 userdata: ?*anyopaque,
11212 options: net.Socket.CreatePairOptions,
11213) net.Socket.CreatePairError![2]net.Socket {
11214 _ = userdata;
11215 _ = options;
11216 return error.OperationUnsupported;
11217}
11218
1116111219fn openSocketWsa(
1116211220 t: *Threaded,
1116311221 family: posix.sa_family_t,
......@@ -11216,20 +11274,10 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle) net.Serve
1121611274 posix.system.accept(listen_fd, &storage.any, &addr_len);
1121711275 switch (posix.errno(rc)) {
1121811276 .SUCCESS => {
11277 syscall.finish();
1121911278 const fd: posix.fd_t = @intCast(rc);
1122011279 errdefer posix.close(fd);
11221 if (!have_accept4) while (true) {
11222 try syscall.checkCancel();
11223 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
11224 .SUCCESS => break,
11225 .INTR => continue,
11226 else => |err| {
11227 syscall.finish();
11228 return posix.unexpectedErrno(err);
11229 },
11230 }
11231 };
11232 syscall.finish();
11280 if (!have_accept4) try setCloexec(fd);
1123311281 break fd;
1123411282 },
1123511283 .INTR => {
lib/std/Io/net.zig+29
......@@ -1187,6 +1187,35 @@ pub const Socket = struct {
11871187 ) struct { ?ReceiveTimeoutError, usize } {
11881188 return io.vtable.netReceive(io.userdata, s.handle, message_buffer, data_buffer, flags, timeout);
11891189 }
1190
1191 pub const CreatePairError = error{
1192 OperationUnsupported,
1193 AccessDenied,
1194 AddressFamilyUnsupported,
1195 ProtocolUnsupportedBySystem,
1196 /// The per-process limit on the number of open file descriptors has been reached.
1197 ProcessFdQuotaExceeded,
1198 /// The system-wide limit on the total number of open files has been reached.
1199 SystemFdQuotaExceeded,
1200 /// Insufficient memory is available. The socket cannot be created
1201 /// until sufficient resources are freed.
1202 SystemResources,
1203 ProtocolUnsupportedByAddressFamily,
1204 SocketModeUnsupported,
1205 } || Io.UnexpectedError || Io.Cancelable;
1206
1207 pub const CreatePairOptions = struct {
1208 family: IpAddress.Family = .ip4,
1209 mode: Mode = .stream,
1210 protocol: ?Protocol = null,
1211 };
1212
1213 /// Create a set of two sockets that are connected to each other.
1214 ///
1215 /// Also known as "socketpair".
1216 pub fn createPair(io: Io, options: CreatePairOptions) CreatePairError![2]Socket {
1217 return io.vtable.netSocketCreatePair(io.userdata, options);
1218 }
11901219};
11911220
11921221/// An open socket connection with a network protocol that guarantees
lib/std/Thread.zig+9-6
......@@ -809,12 +809,15 @@ const PosixThreadImpl = struct {
809809 else => {
810810 var count: c_int = undefined;
811811 var count_len: usize = @sizeOf(c_int);
812 const name = if (comptime target.os.tag.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
813 posix.sysctlbynameZ(name, &count, &count_len, null, 0) catch |err| switch (err) {
814 error.UnknownName => unreachable,
815 else => |e| return e,
816 };
817 return @as(usize, @intCast(count));
812 const name = comptime if (target.os.tag.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
813 switch (posix.errno(posix.system.sysctlbyname(name, &count, &count_len, null, 0))) {
814 .SUCCESS => return @intCast(count),
815 .FAULT => unreachable,
816 .PERM => return error.PermissionDenied,
817 .NOMEM => return error.SystemResources,
818 .NOENT => unreachable,
819 else => |err| return posix.unexpectedErrno(err),
820 }
818821 },
819822 }
820823 }
lib/std/os/linux/IoUring/test.zig+12-5
......@@ -1755,7 +1755,7 @@ test "accept multishot" {
17551755 // connect client
17561756 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
17571757 errdefer posix.close(client);
1758 try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1758 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
17591759
17601760 // test accept completion
17611761 var cqe = try ring.copy_cqe();
......@@ -1865,7 +1865,7 @@ test "accept_direct" {
18651865
18661866 // connect
18671867 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1868 try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1868 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
18691869 defer posix.close(client);
18701870
18711871 // accept completion
......@@ -1899,7 +1899,7 @@ test "accept_direct" {
18991899 try testing.expectEqual(@as(u32, 1), try ring.submit());
19001900 // connect
19011901 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1902 try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1902 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
19031903 defer posix.close(client);
19041904 // completion with error
19051905 const cqe_accept = try ring.copy_cqe();
......@@ -1949,7 +1949,7 @@ test "accept_multishot_direct" {
19491949 for (registered_fds) |_| {
19501950 // connect
19511951 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1952 try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1952 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
19531953 defer posix.close(client);
19541954
19551955 // accept completion
......@@ -1964,7 +1964,7 @@ test "accept_multishot_direct" {
19641964 {
19651965 // connect
19661966 const client = try socket(address.family, posix.SOCK.STREAM | posix.SOCK.CLOEXEC, 0);
1967 try posix.connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
1967 try connect(client, addrAny(&address), @sizeOf(linux.sockaddr.in));
19681968 defer posix.close(client);
19691969 // completion with error
19701970 const cqe_accept = try ring.copy_cqe();
......@@ -2734,3 +2734,10 @@ fn send(sockfd: posix.socket_t, buf: []const u8, flags: u32) !usize {
27342734 else => return error.SendFailed,
27352735 }
27362736}
2737
2738fn connect(sock: posix.socket_t, sock_addr: *const posix.sockaddr, len: posix.socklen_t) !void {
2739 switch (posix.errno(posix.system.connect(sock, sock_addr, len))) {
2740 .SUCCESS => return,
2741 else => return error.ConnectFailed,
2742 }
2743}
lib/std/posix.zig+7-347
......@@ -1,27 +1,18 @@
11//! POSIX API layer.
22//!
33//! This is more cross platform than using OS-specific APIs, however, it is
4//! lower-level and less portable than other namespaces such as `std.fs` and
4//! lower-level and less portable than other namespaces such as `std.Io` and
55//! `std.process`.
66//!
77//! These APIs are generally lowered to libc function calls if and only if libc
88//! is linked. Most operating systems other than Windows, Linux, and WASI
99//! require always linking libc because they use it as the stable syscall ABI.
10//!
11//! Operating systems that are not POSIX-compliant are sometimes supported by
12//! this API layer; sometimes not. Generally, an implementation will be
13//! provided only if such implementation is straightforward on that operating
14//! system. Otherwise, programmers are expected to use OS-specific logic to
15//! deal with the exception.
16
1710const builtin = @import("builtin");
1811const native_os = builtin.os.tag;
1912
2013const std = @import("std.zig");
2114const Io = std.Io;
2215const mem = std.mem;
23const fs = std.fs;
24const max_path_bytes = std.fs.max_path_bytes;
2516const maxInt = std.math.maxInt;
2617const cast = std.math.cast;
2718const assert = std.debug.assert;
......@@ -122,15 +113,14 @@ pub const STDIN_FILENO = system.STDIN_FILENO;
122113pub const STDOUT_FILENO = system.STDOUT_FILENO;
123114pub const SYS = system.SYS;
124115pub const Sigaction = system.Sigaction;
116/// Windows has no concept of `stat`.
117///
118/// On Linux, the `stat` bits/wrappers are removed due to having to maintain
119/// the different varying stat structs per target and libc, leading to runtime
120/// errors. Users targeting Linux should add a comptime check and use statx,
121/// similar to how `Io.File.stat` does.
125122pub const Stat = switch (native_os) {
126 // Has no concept of `stat`.
127123 .windows => void,
128 // The `stat` bits/wrappers are removed due to having to maintain the
129 // different varying `struct stat`s per target and libc, leading to runtime
130 // errors.
131 //
132 // Users targeting linux should add a comptime check and use `statx`,
133 // similar to how `std.fs.File.stat` does.
134124 .linux => void,
135125 else => system.Stat,
136126};
......@@ -519,152 +509,6 @@ pub fn getppid() pid_t {
519509 return system.getppid();
520510}
521511
522pub const SocketError = error{
523 /// Permission to create a socket of the specified type and/or
524 /// pro‐tocol is denied.
525 AccessDenied,
526
527 /// The implementation does not support the specified address family.
528 AddressFamilyUnsupported,
529
530 /// Unknown protocol, or protocol family not available.
531 ProtocolFamilyNotAvailable,
532
533 /// The per-process limit on the number of open file descriptors has been reached.
534 ProcessFdQuotaExceeded,
535
536 /// The system-wide limit on the total number of open files has been reached.
537 SystemFdQuotaExceeded,
538
539 /// Insufficient memory is available. The socket cannot be created until sufficient
540 /// resources are freed.
541 SystemResources,
542
543 /// The protocol type or the specified protocol is not supported within this domain.
544 ProtocolNotSupported,
545
546 /// The socket type is not supported by the protocol.
547 SocketTypeNotSupported,
548} || UnexpectedError;
549
550pub fn socketpair(domain: u32, socket_type: u32, protocol: u32) SocketError![2]socket_t {
551 // Note to the future: we could provide a shim here for e.g. windows which
552 // creates a listening socket, then creates a second socket and connects it
553 // to the listening socket, and then returns the two.
554 if (@TypeOf(system.socketpair) == void)
555 @compileError("socketpair() not supported by this OS");
556
557 // I'm not really sure if haiku supports flags here. I'm following the
558 // existing filter here from pipe2(), because it sure seems like it
559 // supports flags there too, but haiku can be hard to understand.
560 const have_sock_flags = !builtin.target.os.tag.isDarwin() and native_os != .haiku;
561 const filtered_sock_type = if (!have_sock_flags)
562 socket_type & ~@as(u32, SOCK.NONBLOCK | SOCK.CLOEXEC)
563 else
564 socket_type;
565 var socks: [2]socket_t = undefined;
566 const rc = system.socketpair(domain, filtered_sock_type, protocol, &socks);
567 switch (errno(rc)) {
568 .SUCCESS => {
569 errdefer close(socks[0]);
570 errdefer close(socks[1]);
571 if (!have_sock_flags) {
572 try setSockFlags(socks[0], socket_type);
573 try setSockFlags(socks[1], socket_type);
574 }
575 return socks;
576 },
577 .ACCES => return error.AccessDenied,
578 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
579 .INVAL => return error.ProtocolFamilyNotAvailable,
580 .MFILE => return error.ProcessFdQuotaExceeded,
581 .NFILE => return error.SystemFdQuotaExceeded,
582 .NOBUFS => return error.SystemResources,
583 .NOMEM => return error.SystemResources,
584 .PROTONOSUPPORT => return error.ProtocolNotSupported,
585 .PROTOTYPE => return error.SocketTypeNotSupported,
586 else => |err| return unexpectedErrno(err),
587 }
588}
589
590fn setSockFlags(sock: socket_t, flags: u32) !void {
591 if ((flags & SOCK.CLOEXEC) != 0) {
592 if (native_os == .windows) {
593 // TODO: Find out if this is supported for sockets
594 } else {
595 var fd_flags = fcntl(sock, F.GETFD, 0) catch |err| switch (err) {
596 error.FileBusy => unreachable,
597 error.Locked => unreachable,
598 error.PermissionDenied => unreachable,
599 error.DeadLock => unreachable,
600 error.LockedRegionLimitExceeded => unreachable,
601 else => |e| return e,
602 };
603 fd_flags |= FD_CLOEXEC;
604 _ = fcntl(sock, F.SETFD, fd_flags) catch |err| switch (err) {
605 error.FileBusy => unreachable,
606 error.Locked => unreachable,
607 error.PermissionDenied => unreachable,
608 error.DeadLock => unreachable,
609 error.LockedRegionLimitExceeded => unreachable,
610 else => |e| return e,
611 };
612 }
613 }
614 if ((flags & SOCK.NONBLOCK) != 0) {
615 if (native_os == .windows) {
616 var mode: c_ulong = 1;
617 if (windows.ws2_32.ioctlsocket(sock, windows.ws2_32.FIONBIO, &mode) == windows.ws2_32.SOCKET_ERROR) {
618 switch (windows.ws2_32.WSAGetLastError()) {
619 .NOTINITIALISED => unreachable,
620 .ENETDOWN => return error.NetworkDown,
621 .ENOTSOCK => return error.FileDescriptorNotASocket,
622 // TODO: handle more errors
623 else => |err| return windows.unexpectedWSAError(err),
624 }
625 }
626 } else {
627 var fl_flags = fcntl(sock, F.GETFL, 0) catch |err| switch (err) {
628 error.FileBusy => unreachable,
629 error.Locked => unreachable,
630 error.PermissionDenied => unreachable,
631 error.DeadLock => unreachable,
632 error.LockedRegionLimitExceeded => unreachable,
633 else => |e| return e,
634 };
635 fl_flags |= 1 << @bitOffsetOf(O, "NONBLOCK");
636 _ = fcntl(sock, F.SETFL, fl_flags) catch |err| switch (err) {
637 error.FileBusy => unreachable,
638 error.Locked => unreachable,
639 error.PermissionDenied => unreachable,
640 error.DeadLock => unreachable,
641 error.LockedRegionLimitExceeded => unreachable,
642 else => |e| return e,
643 };
644 }
645 }
646}
647
648pub const EventFdError = error{
649 SystemResources,
650 ProcessFdQuotaExceeded,
651 SystemFdQuotaExceeded,
652} || UnexpectedError;
653
654pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {
655 const rc = system.eventfd(initval, flags);
656 switch (errno(rc)) {
657 .SUCCESS => return @intCast(rc),
658 else => |err| return unexpectedErrno(err),
659
660 .INVAL => unreachable, // invalid parameters
661 .MFILE => return error.ProcessFdQuotaExceeded,
662 .NFILE => return error.SystemFdQuotaExceeded,
663 .NODEV => return error.SystemResources,
664 .NOMEM => return error.SystemResources,
665 }
666}
667
668512pub const GetSockNameError = error{
669513 /// Insufficient resources were available in the system to perform the operation.
670514 SystemResources,
......@@ -707,123 +551,6 @@ pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
707551 }
708552}
709553
710pub const ConnectError = std.Io.net.IpAddress.ConnectError || std.Io.net.UnixAddress.ConnectError;
711
712pub fn connect(sock: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
713 if (native_os == .windows) {
714 @compileError("use std.Io instead");
715 }
716
717 while (true) {
718 switch (errno(system.connect(sock, sock_addr, len))) {
719 .SUCCESS => return,
720 .ACCES => return error.AccessDenied,
721 .PERM => return error.PermissionDenied,
722 .ADDRNOTAVAIL => return error.AddressUnavailable,
723 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
724 .AGAIN, .INPROGRESS => return error.WouldBlock,
725 .ALREADY => return error.ConnectionPending,
726 .BADF => unreachable, // sockfd is not a valid open file descriptor.
727 .CONNREFUSED => return error.ConnectionRefused,
728 .CONNRESET => return error.ConnectionResetByPeer,
729 .FAULT => unreachable, // The socket structure address is outside the user's address space.
730 .INTR => continue,
731 .ISCONN => @panic("AlreadyConnected"), // The socket is already connected.
732 .HOSTUNREACH => return error.NetworkUnreachable,
733 .NETUNREACH => return error.NetworkUnreachable,
734 .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
735 .PROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
736 .TIMEDOUT => return error.Timeout,
737 .NOENT => return error.FileNotFound, // Returned when socket is AF.UNIX and the given path does not exist.
738 .CONNABORTED => unreachable, // Tried to reuse socket that previously received error.ConnectionRefused.
739 else => |err| return unexpectedErrno(err),
740 }
741 }
742}
743
744pub const FStatError = std.Io.File.StatError;
745
746/// Return information about a file descriptor.
747pub fn fstat(fd: fd_t) FStatError!Stat {
748 if (native_os == .wasi and !builtin.link_libc) {
749 @compileError("unsupported OS");
750 }
751
752 var stat = mem.zeroes(Stat);
753 switch (errno(system.fstat(fd, &stat))) {
754 .SUCCESS => return stat,
755 .INVAL => unreachable,
756 .BADF => unreachable, // Always a race condition.
757 .NOMEM => return error.SystemResources,
758 .ACCES => return error.AccessDenied,
759 else => |err| return unexpectedErrno(err),
760 }
761}
762
763pub const INotifyInitError = error{
764 ProcessFdQuotaExceeded,
765 SystemFdQuotaExceeded,
766 SystemResources,
767} || UnexpectedError;
768
769/// initialize an inotify instance
770pub fn inotify_init1(flags: u32) INotifyInitError!i32 {
771 const rc = system.inotify_init1(flags);
772 switch (errno(rc)) {
773 .SUCCESS => return @intCast(rc),
774 .INVAL => unreachable,
775 .MFILE => return error.ProcessFdQuotaExceeded,
776 .NFILE => return error.SystemFdQuotaExceeded,
777 .NOMEM => return error.SystemResources,
778 else => |err| return unexpectedErrno(err),
779 }
780}
781
782pub const INotifyAddWatchError = error{
783 AccessDenied,
784 NameTooLong,
785 FileNotFound,
786 SystemResources,
787 UserResourceLimitReached,
788 NotDir,
789 WatchAlreadyExists,
790} || UnexpectedError;
791
792/// add a watch to an initialized inotify instance
793pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INotifyAddWatchError!i32 {
794 const pathname_c = try toPosixPath(pathname);
795 return inotify_add_watchZ(inotify_fd, &pathname_c, mask);
796}
797
798/// Same as `inotify_add_watch` except pathname is null-terminated.
799pub fn inotify_add_watchZ(inotify_fd: i32, pathname: [*:0]const u8, mask: u32) INotifyAddWatchError!i32 {
800 const rc = system.inotify_add_watch(inotify_fd, pathname, mask);
801 switch (errno(rc)) {
802 .SUCCESS => return @intCast(rc),
803 .ACCES => return error.AccessDenied,
804 .BADF => unreachable,
805 .FAULT => unreachable,
806 .INVAL => unreachable,
807 .NAMETOOLONG => return error.NameTooLong,
808 .NOENT => return error.FileNotFound,
809 .NOMEM => return error.SystemResources,
810 .NOSPC => return error.UserResourceLimitReached,
811 .NOTDIR => return error.NotDir,
812 .EXIST => return error.WatchAlreadyExists,
813 else => |err| return unexpectedErrno(err),
814 }
815}
816
817/// remove an existing watch from an inotify instance
818pub fn inotify_rm_watch(inotify_fd: i32, wd: i32) void {
819 switch (errno(system.inotify_rm_watch(inotify_fd, wd))) {
820 .SUCCESS => return,
821 .BADF => unreachable,
822 .INVAL => unreachable,
823 else => unreachable,
824 }
825}
826
827554pub const FanotifyInitError = error{
828555 ProcessFdQuotaExceeded,
829556 SystemFdQuotaExceeded,
......@@ -1060,73 +787,6 @@ pub fn sysctl(
1060787 }
1061788}
1062789
1063pub const SysCtlByNameError = error{
1064 PermissionDenied,
1065 SystemResources,
1066 UnknownName,
1067} || UnexpectedError;
1068
1069pub fn sysctlbynameZ(
1070 name: [*:0]const u8,
1071 oldp: ?*anyopaque,
1072 oldlenp: ?*usize,
1073 newp: ?*anyopaque,
1074 newlen: usize,
1075) SysCtlByNameError!void {
1076 if (native_os == .wasi) {
1077 @compileError("sysctl not supported on WASI");
1078 }
1079 if (native_os == .haiku) {
1080 @compileError("sysctl not supported on Haiku");
1081 }
1082
1083 switch (errno(system.sysctlbyname(name, oldp, oldlenp, newp, newlen))) {
1084 .SUCCESS => return,
1085 .FAULT => unreachable,
1086 .PERM => return error.PermissionDenied,
1087 .NOMEM => return error.SystemResources,
1088 .NOENT => return error.UnknownName,
1089 else => |err| return unexpectedErrno(err),
1090 }
1091}
1092
1093pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {
1094 switch (errno(system.gettimeofday(tv, tz))) {
1095 .SUCCESS => return,
1096 .INVAL => unreachable,
1097 else => unreachable,
1098 }
1099}
1100
1101pub const FcntlError = error{
1102 PermissionDenied,
1103 FileBusy,
1104 ProcessFdQuotaExceeded,
1105 Locked,
1106 DeadLock,
1107 LockedRegionLimitExceeded,
1108} || UnexpectedError;
1109
1110pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
1111 while (true) {
1112 const rc = system.fcntl(fd, cmd, arg);
1113 switch (errno(rc)) {
1114 .SUCCESS => return @intCast(rc),
1115 .INTR => continue,
1116 .AGAIN, .ACCES => return error.Locked,
1117 .BADF => unreachable,
1118 .BUSY => return error.FileBusy,
1119 .INVAL => unreachable, // invalid parameters
1120 .PERM => return error.PermissionDenied,
1121 .MFILE => return error.ProcessFdQuotaExceeded,
1122 .NOTDIR => unreachable, // invalid parameter
1123 .DEADLK => return error.DeadLock,
1124 .NOLCK => return error.LockedRegionLimitExceeded,
1125 else => |err| return unexpectedErrno(err),
1126 }
1127 }
1128}
1129
1130790pub fn getSelfPhdrs() []std.elf.ElfN.Phdr {
1131791 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
1132792 assert(getauxval(std.elf.AT_PHENT) == @sizeOf(std.elf.ElfN.Phdr));
lib/std/posix/test.zig+5-5
......@@ -273,17 +273,17 @@ test "fcntl" {
273273
274274 // Note: The test assumes createFile opens the file with CLOEXEC
275275 {
276 const flags = try posix.fcntl(file.handle, posix.F.GETFD, 0);
276 const flags = posix.system.fcntl(file.handle, posix.F.GETFD, @as(usize, 0));
277277 try expect((flags & posix.FD_CLOEXEC) != 0);
278278 }
279279 {
280 _ = try posix.fcntl(file.handle, posix.F.SETFD, 0);
281 const flags = try posix.fcntl(file.handle, posix.F.GETFD, 0);
280 _ = posix.system.fcntl(file.handle, posix.F.SETFD, @as(usize, 0));
281 const flags = posix.system.fcntl(file.handle, posix.F.GETFD, @as(usize, 0));
282282 try expect((flags & posix.FD_CLOEXEC) == 0);
283283 }
284284 {
285 _ = try posix.fcntl(file.handle, posix.F.SETFD, posix.FD_CLOEXEC);
286 const flags = try posix.fcntl(file.handle, posix.F.GETFD, 0);
285 _ = posix.system.fcntl(file.handle, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC));
286 const flags = posix.system.fcntl(file.handle, posix.F.GETFD, @as(usize, 0));
287287 try expect((flags & posix.FD_CLOEXEC) != 0);
288288 }
289289}
lib/std/process.zig+14-12
......@@ -556,26 +556,28 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
556556 const name = if (native_os == .netbsd) "hw.physmem64" else "hw.physmem";
557557 var physmem: c_ulong = undefined;
558558 var len: usize = @sizeOf(c_ulong);
559 posix.sysctlbynameZ(name, &physmem, &len, null, 0) catch |err| switch (err) {
560 error.PermissionDenied => unreachable, // only when setting values,
561 error.SystemResources => unreachable, // memory already on the stack
562 error.UnknownName => unreachable,
559 switch (posix.errno(posix.system.sysctlbyname(name, &physmem, &len, null, 0))) {
560 .SUCCESS => return @intCast(physmem),
561 .FAULT => unreachable,
562 .PERM => unreachable, // only when setting values
563 .NOMEM => unreachable, // memory already on the stack
564 .NOENT => unreachable,
563565 else => return error.UnknownTotalSystemMemory,
564 };
565 return @intCast(physmem);
566 }
566567 },
567568 // whole Darwin family
568569 .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => {
569570 // "hw.memsize" returns uint64_t
570571 var physmem: u64 = undefined;
571572 var len: usize = @sizeOf(u64);
572 posix.sysctlbynameZ("hw.memsize", &physmem, &len, null, 0) catch |err| switch (err) {
573 error.PermissionDenied => unreachable, // only when setting values,
574 error.SystemResources => unreachable, // memory already on the stack
575 error.UnknownName => unreachable, // constant, known good value
573 switch (posix.errno(posix.system.sysctlbyname("hw.memsize", &physmem, &len, null, 0))) {
574 .SUCCESS => return physmem,
575 .FAULT => unreachable,
576 .PERM => unreachable, // only when setting values
577 .NOMEM => unreachable, // memory already on the stack
578 .NOENT => unreachable, // constant, known good value
576579 else => return error.UnknownTotalSystemMemory,
577 };
578 return physmem;
580 }
579581 },
580582 .openbsd => {
581583 const mib: [2]c_int = [_]c_int{
lib/std/zig/system.zig+8-6
......@@ -260,12 +260,14 @@ pub fn resolveTargetQuery(io: Io, query: Target.Query) DetectError!Target {
260260 var value: u32 = undefined;
261261 var len: usize = @sizeOf(@TypeOf(value));
262262
263 posix.sysctlbynameZ(key, &value, &len, null, 0) catch |err| switch (err) {
264 error.PermissionDenied => unreachable, // only when setting values,
265 error.SystemResources => unreachable, // memory already on the stack
266 error.UnknownName => unreachable, // constant, known good value
267 error.Unexpected => return error.OSVersionDetectionFail,
268 };
263 switch (posix.errno(posix.system.sysctlbyname(key, &value, &len, null, 0))) {
264 .SUCCESS => {},
265 .FAULT => unreachable,
266 .PERM => unreachable, // only when setting values,
267 .NOMEM => unreachable, // memory already on the stack
268 .NOENT => unreachable, // constant, known good value
269 else => return error.OSVersionDetectionFail,
270 }
269271
270272 switch (builtin.target.os.tag) {
271273 .freebsd => {
lib/std/zig/system/darwin/macos.zig+9-6
......@@ -2,6 +2,7 @@ const builtin = @import("builtin");
22
33const std = @import("std");
44const Io = std.Io;
5const posix = std.posix;
56const assert = std.debug.assert;
67const mem = std.mem;
78const testing = std.testing;
......@@ -399,12 +400,14 @@ test "detect" {
399400pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
400401 var cpu_family: std.c.CPUFAMILY = undefined;
401402 var len: usize = @sizeOf(std.c.CPUFAMILY);
402 std.posix.sysctlbynameZ("hw.cpufamily", &cpu_family, &len, null, 0) catch |err| switch (err) {
403 error.PermissionDenied => unreachable, // only when setting values,
404 error.SystemResources => unreachable, // memory already on the stack
405 error.UnknownName => unreachable, // constant, known good value
406 error.Unexpected => unreachable, // EFAULT: stack should be safe, EISDIR/ENOTDIR: constant, known good value
407 };
403 switch (posix.errno(posix.system.sysctlbyname("hw.cpufamily", &cpu_family, &len, null, 0))) {
404 .SUCCESS => {},
405 .FAULT => unreachable, // segmentation fault
406 .PERM => unreachable, // only when setting values,
407 .NOMEM => unreachable, // memory already on the stack
408 .NOENT => unreachable, // constant, known good value
409 else => unreachable,
410 }
408411
409412 const current_arch = builtin.cpu.arch;
410413 switch (current_arch) {