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 )