IPC-Shareable
view release on metacpan or search on metacpan
t/IPCShareableTest.pm view on Meta::CPAN
# when the limit cannot be determined. Unlike low_sem_resources() -- which
# looks only at the LIMIT -- this accounts for sets already consumed, eg. by a
# concurrent smoker or stale sets leaked by previously crashed runs, which is
# what actually starves semget() into ENOSPC on wedged hosts.
sub free_sem_sets {
my $limit = sem_set_limit();
return undef if ! defined $limit;
my $free = $limit - IPC::Shareable::sem_count();
return $free < 0 ? 0 : $free;
}
# Count of IPC::Shareable segments currently live and owned by THIS process
# (a tied structure's root plus its nested-reference children), via the
# module's own global register. Process-scoped, so it is immune to unrelated
# IPC activity from other processes -- and unlike tree_seg_count() it works for
# every serializer, including the binary 'storable' format whose child links
# shm_segments() cannot parse back out of segment content.
sub live_seg_count {
return scalar keys %{ IPC::Shareable->global_register };
}
my $_low_sem_cache;
# True when the host has a small SysV semaphore-set budget (see LOW_SEM_SETS),
# such that a test that creates many tied variables without releasing them
# between steps would exhaust it. Each tie consumes one semaphore set, and on
# OpenBSD the default kern.seminfo.semmni is only 10. An undeterminable limit is
# treated as NOT constrained, so behaviour changes only on platforms we can
# positively identify as small. Cached: the underlying probe runs once.
sub low_sem_resources {
return $_low_sem_cache if defined $_low_sem_cache;
my $limit = sem_set_limit();
$_low_sem_cache = (defined $limit && $limit < LOW_SEM_SETS) ? 1 : 0;
return $_low_sem_cache;
}
# Release every IPC::Shareable segment this process currently holds, but ONLY on
# hosts with a small semaphore-set budget (see low_sem_resources()). A test that
# creates many tied variables calls this between independent steps to stay under
# the limit. On roomy platforms it is a no-op, so the test's behaviour there is
# unchanged.
sub relieve_ipc_pressure {
IPC::Shareable::clean_up_all if low_sem_resources();
}
# Skip the entire test file when the host does not have at least $needed free
# SysV semaphore sets. Every tie consumes one set, so a file whose peak
# concurrent tie count cannot be satisfied dies mid-run with "Could not create
# semaphore set: No space left on device" (ENOSPC) -- the mass CPAN tester
# FAIL mode on OpenBSD smokers (semmni=10) pre-wedged by stale sets from
# previously crashed runs. Skipping is the honest grade there: the environment
# cannot run the file, and a FAIL cascade (croaking mid-test and leaking yet
# more IPC resources on the way down) helps nobody. No-op when the limit
# cannot be determined. Call it before the first tie, after testing_set().
sub require_free_sem_sets {
my ($needed) = @_;
$needed = FREE_SEM_SETS_NEEDED if ! defined $needed;
my $free = free_sem_sets();
return 1 if ! defined $free;
if ($free < $needed) {
plan skip_all => "insufficient free SysV semaphore sets "
. "(free: $free, need: $needed)";
}
return 1;
}
# Return the system-wide limit on SysV semaphore sets (SEMMNI) for the current
# platform, or undef if it cannot be determined. Each IPC::Shareable tie consumes
# one set, so this bounds how many live ties a process may hold at once.
sub sem_set_limit {
# Reuse the module's own cross-platform probe rather than re-deriving the
# per-OS sysctl names here: sysv_info() reads kern.sysv (macOS), kern.ipc
# (FreeBSD), kern.seminfo (OpenBSD), and /proc (Linux). Call it as a class
# method (it shift()s its invocant) and trap its die-on-missing-sysctl.
my $info = eval { IPC::Shareable->sysv_info };
return undef if ! $info;
my $semmni = $info->{semmni};
return defined $semmni && $semmni =~ /^\d+$/ ? $semmni : undef;
}
# Number of live IPC::Shareable segments in this glue's segment tree (the root
# plus any nested-reference child segments), as seen in the OS at the key
# level. Used by assert_clean() to confirm real cleanup. Note: only the JSON
# serializer records child links in a form shm_segments() can follow, so for
# measuring a live storable structure's size use live_seg_count() instead.
sub tree_seg_count {
my ($glue) = @_;
if (! defined $glue) {
croak "tree_seg_count() requires a \$glue param";
}
my $segs = IPC::Shareable::shm_segments($glue);
return scalar keys %$segs;
}
# Turn a human-readable base name into a glue string that is unique to this
# process. Deterministic within a process: unique_glue('foo') always returns
# the same string, in both the parent and any forked child, so both sides of a
# fork tie to the same key.
( run in 1.793 second using v1.01-cache-2.11-cpan-9581c071862 )