about summary refs log tree commit homepage
path: root/lib/PublicInbox/IPC.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2023-03-25 02:08:52 +0000
committerEric Wong <e@80x24.org>2023-03-25 02:12:54 +0000
commitcfd20b04dfe495df80ad9c62949103d555f65f49 (patch)
tree6d090488a42f47111d1d7ef0f06d127ec1d55a58 /lib/PublicInbox/IPC.pm
parente28c01f038ddafa1f78c1ba47b5593fe353b5978 (diff)
downloadpublic-inbox-cfd20b04dfe495df80ad9c62949103d555f65f49.tar.gz
I'm not sure how this went undetected for so long, but EINTR
must be checked for when working with blocking sockets.  EINTR
shouldn't happen for non-blocking sockets, though, but it's
easier to just use the new wrapper in most of those places.

I don't know what I was smoking when I left out EINTR checks :x
Diffstat (limited to 'lib/PublicInbox/IPC.pm')
-rw-r--r--lib/PublicInbox/IPC.pm35
1 files changed, 28 insertions, 7 deletions
diff --git a/lib/PublicInbox/IPC.pm b/lib/PublicInbox/IPC.pm
index 548a72eb..7fa656d0 100644
--- a/lib/PublicInbox/IPC.pm
+++ b/lib/PublicInbox/IPC.pm
@@ -216,9 +216,27 @@ sub ipc_sibling_atfork_child {
         $pid == $$ and die "BUG: $$ ipc_atfork_child called on itself";
 }
 
+sub send_cmd ($$$$) {
+        my ($s, $fds, $buf, $fl) = @_;
+        while (1) {
+                my $n = $send_cmd->($s, $fds, $buf, $fl);
+                next if !defined($n) && $!{EINTR};
+                return $n;
+        }
+}
+
+sub recv_cmd ($$$) {
+        my ($s, undef, $len) = @_; # $_[1] is $buf
+        while (1) {
+                my @fds = $recv_cmd->($s, $_[1], $len);
+                next if scalar(@fds) == 1 && !defined($fds[0]) && $!{EINTR};
+                return @fds;
+        }
+}
+
 sub recv_and_run {
         my ($self, $s2, $len, $full_stream) = @_;
-        my @fds = $recv_cmd->($s2, my $buf, $len // $MY_MAX_ARG_STRLEN);
+        my @fds = recv_cmd($s2, my $buf, $len // $MY_MAX_ARG_STRLEN);
         return if scalar(@fds) && !defined($fds[0]);
         my $n = length($buf) or return 0;
         my $nfd = 0;
@@ -278,15 +296,18 @@ sub stream_in_full ($$$) {
         my ($s1, $fds, $buf) = @_;
         socketpair(my $r, my $w, AF_UNIX, SOCK_STREAM, 0) or
                 croak "socketpair: $!";
-        my $n = $send_cmd->($s1, [ fileno($r) ],
+        my $n = send_cmd($s1, [ fileno($r) ],
                         ipc_freeze(['do_sock_stream', length($buf)]),
                         MSG_EOR) // croak "sendmsg: $!";
         undef $r;
-        $n = $send_cmd->($w, $fds, $buf, 0) // croak "sendmsg: $!";
+        $n = send_cmd($w, $fds, $buf, 0) // croak "sendmsg: $!";
         while ($n < length($buf)) {
-                my $x = syswrite($w, $buf, length($buf) - $n, $n) //
-                                croak "syswrite: $!";
-                croak "syswrite wrote 0 bytes" if $x == 0;
+                my $x = syswrite($w, $buf, length($buf) - $n, $n);
+                if (!defined($n)) {
+                        next if $!{EINTR};
+                        croak "syswrite: $!";
+                }
+                $x or croak "syswrite wrote 0 bytes";
                 $n += $x;
         }
 }
@@ -299,7 +320,7 @@ sub wq_io_do { # always async
                 if (length($buf) > $MY_MAX_ARG_STRLEN) {
                         stream_in_full($s1, $fds, $buf);
                 } else {
-                        my $n = $send_cmd->($s1, $fds, $buf, MSG_EOR);
+                        my $n = send_cmd $s1, $fds, $buf, MSG_EOR;
                         return if defined($n); # likely
                         $!{ETOOMANYREFS} and
                                 croak "sendmsg: $! (check RLIMIT_NOFILE)";