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 {
648648};
649649
650650pub const msghdr = extern struct {
651 msg_name: ?*sockaddr,
652 msg_namelen: socklen_t,
653 msg_iov: [*]iovec,
654 msg_iovlen: i32,
655 msg_control: ?*anyopaque,
656 msg_controllen: socklen_t,
657 msg_flags: i32,
651 name: ?*sockaddr,
652 namelen: socklen_t,
653 iov: [*]iovec,
654 iovlen: i32,
655 control: ?*anyopaque,
656 controllen: socklen_t,
657 flags: i32,
658658};
659659
660660pub const msghdr_const = extern struct {
661 msg_name: ?*const sockaddr,
662 msg_namelen: socklen_t,
663 msg_iov: [*]iovec_const,
664 msg_iovlen: i32,
665 msg_control: ?*anyopaque,
666 msg_controllen: socklen_t,
667 msg_flags: i32,
661 name: ?*const sockaddr,
662 namelen: socklen_t,
663 iov: [*]iovec_const,
664 iovlen: i32,
665 control: ?*anyopaque,
666 controllen: socklen_t,
667 flags: i32,
668668};
669669
670670pub const blksize_t = i32;
lib/std/os/linux/arm64.zig+16-16
......@@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;
33const linux = std.os.linux;
44const socklen_t = linux.socklen_t;
55const sockaddr = linux.sockaddr;
6const iovec = linux.iovec;
7const iovec_const = linux.iovec_const;
6const iovec = std.os.iovec;
7const iovec_const = std.os.iovec_const;
88const uid_t = linux.uid_t;
99const gid_t = linux.gid_t;
1010const pid_t = linux.pid_t;
......@@ -499,27 +499,27 @@ pub const Flock = extern struct {
499499};
500500
501501pub const msghdr = extern struct {
502 msg_name: ?*sockaddr,
503 msg_namelen: socklen_t,
504 msg_iov: [*]iovec,
505 msg_iovlen: i32,
502 name: ?*sockaddr,
503 namelen: socklen_t,
504 iov: [*]iovec,
505 iovlen: i32,
506506 __pad1: i32 = 0,
507 msg_control: ?*anyopaque,
508 msg_controllen: socklen_t,
507 control: ?*anyopaque,
508 controllen: socklen_t,
509509 __pad2: socklen_t = 0,
510 msg_flags: i32,
510 flags: i32,
511511};
512512
513513pub const msghdr_const = extern struct {
514 msg_name: ?*const sockaddr,
515 msg_namelen: socklen_t,
516 msg_iov: [*]iovec_const,
517 msg_iovlen: i32,
514 name: ?*const sockaddr,
515 namelen: socklen_t,
516 iov: [*]iovec_const,
517 iovlen: i32,
518518 __pad1: i32 = 0,
519 msg_control: ?*anyopaque,
520 msg_controllen: socklen_t,
519 control: ?*anyopaque,
520 controllen: socklen_t,
521521 __pad2: socklen_t = 0,
522 msg_flags: i32,
522 flags: i32,
523523};
524524
525525pub const blksize_t = i32;
lib/std/os/linux/i386.zig+2-2
......@@ -2,8 +2,8 @@ const std = @import("../../std.zig");
22const maxInt = std.math.maxInt;
33const linux = std.os.linux;
44const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;
6const iovec_const = linux.iovec_const;
5const iovec = std.os.iovec;
6const iovec_const = std.os.iovec_const;
77const uid_t = linux.uid_t;
88const gid_t = linux.gid_t;
99const pid_t = linux.pid_t;
lib/std/os/linux/io_uring.zig+132
......@@ -537,6 +537,36 @@ pub const IO_Uring = struct {
537537 return sqe;
538538 }
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
540570 /// Queues (but does not submit) an SQE to perform an `openat(2)`.
541571 /// Returns a pointer to the SQE.
542572 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
12371267 sqe.rw_flags = flags;
12381268}
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
12401290pub fn io_uring_prep_openat(
12411291 sqe: *io_uring_sqe,
12421292 fd: os.fd_t,
......@@ -1908,6 +1958,88 @@ test "accept/connect/send/recv" {
19081958 try testing.expectEqualSlices(u8, buffer_send[0..buffer_recv.len], buffer_recv[0..]);
19091959}
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
19112043test "timeout (after a relative time)" {
19122044 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");
22const maxInt = std.math.maxInt;
33const linux = std.os.linux;
44const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;
6const iovec_const = linux.iovec_const;
5const iovec = std.os.iovec;
6const iovec_const = std.os.iovec_const;
77const uid_t = linux.uid_t;
88const gid_t = linux.gid_t;
99const pid_t = linux.pid_t;
10const sockaddr = linux.sockaddr;
1011const timespec = linux.timespec;
1112
1213pub fn syscall0(number: SYS) usize {
......@@ -716,6 +717,26 @@ pub const Flock = extern struct {
716717 __unused: [4]u8,
717718};
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
719740pub const blksize_t = i32;
720741pub const nlink_t = u32;
721742pub const time_t = i32;
lib/std/os/linux/powerpc.zig+16-16
......@@ -2,8 +2,8 @@ const std = @import("../../std.zig");
22const maxInt = std.math.maxInt;
33const linux = std.os.linux;
44const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;
6const iovec_const = linux.iovec_const;
5const iovec = std.os.iovec;
6const iovec_const = std.os.iovec_const;
77const uid_t = linux.uid_t;
88const gid_t = linux.gid_t;
99const pid_t = linux.pid_t;
......@@ -651,23 +651,23 @@ pub const Flock = extern struct {
651651};
652652
653653pub const msghdr = extern struct {
654 msg_name: ?*sockaddr,
655 msg_namelen: socklen_t,
656 msg_iov: [*]iovec,
657 msg_iovlen: usize,
658 msg_control: ?*anyopaque,
659 msg_controllen: socklen_t,
660 msg_flags: i32,
654 name: ?*sockaddr,
655 namelen: socklen_t,
656 iov: [*]iovec,
657 iovlen: usize,
658 control: ?*anyopaque,
659 controllen: socklen_t,
660 flags: i32,
661661};
662662
663663pub const msghdr_const = extern struct {
664 msg_name: ?*const sockaddr,
665 msg_namelen: socklen_t,
666 msg_iov: [*]iovec_const,
667 msg_iovlen: usize,
668 msg_control: ?*anyopaque,
669 msg_controllen: socklen_t,
670 msg_flags: i32,
664 name: ?*const sockaddr,
665 namelen: socklen_t,
666 iov: [*]iovec_const,
667 iovlen: usize,
668 control: ?*anyopaque,
669 controllen: socklen_t,
670 flags: i32,
671671};
672672
673673pub const blksize_t = i32;
lib/std/os/linux/powerpc64.zig+16-16
......@@ -2,8 +2,8 @@ const std = @import("../../std.zig");
22const maxInt = std.math.maxInt;
33const linux = std.os.linux;
44const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;
6const iovec_const = linux.iovec_const;
5const iovec = std.os.iovec;
6const iovec_const = std.os.iovec_const;
77const uid_t = linux.uid_t;
88const gid_t = linux.gid_t;
99const pid_t = linux.pid_t;
......@@ -626,23 +626,23 @@ pub const Flock = extern struct {
626626};
627627
628628pub const msghdr = extern struct {
629 msg_name: ?*sockaddr,
630 msg_namelen: socklen_t,
631 msg_iov: [*]iovec,
632 msg_iovlen: usize,
633 msg_control: ?*anyopaque,
634 msg_controllen: usize,
635 msg_flags: i32,
629 name: ?*sockaddr,
630 namelen: socklen_t,
631 iov: [*]iovec,
632 iovlen: usize,
633 control: ?*anyopaque,
634 controllen: usize,
635 flags: i32,
636636};
637637
638638pub const msghdr_const = extern struct {
639 msg_name: ?*const sockaddr,
640 msg_namelen: socklen_t,
641 msg_iov: [*]iovec_const,
642 msg_iovlen: usize,
643 msg_control: ?*anyopaque,
644 msg_controllen: usize,
645 msg_flags: i32,
639 name: ?*const sockaddr,
640 namelen: socklen_t,
641 iov: [*]iovec_const,
642 iovlen: usize,
643 control: ?*anyopaque,
644 controllen: usize,
645 flags: i32,
646646};
647647
648648pub const blksize_t = i64;
lib/std/os/linux/riscv64.zig+29
......@@ -1,7 +1,12 @@
11const std = @import("../../std.zig");
2const iovec = std.os.iovec;
3const iovec_const = std.os.iovec_const;
4const linux = std.os.linux;
25const uid_t = std.os.linux.uid_t;
36const gid_t = std.os.linux.gid_t;
47const pid_t = std.os.linux.pid_t;
8const sockaddr = linux.sockaddr;
9const socklen_t = linux.socklen_t;
510const timespec = std.os.linux.timespec;
611
712pub fn syscall0(number: SYS) usize {
......@@ -488,6 +493,30 @@ pub const Flock = extern struct {
488493 __unused: [4]u8,
489494};
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
491520// The `stat` definition used by the Linux kernel.
492521pub const Stat = extern struct {
493522 dev: dev_t,
lib/std/os/linux/sparc64.zig+16-16
......@@ -9,8 +9,8 @@ const sigset_t = linux.sigset_t;
99const linux = std.os.linux;
1010const sockaddr = linux.sockaddr;
1111const socklen_t = linux.socklen_t;
12const iovec = linux.iovec;
13const iovec_const = linux.iovec_const;
12const iovec = std.os.iovec;
13const iovec_const = std.os.iovec_const;
1414const timespec = linux.timespec;
1515
1616pub fn syscall_pipe(fd: *[2]i32) usize {
......@@ -656,23 +656,23 @@ pub const Flock = extern struct {
656656};
657657
658658pub const msghdr = extern struct {
659 msg_name: ?*sockaddr,
660 msg_namelen: socklen_t,
661 msg_iov: [*]iovec,
662 msg_iovlen: u64,
663 msg_control: ?*anyopaque,
664 msg_controllen: u64,
665 msg_flags: i32,
659 name: ?*sockaddr,
660 namelen: socklen_t,
661 iov: [*]iovec,
662 iovlen: u64,
663 control: ?*anyopaque,
664 controllen: u64,
665 flags: i32,
666666};
667667
668668pub const msghdr_const = extern struct {
669 msg_name: ?*const sockaddr,
670 msg_namelen: socklen_t,
671 msg_iov: [*]iovec_const,
672 msg_iovlen: u64,
673 msg_control: ?*anyopaque,
674 msg_controllen: u64,
675 msg_flags: i32,
669 name: ?*const sockaddr,
670 namelen: socklen_t,
671 iov: [*]iovec_const,
672 iovlen: u64,
673 control: ?*anyopaque,
674 controllen: u64,
675 flags: i32,
676676};
677677
678678pub const off_t = i64;