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
Backing files are created securely: the path is opened with
O_CREAT|O_EXCL|O_NOFOLLOW (a pre-existing symlink at the path is
rejected, and an existing regular file is attached rather than
truncated) and the new file is created mode 0600 (owner-only) by
default, so a segment is not world-writable unless you opt in. To
share a file with a peer group, pass an explicit octal mode as the
last argument to new():
my $sem = Data::Sync::Shared::Semaphore->new($path, $max, $initial, 0660);
my $rw = Data::Sync::Shared::RWLock->new($path, 0660);
The mode is still subject to the caller's umask, exactly like open().
Offsets read back from an attached segment are bounds-checked before
use, so a poisoned reader-slot offset cannot steer a pointer outside
the mapping.
=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
( run in 1.171 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )