]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Syscall.pm
update copyrights for 2021
[public-inbox.git] / lib / PublicInbox / Syscall.pm
index c66ea51b4c6a8180810a01538e9a8e3945f69766..a1f532353eab391020be7a94710433839fc2d278 100644 (file)
@@ -5,7 +5,7 @@
 # This license differs from the rest of public-inbox
 #
 # This module is Copyright (c) 2005 Six Apart, Ltd.
-# Copyright (C) 2019 all contributors <meta@public-inbox.org>
+# Copyright (C) 2019-2021 all contributors <meta@public-inbox.org>
 #
 # All rights reserved.
 #
@@ -14,7 +14,7 @@
 package PublicInbox::Syscall;
 use strict;
 use parent qw(Exporter);
-use POSIX qw(ENOSYS SEEK_CUR);
+use POSIX qw(ENOSYS O_NONBLOCK);
 use Config;
 
 # $VERSION = '0.25'; # Sys::Syscall version
@@ -41,9 +41,6 @@ use constant {
        EPOLL_CTL_ADD => 1,
        EPOLL_CTL_DEL => 2,
        EPOLL_CTL_MOD => 3,
-
-       SFD_CLOEXEC => 02000000,
-       SFD_NONBLOCK => 00004000,
 };
 
 our $loaded_syscall = 0;
@@ -69,6 +66,8 @@ our (
      $SYS_signalfd4,
      );
 
+my $SFD_CLOEXEC = 02000000; # Perl does not expose O_CLOEXEC
+sub SFD_NONBLOCK () { O_NONBLOCK }
 our $no_deprecated = 0;
 
 if ($^O eq "linux") {
@@ -78,9 +77,9 @@ if ($^O eq "linux") {
     my $u64_mod_8 = 0;
 
     # if we're running on an x86_64 kernel, but a 32-bit process,
-    # we need to use the i386 syscall numbers.
+    # we need to use the x32 or i386 syscall numbers.
     if ($machine eq "x86_64" && $Config{ptrsize} == 4) {
-        $machine = "i386";
+        $machine = $Config{cppsymbols} =~ /\b__ILP32__=1\b/ ? 'x32' : 'i386';
     }
 
     # Similarly for mips64 vs mips
@@ -98,6 +97,18 @@ if ($^O eq "linux") {
         $SYS_epoll_ctl    = 233;
         $SYS_epoll_wait   = 232;
         $SYS_signalfd4 = 289;
+    } elsif ($machine eq 'x32') {
+        $SYS_epoll_create = 1073742037;
+        $SYS_epoll_ctl = 1073742057;
+        $SYS_epoll_wait = 1073742056;
+        $SYS_signalfd4 = 1073742113;
+    } elsif ($machine eq 'sparc64') {
+       $SYS_epoll_create = 193;
+       $SYS_epoll_ctl = 194;
+       $SYS_epoll_wait = 195;
+       $u64_mod_8 = 1;
+       $SYS_signalfd4 = 317;
+       $SFD_CLOEXEC = 020000000;
     } elsif ($machine =~ m/^parisc/) {
         $SYS_epoll_create = 224;
         $SYS_epoll_ctl    = 225;
@@ -135,6 +146,7 @@ if ($^O eq "linux") {
         $SYS_epoll_wait   = 409;
         $u64_mod_8        = 1;
         $SYS_signalfd4 = 484;
+       $SFD_CLOEXEC = 010000000;
     } elsif ($machine eq "aarch64") {
         $SYS_epoll_create = 20;  # (sys_epoll_create1)
         $SYS_epoll_ctl    = 21;
@@ -215,50 +227,56 @@ sub epoll_ctl_mod8 {
 our $epoll_wait_events;
 our $epoll_wait_size = 0;
 sub epoll_wait_mod4 {
-    # resize our static buffer if requested size is bigger than we've ever done
-    if ($_[1] > $epoll_wait_size) {
-        $epoll_wait_size = $_[1];
-        $epoll_wait_events = "\0" x 12 x $epoll_wait_size;
-    }
-    my $ct = syscall($SYS_epoll_wait, $_[0]+0, $epoll_wait_events, $_[1]+0, $_[2]+0);
-    for (0..$ct-1) {
-        @{$_[3]->[$_]}[1,0] = unpack("LL", substr($epoll_wait_events, 12*$_, 8));
-    }
-    return $ct;
+       my ($epfd, $maxevents, $timeout_msec, $events) = @_;
+       # resize our static buffer if maxevents bigger than we've ever done
+       if ($maxevents > $epoll_wait_size) {
+               $epoll_wait_size = $maxevents;
+               vec($epoll_wait_events, $maxevents * 12 * 8 - 1, 1) = 0;
+       }
+       @$events = ();
+       my $ct = syscall($SYS_epoll_wait, $epfd, $epoll_wait_events,
+                       $maxevents, $timeout_msec);
+       for (0..$ct - 1) {
+               # 12-byte struct epoll_event
+               # 4 bytes uint32_t events mask (skipped, useless to us)
+               # 8 bytes: epoll_data_t union (first 4 bytes are the fd)
+               # So we skip the first 4 bytes and take the middle 4:
+               $events->[$_] = unpack('L', substr($epoll_wait_events,
+                                                       12 * $_ + 4, 4));
+       }
 }
 
 sub epoll_wait_mod8 {
-    # resize our static buffer if requested size is bigger than we've ever done
-    if ($_[1] > $epoll_wait_size) {
-        $epoll_wait_size = $_[1];
-        $epoll_wait_events = "\0" x 16 x $epoll_wait_size;
-    }
-    my $ct;
-    if ($no_deprecated) {
-        $ct = syscall($SYS_epoll_wait, $_[0]+0, $epoll_wait_events, $_[1]+0, $_[2]+0, undef);
-    } else {
-        $ct = syscall($SYS_epoll_wait, $_[0]+0, $epoll_wait_events, $_[1]+0, $_[2]+0);
-    }
-    for (0..$ct-1) {
-        # 16 byte epoll_event structs, with format:
-        #    4 byte mask [idx 1]
-        #    4 byte padding (we put it into idx 2, useless)
-        #    8 byte data (first 4 bytes are fd, into idx 0)
-        @{$_[3]->[$_]}[1,2,0] = unpack("LLL", substr($epoll_wait_events, 16*$_, 12));
-    }
-    return $ct;
+       my ($epfd, $maxevents, $timeout_msec, $events) = @_;
+
+       # resize our static buffer if maxevents bigger than we've ever done
+       if ($maxevents > $epoll_wait_size) {
+               $epoll_wait_size = $maxevents;
+               vec($epoll_wait_events, $maxevents * 16 * 8 - 1, 1) = 0;
+       }
+       @$events = ();
+       my $ct = syscall($SYS_epoll_wait, $epfd, $epoll_wait_events,
+                       $maxevents, $timeout_msec,
+                       $no_deprecated ? undef : ());
+       for (0..$ct - 1) {
+               # 16-byte struct epoll_event
+               # 4 bytes uint32_t events mask (skipped, useless to us)
+               # 4 bytes padding (skipped, useless)
+               # 8 bytes epoll_data_t union (first 4 bytes are the fd)
+               # So skip the first 8 bytes, take 4, and ignore the last 4:
+               $events->[$_] = unpack('L', substr($epoll_wait_events,
+                                                       16 * $_ + 8, 4));
+       }
 }
 
 sub signalfd ($$$) {
        my ($fd, $signos, $flags) = @_;
        if ($SYS_signalfd4) {
-               # Not sure if there's a way to get pack/unpack to get the
-               # contents of POSIX::SigSet to a buffer, but prepping the
-               # bitmap like one would for select() works:
-               my $buf = "\0" x 8;
-               vec($buf, $_ - 1, 1) = 1 for @$signos;
-
-               syscall($SYS_signalfd4, $fd, $buf, 8, $flags|SFD_CLOEXEC);
+               my $set = POSIX::SigSet->new(@$signos);
+               syscall($SYS_signalfd4, $fd, "$$set",
+                       # $Config{sig_count} is NSIG, so this is NSIG/8:
+                       int($Config{sig_count}/8),
+                       $flags|$SFD_CLOEXEC);
        } else {
                $! = ENOSYS;
                undef;