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
signaturebadge-question-mark 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 {...@@ -721,6 +721,50 @@ pub const Loop = struct {
721 }721 }
722 }722 }
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
724 /// Performs an async `os.open` using a separate thread.768 /// Performs an async `os.open` using a separate thread.
725 pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t {769 pub fn openZ(self: *Loop, file_path: [*:0]const u8, flags: u32, mode: os.mode_t) os.OpenError!os.fd_t {
726 var req_node = Request.Node{770 var req_node = Request.Node{
...@@ -779,152 +823,309 @@ pub const Loop = struct {...@@ -779,152 +823,309 @@ pub const Loop = struct {
779823
780 /// Performs an async `os.read` using a separate thread.824 /// Performs an async `os.read` using a separate thread.
781 /// `fd` must block and not return EAGAIN.825 /// `fd` must block and not return EAGAIN.
782 pub fn read(self: *Loop, fd: os.fd_t, buf: []u8) os.ReadError!usize {826 pub fn read(self: *Loop, fd: os.fd_t, buf: []u8, simulate_evented: bool) os.ReadError!usize {
783 var req_node = Request.Node{827 if (simulate_evented) {
784 .data = .{828 var req_node = Request.Node{
785 .msg = .{829 .data = .{
786 .read = .{830 .msg = .{
787 .fd = fd,831 .read = .{
788 .buf = buf,832 .fd = fd,
789 .result = undefined,833 .buf = buf,
834 .result = undefined,
835 },
790 },836 },
837 .finish = .{ .TickNode = .{ .data = @frame() } },
791 },838 },
792 .finish = .{ .TickNode = .{ .data = @frame() } },839 };
793 },840 suspend {
794 };841 self.posixFsRequest(&req_node);
795 suspend {842 }
796 self.posixFsRequest(&req_node);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 }
797 }854 }
798 return req_node.data.msg.read.result;
799 }855 }
800856
801 /// Performs an async `os.readv` using a separate thread.857 /// Performs an async `os.readv` using a separate thread.
802 /// `fd` must block and not return EAGAIN.858 /// `fd` must block and not return EAGAIN.
803 pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec) os.ReadError!usize {859 pub fn readv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, simulate_evented: bool) os.ReadError!usize {
804 var req_node = Request.Node{860 if (simulate_evented) {
805 .data = .{861 var req_node = Request.Node{
806 .msg = .{862 .data = .{
807 .readv = .{863 .msg = .{
808 .fd = fd,864 .readv = .{
809 .iov = iov,865 .fd = fd,
810 .result = undefined,866 .iov = iov,
867 .result = undefined,
868 },
811 },869 },
870 .finish = .{ .TickNode = .{ .data = @frame() } },
812 },871 },
813 .finish = .{ .TickNode = .{ .data = @frame() } },872 };
814 },873 suspend {
815 };874 self.posixFsRequest(&req_node);
816 suspend {875 }
817 self.posixFsRequest(&req_node);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 }
818 }887 }
819 return req_node.data.msg.readv.result;
820 }888 }
821889
822 /// Performs an async `os.pread` using a separate thread.890 /// Performs an async `os.pread` using a separate thread.
823 /// `fd` must block and not return EAGAIN.891 /// `fd` must block and not return EAGAIN.
824 pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64) os.PReadError!usize {892 pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64, simulate_evented: bool) os.PReadError!usize {
825 var req_node = Request.Node{893 if (simulate_evented) {
826 .data = .{894 var req_node = Request.Node{
827 .msg = .{895 .data = .{
828 .pread = .{896 .msg = .{
829 .fd = fd,897 .pread = .{
830 .buf = buf,898 .fd = fd,
831 .offset = offset,899 .buf = buf,
832 .result = undefined,900 .offset = offset,
901 .result = undefined,
902 },
833 },903 },
904 .finish = .{ .TickNode = .{ .data = @frame() } },
834 },905 },
835 .finish = .{ .TickNode = .{ .data = @frame() } },906 };
836 },907 suspend {
837 };908 self.posixFsRequest(&req_node);
838 suspend {909 }
839 self.posixFsRequest(&req_node);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 }
840 }921 }
841 return req_node.data.msg.pread.result;
842 }922 }
843923
844 /// Performs an async `os.preadv` using a separate thread.924 /// Performs an async `os.preadv` using a separate thread.
845 /// `fd` must block and not return EAGAIN.925 /// `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 {926 pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64, simulate_evented: bool) os.ReadError!usize {
847 var req_node = Request.Node{927 if (simulate_evented) {
848 .data = .{928 var req_node = Request.Node{
849 .msg = .{929 .data = .{
850 .preadv = .{930 .msg = .{
851 .fd = fd,931 .preadv = .{
852 .iov = iov,932 .fd = fd,
853 .offset = offset,933 .iov = iov,
854 .result = undefined,934 .offset = offset,
935 .result = undefined,
936 },
855 },937 },
938 .finish = .{ .TickNode = .{ .data = @frame() } },
856 },939 },
857 .finish = .{ .TickNode = .{ .data = @frame() } },940 };
858 },941 suspend {
859 };942 self.posixFsRequest(&req_node);
860 suspend {943 }
861 self.posixFsRequest(&req_node);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 }
862 }955 }
863 return req_node.data.msg.preadv.result;
864 }956 }
865957
866 /// Performs an async `os.write` using a separate thread.958 /// Performs an async `os.write` using a separate thread.
867 /// `fd` must block and not return EAGAIN.959 /// `fd` must block and not return EAGAIN.
868 pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8) os.WriteError!usize {960 pub fn write(self: *Loop, fd: os.fd_t, bytes: []const u8, simulate_evented: bool) os.WriteError!usize {
869 var req_node = Request.Node{961 if (simulate_evented) {
870 .data = .{962 var req_node = Request.Node{
871 .msg = .{963 .data = .{
872 .write = .{964 .msg = .{
873 .fd = fd,965 .write = .{
874 .bytes = bytes,966 .fd = fd,
875 .result = undefined,967 .bytes = bytes,
968 .result = undefined,
969 },
876 },970 },
971 .finish = .{ .TickNode = .{ .data = @frame() } },
877 },972 },
878 .finish = .{ .TickNode = .{ .data = @frame() } },973 };
879 },974 suspend {
880 };975 self.posixFsRequest(&req_node);
881 suspend {976 }
882 self.posixFsRequest(&req_node);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 }
883 }988 }
884 return req_node.data.msg.write.result;
885 }989 }
886990
887 /// Performs an async `os.writev` using a separate thread.991 /// Performs an async `os.writev` using a separate thread.
888 /// `fd` must block and not return EAGAIN.992 /// `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 {993 pub fn writev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, simulate_evented: bool) os.WriteError!usize {
890 var req_node = Request.Node{994 if (simulate_evented) {
891 .data = .{995 var req_node = Request.Node{
892 .msg = .{996 .data = .{
893 .writev = .{997 .msg = .{
894 .fd = fd,998 .writev = .{
895 .iov = iov,999 .fd = fd,
896 .result = undefined,1000 .iov = iov,
1001 .result = undefined,
1002 },
897 },1003 },
1004 .finish = .{ .TickNode = .{ .data = @frame() } },
898 },1005 },
899 .finish = .{ .TickNode = .{ .data = @frame() } },1006 };
900 },1007 suspend {
901 };1008 self.posixFsRequest(&req_node);
902 suspend {1009 }
903 self.posixFsRequest(&req_node);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 }
904 }1055 }
905 return req_node.data.msg.writev.result;
906 }1056 }
9071057
908 /// Performs an async `os.pwritev` using a separate thread.1058 /// Performs an async `os.pwritev` using a separate thread.
909 /// `fd` must block and not return EAGAIN.1059 /// `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 {1060 pub fn pwritev(self: *Loop, fd: os.fd_t, iov: []const os.iovec_const, offset: u64, simulate_evented: bool) os.PWriteError!usize {
911 var req_node = Request.Node{1061 if (simulate_evented) {
912 .data = .{1062 var req_node = Request.Node{
913 .msg = .{1063 .data = .{
914 .pwritev = .{1064 .msg = .{
915 .fd = fd,1065 .pwritev = .{
916 .iov = iov,1066 .fd = fd,
917 .offset = offset,1067 .iov = iov,
918 .result = undefined,1068 .offset = offset,
1069 .result = undefined,
1070 },
919 },1071 },
1072 .finish = .{ .TickNode = .{ .data = @frame() } },
920 },1073 },
921 .finish = .{ .TickNode = .{ .data = @frame() } },1074 };
922 },1075 suspend {
923 };1076 self.posixFsRequest(&req_node);
924 suspend {1077 }
925 self.posixFsRequest(&req_node);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 };
926 }1128 }
927 return req_node.data.msg.pwritev.result;
928 }1129 }
9291130
930 /// Performs an async `os.faccessatZ` using a separate thread.1131 /// Performs an async `os.faccessatZ` using a separate thread.
...@@ -1079,6 +1280,9 @@ pub const Loop = struct {...@@ -1079,6 +1280,9 @@ pub const Loop = struct {
1079 .writev => |*msg| {1280 .writev => |*msg| {
1080 msg.result = os.writev(msg.fd, msg.iov);1281 msg.result = os.writev(msg.fd, msg.iov);
1081 },1282 },
1283 .pwrite => |*msg| {
1284 msg.result = os.pwrite(msg.fd, msg.bytes, msg.offset);
1285 },
1082 .pwritev => |*msg| {1286 .pwritev => |*msg| {
1083 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);1287 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
1084 },1288 },
...@@ -1148,6 +1352,7 @@ pub const Loop = struct {...@@ -1148,6 +1352,7 @@ pub const Loop = struct {
1148 readv: ReadV,1352 readv: ReadV,
1149 write: Write,1353 write: Write,
1150 writev: WriteV,1354 writev: WriteV,
1355 pwrite: PWrite,
1151 pwritev: PWriteV,1356 pwritev: PWriteV,
1152 pread: PRead,1357 pread: PRead,
1153 preadv: PReadV,1358 preadv: PReadV,
...@@ -1191,6 +1396,15 @@ pub const Loop = struct {...@@ -1191,6 +1396,15 @@ pub const Loop = struct {
1191 pub const Error = os.WriteError;1396 pub const Error = os.WriteError;
1192 };1397 };
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
1194 pub const PWriteV = struct {1408 pub const PWriteV = struct {
1195 fd: os.fd_t,1409 fd: os.fd_t,
1196 iov: []const os.iovec_const,1410 iov: []const os.iovec_const,
lib/std/fs/file.zig+40-24
...@@ -414,10 +414,12 @@ pub const File = struct {...@@ -414,10 +414,12 @@ pub const File = struct {
414 pub fn read(self: File, buffer: []u8) ReadError!usize {414 pub fn read(self: File, buffer: []u8) ReadError!usize {
415 if (is_windows) {415 if (is_windows) {
416 return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode);416 return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode);
417 } else if (self.capable_io_mode != self.intended_io_mode) {417 }
418 return std.event.Loop.instance.?.read(self.handle, buffer);418
419 } else {419 if (self.intended_io_mode == .blocking) {
420 return os.read(self.handle, buffer);420 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);
421 }423 }
422 }424 }
423425
...@@ -436,10 +438,12 @@ pub const File = struct {...@@ -436,10 +438,12 @@ pub const File = struct {
436 pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {438 pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
437 if (is_windows) {439 if (is_windows) {
438 return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode);440 return windows.ReadFile(self.handle, buffer, offset, self.intended_io_mode);
439 } else if (self.capable_io_mode != self.intended_io_mode) {441 }
440 return std.event.Loop.instance.?.pread(self.handle, buffer, offset);442
441 } else {443 if (self.intended_io_mode == .blocking) {
442 return os.pread(self.handle, buffer, offset);444 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);
443 }447 }
444 }448 }
445449
...@@ -461,10 +465,12 @@ pub const File = struct {...@@ -461,10 +465,12 @@ pub const File = struct {
461 if (iovecs.len == 0) return @as(usize, 0);465 if (iovecs.len == 0) return @as(usize, 0);
462 const first = iovecs[0];466 const first = iovecs[0];
463 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);467 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) {468 }
465 return std.event.Loop.instance.?.readv(self.handle, iovecs);469
466 } else {470 if (self.intended_io_mode == .blocking) {
467 return os.readv(self.handle, iovecs);471 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);
468 }474 }
469 }475 }
470476
...@@ -500,10 +506,12 @@ pub const File = struct {...@@ -500,10 +506,12 @@ pub const File = struct {
500 if (iovecs.len == 0) return @as(usize, 0);506 if (iovecs.len == 0) return @as(usize, 0);
501 const first = iovecs[0];507 const first = iovecs[0];
502 return windows.ReadFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);508 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) {509 }
504 return std.event.Loop.instance.?.preadv(self.handle, iovecs, offset);510
505 } else {511 if (self.intended_io_mode == .blocking) {
506 return os.preadv(self.handle, iovecs, offset);512 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);
507 }515 }
508 }516 }
509517
...@@ -539,10 +547,12 @@ pub const File = struct {...@@ -539,10 +547,12 @@ pub const File = struct {
539 pub fn write(self: File, bytes: []const u8) WriteError!usize {547 pub fn write(self: File, bytes: []const u8) WriteError!usize {
540 if (is_windows) {548 if (is_windows) {
541 return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode);549 return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode);
542 } else if (self.capable_io_mode != self.intended_io_mode) {550 }
543 return std.event.Loop.instance.?.write(self.handle, bytes);551
544 } else {552 if (self.intended_io_mode == .blocking) {
545 return os.write(self.handle, bytes);553 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);
546 }556 }
547 }557 }
548558
...@@ -556,10 +566,12 @@ pub const File = struct {...@@ -556,10 +566,12 @@ pub const File = struct {
556 pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {566 pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
557 if (is_windows) {567 if (is_windows) {
558 return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode);568 return windows.WriteFile(self.handle, bytes, offset, self.intended_io_mode);
559 } else if (self.capable_io_mode != self.intended_io_mode) {569 }
560 return std.event.Loop.instance.?.pwrite(self.handle, bytes, offset);570
561 } else {571 if (self.intended_io_mode == .blocking) {
562 return os.pwrite(self.handle, bytes, offset);572 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);
563 }575 }
564 }576 }
565577
...@@ -576,10 +588,12 @@ pub const File = struct {...@@ -576,10 +588,12 @@ pub const File = struct {
576 if (iovecs.len == 0) return @as(usize, 0);588 if (iovecs.len == 0) return @as(usize, 0);
577 const first = iovecs[0];589 const first = iovecs[0];
578 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], null, self.intended_io_mode);590 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) {591 }
580 return std.event.Loop.instance.?.writev(self.handle, iovecs);592
581 } else {593 if (self.intended_io_mode == .blocking) {
582 return os.writev(self.handle, iovecs);594 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);
583 }597 }
584 }598 }
585599
...@@ -607,10 +621,12 @@ pub const File = struct {...@@ -607,10 +621,12 @@ pub const File = struct {
607 if (iovecs.len == 0) return @as(usize, 0);621 if (iovecs.len == 0) return @as(usize, 0);
608 const first = iovecs[0];622 const first = iovecs[0];
609 return windows.WriteFile(self.handle, first.iov_base[0..first.iov_len], offset, self.intended_io_mode);623 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) {624 }
611 return std.event.Loop.instance.?.pwritev(self.handle, iovecs, offset);625
612 } else {626 if (self.intended_io_mode == .blocking) {
613 return os.pwritev(self.handle, iovecs, offset);627 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);
614 }630 }
615 }631 }
616632
lib/std/net.zig+36-14
...@@ -614,11 +614,11 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {...@@ -614,11 +614,11 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
614614
615 var addr = try std.net.Address.initUnix(path);615 var addr = try std.net.Address.initUnix(path);
616616
617 try os.connect(617 if (std.io.is_async) {
618 sockfd,618 try loop.connect(sockfd, &addr.any, addr.getOsSockLen());
619 &addr.any,619 } else {
620 addr.getOsSockLen(),620 try os.connect(sockfd, &addr.any, addr.getOsSockLen());
621 );621 }
622622
623 return fs.File{623 return fs.File{
624 .handle = sockfd,624 .handle = sockfd,
...@@ -677,7 +677,13 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {...@@ -677,7 +677,13 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
677 (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);677 (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
678 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);678 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
679 errdefer os.close(sockfd);679 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
682 return fs.File{ .handle = sockfd };688 return fs.File{ .handle = sockfd };
683}689}
...@@ -1429,7 +1435,11 @@ fn resMSendRc(...@@ -1429,7 +1435,11 @@ fn resMSendRc(
1429 if (answers[i].len == 0) {1435 if (answers[i].len == 0) {
1430 var j: usize = 0;1436 var j: usize = 0;
1431 while (j < ns.len) : (j += 1) {1437 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 }
1433 }1443 }
1434 }1444 }
1435 }1445 }
...@@ -1444,7 +1454,10 @@ fn resMSendRc(...@@ -1444,7 +1454,10 @@ fn resMSendRc(
14441454
1445 while (true) {1455 while (true) {
1446 var sl_copy = sl;1456 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
1449 // Ignore non-identifiable packets1462 // Ignore non-identifiable packets
1450 if (rlen < 4) continue;1463 if (rlen < 4) continue;
...@@ -1470,7 +1483,11 @@ fn resMSendRc(...@@ -1470,7 +1483,11 @@ fn resMSendRc(
1470 0, 3 => {},1483 0, 3 => {},
1471 2 => if (servfail_retry != 0) {1484 2 => if (servfail_retry != 0) {
1472 servfail_retry -= 1;1485 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 }
1474 },1491 },
1475 else => continue,1492 else => continue,
1476 }1493 }
...@@ -1661,18 +1678,23 @@ pub const StreamServer = struct {...@@ -1661,18 +1678,23 @@ pub const StreamServer = struct {
16611678
1662 /// If this function succeeds, the returned `Connection` is a caller-managed resource.1679 /// If this function succeeds, the returned `Connection` is a caller-managed resource.
1663 pub fn accept(self: *StreamServer) AcceptError!Connection {1680 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;
1666 var accepted_addr: Address = undefined;1681 var accepted_addr: Address = undefined;
1667 var adr_len: os.socklen_t = @sizeOf(Address);1682 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| {
1669 return Connection{1693 return Connection{
1670 .file = fs.File{ .handle = fd },1694 .file = fs.File{ .handle = fd },
1671 .address = accepted_addr,1695 .address = accepted_addr,
1672 };1696 };
1673 } else |err| switch (err) {1697 } 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.
1676 error.WouldBlock => unreachable,1698 error.WouldBlock => unreachable,
1677 else => |e| return e,1699 else => |e| return e,
1678 }1700 }
lib/std/os.zig+34-90
...@@ -314,8 +314,8 @@ pub const ReadError = error{...@@ -314,8 +314,8 @@ pub const ReadError = error{
314314
315/// Returns the number of bytes that were read, which can be less than315/// Returns the number of bytes that were read, which can be less than
316/// buf.len. If 0 bytes were read, that means EOF.316/// buf.len. If 0 bytes were read, that means EOF.
317/// If the application has a global event loop enabled, EAGAIN is handled317/// If `fd` is opened in non blocking mode, the function will return error.WouldBlock
318/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.318/// when EAGAIN is received.
319///319///
320/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`320/// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000`
321/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as321/// 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 {...@@ -366,12 +366,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
366 EINTR => continue,366 EINTR => continue,
367 EINVAL => unreachable,367 EINVAL => unreachable,
368 EFAULT => unreachable,368 EFAULT => unreachable,
369 EAGAIN => if (std.event.Loop.instance) |loop| {369 EAGAIN => return error.WouldBlock,
370 loop.waitUntilFdReadable(fd);
371 continue;
372 } else {
373 return error.WouldBlock;
374 },
375 EBADF => return error.NotOpenForReading, // Can be a race condition.370 EBADF => return error.NotOpenForReading, // Can be a race condition.
376 EIO => return error.InputOutput,371 EIO => return error.InputOutput,
377 EISDIR => return error.IsDir,372 EISDIR => return error.IsDir,
...@@ -387,8 +382,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {...@@ -387,8 +382,8 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
387382
388/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.383/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
389///384///
390/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled385/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
391/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.386/// return error.WouldBlock when EAGAIN is received.
392/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are387/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
393/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.388/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
394///389///
...@@ -428,12 +423,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {...@@ -428,12 +423,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
428 EINTR => continue,423 EINTR => continue,
429 EINVAL => unreachable,424 EINVAL => unreachable,
430 EFAULT => unreachable,425 EFAULT => unreachable,
431 EAGAIN => if (std.event.Loop.instance) |loop| {426 EAGAIN => return error.WouldBlock,
432 loop.waitUntilFdReadable(fd);
433 continue;
434 } else {
435 return error.WouldBlock;
436 },
437 EBADF => return error.NotOpenForReading, // can be a race condition427 EBADF => return error.NotOpenForReading, // can be a race condition
438 EIO => return error.InputOutput,428 EIO => return error.InputOutput,
439 EISDIR => return error.IsDir,429 EISDIR => return error.IsDir,
...@@ -450,8 +440,8 @@ pub const PReadError = ReadError || error{Unseekable};...@@ -450,8 +440,8 @@ pub const PReadError = ReadError || error{Unseekable};
450///440///
451/// Retries when interrupted by a signal.441/// Retries when interrupted by a signal.
452///442///
453/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled443/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
454/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.444/// return error.WouldBlock when EAGAIN is received.
455/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are445/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
456/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.446/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
457pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {447pub 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 {...@@ -492,12 +482,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
492 EINTR => continue,482 EINTR => continue,
493 EINVAL => unreachable,483 EINVAL => unreachable,
494 EFAULT => unreachable,484 EFAULT => unreachable,
495 EAGAIN => if (std.event.Loop.instance) |loop| {485 EAGAIN => return error.WouldBlock,
496 loop.waitUntilFdReadable(fd);
497 continue;
498 } else {
499 return error.WouldBlock;
500 },
501 EBADF => return error.NotOpenForReading, // Can be a race condition.486 EBADF => return error.NotOpenForReading, // Can be a race condition.
502 EIO => return error.InputOutput,487 EIO => return error.InputOutput,
503 EISDIR => return error.IsDir,488 EISDIR => return error.IsDir,
...@@ -586,8 +571,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -586,8 +571,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
586///571///
587/// Retries when interrupted by a signal.572/// Retries when interrupted by a signal.
588///573///
589/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled574/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
590/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.575/// return error.WouldBlock when EAGAIN is received.
591/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are576/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
592/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.577/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
593///578///
...@@ -637,12 +622,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {...@@ -637,12 +622,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
637 EINTR => continue,622 EINTR => continue,
638 EINVAL => unreachable,623 EINVAL => unreachable,
639 EFAULT => unreachable,624 EFAULT => unreachable,
640 EAGAIN => if (std.event.Loop.instance) |loop| {625 EAGAIN => return error.WouldBlock,
641 loop.waitUntilFdReadable(fd);
642 continue;
643 } else {
644 return error.WouldBlock;
645 },
646 EBADF => return error.NotOpenForReading, // can be a race condition626 EBADF => return error.NotOpenForReading, // can be a race condition
647 EIO => return error.InputOutput,627 EIO => return error.InputOutput,
648 EISDIR => return error.IsDir,628 EISDIR => return error.IsDir,
...@@ -687,8 +667,8 @@ pub const WriteError = error{...@@ -687,8 +667,8 @@ pub const WriteError = error{
687/// another write() call to transfer the remaining bytes. The subsequent call will either667/// another write() call to transfer the remaining bytes. The subsequent call will either
688/// transfer further bytes or may result in an error (e.g., if the disk is now full).668/// transfer further bytes or may result in an error (e.g., if the disk is now full).
689///669///
690/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled670/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
691/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.671/// return error.WouldBlock when EAGAIN is received.
692/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are672/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
693/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.673/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
694///674///
...@@ -741,12 +721,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -741,12 +721,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
741 EINTR => continue,721 EINTR => continue,
742 EINVAL => unreachable,722 EINVAL => unreachable,
743 EFAULT => unreachable,723 EFAULT => unreachable,
744 EAGAIN => if (std.event.Loop.instance) |loop| {724 EAGAIN => return error.WouldBlock,
745 loop.waitUntilFdWritable(fd);
746 continue;
747 } else {
748 return error.WouldBlock;
749 },
750 EBADF => return error.NotOpenForWriting, // can be a race condition.725 EBADF => return error.NotOpenForWriting, // can be a race condition.
751 EDESTADDRREQ => unreachable, // `connect` was never called.726 EDESTADDRREQ => unreachable, // `connect` was never called.
752 EDQUOT => return error.DiskQuota,727 EDQUOT => return error.DiskQuota,
...@@ -772,8 +747,8 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {...@@ -772,8 +747,8 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
772/// another write() call to transfer the remaining bytes. The subsequent call will either747/// another write() call to transfer the remaining bytes. The subsequent call will either
773/// transfer further bytes or may result in an error (e.g., if the disk is now full).748/// transfer further bytes or may result in an error (e.g., if the disk is now full).
774///749///
775/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled750/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
776/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.751/// return error.WouldBlock when EAGAIN is received.k`.
777/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are752/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
778/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.753/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
779///754///
...@@ -814,12 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {...@@ -814,12 +789,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
814 EINTR => continue,789 EINTR => continue,
815 EINVAL => unreachable,790 EINVAL => unreachable,
816 EFAULT => unreachable,791 EFAULT => unreachable,
817 EAGAIN => if (std.event.Loop.instance) |loop| {792 EAGAIN => return error.WouldBlock,
818 loop.waitUntilFdWritable(fd);
819 continue;
820 } else {
821 return error.WouldBlock;
822 },
823 EBADF => return error.NotOpenForWriting, // Can be a race condition.793 EBADF => return error.NotOpenForWriting, // Can be a race condition.
824 EDESTADDRREQ => unreachable, // `connect` was never called.794 EDESTADDRREQ => unreachable, // `connect` was never called.
825 EDQUOT => return error.DiskQuota,795 EDQUOT => return error.DiskQuota,
...@@ -847,8 +817,8 @@ pub const PWriteError = WriteError || error{Unseekable};...@@ -847,8 +817,8 @@ pub const PWriteError = WriteError || error{Unseekable};
847/// another write() call to transfer the remaining bytes. The subsequent call will either817/// another write() call to transfer the remaining bytes. The subsequent call will either
848/// transfer further bytes or may result in an error (e.g., if the disk is now full).818/// transfer further bytes or may result in an error (e.g., if the disk is now full).
849///819///
850/// For POSIX systems, if the application has a global event loop enabled, EAGAIN is handled820/// For POSIX systems, if `fd` is opened in non blocking mode, the function will
851/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.821/// return error.WouldBlock when EAGAIN is received.
852/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are822/// On Windows, if the application has a global event loop enabled, I/O Completion Ports are
853/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.823/// used to perform the I/O. `error.WouldBlock` is not possible on Windows.
854///824///
...@@ -905,12 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -905,12 +875,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
905 EINTR => continue,875 EINTR => continue,
906 EINVAL => unreachable,876 EINVAL => unreachable,
907 EFAULT => unreachable,877 EFAULT => unreachable,
908 EAGAIN => if (std.event.Loop.instance) |loop| {878 EAGAIN => return error.WouldBlock,
909 loop.waitUntilFdWritable(fd);
910 continue;
911 } else {
912 return error.WouldBlock;
913 },
914 EBADF => return error.NotOpenForWriting, // Can be a race condition.879 EBADF => return error.NotOpenForWriting, // Can be a race condition.
915 EDESTADDRREQ => unreachable, // `connect` was never called.880 EDESTADDRREQ => unreachable, // `connect` was never called.
916 EDQUOT => return error.DiskQuota,881 EDQUOT => return error.DiskQuota,
...@@ -939,8 +904,8 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -939,8 +904,8 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
939/// another write() call to transfer the remaining bytes. The subsequent call will either904/// another write() call to transfer the remaining bytes. The subsequent call will either
940/// transfer further bytes or may result in an error (e.g., if the disk is now full).905/// transfer further bytes or may result in an error (e.g., if the disk is now full).
941///906///
942/// If the application has a global event loop enabled, EAGAIN is handled907/// If `fd` is opened in non blocking mode, the function will
943/// via the event loop. Otherwise EAGAIN results in `error.WouldBlock`.908/// return error.WouldBlock when EAGAIN is received.
944///909///
945/// The following systems do not have this syscall, and will return partial writes if more than one910/// The following systems do not have this syscall, and will return partial writes if more than one
946/// vector is provided:911/// vector is provided:
...@@ -993,12 +958,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -993,12 +958,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
993 EINTR => continue,958 EINTR => continue,
994 EINVAL => unreachable,959 EINVAL => unreachable,
995 EFAULT => unreachable,960 EFAULT => unreachable,
996 EAGAIN => if (std.event.Loop.instance) |loop| {961 EAGAIN => return error.WouldBlock,
997 loop.waitUntilFdWritable(fd);
998 continue;
999 } else {
1000 return error.WouldBlock;
1001 },
1002 EBADF => return error.NotOpenForWriting, // Can be a race condition.962 EBADF => return error.NotOpenForWriting, // Can be a race condition.
1003 EDESTADDRREQ => unreachable, // `connect` was never called.963 EDESTADDRREQ => unreachable, // `connect` was never called.
1004 EDQUOT => return error.DiskQuota,964 EDQUOT => return error.DiskQuota,
...@@ -2846,8 +2806,8 @@ pub const AcceptError = error{...@@ -2846,8 +2806,8 @@ pub const AcceptError = error{
2846} || UnexpectedError;2806} || UnexpectedError;
28472807
2848/// Accept a connection on a socket.2808/// Accept a connection on a socket.
2849/// If the application has a global event loop enabled, EAGAIN is handled2809/// If `sockfd` is opened in non blocking mode, the function will
2850/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.2810/// return error.WouldBlock when EAGAIN is received.
2851pub fn accept(2811pub fn accept(
2852 /// This argument is a socket that has been created with `socket`, bound to a local address2812 /// This argument is a socket that has been created with `socket`, bound to a local address
2853 /// with `bind`, and is listening for connections after a `listen`.2813 /// with `bind`, and is listening for connections after a `listen`.
...@@ -2890,12 +2850,7 @@ pub fn accept(...@@ -2890,12 +2850,7 @@ pub fn accept(
2890 return fd;2850 return fd;
2891 },2851 },
2892 EINTR => continue,2852 EINTR => continue,
2893 EAGAIN => if (std.event.Loop.instance) |loop| {2853 EAGAIN => return error.WouldBlock,
2894 loop.waitUntilFdReadable(sockfd);
2895 continue;
2896 } else {
2897 return error.WouldBlock;
2898 },
2899 EBADF => unreachable, // always a race condition2854 EBADF => unreachable, // always a race condition
2900 ECONNABORTED => return error.ConnectionAborted,2855 ECONNABORTED => return error.ConnectionAborted,
2901 EFAULT => unreachable,2856 EFAULT => unreachable,
...@@ -3081,6 +3036,8 @@ pub const ConnectError = error{...@@ -3081,6 +3036,8 @@ pub const ConnectError = error{
3081} || UnexpectedError;3036} || UnexpectedError;
30823037
3083/// Initiate a connection on a socket.3038/// 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.
3084pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {3041pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
3085 if (builtin.os.tag == .windows) {3042 if (builtin.os.tag == .windows) {
3086 const rc = windows.ws2_32.connect(sockfd, sock_addr, len);3043 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...@@ -3113,11 +3070,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con
3113 EADDRINUSE => return error.AddressInUse,3070 EADDRINUSE => return error.AddressInUse,
3114 EADDRNOTAVAIL => return error.AddressNotAvailable,3071 EADDRNOTAVAIL => return error.AddressNotAvailable,
3115 EAFNOSUPPORT => return error.AddressFamilyNotSupported,3072 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
3116 EAGAIN, EINPROGRESS => {3073 EAGAIN, EINPROGRESS => return error.WouldBlock,
3117 const loop = std.event.Loop.instance orelse return error.WouldBlock;
3118 loop.waitUntilFdWritable(sockfd);
3119 return getsockoptError(sockfd);
3120 },
3121 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.3074 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
3122 EBADF => unreachable, // sockfd is not a valid open file descriptor.3075 EBADF => unreachable, // sockfd is not a valid open file descriptor.
3123 ECONNREFUSED => return error.ConnectionRefused,3076 ECONNREFUSED => return error.ConnectionRefused,
...@@ -4620,14 +4573,8 @@ pub fn sendto(...@@ -4620,14 +4573,8 @@ pub fn sendto(
4620 const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);4573 const rc = system.sendto(sockfd, buf.ptr, buf.len, flags, dest_addr, addrlen);
4621 switch (errno(rc)) {4574 switch (errno(rc)) {
4622 0 => return @intCast(usize, rc),4575 0 => return @intCast(usize, rc),
4623
4624 EACCES => return error.AccessDenied,4576 EACCES => return error.AccessDenied,
4625 EAGAIN => if (std.event.Loop.instance) |loop| {4577 EAGAIN => return error.WouldBlock,
4626 loop.waitUntilFdWritable(sockfd);
4627 continue;
4628 } else {
4629 return error.WouldBlock;
4630 },
4631 EALREADY => return error.FastOpenAlreadyInProgress,4578 EALREADY => return error.FastOpenAlreadyInProgress,
4632 EBADF => unreachable, // always a race condition4579 EBADF => unreachable, // always a race condition
4633 ECONNRESET => return error.ConnectionResetByPeer,4580 ECONNRESET => return error.ConnectionResetByPeer,
...@@ -5106,6 +5053,8 @@ pub const RecvFromError = error{...@@ -5106,6 +5053,8 @@ pub const RecvFromError = error{
5106 SystemResources,5053 SystemResources,
5107} || UnexpectedError;5054} || UnexpectedError;
51085055
5056/// If `sockfd` is opened in non blocking mode, the function will
5057/// return error.WouldBlock when EAGAIN is received.
5109pub fn recvfrom(5058pub fn recvfrom(
5110 sockfd: fd_t,5059 sockfd: fd_t,
5111 buf: []u8,5060 buf: []u8,
...@@ -5123,12 +5072,7 @@ pub fn recvfrom(...@@ -5123,12 +5072,7 @@ pub fn recvfrom(
5123 ENOTCONN => unreachable,5072 ENOTCONN => unreachable,
5124 ENOTSOCK => unreachable,5073 ENOTSOCK => unreachable,
5125 EINTR => continue,5074 EINTR => continue,
5126 EAGAIN => if (std.event.Loop.instance) |loop| {5075 EAGAIN => return error.WouldBlock,
5127 loop.waitUntilFdReadable(sockfd);
5128 continue;
5129 } else {
5130 return error.WouldBlock;
5131 },
5132 ENOMEM => return error.SystemResources,5076 ENOMEM => return error.SystemResources,
5133 ECONNREFUSED => return error.ConnectionRefused,5077 ECONNREFUSED => return error.ConnectionRefused,
5134 else => |err| return unexpectedErrno(err),5078 else => |err| return unexpectedErrno(err),