IPC-Manager-Client-SharedMem

 view release on metacpan or  search on metacpan

Makefile.PL  view on Meta::CPAN

            }
            unless (semop($sem_id, $UNLOCK)) {
                $reason = "churn-probe unlock iter $iter failed: $!";
                semctl($sem_id, 0, $IPC_RMID, 0);
                last;
            }
            semctl($sem_id, 0, $IPC_RMID, 0);
        }
    }

    # A. systemd-logind RemoveIPC probe (informational, Linux-only).
    #
    # When logind is configured with RemoveIPC=yes (the default on
    # recent Debian/Ubuntu/RHEL) every SysV IPC object owned by a
    # user is destroyed when that user's last login session ends.
    # CPAN smokers that transition across session boundaries during
    # a test run see their semaphores yanked by the kernel, producing
    # sporadic EINVAL from semop.  Linger (`loginctl enable-linger`)
    # suppresses this cleanup.
    #
    # We can't tell from config alone whether a given run will
    # actually straddle a session boundary, and on interactive
    # developer machines it usually won't.  So phase A is a
    # diagnostic: we record the finding and, if a later gating
    # phase (B or C) trips, include it in the failure reason so
    # the affected user has something actionable to read.
    #
    # systemd-logind is Linux-only, so skip this phase on every
    # other platform -- BSD / macOS / Solaris / AIX / etc. all
    # support SysV IPC but do not have logind.
    my $logind_hint;
    if ($^O eq 'linux') {
        my $remove_ipc;

        my @conf_paths = ('/etc/systemd/logind.conf');
        if (opendir my $dh, '/etc/systemd/logind.conf.d') {
            push @conf_paths, map { "/etc/systemd/logind.conf.d/$_" }
                              grep { /\.conf\z/ } readdir $dh;
            closedir $dh;
        }
        for my $path (@conf_paths) {
            next unless -r $path;
            open my $fh, '<', $path or next;
            while (defined(my $line = <$fh>)) {
                next if $line =~ /^\s*(?:#|$)/;
                if ($line =~ /^\s*RemoveIPC\s*=\s*(\S+)/i) {
                    my $val = lc $1;
                    $remove_ipc = ($val eq 'yes' || $val eq 'true'
                                || $val eq 'on'  || $val eq '1') ? 1 : 0;
                }
            }
            close $fh;
        }

        # If no config said anything but systemd-logind appears to be
        # running, the compiled-in default is RemoveIPC=yes.
        $remove_ipc //= -d '/run/systemd/users' ? 1 : 0;

        if ($remove_ipc) {
            my $uid  = $<;
            my $user = eval { scalar getpwuid($uid) };

            my $linger = 0;
            if ($user && -e "/var/lib/systemd/linger/$user") {
                $linger = 1;
            }
            elsif (-d '/run/systemd/users') {
                local $ENV{LC_ALL} = 'C';
                my $out = eval { `loginctl show-user $uid --property=Linger 2>/dev/null` };
                $linger = 1 if defined $out && $out =~ /Linger\s*=\s*yes/i;
            }

            unless ($linger) {
                $logind_hint = "systemd-logind has RemoveIPC=yes and this user "
                             . "has no linger, so SysV IPC objects will be "
                             . "destroyed when the login session ends "
                             . "(workaround: sudo loginctl enable-linger \$USER)";
            }
        }
    }

    # B. Kernel SysV IPC limit probe (Linux-only).
    #
    # Hosts with absurdly tight SysV IPC limits cannot support the
    # SharedMem protocol even when semop/shmop work in isolation.
    # We require enough capacity for SharedMem's per-spawn pair
    # (one semaphore set, one shared-memory segment, plus transient
    # extras when segments are grown) and a default-sized shm
    # segment (65 536 bytes).
    #
    # The four-integer /proc/sys/kernel/sem layout and the
    # /proc/sys/kernel/shm* files are Linux-specific.  *BSD,
    # macOS, Solaris, AIX, and HP-UX expose comparable tunables
    # via sysctl or kstat in incompatible formats and names, and
    # their defaults are already sufficient for SharedMem, so we
    # simply skip this phase off-Linux rather than try to parse
    # every platform's flavour.
    if (!$reason && $^O eq 'linux') {
        my $read_first_line = sub {
            my ($path) = @_;
            return undef unless -r $path;
            open my $fh, '<', $path or return undef;
            my $line = <$fh>;
            close $fh;
            return undef unless defined $line;
            chomp $line;
            return $line;
        };

        # /proc/sys/kernel/sem: SEMMSL SEMMNS SEMOPM SEMMNI
        if (defined(my $line = $read_first_line->('/proc/sys/kernel/sem'))) {
            my ($semmsl, undef, $semopm, $semmni) = split /\s+/, $line;
            if (defined $semmsl && $semmsl =~ /^\d+$/ && $semmsl < 1) {
                $reason = "kernel SEMMSL=$semmsl is below 1";
            }
            elsif (defined $semopm && $semopm =~ /^\d+$/ && $semopm < 3) {
                $reason = "kernel SEMOPM=$semopm is below required 3";
            }
            elsif (defined $semmni && $semmni =~ /^\d+$/ && $semmni < 8) {
                $reason = "kernel SEMMNI=$semmni is too low to support concurrent SharedMem spawns";
            }



( run in 0.693 second using v1.01-cache-2.11-cpan-6aa56a78535 )