authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-25 17:26:44-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-25 17:26:44-04:00
loga502604702726f3983f8a8b80bb73d9d5381baab
tree575256c4d14b2ffd666d040e076bb082223baf6c
parent288198e51d4b6a0bde8b6beae9dd63f68c55e1eb
parentdc01ef738828a4eba08e95eaaf89442ca2f3e2f8
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6412 from kristoff-it/generalize-event-loop

Make os.zig not depend on the event loop

4 files changed, 425 insertions(+), 229 deletions(-)

lib/std/event/loop.zig+315-101
......@@ -721,6 +721,50 @@ pub const Loop = struct {
721721 }
722722 }
723723
724 /// ------- I/0 APIs -------
725 pub fn accept(
726 self: *Loop,
727 /// This argument is a socket that has been created with `socket`, bound to a local address
728 /// with `bind`, and is listening for connections after a `listen`.
729 sockfd: os.fd_t,
730 /// This argument is a pointer to a sockaddr structure. This structure is filled in with the
731 /// address of the peer socket, as known to the communications layer. The exact format of the
732 /// address returned addr is determined by the socket's address family (see `socket` and the
733 /// respective protocol man pages).
734 addr: *os.sockaddr,
735 /// This argument is a value-result argument: the caller must initialize it to contain the
736 /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size
737 /// of the peer address.
738 ///
739 /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`
740 /// will return a value greater than was supplied to the call.
741 addr_size: *os.socklen_t,
742 /// The following values can be bitwise ORed in flags to obtain different behavior:
743 /// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
744 /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
745 flags: u32,
746 ) os.AcceptError!os.fd_t {
747 while (true) {
748 return os.accept(sockfd, addr, addr_size, flags | os.SOCK_NONBLOCK) catch |err| switch (err) {
749 error.WouldBlock => {
750 self.waitUntilFdReadable(sockfd);
751 continue;
752 },
753 else => return err,
754 };
755 }
756 }
757
758 pub fn connect(self: *Loop, sockfd: os.socket_t, sock_addr: *const os.sockaddr, len: os.socklen_t) os.ConnectError!void {
759 os.connect(sockfd, sock_addr, len) catch |err| switch (err) {
760 error.WouldBlock => {
761 self.waitUntilFdWritable(sockfd);
762 return os.getsockoptError(sockfd);
763 },
764 else => return err,
765 };
766 }
767
724768 /// Performs an async `os.open` using a separate thread.
725769 pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t {
726770 var req_node = Request.Node{
......@@ -779,152 +823,309 @@ pub const Loop = struct {
779823
780824 /// Performs an async `os.read` using a separate thread.
781825 /// `fd` must block and not return EAGAIN.
782 pub fn read(self: *Loop, fd: os.fd_t, buf: []u8) os.ReadError!usize {
783 var req_node = Request.Node{
784 .data = .{
785 .msg = .{
786 .read = .{
787 .fd = fd,
788 .buf = buf,
789 .result = undefined,
826 pub fn read(self: *Loop, fd: os.fd_t, buf: []u8, simulate_evented: bool) os.ReadError!usize {
827 if (simulate_evented) {
828 var req_node = Request.Node{
829 .data = .{
830 .msg = .{
831 .read = .{
832 .fd = fd,
833 .buf = buf,
834 .result = undefined,
835 },
790836 },
837 .finish = .{ .TickNode = .{ .data = @frame() } },
791838 },
792 .finish = .{ .TickNode = .{ .data = @frame() } },
793 },
794 };
795 suspend {
796 self.posixFsRequest(&req_node);
839 };
840 suspend {
841 self.posixFsRequest(&req_node);
842 }
843 return req_node.data.msg.read.result;
844 } else {
845 while (true) {
846 return os.read(fd, buf) catch |err| switch (err) {
847 error.WouldBlock => {
848 self.waitUntilFdReadable(fd);
849 continue;
850 },
851 else => return err,
852 };
853 }
797854 }
798 return req_node.data.msg.read.result;
799855 }
800856
801857 /// Performs an async `os.readv` using a separate thread.
802858 /// `fd` must block and not return EAGAIN.
803 pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec) os.ReadError!usize {
804 var req_node = Request.Node{
805 .data = .{
806 .msg = .{
807 .readv = .{
808 .fd = fd,
809 .iov = iov,
810 .result = undefined,
859 pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, simulate_evented: bool) os.ReadError!usize {
860 if (simulate_evented) {
861 var req_node = Request.Node{
862 .data = .{
863 .msg = .{
864 .readv = .{
865 .fd = fd,
866 .iov = iov,
867 .result = undefined,
868 },
811869 },
870 .finish = .{ .TickNode = .{ .data = @frame() } },
812871 },
813 .finish = .{ .TickNode = .{ .data = @frame() } },
814 },
815 };
816 suspend {
817 self.posixFsRequest(&req_node);
872 };
873 suspend {
874 self.posixFsRequest(&req_node);
875 }
876 return req_node.data.msg.readv.result;
877 } else {
878 while (true) {
879 return os.readv(fd, iov) catch |err| switch (err) {
880 error.WouldBlock => {
881 self.waitUntilFdReadable(fd);
882 continue;
883 },
884 else => return err,
885 };
886 }
818887 }
819 return req_node.data.msg.readv.result;
820888 }
821889
822890 /// Performs an async `os.pread` using a separate thread.
823891 /// `fd` must block and not return EAGAIN.
824 pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64) os.PReadError!usize {
825 var req_node = Request.Node{
826 .data = .{
827 .msg = .{
828 .pread = .{
829 .fd = fd,
830 .buf = buf,
831 .offset = offset,
832 .result = undefined,
892 pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64, simulate_evented: bool) os.PReadError!usize {
893 if (simulate_evented) {
894 var req_node = Request.Node{
895 .data = .{
896 .msg = .{
897 .pread = .{
898 .fd = fd,
899 .buf = buf,
900 .offset = offset,
901 .result = undefined,
902 },
833903 },
904 .finish = .{ .TickNode = .{ .data = @frame() } },
834905 },
835 .finish = .{ .TickNode = .{ .data = @frame() } },
836 },
837 };
838 suspend {
839 self.posixFsRequest(&req_node);
906 };
907 suspend {
908 self.posixFsRequest(&req_node);
909 }
910 return req_node.data.msg.pread.result;
911 } else {
912 while (true) {
913 return os.pread(fd, buf, offset) catch |err| switch (err) {
914 error.WouldBlock => {
915 self.waitUntilFdReadable(fd);
916 continue;
917 },
918 else => return err,
919 };
920 }
840921 }
841 return req_node.data.msg.pread.result;
842922 }
843923
844924 /// Performs an async `os.preadv` using a separate thread.
845925 /// `fd` must block and not return EAGAIN.
846 pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64) os.ReadError!usize {
847 var req_node = Request.Node{
848 .data = .{
849 .msg = .{
850 .preadv = .{
851 .fd = fd,
852 .iov = iov,
853 .offset = offset,
854 .result = undefined,
926 pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64, simulate_evented: bool) os.ReadError!usize {
927 if (simulate_evented) {
928 var req_node = Request.Node{
929 .data = .{
930 .msg = .{
931 .preadv = .{
932 .fd = fd,
933 .iov = iov,
934 .offset = offset,
935 .result = undefined,
936 },
855937 },
938 .finish = .{ .TickNode = .{ .data = @frame() } },
856939 },
857 .finish = .{ .TickNode = .{ .data = @frame() } },
858 },
859 };
860 suspend {
861 self.posixFsRequest(&req_node);
940 };
941 suspend {
942 self.posixFsRequest(&req_node);
943 }
944 return req_node.data.msg.preadv.result;
945 } else {
946 while (true) {
947 return os.preadv(fd, iov, offset) catch |err| switch (err) {
948 error.WouldBlock => {
949 self.waitUntilFdReadable(fd);
950 continue;
951 },
952 else => return err,
953 };
954 }
862955 }
863 return req_node.data.msg.preadv.result;
864956 }
865957
866958 /// Performs an async `os.write` using a separate thread.
867959 /// `fd` must block and not return EAGAIN.
868 pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8) os.WriteError!usize {
869 var req_node = Request.Node{
870 .data = .{
871 .msg = .{
872 .write = .{
873 .fd = fd,
874 .bytes = bytes,
875 .result = undefined,
960 pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8, simulate_evented: bool) os.WriteError!usize {
961 if (simulate_evented) {
962 var req_node = Request.Node{
963 .data = .{
964 .msg = .{
965 .write = .{
966 .fd = fd,
967 .bytes = bytes,
968 .result = undefined,
969 },
876970 },
971 .finish = .{ .TickNode = .{ .data = @frame() } },
877972 },
878 .finish = .{ .TickNode = .{ .data = @frame() } },
879 },
880 };
881 suspend {
882 self.posixFsRequest(&req_node);
973 };
974 suspend {
975 self.posixFsRequest(&req_node);
976 }
977 return req_node.data.msg.write.result;
978 } else {
979 while (true) {
980 return os.write(fd, bytes) catch |err| switch (err) {
981 error.WouldBlock => {
982 self.waitUntilFdWritable(fd);
983 continue;
984 },
985 else => return err,
986 };
987 }
883988 }
884 return req_node.data.msg.write.result;
885989 }
886990
887991 /// Performs an async `os.writev` using a separate thread.
888992 /// `fd` must block and not return EAGAIN.
889 pub fn writev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const) os.WriteError!usize {
890 var req_node = Request.Node{
891 .data = .{
892 .msg = .{
893 .writev = .{
894 .fd = fd,
895 .iov = iov,
896 .result = undefined,
993 pub fn writev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, simulate_evented: bool) os.WriteError!usize {
994 if (simulate_evented) {
995 var req_node = Request.Node{
996 .data = .{
997 .msg = .{
998 .writev = .{
999 .fd = fd,
1000 .iov = iov,
1001 .result = undefined,
1002 },
8971003 },
1004 .finish = .{ .TickNode = .{ .data = @frame() } },
8981005 },
899 .finish = .{ .TickNode = .{ .data = @frame() } },
900 },
901 };
902 suspend {
903 self.posixFsRequest(&req_node);
1006 };
1007 suspend {
1008 self.posixFsRequest(&req_node);
1009 }
1010 return req_node.data.msg.writev.result;
1011 } else {
1012 while (true) {
1013 return os.writev(fd, iov) catch |err| switch (err) {
1014 error.WouldBlock => {
1015 self.waitUntilFdWritable(fd);
1016 continue;
1017 },
1018 else => return err,
1019 };
1020 }
1021 }
1022 }
1023
1024 /// Performs an async `os.pwrite` using a separate thread.
1025 /// `fd` must block and not return EAGAIN.
1026 pub fn pwrite(self: *Loop, fd: os.fd_t, bytes: []const u8, offset: u64, simulate_evented: bool) os.PerformsWriteError!usize {
1027 if (simulate_evented) {
1028 var req_node = Request.Node{
1029 .data = .{
1030 .msg = .{
1031 .pwrite = .{
1032 .fd = fd,
1033 .bytes = bytes,
1034 .offset = offset,
1035 .result = undefined,
1036 },
1037 },
1038 .finish = .{ .TickNode = .{ .data = @frame() } },
1039 },
1040 };
1041 suspend {
1042 self.posixFsRequest(&req_node);
1043 }
1044 return req_node.data.msg.pwrite.result;
1045 } else {
1046 while (true) {
1047 return os.pwrite(fd, bytes, offset) catch |err| switch (err) {
1048 error.WouldBlock => {
1049 self.waitUntilFdWritable(fd);
1050 continue;
1051 },
1052 else => return err,
1053 };
1054 }
9041055 }
905 return req_node.data.msg.writev.result;
9061056 }
9071057
9081058 /// Performs an async `os.pwritev` using a separate thread.
9091059 /// `fd` must block and not return EAGAIN.
910 pub fn pwritev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, offset: u64) os.WriteError!usize {
911 var req_node = Request.Node{
912 .data = .{
913 .msg = .{
914 .pwritev = .{
915 .fd = fd,
916 .iov = iov,
917 .offset = offset,
918 .result = undefined,
1060 pub fn pwritev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, offset: u64, simulate_evented: bool) os.PWriteError!usize {
1061 if (simulate_evented) {
1062 var req_node = Request.Node{
1063 .data = .{
1064 .msg = .{
1065 .pwritev = .{
1066 .fd = fd,
1067 .iov = iov,
1068 .offset = offset,
1069 .result = undefined,
1070 },
9191071 },
1072 .finish = .{ .TickNode = .{ .data = @frame() } },
9201073 },
921 .finish = .{ .TickNode = .{ .data = @frame() } },
922 },
923 };
924 suspend {
925 self.posixFsRequest(&req_node);
1074 };
1075 suspend {
1076 self.posixFsRequest(&req_node);
1077 }
1078 return req_node.data.msg.pwritev.result;
1079 } else {
1080 while (true) {
1081 return os.pwritev(fd, iov, offset) catch |err| switch (err) {
1082 error.WouldBlock => {
1083 self.waitUntilFdWritable(fd);
1084 continue;
1085 },
1086 else => return err,
1087 };
1088 }
1089 }
1090 }
1091
1092 pub fn sendto(
1093 self: *Loop,
1094 /// The file descriptor of the sending socket.
1095 sockfd: os.fd_t,
1096 /// Message to send.
1097 buf: []const u8,
1098 flags: u32,
1099 dest_addr: ?*const os.sockaddr,
1100 addrlen: os.socklen_t,
1101 ) os.SendError!usize {
1102 while (true) {
1103 return os.sendto(sockfd, buf, flags, dest_addr, addrlen) catch |err| switch (err) {
1104 error.WouldBlock => {
1105 self.waitUntilFdWritable(sockfd);
1106 continue;
1107 },
1108 else => return err,
1109 };
1110 }
1111 }
1112
1113 pub fn recvfrom(
1114 sockfd: os.fd_t,
1115 buf: []u8,
1116 flags: u32,
1117 src_addr: ?*os.sockaddr,
1118 addrlen: ?*os.socklen_t,
1119 ) os.RecvFromError!usize {
1120 while (true) {
1121 return os.recvfrom(sockfd, buf, flags, src_addr, addrlen) catch |err| switch (err) {
1122 error.WouldBlock => {
1123 self.waitUntilFdReadable(sockfd);
1124 continue;
1125 },
1126 else => return err,
1127 };
9261128 }
927 return req_node.data.msg.pwritev.result;
9281129 }
9291130
9301131 /// Performs an async `os.faccessatZ` using a separate thread.
......@@ -1079,6 +1280,9 @@ pub const Loop = struct {
10791280 .writev => |*msg| {
10801281 msg.result = os.writev(msg.fd, msg.iov);
10811282 },
1283 .pwrite => |*msg| {
1284 msg.result = os.pwrite(msg.fd, msg.bytes, msg.offset);
1285 },
10821286 .pwritev => |*msg| {
10831287 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
10841288 },
......@@ -1148,6 +1352,7 @@ pub const Loop = struct {
11481352 readv: ReadV,
11491353 write: Write,
11501354 writev: WriteV,
1355 pwrite: PWrite,
11511356 pwritev: PWriteV,
11521357 pread: PRead,
11531358 preadv: PReadV,
......@@ -1191,6 +1396,15 @@ pub const Loop = struct {
11911396 pub const Error = os.WriteError;
11921397 };
11931398
1399 pub const PWrite = struct {
1400 fd: os.fd_t,
1401 bytes: []const u8,
1402 offset: usize,
1403 result: Error!usize,
1404
1405 pub const Error = os.PWriteError;
1406 };
1407
11941408 pub const PWriteV = struct {
11951409 fd: os.fd_t,
11961410 iov: []const os.iovec_const,
lib/std/fs/file.zig+40-24
......@@ -414,10 +414,12 @@ pub const File = struct {
414414 pub fn read(self: File, buffer: []u8) ReadError!usize {
415415 if (is_windows) {
416416 return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode);
417 } else if (self.capable_io_mode != self.intended_io_mode) {
418 return std.event.Loop.instance.?.read(self.handle, buffer);
419 } else {
417 }
418
419 if (self.intended_io_mode == .blocking) {
420420 return os.read(self.handle, buffer);
421 } else {
422 return std.event.Loop.instance.?.read(self.handle, buffer, self.capable_io_mode != self.intended_io_mode);
421423 }
422424 }
423425
......@@ -436,10 +438,12 @@ pub const File = struct {
436438 pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
437439 if (is_windows) {
438440 return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode);
439 } else if (self.capable_io_mode != self.intended_io_mode) {
440 return std.event.Loop.instance.?.pread(self.handle, buffer, offset);
441 } else {
441 }
442
443 if (self.intended_io_mode == .blocking) {
442444 return os.pread(self.handle, buffer, offset);
445 } else {
446 return std.event.Loop.instance.?.pread(self.handle, buffer, offset, self.capable_io_mode != self.intended_io_mode);
443447 }
444448 }
445449
......@@ -461,10 +465,12 @@ pub const File = struct {
461465 if (iovecs.len == 0) return @as(usize, 0);
462466 const first = iovecs[0];
463467 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
464 } else if (self.capable_io_mode != self.intended_io_mode) {
465 return std.event.Loop.instance.?.readv(self.handle, iovecs);
466 } else {
468 }
469
470 if (self.intended_io_mode == .blocking) {
467471 return os.readv(self.handle, iovecs);
472 } else {
473 return std.event.Loop.instance.?.readv(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode);
468474 }
469475 }
470476
......@@ -500,10 +506,12 @@ pub const File = struct {
500506 if (iovecs.len == 0) return @as(usize, 0);
501507 const first = iovecs[0];
502508 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
503 } else if (self.capable_io_mode != self.intended_io_mode) {
504 return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset);
505 } else {
509 }
510
511 if (self.intended_io_mode == .blocking) {
506512 return os.preadv(self.handle, iovecs, offset);
513 } else {
514 return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode);
507515 }
508516 }
509517
......@@ -539,10 +547,12 @@ pub const File = struct {
539547 pub fn write(self: File, bytes: []const u8) WriteError!usize {
540548 if (is_windows) {
541549 return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode);
542 } else if (self.capable_io_mode != self.intended_io_mode) {
543 return std.event.Loop.instance.?.write(self.handle, bytes);
544 } else {
550 }
551
552 if (self.intended_io_mode == .blocking) {
545553 return os.write(self.handle, bytes);
554 } else {
555 return std.event.Loop.instance.?.write(self.handle, bytes, self.capable_io_mode != self.intended_io_mode);
546556 }
547557 }
548558
......@@ -556,10 +566,12 @@ pub const File = struct {
556566 pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
557567 if (is_windows) {
558568 return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode);
559 } else if (self.capable_io_mode != self.intended_io_mode) {
560 return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset);
561 } else {
569 }
570
571 if (self.intended_io_mode == .blocking) {
562572 return os.pwrite(self.handle, bytes, offset);
573 } else {
574 return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset, self.capable_io_mode != self.intended_io_mode);
563575 }
564576 }
565577
......@@ -576,10 +588,12 @@ pub const File = struct {
576588 if (iovecs.len == 0) return @as(usize, 0);
577589 const first = iovecs[0];
578590 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);
579 } else if (self.capable_io_mode != self.intended_io_mode) {
580 return std.event.Loop.instance.?.writev(self.handle, iovecs);
581 } else {
591 }
592
593 if (self.intended_io_mode == .blocking) {
582594 return os.writev(self.handle, iovecs);
595 } else {
596 return std.event.Loop.instance.?.writev(self.handle, iovecs, self.capable_io_mode != self.intended_io_mode);
583597 }
584598 }
585599
......@@ -607,10 +621,12 @@ pub const File = struct {
607621 if (iovecs.len == 0) return @as(usize, 0);
608622 const first = iovecs[0];
609623 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);
610 } else if (self.capable_io_mode != self.intended_io_mode) {
611 return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset);
612 } else {
624 }
625
626 if (self.intended_io_mode == .blocking) {
613627 return os.pwritev(self.handle, iovecs, offset);
628 } else {
629 return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset, self.capable_io_mode != self.intended_io_mode);
614630 }
615631 }
616632
lib/std/net.zig+36-14
......@@ -614,11 +614,11 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
614614
615615 var addr = try std.net.Address.initUnix(path);
616616
617 try os.connect(
618 sockfd,
619 &addr.any,
620 addr.getOsSockLen(),
621 );
617 if (std.io.is_async) {
618 try loop.connect(sockfd, &addr.any, addr.getOsSockLen());
619 } else {
620 try os.connect(sockfd, &addr.any, addr.getOsSockLen());
621 }
622622
623623 return fs.File{
624624 .handle = sockfd,
......@@ -677,7 +677,13 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
677677 (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
678678 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
679679 errdefer os.close(sockfd);
680 try os.connect(sockfd, &address.any, address.getOsSockLen());
680
681 if (std.io.is_async) {
682 const loop = std.event.Loop.instance orelse return error.WouldBlock;
683 try loop.connect(sockfd, &address.any, address.getOsSockLen());
684 } else {
685 try os.connect(sockfd, &address.any, address.getOsSockLen());
686 }
681687
682688 return fs.File{ .handle = sockfd };
683689}
......@@ -1429,7 +1435,11 @@ fn resMSendRc(
14291435 if (answers[i].len == 0) {
14301436 var j: usize = 0;
14311437 while (j < ns.len) : (j += 1) {
1432 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1438 if (std.io.is_async) {
1439 _ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1440 } else {
1441 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1442 }
14331443 }
14341444 }
14351445 }
......@@ -1444,7 +1454,10 @@ fn resMSendRc(
14441454
14451455 while (true) {
14461456 var sl_copy = sl;
1447 const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
1457 const rlen = if (std.io.is_async)
1458 std.event.Loop.instance.?.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break
1459 else
1460 os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
14481461
14491462 // Ignore non-identifiable packets
14501463 if (rlen < 4) continue;
......@@ -1470,7 +1483,11 @@ fn resMSendRc(
14701483 0, 3 => {},
14711484 2 => if (servfail_retry != 0) {
14721485 servfail_retry -= 1;
1473 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1486 if (std.io.is_async) {
1487 _ = std.event.Loop.instance.?.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1488 } else {
1489 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1490 }
14741491 },
14751492 else => continue,
14761493 }
......@@ -1661,18 +1678,23 @@ pub const StreamServer = struct {
16611678
16621679 /// If this function succeeds, the returned `Connection` is a caller-managed resource.
16631680 pub fn accept(self: *StreamServer) AcceptError!Connection {
1664 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
1665 const accept_flags = nonblock | os.SOCK_CLOEXEC;
16661681 var accepted_addr: Address = undefined;
16671682 var adr_len: os.socklen_t = @sizeOf(Address);
1668 if (os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
1683 const accept_result = blk: {
1684 if (std.io.is_async) {
1685 const loop = std.event.Loop.instance orelse return error.UnexpectedError;
1686 break :blk loop.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
1687 } else {
1688 break :blk os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, os.SOCK_CLOEXEC);
1689 }
1690 };
1691
1692 if (accept_result) |fd| {
16691693 return Connection{
16701694 .file = fs.File{ .handle = fd },
16711695 .address = accepted_addr,
16721696 };
16731697 } else |err| switch (err) {
1674 // We only give SOCK_NONBLOCK when I/O mode is async, in which case this error
1675 // is handled by os.accept4.
16761698 error.WouldBlock => unreachable,
16771699 else => |e| return e,
16781700 }
lib/std/os.zig+34-90
......@@ -314,8 +314,8 @@ pub const ReadError = error{
314314
315315/// Returns the number of bytes that were read, which can be less than
316316/// buf.len. If 0 bytes were read, that means EOF.
317/// If the application has a global event loop enabled, EAGAIN is handled
318/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
317/// If `fd` is opened in non blocking mode, the function will return error.WouldBlock
318/// when EAGAIN is received.
319319///
320320/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`
321321/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
......@@ -366,12 +366,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
366366 EINTR => continue,
367367 EINVAL => unreachable,
368368 EFAULT => unreachable,
369 EAGAIN => if (std.event.Loop.instance) |loop| {
370 loop.waitUntilFdReadable(fd);
371 continue;
372 } else {
373 return error.WouldBlock;
374 },
369 EAGAIN => return error.WouldBlock,
375370 EBADF => return error.NotOpenForReading, // Can be a race condition.
376371 EIO => return error.InputOutput,
377372 EISDIR => return error.IsDir,
......@@ -387,8 +382,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
387382
388383/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
389384///
390/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
391/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
385/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
386/// return error.WouldBlock when EAGAIN is received.
392387/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
393388/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
394389///
......@@ -428,12 +423,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
428423 EINTR => continue,
429424 EINVAL => unreachable,
430425 EFAULT => unreachable,
431 EAGAIN => if (std.event.Loop.instance) |loop| {
432 loop.waitUntilFdReadable(fd);
433 continue;
434 } else {
435 return error.WouldBlock;
436 },
426 EAGAIN => return error.WouldBlock,
437427 EBADF => return error.NotOpenForReading, // can be a race condition
438428 EIO => return error.InputOutput,
439429 EISDIR => return error.IsDir,
......@@ -450,8 +440,8 @@ pub const PReadError = ReadError || error{Unseekable};
450440///
451441/// Retries when interrupted by a signal.
452442///
453/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
454/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
443/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
444/// return error.WouldBlock when EAGAIN is received.
455445/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
456446/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
457447pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
......@@ -492,12 +482,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
492482 EINTR => continue,
493483 EINVAL => unreachable,
494484 EFAULT => unreachable,
495 EAGAIN => if (std.event.Loop.instance) |loop| {
496 loop.waitUntilFdReadable(fd);
497 continue;
498 } else {
499 return error.WouldBlock;
500 },
485 EAGAIN => return error.WouldBlock,
501486 EBADF => return error.NotOpenForReading, // Can be a race condition.
502487 EIO => return error.InputOutput,
503488 EISDIR => return error.IsDir,
......@@ -586,8 +571,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
586571///
587572/// Retries when interrupted by a signal.
588573///
589/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
590/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
574/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
575/// return error.WouldBlock when EAGAIN is received.
591576/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
592577/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
593578///
......@@ -637,12 +622,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
637622 EINTR => continue,
638623 EINVAL => unreachable,
639624 EFAULT => unreachable,
640 EAGAIN => if (std.event.Loop.instance) |loop| {
641 loop.waitUntilFdReadable(fd);
642 continue;
643 } else {
644 return error.WouldBlock;
645 },
625 EAGAIN => return error.WouldBlock,
646626 EBADF => return error.NotOpenForReading, // can be a race condition
647627 EIO => return error.InputOutput,
648628 EISDIR => return error.IsDir,
......@@ -687,8 +667,8 @@ pub const WriteError = error{
687667/// another write() call to transfer the remaining bytes. The subsequent call will either
688668/// transfer further bytes or may result in an error (e.g., if the disk is now full).
689669///
690/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
691/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
670/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
671/// return error.WouldBlock when EAGAIN is received.
692672/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
693673/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
694674///
......@@ -741,12 +721,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
741721 EINTR => continue,
742722 EINVAL => unreachable,
743723 EFAULT => unreachable,
744 EAGAIN => if (std.event.Loop.instance) |loop| {
745 loop.waitUntilFdWritable(fd);
746 continue;
747 } else {
748 return error.WouldBlock;
749 },
724 EAGAIN => return error.WouldBlock,
750725 EBADF => return error.NotOpenForWriting, // can be a race condition.
751726 EDESTADDRREQ => unreachable, // `connect` was never called.
752727 EDQUOT => return error.DiskQuota,
......@@ -772,8 +747,8 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
772747/// another write() call to transfer the remaining bytes. The subsequent call will either
773748/// transfer further bytes or may result in an error (e.g., if the disk is now full).
774749///
775/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
776/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
750/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
751/// return error.WouldBlock when EAGAIN is received.k`.
777752/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
778753/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
779754///
......@@ -814,12 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
814789 EINTR => continue,
815790 EINVAL => unreachable,
816791 EFAULT => unreachable,
817 EAGAIN => if (std.event.Loop.instance) |loop| {
818 loop.waitUntilFdWritable(fd);
819 continue;
820 } else {
821 return error.WouldBlock;
822 },
792 EAGAIN => return error.WouldBlock,
823793 EBADF => return error.NotOpenForWriting, // Can be a race condition.
824794 EDESTADDRREQ => unreachable, // `connect` was never called.
825795 EDQUOT => return error.DiskQuota,
......@@ -847,8 +817,8 @@ pub const PWriteError = WriteError || error{Unseekable};
847817/// another write() call to transfer the remaining bytes. The subsequent call will either
848818/// transfer further bytes or may result in an error (e.g., if the disk is now full).
849819///
850/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled
851/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
820/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
821/// return error.WouldBlock when EAGAIN is received.
852822/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
853823/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
854824///
......@@ -905,12 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
905875 EINTR => continue,
906876 EINVAL => unreachable,
907877 EFAULT => unreachable,
908 EAGAIN => if (std.event.Loop.instance) |loop| {
909 loop.waitUntilFdWritable(fd);
910 continue;
911 } else {
912 return error.WouldBlock;
913 },
878 EAGAIN => return error.WouldBlock,
914879 EBADF => return error.NotOpenForWriting, // Can be a race condition.
915880 EDESTADDRREQ => unreachable, // `connect` was never called.
916881 EDQUOT => return error.DiskQuota,
......@@ -939,8 +904,8 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
939904/// another write() call to transfer the remaining bytes. The subsequent call will either
940905/// transfer further bytes or may result in an error (e.g., if the disk is now full).
941906///
942/// If the application has a global event loop enabled, EAGAIN is handled
943/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.
907/// If `fd` is opened in non blocking mode, the function will
908/// return error.WouldBlock when EAGAIN is received.
944909///
945910/// The following systems do not have this syscall, and will return partial writes if more than one
946911/// vector is provided:
......@@ -993,12 +958,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
993958 EINTR => continue,
994959 EINVAL => unreachable,
995960 EFAULT => unreachable,
996 EAGAIN => if (std.event.Loop.instance) |loop| {
997 loop.waitUntilFdWritable(fd);
998 continue;
999 } else {
1000 return error.WouldBlock;
1001 },
961 EAGAIN => return error.WouldBlock,
1002962 EBADF => return error.NotOpenForWriting, // Can be a race condition.
1003963 EDESTADDRREQ => unreachable, // `connect` was never called.
1004964 EDQUOT => return error.DiskQuota,
......@@ -2846,8 +2806,8 @@ pub const AcceptError = error{
28462806} || UnexpectedError;
28472807
28482808/// Accept a connection on a socket.
2849/// If the application has a global event loop enabled, EAGAIN is handled
2850/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
2809/// If `sockfd` is opened in non blocking mode, the function will
2810/// return error.WouldBlock when EAGAIN is received.
28512811pub fn accept(
28522812 /// This argument is a socket that has been created with `socket`, bound to a local address
28532813 /// with `bind`, and is listening for connections after a `listen`.
......@@ -2890,12 +2850,7 @@ pub fn accept(
28902850 return fd;
28912851 },
28922852 EINTR => continue,
2893 EAGAIN => if (std.event.Loop.instance) |loop| {
2894 loop.waitUntilFdReadable(sockfd);
2895 continue;
2896 } else {
2897 return error.WouldBlock;
2898 },
2853 EAGAIN => return error.WouldBlock,
28992854 EBADF => unreachable, // always a race condition
29002855 ECONNABORTED => return error.ConnectionAborted,
29012856 EFAULT => unreachable,
......@@ -3081,6 +3036,8 @@ pub const ConnectError = error{
30813036} || UnexpectedError;
30823037
30833038/// Initiate a connection on a socket.
3039/// If `sockfd` is opened in non blocking mode, the function will
3040/// return error.WouldBlock when EAGAIN or EINPROGRESS is received.
30843041pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
30853042 if (builtin.os.tag == .windows) {
30863043 const rc = windows.ws2_32.connect(sockfd, sock_addr, len);
......@@ -3113,11 +3070,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
31133070 EADDRINUSE => return error.AddressInUse,
31143071 EADDRNOTAVAIL => return error.AddressNotAvailable,
31153072 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
3116 EAGAIN, EINPROGRESS => {
3117 const loop = std.event.Loop.instance orelse return error.WouldBlock;
3118 loop.waitUntilFdWritable(sockfd);
3119 return getsockoptError(sockfd);
3120 },
3073 EAGAIN, EINPROGRESS => return error.WouldBlock,
31213074 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
31223075 EBADF => unreachable, // sockfd is not a valid open file descriptor.
31233076 ECONNREFUSED => return error.ConnectionRefused,
......@@ -4620,14 +4573,8 @@ pub fn sendto(
46204573 const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
46214574 switch (errno(rc)) {
46224575 0 => return @intCast(usize, rc),
4623
46244576 EACCES => return error.AccessDenied,
4625 EAGAIN => if (std.event.Loop.instance) |loop| {
4626 loop.waitUntilFdWritable(sockfd);
4627 continue;
4628 } else {
4629 return error.WouldBlock;
4630 },
4577 EAGAIN => return error.WouldBlock,
46314578 EALREADY => return error.FastOpenAlreadyInProgress,
46324579 EBADF => unreachable, // always a race condition
46334580 ECONNRESET => return error.ConnectionResetByPeer,
......@@ -5106,6 +5053,8 @@ pub const RecvFromError = error{
51065053 SystemResources,
51075054} || UnexpectedError;
51085055
5056/// If `sockfd` is opened in non blocking mode, the function will
5057/// return error.WouldBlock when EAGAIN is received.
51095058pub fn recvfrom(
51105059 sockfd: fd_t,
51115060 buf: []u8,
......@@ -5123,12 +5072,7 @@ pub fn recvfrom(
51235072 ENOTCONN => unreachable,
51245073 ENOTSOCK => unreachable,
51255074 EINTR => continue,
5126 EAGAIN => if (std.event.Loop.instance) |loop| {
5127 loop.waitUntilFdReadable(sockfd);
5128 continue;
5129 } else {
5130 return error.WouldBlock;
5131 },
5075 EAGAIN => return error.WouldBlock,
51325076 ENOMEM => return error.SystemResources,
51335077 ECONNREFUSED => return error.ConnectionRefused,
51345078 else => |err| return unexpectedErrno(err),