authorgravatar for hnakamur@gmail.comHiroaki Nakamura <hnakamur@gmail.com> 2022-03-04 05:13:54+09:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-03 14:13:54-06:00
log3605dd307ffff74726cc0ce5099599f1a6f9ddb2
treeea6c21101194923176347c639328edf65cac2e04
parente91c16e38b58611217f225d002a3321aa24bb47f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

os/linux/io_uring: add recvmsg and sendmsg (#10212)

* os/linux/io_uring: add recvmsg and sendmsg * Use std.os.iovec and std.os.iovec_const * Remove msg_ prefix in msghdr and msghdr_const in arm64 etc * Strip msg_ prefix in msghdr and msghdr_const for linux arm-eabi * Copy msghdr and msghdr_const from i386 to mips * Add sockaddr to lib/std/os/linux/mips.zig * Copy msghdr and msghdr_const from x86_64 to riscv64

9 files changed, 264 insertions(+), 82 deletions(-)

lib/std/os/linux/arm-eabi.zig+14-14
...@@ -648,23 +648,23 @@ pub const Flock = extern struct {...@@ -648,23 +648,23 @@ pub const Flock = extern struct {
648};648};
649649
650pub const msghdr = extern struct {650pub const msghdr = extern struct {
651 msg_name: ?*sockaddr,651 name: ?*sockaddr,
652 msg_namelen: socklen_t,652 namelen: socklen_t,
653 msg_iov: [*]iovec,653 iov: [*]iovec,
654 msg_iovlen: i32,654 iovlen: i32,
655 msg_control: ?*anyopaque,655 control: ?*anyopaque,
656 msg_controllen: socklen_t,656 controllen: socklen_t,
657 msg_flags: i32,657 flags: i32,
658};658};
659659
660pub const msghdr_const = extern struct {660pub const msghdr_const = extern struct {
661 msg_name: ?*const sockaddr,661 name: ?*const sockaddr,
662 msg_namelen: socklen_t,662 namelen: socklen_t,
663 msg_iov: [*]iovec_const,663 iov: [*]iovec_const,
664 msg_iovlen: i32,664 iovlen: i32,
665 msg_control: ?*anyopaque,665 control: ?*anyopaque,
666 msg_controllen: socklen_t,666 controllen: socklen_t,
667 msg_flags: i32,667 flags: i32,
668};668};
669669
670pub const blksize_t = i32;670pub const blksize_t = i32;
lib/std/os/linux/arm64.zig+16-16
...@@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;...@@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;
3const linux = std.os.linux;3const linux = std.os.linux;
4const socklen_t = linux.socklen_t;4const socklen_t = linux.socklen_t;
5const sockaddr = linux.sockaddr;5const sockaddr = linux.sockaddr;
6const iovec = linux.iovec;6const iovec = std.os.iovec;
7const iovec_const = linux.iovec_const;7const iovec_const = std.os.iovec_const;
8const uid_t = linux.uid_t;8const uid_t = linux.uid_t;
9const gid_t = linux.gid_t;9const gid_t = linux.gid_t;
10const pid_t = linux.pid_t;10const pid_t = linux.pid_t;
...@@ -499,27 +499,27 @@ pub const Flock = extern struct {...@@ -499,27 +499,27 @@ pub const Flock = extern struct {
499};499};
500500
501pub const msghdr = extern struct {501pub const msghdr = extern struct {
502 msg_name: ?*sockaddr,502 name: ?*sockaddr,
503 msg_namelen: socklen_t,503 namelen: socklen_t,
504 msg_iov: [*]iovec,504 iov: [*]iovec,
505 msg_iovlen: i32,505 iovlen: i32,
506 __pad1: i32 = 0,506 __pad1: i32 = 0,
507 msg_control: ?*anyopaque,507 control: ?*anyopaque,
508 msg_controllen: socklen_t,508 controllen: socklen_t,
509 __pad2: socklen_t = 0,509 __pad2: socklen_t = 0,
510 msg_flags: i32,510 flags: i32,
511};511};
512512
513pub const msghdr_const = extern struct {513pub const msghdr_const = extern struct {
514 msg_name: ?*const sockaddr,514 name: ?*const sockaddr,
515 msg_namelen: socklen_t,515 namelen: socklen_t,
516 msg_iov: [*]iovec_const,516 iov: [*]iovec_const,
517 msg_iovlen: i32,517 iovlen: i32,
518 __pad1: i32 = 0,518 __pad1: i32 = 0,
519 msg_control: ?*anyopaque,519 control: ?*anyopaque,
520 msg_controllen: socklen_t,520 controllen: socklen_t,
521 __pad2: socklen_t = 0,521 __pad2: socklen_t = 0,
522 msg_flags: i32,522 flags: i32,
523};523};
524524
525pub const blksize_t = i32;525pub const blksize_t = i32;
lib/std/os/linux/i386.zig+2-2
...@@ -2,8 +2,8 @@ const std = @import("../../std.zig");...@@ -2,8 +2,8 @@ const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;2const maxInt = std.math.maxInt;
3const linux = std.os.linux;3const linux = std.os.linux;
4const socklen_t = linux.socklen_t;4const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;5const iovec = std.os.iovec;
6const iovec_const = linux.iovec_const;6const iovec_const = std.os.iovec_const;
7const uid_t = linux.uid_t;7const uid_t = linux.uid_t;
8const gid_t = linux.gid_t;8const gid_t = linux.gid_t;
9const pid_t = linux.pid_t;9const pid_t = linux.pid_t;
lib/std/os/linux/io_uring.zig+132
...@@ -537,6 +537,36 @@ pub const IO_Uring = struct {...@@ -537,6 +537,36 @@ pub const IO_Uring = struct {
537 return sqe;537 return sqe;
538 }538 }
539539
540 /// Queues (but does not submit) an SQE to perform a `recvmsg(2)`.
541 /// Returns a pointer to the SQE.
542 pub fn recvmsg(
543 self: *IO_Uring,
544 user_data: u64,
545 fd: os.fd_t,
546 msg: *os.msghdr,
547 flags: u32,
548 ) !*io_uring_sqe {
549 const sqe = try self.get_sqe();
550 io_uring_prep_recvmsg(sqe, fd, msg, flags);
551 sqe.user_data = user_data;
552 return sqe;
553 }
554
555 /// Queues (but does not submit) an SQE to perform a `sendmsg(2)`.
556 /// Returns a pointer to the SQE.
557 pub fn sendmsg(
558 self: *IO_Uring,
559 user_data: u64,
560 fd: os.fd_t,
561 msg: *const os.msghdr_const,
562 flags: u32,
563 ) !*io_uring_sqe {
564 const sqe = try self.get_sqe();
565 io_uring_prep_sendmsg(sqe, fd, msg, flags);
566 sqe.user_data = user_data;
567 return sqe;
568 }
569
540 /// Queues (but does not submit) an SQE to perform an `openat(2)`.570 /// Queues (but does not submit) an SQE to perform an `openat(2)`.
541 /// Returns a pointer to the SQE.571 /// Returns a pointer to the SQE.
542 pub fn openat(572 pub fn openat(
...@@ -1237,6 +1267,26 @@ pub fn io_uring_prep_send(sqe: *io_uring_sqe, fd: os.fd_t, buffer: []const u8, f...@@ -1237,6 +1267,26 @@ pub fn io_uring_prep_send(sqe: *io_uring_sqe, fd: os.fd_t, buffer: []const u8, f
1237 sqe.rw_flags = flags;1267 sqe.rw_flags = flags;
1238}1268}
12391269
1270pub fn io_uring_prep_recvmsg(
1271 sqe: *io_uring_sqe,
1272 fd: os.fd_t,
1273 msg: *os.msghdr,
1274 flags: u32,
1275) void {
1276 linux.io_uring_prep_rw(.RECVMSG, sqe, fd, @ptrToInt(msg), 1, 0);
1277 sqe.rw_flags = flags;
1278}
1279
1280pub fn io_uring_prep_sendmsg(
1281 sqe: *io_uring_sqe,
1282 fd: os.fd_t,
1283 msg: *const os.msghdr_const,
1284 flags: u32,
1285) void {
1286 linux.io_uring_prep_rw(.SENDMSG, sqe, fd, @ptrToInt(msg), 1, 0);
1287 sqe.rw_flags = flags;
1288}
1289
1240pub fn io_uring_prep_openat(1290pub fn io_uring_prep_openat(
1241 sqe: *io_uring_sqe,1291 sqe: *io_uring_sqe,
1242 fd: os.fd_t,1292 fd: os.fd_t,
...@@ -1908,6 +1958,88 @@ test "accept/connect/send/recv" {...@@ -1908,6 +1958,88 @@ test "accept/connect/send/recv" {
1908 try testing.expectEqualSlices(u8, buffer_send[0..buffer_recv.len], buffer_recv[0..]);1958 try testing.expectEqualSlices(u8, buffer_send[0..buffer_recv.len], buffer_recv[0..]);
1909}1959}
19101960
1961test "sendmsg/recvmsg" {
1962 if (builtin.os.tag != .linux) return error.SkipZigTest;
1963
1964 var ring = IO_Uring.init(2, 0) catch |err| switch (err) {
1965 error.SystemOutdated => return error.SkipZigTest,
1966 error.PermissionDenied => return error.SkipZigTest,
1967 else => return err,
1968 };
1969 defer ring.deinit();
1970
1971 const address_server = try net.Address.parseIp4("127.0.0.1", 3131);
1972
1973 const server = try os.socket(address_server.any.family, os.SOCK.DGRAM, 0);
1974 defer os.close(server);
1975 try os.setsockopt(server, os.SOL.SOCKET, os.SO.REUSEPORT, &mem.toBytes(@as(c_int, 1)));
1976 try os.setsockopt(server, os.SOL.SOCKET, os.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1)));
1977 try os.bind(server, &address_server.any, address_server.getOsSockLen());
1978
1979 const client = try os.socket(address_server.any.family, os.SOCK.DGRAM, 0);
1980 defer os.close(client);
1981
1982 const buffer_send = [_]u8{42} ** 128;
1983 var iovecs_send = [_]os.iovec_const{
1984 os.iovec_const{ .iov_base = &buffer_send, .iov_len = buffer_send.len },
1985 };
1986 const msg_send = os.msghdr_const{
1987 .name = &address_server.any,
1988 .namelen = address_server.getOsSockLen(),
1989 .iov = &iovecs_send,
1990 .iovlen = 1,
1991 .control = null,
1992 .controllen = 0,
1993 .flags = 0,
1994 };
1995 const sqe_sendmsg = try ring.sendmsg(0x11111111, client, &msg_send, 0);
1996 sqe_sendmsg.flags |= linux.IOSQE_IO_LINK;
1997 try testing.expectEqual(linux.IORING_OP.SENDMSG, sqe_sendmsg.opcode);
1998 try testing.expectEqual(client, sqe_sendmsg.fd);
1999
2000 var buffer_recv = [_]u8{0} ** 128;
2001 var iovecs_recv = [_]os.iovec{
2002 os.iovec{ .iov_base = &buffer_recv, .iov_len = buffer_recv.len },
2003 };
2004 var addr = [_]u8{0} ** 4;
2005 var address_recv = net.Address.initIp4(addr, 0);
2006 var msg_recv: os.msghdr = os.msghdr{
2007 .name = &address_recv.any,
2008 .namelen = address_recv.getOsSockLen(),
2009 .iov = &iovecs_recv,
2010 .iovlen = 1,
2011 .control = null,
2012 .controllen = 0,
2013 .flags = 0,
2014 };
2015 const sqe_recvmsg = try ring.recvmsg(0x22222222, server, &msg_recv, 0);
2016 try testing.expectEqual(linux.IORING_OP.RECVMSG, sqe_recvmsg.opcode);
2017 try testing.expectEqual(server, sqe_recvmsg.fd);
2018
2019 try testing.expectEqual(@as(u32, 2), ring.sq_ready());
2020 try testing.expectEqual(@as(u32, 2), try ring.submit_and_wait(2));
2021 try testing.expectEqual(@as(u32, 0), ring.sq_ready());
2022 try testing.expectEqual(@as(u32, 2), ring.cq_ready());
2023
2024 const cqe_sendmsg = try ring.copy_cqe();
2025 if (cqe_sendmsg.res == -@as(i32, @enumToInt(linux.E.INVAL))) return error.SkipZigTest;
2026 try testing.expectEqual(linux.io_uring_cqe{
2027 .user_data = 0x11111111,
2028 .res = buffer_send.len,
2029 .flags = 0,
2030 }, cqe_sendmsg);
2031
2032 const cqe_recvmsg = try ring.copy_cqe();
2033 if (cqe_recvmsg.res == -@as(i32, @enumToInt(linux.E.INVAL))) return error.SkipZigTest;
2034 try testing.expectEqual(linux.io_uring_cqe{
2035 .user_data = 0x22222222,
2036 .res = buffer_recv.len,
2037 .flags = 0,
2038 }, cqe_recvmsg);
2039
2040 try testing.expectEqualSlices(u8, buffer_send[0..buffer_recv.len], buffer_recv[0..]);
2041}
2042
1911test "timeout (after a relative time)" {2043test "timeout (after a relative time)" {
1912 if (builtin.os.tag != .linux) return error.SkipZigTest;2044 if (builtin.os.tag != .linux) return error.SkipZigTest;
19132045
lib/std/os/linux/mips.zig+23-2
...@@ -2,11 +2,12 @@ const std = @import("../../std.zig");...@@ -2,11 +2,12 @@ const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;2const maxInt = std.math.maxInt;
3const linux = std.os.linux;3const linux = std.os.linux;
4const socklen_t = linux.socklen_t;4const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;5const iovec = std.os.iovec;
6const iovec_const = linux.iovec_const;6const iovec_const = std.os.iovec_const;
7const uid_t = linux.uid_t;7const uid_t = linux.uid_t;
8const gid_t = linux.gid_t;8const gid_t = linux.gid_t;
9const pid_t = linux.pid_t;9const pid_t = linux.pid_t;
10const sockaddr = linux.sockaddr;
10const timespec = linux.timespec;11const timespec = linux.timespec;
1112
12pub fn syscall0(number: SYS) usize {13pub fn syscall0(number: SYS) usize {
...@@ -716,6 +717,26 @@ pub const Flock = extern struct {...@@ -716,6 +717,26 @@ pub const Flock = extern struct {
716 __unused: [4]u8,717 __unused: [4]u8,
717};718};
718719
720pub const msghdr = extern struct {
721 name: ?*sockaddr,
722 namelen: socklen_t,
723 iov: [*]iovec,
724 iovlen: i32,
725 control: ?*anyopaque,
726 controllen: socklen_t,
727 flags: i32,
728};
729
730pub const msghdr_const = extern struct {
731 name: ?*const sockaddr,
732 namelen: socklen_t,
733 iov: [*]iovec_const,
734 iovlen: i32,
735 control: ?*anyopaque,
736 controllen: socklen_t,
737 flags: i32,
738};
739
719pub const blksize_t = i32;740pub const blksize_t = i32;
720pub const nlink_t = u32;741pub const nlink_t = u32;
721pub const time_t = i32;742pub const time_t = i32;
lib/std/os/linux/powerpc.zig+16-16
...@@ -2,8 +2,8 @@ const std = @import("../../std.zig");...@@ -2,8 +2,8 @@ const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;2const maxInt = std.math.maxInt;
3const linux = std.os.linux;3const linux = std.os.linux;
4const socklen_t = linux.socklen_t;4const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;5const iovec = std.os.iovec;
6const iovec_const = linux.iovec_const;6const iovec_const = std.os.iovec_const;
7const uid_t = linux.uid_t;7const uid_t = linux.uid_t;
8const gid_t = linux.gid_t;8const gid_t = linux.gid_t;
9const pid_t = linux.pid_t;9const pid_t = linux.pid_t;
...@@ -651,23 +651,23 @@ pub const Flock = extern struct {...@@ -651,23 +651,23 @@ pub const Flock = extern struct {
651};651};
652652
653pub const msghdr = extern struct {653pub const msghdr = extern struct {
654 msg_name: ?*sockaddr,654 name: ?*sockaddr,
655 msg_namelen: socklen_t,655 namelen: socklen_t,
656 msg_iov: [*]iovec,656 iov: [*]iovec,
657 msg_iovlen: usize,657 iovlen: usize,
658 msg_control: ?*anyopaque,658 control: ?*anyopaque,
659 msg_controllen: socklen_t,659 controllen: socklen_t,
660 msg_flags: i32,660 flags: i32,
661};661};
662662
663pub const msghdr_const = extern struct {663pub const msghdr_const = extern struct {
664 msg_name: ?*const sockaddr,664 name: ?*const sockaddr,
665 msg_namelen: socklen_t,665 namelen: socklen_t,
666 msg_iov: [*]iovec_const,666 iov: [*]iovec_const,
667 msg_iovlen: usize,667 iovlen: usize,
668 msg_control: ?*anyopaque,668 control: ?*anyopaque,
669 msg_controllen: socklen_t,669 controllen: socklen_t,
670 msg_flags: i32,670 flags: i32,
671};671};
672672
673pub const blksize_t = i32;673pub const blksize_t = i32;
lib/std/os/linux/powerpc64.zig+16-16
...@@ -2,8 +2,8 @@ const std = @import("../../std.zig");...@@ -2,8 +2,8 @@ const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;2const maxInt = std.math.maxInt;
3const linux = std.os.linux;3const linux = std.os.linux;
4const socklen_t = linux.socklen_t;4const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;5const iovec = std.os.iovec;
6const iovec_const = linux.iovec_const;6const iovec_const = std.os.iovec_const;
7const uid_t = linux.uid_t;7const uid_t = linux.uid_t;
8const gid_t = linux.gid_t;8const gid_t = linux.gid_t;
9const pid_t = linux.pid_t;9const pid_t = linux.pid_t;
...@@ -626,23 +626,23 @@ pub const Flock = extern struct {...@@ -626,23 +626,23 @@ pub const Flock = extern struct {
626};626};
627627
628pub const msghdr = extern struct {628pub const msghdr = extern struct {
629 msg_name: ?*sockaddr,629 name: ?*sockaddr,
630 msg_namelen: socklen_t,630 namelen: socklen_t,
631 msg_iov: [*]iovec,631 iov: [*]iovec,
632 msg_iovlen: usize,632 iovlen: usize,
633 msg_control: ?*anyopaque,633 control: ?*anyopaque,
634 msg_controllen: usize,634 controllen: usize,
635 msg_flags: i32,635 flags: i32,
636};636};
637637
638pub const msghdr_const = extern struct {638pub const msghdr_const = extern struct {
639 msg_name: ?*const sockaddr,639 name: ?*const sockaddr,
640 msg_namelen: socklen_t,640 namelen: socklen_t,
641 msg_iov: [*]iovec_const,641 iov: [*]iovec_const,
642 msg_iovlen: usize,642 iovlen: usize,
643 msg_control: ?*anyopaque,643 control: ?*anyopaque,
644 msg_controllen: usize,644 controllen: usize,
645 msg_flags: i32,645 flags: i32,
646};646};
647647
648pub const blksize_t = i64;648pub const blksize_t = i64;
lib/std/os/linux/riscv64.zig+29
...@@ -1,7 +1,12 @@...@@ -1,7 +1,12 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const iovec = std.os.iovec;
3const iovec_const = std.os.iovec_const;
4const linux = std.os.linux;
2const uid_t = std.os.linux.uid_t;5const uid_t = std.os.linux.uid_t;
3const gid_t = std.os.linux.gid_t;6const gid_t = std.os.linux.gid_t;
4const pid_t = std.os.linux.pid_t;7const pid_t = std.os.linux.pid_t;
8const sockaddr = linux.sockaddr;
9const socklen_t = linux.socklen_t;
5const timespec = std.os.linux.timespec;10const timespec = std.os.linux.timespec;
611
7pub fn syscall0(number: SYS) usize {12pub fn syscall0(number: SYS) usize {
...@@ -488,6 +493,30 @@ pub const Flock = extern struct {...@@ -488,6 +493,30 @@ pub const Flock = extern struct {
488 __unused: [4]u8,493 __unused: [4]u8,
489};494};
490495
496pub const msghdr = extern struct {
497 name: ?*sockaddr,
498 namelen: socklen_t,
499 iov: [*]iovec,
500 iovlen: i32,
501 __pad1: i32 = 0,
502 control: ?*anyopaque,
503 controllen: socklen_t,
504 __pad2: socklen_t = 0,
505 flags: i32,
506};
507
508pub const msghdr_const = extern struct {
509 name: ?*const sockaddr,
510 namelen: socklen_t,
511 iov: [*]iovec_const,
512 iovlen: i32,
513 __pad1: i32 = 0,
514 control: ?*anyopaque,
515 controllen: socklen_t,
516 __pad2: socklen_t = 0,
517 flags: i32,
518};
519
491// The `stat` definition used by the Linux kernel.520// The `stat` definition used by the Linux kernel.
492pub const Stat = extern struct {521pub const Stat = extern struct {
493 dev: dev_t,522 dev: dev_t,
lib/std/os/linux/sparc64.zig+16-16
...@@ -9,8 +9,8 @@ const sigset_t = linux.sigset_t;...@@ -9,8 +9,8 @@ const sigset_t = linux.sigset_t;
9const linux = std.os.linux;9const linux = std.os.linux;
10const sockaddr = linux.sockaddr;10const sockaddr = linux.sockaddr;
11const socklen_t = linux.socklen_t;11const socklen_t = linux.socklen_t;
12const iovec = linux.iovec;12const iovec = std.os.iovec;
13const iovec_const = linux.iovec_const;13const iovec_const = std.os.iovec_const;
14const timespec = linux.timespec;14const timespec = linux.timespec;
1515
16pub fn syscall_pipe(fd: *[2]i32) usize {16pub fn syscall_pipe(fd: *[2]i32) usize {
...@@ -656,23 +656,23 @@ pub const Flock = extern struct {...@@ -656,23 +656,23 @@ pub const Flock = extern struct {
656};656};
657657
658pub const msghdr = extern struct {658pub const msghdr = extern struct {
659 msg_name: ?*sockaddr,659 name: ?*sockaddr,
660 msg_namelen: socklen_t,660 namelen: socklen_t,
661 msg_iov: [*]iovec,661 iov: [*]iovec,
662 msg_iovlen: u64,662 iovlen: u64,
663 msg_control: ?*anyopaque,663 control: ?*anyopaque,
664 msg_controllen: u64,664 controllen: u64,
665 msg_flags: i32,665 flags: i32,
666};666};
667667
668pub const msghdr_const = extern struct {668pub const msghdr_const = extern struct {
669 msg_name: ?*const sockaddr,669 name: ?*const sockaddr,
670 msg_namelen: socklen_t,670 namelen: socklen_t,
671 msg_iov: [*]iovec_const,671 iov: [*]iovec_const,
672 msg_iovlen: u64,672 iovlen: u64,
673 msg_control: ?*anyopaque,673 control: ?*anyopaque,
674 msg_controllen: u64,674 controllen: u64,
675 msg_flags: i32,675 flags: i32,
676};676};
677677
678pub const off_t = i64;678pub const off_t = i64;