about summary refs log tree commit homepage
path: root/lib/PublicInbox/Spawn.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2021-01-10 12:15:02 +0000
committerEric Wong <e@80x24.org>2021-01-12 03:51:42 +0000
commitc17c44d9e0ef28f0f0521656f335f836ad8b7754 (patch)
tree32ee54ba703a76adbdb91beeba761f18a3d0884b /lib/PublicInbox/Spawn.pm
parenta7e6a8cd68fb6d700337d8dbc7ee2c65ff3d2fc1 (diff)
downloadpublic-inbox-c17c44d9e0ef28f0f0521656f335f836ad8b7754.tar.gz
For another step in in syscall reduction, we'll support
transferring 3 FDs and a buffer with a single sendmsg/recvmsg
syscall using Socket::MsgHdr if available.

Beyond script/lei itself, this will be used for internal IPC
between search backends (perhaps with SOCK_SEQPACKET).  There's
a chance this could make it to the public-facing daemons, too.

This adds an optional dependency on the Socket::MsgHdr package,
available as libsocket-msghdr-perl on Debian-based distros
(but not CentOS 7.x and FreeBSD 11.x, at least).

Our Inline::C version in PublicInbox::Spawn remains the last
choice for script/lei due to the high startup time, and
IO::FDPass remains supported for non-Debian distros.

Since the socket name prefix changes from 3 to 4, we'll also
take this opportunity to make the argv+env buffer transfer less
error-prone by relying on argc instead of designated delimiters.
Diffstat (limited to 'lib/PublicInbox/Spawn.pm')
-rw-r--r--lib/PublicInbox/Spawn.pm45
1 files changed, 27 insertions, 18 deletions
diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm
index cd94ba96..7d0d9597 100644
--- a/lib/PublicInbox/Spawn.pm
+++ b/lib/PublicInbox/Spawn.pm
@@ -201,6 +201,8 @@ void nodatacow_dir(const char *dir)
 }
 SET_NODATACOW
 
+# last choice for script/lei, 1st choice for lei internals
+# compatible with PublicInbox::CmdIPC4
 my $fdpass = <<'FDPASS';
 #include <sys/types.h>
 #include <sys/uio.h>
@@ -213,16 +215,23 @@ union my_cmsg {
         char pad[sizeof(struct cmsghdr)+ 8 + sizeof(struct my_3fds) + 8];
 };
 
-int send_3fds(int sockfd, int infd, int outfd, int errfd)
+int send_cmd4(PerlIO *s, int in, int out, int err, SV *data, int flags)
 {
         struct msghdr msg = { 0 };
         struct iovec iov;
         union my_cmsg cmsg = { 0 };
         int *fdp;
         size_t i;
+        STRLEN dlen = 0;
 
-        iov.iov_base = &msg.msg_namelen; /* whatever */
-        iov.iov_len = 1;
+        if (SvOK(data)) {
+                iov.iov_base = SvPV(data, dlen);
+                iov.iov_len = dlen;
+        }
+        if (!dlen) { /* must be non-zero */
+                iov.iov_base = &msg.msg_namelen; /* whatever */
+                iov.iov_len = 1;
+        }
         msg.msg_iov = &iov;
         msg.msg_iovlen = 1;
         msg.msg_control = &cmsg.hdr;
@@ -232,38 +241,38 @@ int send_3fds(int sockfd, int infd, int outfd, int errfd)
         cmsg.hdr.cmsg_type = SCM_RIGHTS;
         cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct my_3fds));
         fdp = (int *)CMSG_DATA(&cmsg.hdr);
-        *fdp++ = infd;
-        *fdp++ = outfd;
-        *fdp++ = errfd;
-        return sendmsg(sockfd, &msg, 0) >= 0;
+        *fdp++ = in;
+        *fdp++ = out;
+        *fdp++ = err;
+        return sendmsg(PerlIO_fileno(s), &msg, flags) >= 0;
 }
 
-void recv_3fds(int sockfd)
+void recv_cmd4(PerlIO *s, SV *buf, STRLEN n)
 {
         union my_cmsg cmsg = { 0 };
         struct msghdr msg = { 0 };
         struct iovec iov;
         size_t i;
         Inline_Stack_Vars;
+        Inline_Stack_Reset;
 
-        iov.iov_base = &msg.msg_namelen; /* whatever */
-        iov.iov_len = 1;
+        if (!SvOK(buf))
+                sv_setpvn(buf, "", 0);
+        iov.iov_base = SvGROW(buf, n + 1);
+        iov.iov_len = n;
         msg.msg_iov = &iov;
         msg.msg_iovlen = 1;
         msg.msg_control = &cmsg.hdr;
         msg.msg_controllen = CMSG_SPACE(sizeof(struct my_3fds));
 
-        if (recvmsg(sockfd, &msg, 0) <= 0)
-                return;
-
-        errno = EDOM;
-        Inline_Stack_Reset;
-        if (cmsg.hdr.cmsg_level == SOL_SOCKET &&
+        i = recvmsg(PerlIO_fileno(s), &msg, 0);
+        if (i < 0)
+                croak("recvmsg: %s", strerror(errno));
+        SvCUR_set(buf, i);
+        if (i > 0 && cmsg.hdr.cmsg_level == SOL_SOCKET &&
                         cmsg.hdr.cmsg_type == SCM_RIGHTS &&
                         cmsg.hdr.cmsg_len == CMSG_LEN(sizeof(struct my_3fds))) {
                 int *fdp = (int *)CMSG_DATA(&cmsg.hdr);
-                size_t i;
-
                 for (i = 0; i < 3; i++)
                         Inline_Stack_Push(sv_2mortal(newSViv(*fdp++)));
         }