authorgravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2026-05-12 05:14:38-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-10 00:47:09+02:00
log71f6780c98c0f84668385a901bb591d19aa3944d
tree713f57dd6759464f9235e8b1c6ff5e3aba6b54cd
parentf46b6501a2626dae6b6419e904972ab702fab27e

Move netAccept to an Operation


6 files changed, 78 insertions(+), 72 deletions(-)

lib/std/Io.zig+31-2
...@@ -229,7 +229,6 @@ pub const VTable = struct {...@@ -229,7 +229,6 @@ pub const VTable = struct {
229 randomSecure: *const fn (?*anyopaque, buffer: []u8) RandomSecureError!void,229 randomSecure: *const fn (?*anyopaque, buffer: []u8) RandomSecureError!void,
230230
231 netListenIp: *const fn (?*anyopaque, address: *const net.IpAddress, net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Socket,231 netListenIp: *const fn (?*anyopaque, address: *const net.IpAddress, net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Socket,
232 netAccept: *const fn (?*anyopaque, server: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket,
233 netBindIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket,232 netBindIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket,
234 netConnectIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Socket,233 netConnectIp: *const fn (?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Socket,
235 netListenUnix: *const fn (?*anyopaque, *const net.UnixAddress, net.UnixAddress.ListenOptions) net.UnixAddress.ListenError!net.Socket.Handle,234 netListenUnix: *const fn (?*anyopaque, *const net.UnixAddress, net.UnixAddress.ListenOptions) net.UnixAddress.ListenError!net.Socket.Handle,
...@@ -251,6 +250,7 @@ pub const Operation = union(enum) {...@@ -251,6 +250,7 @@ pub const Operation = union(enum) {
251 device_io_control: DeviceIoControl,250 device_io_control: DeviceIoControl,
252 net_receive: NetReceive,251 net_receive: NetReceive,
253 net_send: NetSend,252 net_send: NetSend,
253 net_accept: NetAccept,
254 net_read: NetRead,254 net_read: NetRead,
255 net_write: NetWrite,255 net_write: NetWrite,
256256
...@@ -342,6 +342,35 @@ pub const Operation = union(enum) {...@@ -342,6 +342,35 @@ pub const Operation = union(enum) {
342 },342 },
343 };343 };
344344
345 pub const NetAccept = struct {
346 socket_handle: net.Socket.Handle,
347 options: net.Server.AcceptOptions,
348
349 pub const Error = error{
350 /// The per-process limit on the number of open file descriptors has been reached.
351 ProcessFdQuotaExceeded,
352 /// The system-wide limit on the total number of open files has been reached.
353 SystemFdQuotaExceeded,
354 /// Not enough free memory. This often means that the memory allocation is limited
355 /// by the socket buffer limits, not by the system memory.
356 SystemResources,
357 /// Either `listen` was never called, or `shutdown` was called (possibly while
358 /// this call was blocking). This allows `shutdown` to be used as a concurrent
359 /// cancellation mechanism.
360 SocketNotListening,
361 /// The network subsystem has failed.
362 NetworkDown,
363 /// An incoming connection was indicated, but was subsequently terminated by the
364 /// remote peer prior to accepting the call.
365 ConnectionAborted,
366 /// Firewall rules forbid connection.
367 BlockedByFirewall,
368 ProtocolFailure,
369 } || Io.UnexpectedError;
370
371 pub const Result = Error!net.Socket;
372 };
373
345 pub const NetReceive = struct {374 pub const NetReceive = struct {
346 socket_handle: net.Socket.Handle,375 socket_handle: net.Socket.Handle,
347 message_buffer: []net.IncomingMessage,376 message_buffer: []net.IncomingMessage,
...@@ -2819,7 +2848,6 @@ pub const failing: std.Io = .{...@@ -2819,7 +2848,6 @@ pub const failing: std.Io = .{
2819 .sleep = noSleep,2848 .sleep = noSleep,
28202849
2821 .netListenIp = failingNetListenIp,2850 .netListenIp = failingNetListenIp,
2822 .netAccept = failingNetAccept,
2823 .netBindIp = failingNetBindIp,2851 .netBindIp = failingNetBindIp,
2824 .netConnectIp = failingNetConnectIp,2852 .netConnectIp = failingNetConnectIp,
2825 .netListenUnix = failingNetListenUnix,2853 .netListenUnix = failingNetListenUnix,
...@@ -2972,6 +3000,7 @@ pub fn failingOperate(userdata: ?*anyopaque, operation: Operation) Cancelable!Op...@@ -2972,6 +3000,7 @@ pub fn failingOperate(userdata: ?*anyopaque, operation: Operation) Cancelable!Op
2972 .device_io_control => unreachable,3000 .device_io_control => unreachable,
2973 .net_receive => .{ .net_receive = .{ error.NetworkDown, 0 } },3001 .net_receive => .{ .net_receive = .{ error.NetworkDown, 0 } },
2974 .net_send => .{ .net_send = .{ error.NetworkDown, 0 } },3002 .net_send => .{ .net_send = .{ error.NetworkDown, 0 } },
3003 .net_accept => .{ .net_accept = error.NetworkDown },
2975 .net_read => .{ .net_read = error.NetworkDown },3004 .net_read => .{ .net_read = error.NetworkDown },
2976 .net_write => .{ .net_write = error.NetworkDown },3005 .net_write => .{ .net_write = error.NetworkDown },
2977 };3006 };
lib/std/Io/Dispatch.zig+1-13
...@@ -452,7 +452,6 @@ pub fn io(ev: *Evented) Io {...@@ -452,7 +452,6 @@ pub fn io(ev: *Evented) Io {
452 .randomSecure = randomSecure,452 .randomSecure = randomSecure,
453453
454 .netListenIp = netListenIpUnavailable,454 .netListenIp = netListenIpUnavailable,
455 .netAccept = netAcceptUnavailable,
456 .netBindIp = netBindIpUnavailable,455 .netBindIp = netBindIpUnavailable,
457 .netConnectIp = netConnectIpUnavailable,456 .netConnectIp = netConnectIpUnavailable,
458 .netListenUnix = netListenUnixUnavailable,457 .netListenUnix = netListenUnixUnavailable,
...@@ -1712,6 +1711,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -1712,6 +1711,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
1712 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },1711 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },
1713 .net_receive => @panic("TODO implement net_receive operation"),1712 .net_receive => @panic("TODO implement net_receive operation"),
1714 .net_send => @panic("TODO implement net_send operation"),1713 .net_send => @panic("TODO implement net_send operation"),
1714 .net_accept => @panic("TODO implement net_accept operation"),
1715 .net_read => @panic("TODO implement net_read operation"),1715 .net_read => @panic("TODO implement net_read operation"),
1716 .net_write => @panic("TODO implement net_write operation"),1716 .net_write => @panic("TODO implement net_write operation"),
1717 }1717 }
...@@ -4803,18 +4803,6 @@ fn netListenIpUnavailable(...@@ -4803,18 +4803,6 @@ fn netListenIpUnavailable(
4803 return error.NetworkDown;4803 return error.NetworkDown;
4804}4804}
48054805
4806fn netAcceptUnavailable(
4807 userdata: ?*anyopaque,
4808 listen_handle: net.Socket.Handle,
4809 options: net.Server.AcceptOptions,
4810) net.Server.AcceptError!net.Socket {
4811 const ev: *Evented = @ptrCast(@alignCast(userdata));
4812 _ = ev;
4813 _ = listen_handle;
4814 _ = options;
4815 return error.NetworkDown;
4816}
4817
4818fn netBindIpUnavailable(4806fn netBindIpUnavailable(
4819 userdata: ?*anyopaque,4807 userdata: ?*anyopaque,
4820 address: *const net.IpAddress,4808 address: *const net.IpAddress,
lib/std/Io/Kqueue.zig-8
...@@ -646,7 +646,6 @@ pub fn io(k: *Kqueue) Io {...@@ -646,7 +646,6 @@ pub fn io(k: *Kqueue) Io {
646646
647 .netListenIp = netListenIp,647 .netListenIp = netListenIp,
648 .netListenUnix = netListenUnix,648 .netListenUnix = netListenUnix,
649 .netAccept = netAccept,
650 .netBindIp = netBindIp,649 .netBindIp = netBindIp,
651 .netConnectIp = netConnectIp,650 .netConnectIp = netConnectIp,
652 .netConnectUnix = netConnectUnix,651 .netConnectUnix = netConnectUnix,
...@@ -1008,13 +1007,6 @@ fn netListenIp(...@@ -1008,13 +1007,6 @@ fn netListenIp(
1008 _ = options;1007 _ = options;
1009 @panic("TODO");1008 @panic("TODO");
1010}1009}
1011fn netAccept(userdata: ?*anyopaque, server: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket {
1012 const k: *Kqueue = @ptrCast(@alignCast(userdata));
1013 _ = k;
1014 _ = server;
1015 _ = options;
1016 @panic("TODO");
1017}
1018fn netBindIp(1010fn netBindIp(
1019 userdata: ?*anyopaque,1011 userdata: ?*anyopaque,
1020 address: *const net.IpAddress,1012 address: *const net.IpAddress,
lib/std/Io/Threaded.zig+35-11
...@@ -1969,10 +1969,6 @@ pub fn io(t: *Threaded) Io {...@@ -1969,10 +1969,6 @@ pub fn io(t: *Threaded) Io {
1969 .windows => netListenUnixWindows,1969 .windows => netListenUnixWindows,
1970 else => netListenUnixPosix,1970 else => netListenUnixPosix,
1971 },1971 },
1972 .netAccept = switch (native_os) {
1973 .windows => netAcceptWindows,
1974 else => netAcceptPosix,
1975 },
1976 .netBindIp = switch (native_os) {1972 .netBindIp = switch (native_os) {
1977 .windows => netBindIpWindows,1973 .windows => netBindIpWindows,
1978 else => netBindIpPosix,1974 else => netBindIpPosix,
...@@ -2625,6 +2621,12 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2625,6 +2621,12 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2625 break :o .{ null, sent };2621 break :o .{ null, sent };
2626 },2622 },
2627 },2623 },
2624 .net_accept => |o| return .{
2625 .net_accept = netAccept(t, o.socket_handle, o.options) catch |err| switch (err) {
2626 error.Canceled => |e| return e,
2627 else => |e| e,
2628 },
2629 },
2628 .net_read => |o| return .{2630 .net_read => |o| return .{
2629 .net_read = netRead(o.socket_handle, o.data, o.control) catch |err| switch (err) {2631 .net_read = netRead(o.socket_handle, o.data, o.control) catch |err| switch (err) {
2630 error.Canceled => |e| return e,2632 error.Canceled => |e| return e,
...@@ -2698,6 +2700,14 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {...@@ -2698,6 +2700,14 @@ fn batchAwaitAsync(userdata: ?*anyopaque, b: *Io.Batch) Io.Cancelable!void {
2698 };2700 };
2699 poll_len += 1;2701 poll_len += 1;
2700 },2702 },
2703 .net_accept => |o| {
2704 poll_buffer[poll_len] = .{
2705 .fd = o.socket_handle,
2706 .events = posix.POLL.IN | posix.POLL.ERR,
2707 .revents = 0,
2708 };
2709 poll_len += 1;
2710 },
2701 .net_read => |o| {2711 .net_read => |o| {
2702 poll_buffer[poll_len] = .{2712 poll_buffer[poll_len] = .{
2703 .fd = o.socket_handle,2713 .fd = o.socket_handle,
...@@ -2917,6 +2927,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2917,6 +2927,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2917 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };2927 storage.* = .{ .completion = .{ .node = .{ .next = .none }, .result = result } };
2918 b.completed.tail = index;2928 b.completed.tail = index;
2919 },2929 },
2930 .net_accept => |o| try poll_storage.add(o.socket_handle, posix.POLL.IN | posix.POLL.ERR),
2920 .net_read => |o| try poll_storage.add(o.socket_handle, posix.POLL.IN | posix.POLL.ERR),2931 .net_read => |o| try poll_storage.add(o.socket_handle, posix.POLL.IN | posix.POLL.ERR),
2921 .net_write => |o| try poll_storage.add(o.socket_handle, posix.POLL.OUT | posix.POLL.ERR),2932 .net_write => |o| try poll_storage.add(o.socket_handle, posix.POLL.OUT | posix.POLL.ERR),
2922 }2933 }
...@@ -3115,6 +3126,7 @@ fn batchApc(...@@ -3115,6 +3126,7 @@ fn batchApc(
3115 .device_io_control => .{ .device_io_control = iosb.* },3126 .device_io_control => .{ .device_io_control = iosb.* },
3116 .net_receive => unreachable,3127 .net_receive => unreachable,
3117 .net_send => unreachable,3128 .net_send => unreachable,
3129 .net_accept => unreachable,
3118 .net_read => unreachable,3130 .net_read => unreachable,
3119 .net_write => unreachable,3131 .net_write => unreachable,
3120 };3132 };
...@@ -3332,6 +3344,16 @@ fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io...@@ -3332,6 +3344,16 @@ fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io
3332 .net_send = netSendWindows(t, o.socket_handle, o.messages, o.flags),3344 .net_send = netSendWindows(t, o.socket_handle, o.messages, o.flags),
3333 });3345 });
3334 },3346 },
3347 .net_accept => |o| {
3348 // TODO integrate with overlapped I/O or equivalent to avoid this error
3349 if (concurrency) return error.ConcurrencyUnavailable;
3350 batchCompleteBlockingWindows(b, operation_userdata, .{
3351 .net_accept = netAccept(t, o.socket_handle, o.options) catch |err| switch (err) {
3352 error.Canceled => |e| return e,
3353 else => |e| e,
3354 },
3355 });
3356 },
3335 .net_read => |*o| {3357 .net_read => |*o| {
3336 // TODO integrate with overlapped I/O or equivalent to avoid this error3358 // TODO integrate with overlapped I/O or equivalent to avoid this error
3337 if (concurrency) return error.ConcurrencyUnavailable;3359 if (concurrency) return error.ConcurrencyUnavailable;
...@@ -12813,11 +12835,15 @@ fn bindSocketUnixAfd(socket_handle: net.Socket.Handle, address: *const net.UnixA...@@ -12813,11 +12835,15 @@ fn bindSocketUnixAfd(socket_handle: net.Socket.Handle, address: *const net.UnixA
12813 }12835 }
12814}12836}
1281512837
12816fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket {12838fn netAccept(t: *Threaded, listen_fd: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket {
12817 if (!have_networking) return error.NetworkDown;12839 if (!have_networking) return error.NetworkDown;
12818 const t: *Threaded = @ptrCast(@alignCast(userdata));12840 return if (is_windows)
12819 _ = t;12841 netAcceptWindows(t, listen_fd, options)
12820 options;12842 else
12843 netAcceptPosix(listen_fd);
12844}
12845
12846fn netAcceptPosix(listen_fd: net.Socket.Handle) net.Server.AcceptError!net.Socket {
12821 var storage: PosixAddress = undefined;12847 var storage: PosixAddress = undefined;
12822 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);12848 var addr_len: posix.socklen_t = @sizeOf(PosixAddress);
12823 const syscall: Syscall = try .start();12849 const syscall: Syscall = try .start();
...@@ -12862,9 +12888,7 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle, options:...@@ -12862,9 +12888,7 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: net.Socket.Handle, options:
12862 return .{ .handle = fd, .address = addressFromPosix(&storage) };12888 return .{ .handle = fd, .address = addressFromPosix(&storage) };
12863}12889}
1286412890
12865fn netAcceptWindows(userdata: ?*anyopaque, listen_handle: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket {12891fn netAcceptWindows(t: *Threaded, listen_handle: net.Socket.Handle, options: net.Server.AcceptOptions) net.Server.AcceptError!net.Socket {
12866 if (!have_networking) return error.NetworkDown;
12867 const t: *Threaded = @ptrCast(@alignCast(userdata));
12868 const Storage = extern struct {12892 const Storage = extern struct {
12869 Info: windows.AFD.LISTEN_RESPONSE_INFO,12893 Info: windows.AFD.LISTEN_RESPONSE_INFO,
12870 RemoteAddress: extern union { posix: PosixAddress, unix: UnixAddress },12894 RemoteAddress: extern union { posix: PosixAddress, unix: UnixAddress },
lib/std/Io/Uring.zig+6-13
...@@ -772,7 +772,6 @@ pub fn io(ev: *Evented) Io {...@@ -772,7 +772,6 @@ pub fn io(ev: *Evented) Io {
772 .randomSecure = randomSecure,772 .randomSecure = randomSecure,
773773
774 .netListenIp = netListenIpUnavailable,774 .netListenIp = netListenIpUnavailable,
775 .netAccept = netAcceptUnavailable,
776 .netBindIp = netBindIp,775 .netBindIp = netBindIp,
777 .netConnectIp = netConnectIpUnavailable,776 .netConnectIp = netConnectIpUnavailable,
778 .netListenUnix = netListenUnixUnavailable,777 .netListenUnix = netListenUnixUnavailable,
...@@ -2111,6 +2110,12 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2111,6 +2110,12 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2111 break :r .{ error.NetworkDown, 0 }; // TODO2110 break :r .{ error.NetworkDown, 0 }; // TODO
2112 },2111 },
2113 },2112 },
2113 .net_accept => |o| .{
2114 .net_accept = r: {
2115 _ = o;
2116 break :r error.NetworkDown; // TODO
2117 },
2118 },
2114 .net_read => |o| .{2119 .net_read => |o| .{
2115 .net_read = r: {2120 .net_read = r: {
2116 _ = o;2121 _ = o;
...@@ -4995,18 +5000,6 @@ fn netListenIpUnavailable(...@@ -4995,18 +5000,6 @@ fn netListenIpUnavailable(
4995 return error.NetworkDown;5000 return error.NetworkDown;
4996}5001}
49975002
4998fn netAcceptUnavailable(
4999 userdata: ?*anyopaque,
5000 listen_handle: net.Socket.Handle,
5001 options: net.Server.AcceptOptions,
5002) net.Server.AcceptError!net.Socket {
5003 const ev: *Evented = @ptrCast(@alignCast(userdata));
5004 _ = ev;
5005 _ = listen_handle;
5006 _ = options;
5007 return error.NetworkDown;
5008}
5009
5010fn netBindIp(5003fn netBindIp(
5011 userdata: ?*anyopaque,5004 userdata: ?*anyopaque,
5012 address: *const net.IpAddress,5005 address: *const net.IpAddress,
lib/std/Io/net.zig+5-25
...@@ -1556,30 +1556,7 @@ pub const Server = struct {...@@ -1556,30 +1556,7 @@ pub const Server = struct {
1556 s.* = undefined;1556 s.* = undefined;
1557 }1557 }
15581558
1559 pub const AcceptError = error{1559 pub const AcceptError = Io.Operation.NetAccept.Error || Io.Cancelable;
1560 /// The per-process limit on the number of open file descriptors has been reached.
1561 ProcessFdQuotaExceeded,
1562 /// The system-wide limit on the total number of open files has been reached.
1563 SystemFdQuotaExceeded,
1564 /// Not enough free memory. This often means that the memory allocation is limited
1565 /// by the socket buffer limits, not by the system memory.
1566 SystemResources,
1567 /// Either `listen` was never called, or `shutdown` was called (possibly while
1568 /// this call was blocking). This allows `shutdown` to be used as a concurrent
1569 /// cancellation mechanism.
1570 SocketNotListening,
1571 /// The network subsystem has failed.
1572 NetworkDown,
1573 /// No connection is already queued and ready to be accepted, and
1574 /// the socket is configured as non-blocking.
1575 WouldBlock,
1576 /// An incoming connection was indicated, but was subsequently terminated by the
1577 /// remote peer prior to accepting the call.
1578 ConnectionAborted,
1579 /// Firewall rules forbid connection.
1580 BlockedByFirewall,
1581 ProtocolFailure,
1582 } || Io.UnexpectedError || Io.Cancelable;
15831560
1584 pub const AcceptOptions = switch (native_os) {1561 pub const AcceptOptions = switch (native_os) {
1585 .windows => struct { mode: Socket.Mode, protocol: ?Protocol },1562 .windows => struct { mode: Socket.Mode, protocol: ?Protocol },
...@@ -1588,7 +1565,10 @@ pub const Server = struct {...@@ -1588,7 +1565,10 @@ pub const Server = struct {
15881565
1589 /// Blocks until a client connects to the server.1566 /// Blocks until a client connects to the server.
1590 pub fn accept(s: *Server, io: Io) AcceptError!Stream {1567 pub fn accept(s: *Server, io: Io) AcceptError!Stream {
1591 return .{ .socket = try io.vtable.netAccept(io.userdata, s.socket.handle, s.options) };1568 return .{ .socket = try (try io.operate(.{ .net_accept = .{
1569 .socket_handle = s.socket.handle,
1570 .options = s.options,
1571 } })).net_accept };
1592 }1572 }
1593};1573};
15941574