Data-Sync-Shared
view release on metacpan or search on metacpan
$cv->lock;
$cv->try_lock; # non-blocking
$cv->wait; # atomically unlock + wait + re-lock
$cv->wait(2.0); # with timeout
$cv->signal; # wake one waiter
$cv->broadcast; # wake all waiters
$cv->wait_while(sub { !$ready }, 5.0); # predicate loop
$cv->unlock;
# Once -- one-time initialization gate
my $once = Data::Sync::Shared::Once->new('/tmp/once.shm');
if ($once->enter) { # or enter($timeout)
do_init();
$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;
DESCRIPTION
Data::Sync::Shared provides five cross-process synchronization
primitives stored in file-backed shared memory (mmap(MAP_SHARED)), using
Linux futex for efficient blocking.
Linux-only. Requires 64-bit Perl.
Primitives
Data::Sync::Shared::Semaphore - bounded counter
CAS-based counting semaphore. "acquire" decrements (blocks at 0),
"release" increments (capped at max). Useful for cross-process
resource limiting (connection pools, worker slots).
Data::Sync::Shared::Barrier - rendezvous point
N processes call "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.
Data::Sync::Shared::RWLock - reader-writer lock
Multiple concurrent readers or one exclusive writer. Readers use
"rdlock"/"rdunlock", writers use "wrlock"/"wrunlock". Non-blocking
"try_rdlock"/"try_wrlock" variants available.
Data::Sync::Shared::Condvar - condition variable
Includes a built-in mutex. "lock"/"unlock" protect the predicate.
"wait" atomically releases the mutex and sleeps; on wakeup it
re-acquires the mutex. "signal" wakes one waiter, "broadcast" wakes
all.
Data::Sync::Shared::Once - one-time init gate
"enter" returns true for exactly one process (the initializer); all
others block until "done" is called. If the initializer dies,
waiters detect the stale PID and a new initializer is elected.
Features
* File-backed mmap for cross-process sharing
* Futex-based blocking (no busy-spin, no pthread)
* PID-based stale lock recovery (dead process detection)
* Anonymous and memfd modes
* Timeouts on all blocking operations
* eventfd integration for event-loop wakeup
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 "kill(pid, 0)" and automatically recover.
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.
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
PRIMITIVES
Data::Sync::Shared::Semaphore
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);
( run in 1.259 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )