authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-13 15:53:19-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:49-07:00
logbe1ae430a1d6dff12c6cd7199dd6504fda880caf
treebee5da42b0dd48fe64d7a749d42ecae54cd11643
parent71ff6e0ef748fbc78cd469317f546c99c0dc5074

std.Io.Threaded.netReadPosix: support cancelation


3 files changed, 86 insertions(+), 36 deletions(-)

lib/std/Io/Threaded.zig+51-6
......@@ -1988,7 +1988,7 @@ fn netAcceptPosix(userdata: ?*anyopaque, listen_fd: Io.net.Socket.Handle) Io.net
19881988
19891989fn netReadPosix(userdata: ?*anyopaque, stream: Io.net.Stream, data: [][]u8) Io.net.Stream.Reader.Error!usize {
19901990 const pool: *Pool = @ptrCast(@alignCast(userdata));
1991 try pool.checkCancel();
1991 const fd = stream.socket.handle;
19921992
19931993 var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined;
19941994 var i: usize = 0;
......@@ -2001,9 +2001,54 @@ fn netReadPosix(userdata: ?*anyopaque, stream: Io.net.Stream, data: [][]u8) Io.n
20012001 }
20022002 const dest = iovecs_buffer[0..i];
20032003 assert(dest[0].len > 0);
2004 const n = try posix.readv(stream.socket.handle, dest);
2005 if (n == 0) return error.EndOfStream;
2006 return n;
2004
2005 if (native_os == .wasi and !builtin.link_libc) while (true) {
2006 try pool.checkCancel();
2007 var n: usize = undefined;
2008 switch (std.os.wasi.fd_read(fd, dest.ptr, dest.len, &n)) {
2009 .SUCCESS => {
2010 if (n == 0) return error.EndOfStream;
2011 return n;
2012 },
2013 .INTR => continue,
2014 .INVAL => |err| return errnoBug(err),
2015 .FAULT => |err| return errnoBug(err),
2016 .AGAIN => |err| return errnoBug(err),
2017 .BADF => |err| return errnoBug(err),
2018 .NOBUFS => return error.SystemResources,
2019 .NOMEM => return error.SystemResources,
2020 .NOTCONN => return error.SocketUnconnected,
2021 .CONNRESET => return error.ConnectionResetByPeer,
2022 .TIMEDOUT => return error.ConnectionTimedOut,
2023 .NOTCAPABLE => return error.AccessDenied,
2024 else => |err| return posix.unexpectedErrno(err),
2025 }
2026 };
2027
2028 while (true) {
2029 try pool.checkCancel();
2030 const rc = posix.system.readv(fd, dest.ptr, @intCast(dest.len));
2031 switch (posix.errno(rc)) {
2032 .SUCCESS => {
2033 const n: usize = @intCast(rc);
2034 if (n == 0) return error.EndOfStream;
2035 return n;
2036 },
2037 .INTR => continue,
2038 .INVAL => |err| return errnoBug(err),
2039 .FAULT => |err| return errnoBug(err),
2040 .AGAIN => |err| return errnoBug(err),
2041 .BADF => |err| return errnoBug(err), // Always a race condition.
2042 .NOBUFS => return error.SystemResources,
2043 .NOMEM => return error.SystemResources,
2044 .NOTCONN => return error.SocketUnconnected,
2045 .CONNRESET => return error.ConnectionResetByPeer,
2046 .TIMEDOUT => return error.ConnectionTimedOut,
2047 .PIPE => return error.BrokenPipe,
2048 .NETDOWN => return error.NetworkDown,
2049 else => |err| return posix.unexpectedErrno(err),
2050 }
2051 }
20072052}
20082053
20092054const have_sendmmsg = builtin.os.tag == .linux;
......@@ -2071,7 +2116,7 @@ fn netSendOne(
20712116 .WSAEHOSTUNREACH => return error.NetworkUnreachable,
20722117 // TODO: WSAEINPROGRESS, WSAEINTR
20732118 .WSAEINVAL => unreachable,
2074 .WSAENETDOWN => return error.NetworkSubsystemFailed,
2119 .WSAENETDOWN => return error.NetworkDown,
20752120 .WSAENETRESET => return error.ConnectionResetByPeer,
20762121 .WSAENETUNREACH => return error.NetworkUnreachable,
20772122 .WSAENOTCONN => return error.SocketUnconnected,
......@@ -2114,7 +2159,7 @@ fn netSendOne(
21142159 .HOSTUNREACH => return error.NetworkUnreachable,
21152160 .NETUNREACH => return error.NetworkUnreachable,
21162161 .NOTCONN => return error.SocketUnconnected,
2117 .NETDOWN => return error.NetworkSubsystemFailed,
2162 .NETDOWN => return error.NetworkDown,
21182163 else => |err| return posix.unexpectedErrno(err),
21192164 }
21202165 }
lib/std/Io/net.zig+11-6
......@@ -1087,13 +1087,18 @@ pub const Stream = struct {
10871087 stream: Stream,
10881088 err: ?Error,
10891089
1090 pub const Error = std.posix.ReadError || error{
1091 SocketNotBound,
1092 MessageTooBig,
1093 NetworkSubsystemFailed,
1090 pub const Error = error{
1091 SystemResources,
1092 BrokenPipe,
10941093 ConnectionResetByPeer,
1094 ConnectionTimedOut,
10951095 SocketUnconnected,
1096 } || Io.Cancelable || Io.Writer.Error || error{EndOfStream};
1096 /// The file descriptor does not hold the required rights to read
1097 /// from it.
1098 AccessDenied,
1099 NetworkDown,
1100 EndOfStream,
1101 } || Io.Cancelable || Io.UnexpectedError;
10971102
10981103 pub fn init(stream: Stream, io: Io, buffer: []u8) Reader {
10991104 return .{
......@@ -1140,7 +1145,7 @@ pub const Stream = struct {
11401145 ConnectionResetByPeer,
11411146 SocketNotBound,
11421147 MessageTooBig,
1143 NetworkSubsystemFailed,
1148 NetworkDown,
11441149 SystemResources,
11451150 SocketUnconnected,
11461151 Unexpected,
lib/std/posix.zig+24-24
......@@ -3613,7 +3613,7 @@ pub const ShutdownError = error{
36133613 BlockingOperationInProgress,
36143614
36153615 /// The network subsystem has failed.
3616 NetworkSubsystemFailed,
3616 NetworkDown,
36173617
36183618 /// The socket is not connected (connection-oriented sockets only).
36193619 SocketUnconnected,
......@@ -3635,7 +3635,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void {
36353635 .WSAECONNRESET => return error.ConnectionResetByPeer,
36363636 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
36373637 .WSAEINVAL => unreachable,
3638 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3638 .WSAENETDOWN => return error.NetworkDown,
36393639 .WSAENOTCONN => return error.SocketUnconnected,
36403640 .WSAENOTSOCK => unreachable,
36413641 .WSANOTINITIALISED => unreachable,
......@@ -3697,7 +3697,7 @@ pub const BindError = error{
36973697 ReadOnlyFileSystem,
36983698
36993699 /// The network subsystem has failed.
3700 NetworkSubsystemFailed,
3700 NetworkDown,
37013701
37023702 FileDescriptorNotASocket,
37033703
......@@ -3718,7 +3718,7 @@ pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!voi
37183718 .WSAEFAULT => unreachable, // invalid pointers
37193719 .WSAEINVAL => return error.AlreadyBound,
37203720 .WSAENOBUFS => return error.SystemResources,
3721 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3721 .WSAENETDOWN => return error.NetworkDown,
37223722 else => |err| return windows.unexpectedWSAError(err),
37233723 }
37243724 unreachable;
......@@ -3763,7 +3763,7 @@ pub const ListenError = error{
37633763 OperationNotSupported,
37643764
37653765 /// The network subsystem has failed.
3766 NetworkSubsystemFailed,
3766 NetworkDown,
37673767
37683768 /// Ran out of system resources
37693769 /// On Windows it can either run out of socket descriptors or buffer space
......@@ -3782,7 +3782,7 @@ pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
37823782 if (rc == windows.ws2_32.SOCKET_ERROR) {
37833783 switch (windows.ws2_32.WSAGetLastError()) {
37843784 .WSANOTINITIALISED => unreachable, // not initialized WSA
3785 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3785 .WSAENETDOWN => return error.NetworkDown,
37863786 .WSAEADDRINUSE => return error.AddressInUse,
37873787 .WSAEISCONN => return error.AlreadyConnected,
37883788 .WSAEINVAL => return error.SocketNotBound,
......@@ -3840,7 +3840,7 @@ pub const AcceptError = error{
38403840 ConnectionResetByPeer,
38413841
38423842 /// The network subsystem has failed.
3843 NetworkSubsystemFailed,
3843 NetworkDown,
38443844
38453845 /// The referenced socket is not a type that supports connection-oriented service.
38463846 OperationNotSupported,
......@@ -3893,7 +3893,7 @@ pub fn accept(
38933893 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
38943894 .WSAEINVAL => return error.SocketNotListening,
38953895 .WSAEMFILE => return error.ProcessFdQuotaExceeded,
3896 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3896 .WSAENETDOWN => return error.NetworkDown,
38973897 .WSAENOBUFS => return error.FileDescriptorNotASocket,
38983898 .WSAEOPNOTSUPP => return error.OperationNotSupported,
38993899 .WSAEWOULDBLOCK => return error.WouldBlock,
......@@ -3964,7 +3964,7 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
39643964 if (windows.ws2_32.ioctlsocket(sock, windows.ws2_32.FIONBIO, &mode) == windows.ws2_32.SOCKET_ERROR) {
39653965 switch (windows.ws2_32.WSAGetLastError()) {
39663966 .WSANOTINITIALISED => unreachable,
3967 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3967 .WSAENETDOWN => return error.NetworkDown,
39683968 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
39693969 // TODO: handle more errors
39703970 else => |err| return windows.unexpectedWSAError(err),
......@@ -4105,7 +4105,7 @@ pub const GetSockNameError = error{
41054105 SystemResources,
41064106
41074107 /// The network subsystem has failed.
4108 NetworkSubsystemFailed,
4108 NetworkDown,
41094109
41104110 /// Socket hasn't been bound yet
41114111 SocketNotBound,
......@@ -4119,7 +4119,7 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
41194119 if (rc == windows.ws2_32.SOCKET_ERROR) {
41204120 switch (windows.ws2_32.WSAGetLastError()) {
41214121 .WSANOTINITIALISED => unreachable,
4122 .WSAENETDOWN => return error.NetworkSubsystemFailed,
4122 .WSAENETDOWN => return error.NetworkDown,
41234123 .WSAEFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value
41244124 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
41254125 .WSAEINVAL => return error.SocketNotBound,
......@@ -4148,7 +4148,7 @@ pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
41484148 if (rc == windows.ws2_32.SOCKET_ERROR) {
41494149 switch (windows.ws2_32.WSAGetLastError()) {
41504150 .WSANOTINITIALISED => unreachable,
4151 .WSAENETDOWN => return error.NetworkSubsystemFailed,
4151 .WSAENETDOWN => return error.NetworkDown,
41524152 .WSAEFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value
41534153 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
41544154 .WSAEINVAL => return error.SocketNotBound,
......@@ -6057,7 +6057,7 @@ pub const SendError = error{
60576057 NetworkUnreachable,
60586058
60596059 /// The local network interface used to reach the destination is down.
6060 NetworkSubsystemFailed,
6060 NetworkDown,
60616061
60626062 /// The destination address is not listening.
60636063 ConnectionRefused,
......@@ -6106,7 +6106,7 @@ pub fn sendmsg(
61066106 .WSAEHOSTUNREACH => return error.NetworkUnreachable,
61076107 // TODO: WSAEINPROGRESS, WSAEINTR
61086108 .WSAEINVAL => unreachable,
6109 .WSAENETDOWN => return error.NetworkSubsystemFailed,
6109 .WSAENETDOWN => return error.NetworkDown,
61106110 .WSAENETRESET => return error.ConnectionResetByPeer,
61116111 .WSAENETUNREACH => return error.NetworkUnreachable,
61126112 .WSAENOTCONN => return error.SocketUnconnected,
......@@ -6146,7 +6146,7 @@ pub fn sendmsg(
61466146 .HOSTUNREACH => return error.NetworkUnreachable,
61476147 .NETUNREACH => return error.NetworkUnreachable,
61486148 .NOTCONN => return error.SocketUnconnected,
6149 .NETDOWN => return error.NetworkSubsystemFailed,
6149 .NETDOWN => return error.NetworkDown,
61506150 else => |err| return unexpectedErrno(err),
61516151 }
61526152 }
......@@ -6209,7 +6209,7 @@ pub fn sendto(
62096209 .WSAEHOSTUNREACH => return error.NetworkUnreachable,
62106210 // TODO: WSAEINPROGRESS, WSAEINTR
62116211 .WSAEINVAL => unreachable,
6212 .WSAENETDOWN => return error.NetworkSubsystemFailed,
6212 .WSAENETDOWN => return error.NetworkDown,
62136213 .WSAENETRESET => return error.ConnectionResetByPeer,
62146214 .WSAENETUNREACH => return error.NetworkUnreachable,
62156215 .WSAENOTCONN => return error.SocketUnconnected,
......@@ -6251,7 +6251,7 @@ pub fn sendto(
62516251 .HOSTUNREACH => return error.NetworkUnreachable,
62526252 .NETUNREACH => return error.NetworkUnreachable,
62536253 .NOTCONN => return error.SocketUnconnected,
6254 .NETDOWN => return error.NetworkSubsystemFailed,
6254 .NETDOWN => return error.NetworkDown,
62556255 else => |err| return unexpectedErrno(err),
62566256 }
62576257 }
......@@ -6390,7 +6390,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
63906390
63916391pub const PollError = error{
63926392 /// The network subsystem has failed.
6393 NetworkSubsystemFailed,
6393 NetworkDown,
63946394
63956395 /// The kernel had no space to allocate file descriptor tables.
63966396 SystemResources,
......@@ -6401,7 +6401,7 @@ pub fn poll(fds: []pollfd, timeout: i32) PollError!usize {
64016401 switch (windows.poll(fds.ptr, @intCast(fds.len), timeout)) {
64026402 windows.ws2_32.SOCKET_ERROR => switch (windows.ws2_32.WSAGetLastError()) {
64036403 .WSANOTINITIALISED => unreachable,
6404 .WSAENETDOWN => return error.NetworkSubsystemFailed,
6404 .WSAENETDOWN => return error.NetworkDown,
64056405 .WSAENOBUFS => return error.SystemResources,
64066406 // TODO: handle more errors
64076407 else => |err| return windows.unexpectedWSAError(err),
......@@ -6473,7 +6473,7 @@ pub const RecvFromError = error{
64736473 MessageTooBig,
64746474
64756475 /// The network subsystem has failed.
6476 NetworkSubsystemFailed,
6476 NetworkDown,
64776477
64786478 /// The socket is not connected (connection-oriented sockets only).
64796479 SocketUnconnected,
......@@ -6504,7 +6504,7 @@ pub fn recvfrom(
65046504 .WSAECONNRESET => return error.ConnectionResetByPeer,
65056505 .WSAEINVAL => return error.SocketNotBound,
65066506 .WSAEMSGSIZE => return error.MessageTooBig,
6507 .WSAENETDOWN => return error.NetworkSubsystemFailed,
6507 .WSAENETDOWN => return error.NetworkDown,
65086508 .WSAENOTCONN => return error.SocketUnconnected,
65096509 .WSAEWOULDBLOCK => return error.WouldBlock,
65106510 .WSAETIMEDOUT => return error.ConnectionTimedOut,
......@@ -6578,7 +6578,7 @@ pub fn recvmsg(
65786578 .PIPE => return error.BrokenPipe,
65796579 .OPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
65806580 .CONNRESET => return error.ConnectionResetByPeer,
6581 .NETDOWN => return error.NetworkSubsystemFailed,
6581 .NETDOWN => return error.NetworkDown,
65826582 else => |err| return unexpectedErrno(err),
65836583 }
65846584 }
......@@ -6601,7 +6601,7 @@ pub const SetSockOptError = error{
66016601 PermissionDenied,
66026602
66036603 OperationNotSupported,
6604 NetworkSubsystemFailed,
6604 NetworkDown,
66056605 FileDescriptorNotASocket,
66066606 SocketNotBound,
66076607 NoDevice,
......@@ -6614,7 +6614,7 @@ pub fn setsockopt(fd: socket_t, level: i32, optname: u32, opt: []const u8) SetSo
66146614 if (rc == windows.ws2_32.SOCKET_ERROR) {
66156615 switch (windows.ws2_32.WSAGetLastError()) {
66166616 .WSANOTINITIALISED => unreachable,
6617 .WSAENETDOWN => return error.NetworkSubsystemFailed,
6617 .WSAENETDOWN => return error.NetworkDown,
66186618 .WSAEFAULT => unreachable,
66196619 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
66206620 .WSAEINVAL => return error.SocketNotBound,