Data-Sync-Shared
view release on metacpan or search on metacpan
lib/Data/Sync/Shared.pm view on Meta::CPAN
$once->done;
}
# All primitives support anonymous (fork-inherited) mode:
my $sem = Data::Sync::Shared::Semaphore->new(undef, 4);
# And memfd mode (fd-passable):
my $sem = Data::Sync::Shared::Semaphore->new_memfd("my_sem", 4);
my $fd = $sem->memfd;
=head1 DESCRIPTION
Data::Sync::Shared provides five cross-process synchronization primitives
stored in file-backed shared memory (C<mmap(MAP_SHARED)>), using Linux
futex for efficient blocking.
B<Linux-only>. Requires 64-bit Perl.
=head2 Primitives
=over
=item L<Data::Sync::Shared::Semaphore> - bounded counter
CAS-based counting semaphore. C<acquire> decrements (blocks at 0),
C<release> increments (capped at max). Useful for cross-process resource
limiting (connection pools, worker slots).
=item L<Data::Sync::Shared::Barrier> - rendezvous point
N processes call C<wait>; all block until the last one arrives, then all
proceed. Returns true for one "leader" process. Generation counter tracks
how many times the barrier has tripped.
=item L<Data::Sync::Shared::RWLock> - reader-writer lock
Multiple concurrent readers or one exclusive writer. Readers use
C<rdlock>/C<rdunlock>, writers use C<wrlock>/C<wrunlock>. Non-blocking
C<try_rdlock>/C<try_wrlock> variants available.
=item L<Data::Sync::Shared::Condvar> - condition variable
Includes a built-in mutex. C<lock>/C<unlock> protect the predicate.
C<wait> atomically releases the mutex and sleeps; on wakeup it
re-acquires the mutex. C<signal> wakes one waiter, C<broadcast> wakes all.
=item L<Data::Sync::Shared::Once> - one-time init gate
C<enter> returns true for exactly one process (the initializer); all
others block until C<done> is called. If the initializer dies, waiters
detect the stale PID and a new initializer is elected.
=back
=head2 Features
=over
=item * File-backed mmap for cross-process sharing
=item * Futex-based blocking (no busy-spin, no pthread)
=item * PID-based stale lock recovery (dead process detection)
=item * Anonymous and memfd modes
=item * Timeouts on all blocking operations
=item * eventfd integration for event-loop wakeup
=back
=head2 Crash Safety
All primitives encode the holder's PID in the lock word. If a process
dies while holding a lock, other processes detect the stale lock within
2 seconds via C<kill(pid, 0)> and automatically recover.
=head2 Security
The shared memory region (mmap) is writable by all processes that open
it. A malicious process with write access to the backing file or memfd
can corrupt header fields (lock words, counters, parameters) and cause
other processes to deadlock, spin, or behave incorrectly. Do not share
backing files with untrusted processes. Use anonymous mode or memfd
with restricted fd passing for isolation.
=head2 Guard Objects
All locking primitives provide scope-based guards that auto-release
on scope exit (including exceptions):
{
my $g = $rw->rdlock_guard;
# ... read operations ...
} # rdunlock called automatically
{
my $g = $sem->acquire_guard(3); # acquire 3 permits
# ... use resource ...
} # release(3) called automatically
{
my $g = $cv->lock_guard;
$cv->wait_while(sub { !$ready }, 5.0);
} # unlock called automatically
=head1 PRIMITIVES
=head2 Data::Sync::Shared::Semaphore
=head3 Constructors
my $sem = Data::Sync::Shared::Semaphore->new($path, $max);
my $sem = Data::Sync::Shared::Semaphore->new($path, $max, $initial);
my $sem = Data::Sync::Shared::Semaphore->new(undef, $max);
my $sem = Data::Sync::Shared::Semaphore->new_memfd($name, $max);
my $sem = Data::Sync::Shared::Semaphore->new_memfd($name, $max, $initial);
my $sem = Data::Sync::Shared::Semaphore->new_from_fd($fd);
C<$max> is the maximum permit count. C<$initial> defaults to C<$max>
( run in 0.576 second using v1.01-cache-2.11-cpan-39bf76dae61 )