=head1 NAME Coro::RWLock - reader/write locks =head1 SYNOPSIS use Coro; $lck = new Coro::RWLock; $lck->rdlock; # acquire read lock $lck->unlock; # unlock lock again # or: $lck->wrlock; # acquire write lock $lck->unlock; # unlock lock again # try a readlock if ($lck->tryrdlock) { ...; $l->unlock; } # try a write lock if ($lck->trywrlock) { ...; $l->unlock; } =head1 DESCRIPTION This module implements reader/write locks. A read can be acquired for read by many coroutines in parallel as long as no writer has locked it (shared access). A single write lock can be acquired when no readers exist. RWLocks basically allow many concurrent readers (without writers) OR a single writer (but no readers). You don't have to load C manually, it will be loaded automatically when you C and call the C constructor. =over 4 =cut package Coro::RWLock; use common::sense; use Coro (); our $VERSION = 6.55; =item $l = new Coro::RWLock; Create a new reader/writer lock. =cut sub new { # [wrcount, [wrqueue], rdcount, [rdqueue]] bless [0, [], 0, []], $_[0]; } =item $l->rdlock Acquire a read lock. =item $l->tryrdlock Try to acquire a read lock. =cut sub rdlock { while ($_[0][0]) { push @{$_[0][3]}, $Coro::current; &Coro::schedule; } ++$_[0][2]; } sub tryrdlock { return if $_[0][0]; ++$_[0][2]; } =item $l->wrlock Acquire a write lock. =item $l->trywrlock Try to acquire a write lock. =cut sub wrlock { while ($_[0][0] || $_[0][2]) { push @{$_[0][1]}, $Coro::current; &Coro::schedule; } ++$_[0][0]; } sub trywrlock { return if $_[0][0] || $_[0][2]; ++$_[0][0]; } =item $l->unlock Give up a previous C or C. =cut my $waiter; sub unlock { # either we are a reader or a writer. decrement accordingly. if ($_[0][2]) { return if --$_[0][2]; } else { $_[0][0]--; } # now we have the choice between waking up a writer or all readers. we choose the writer. if (@{$_[0][1]}) { (shift @{$_[0][1]})->ready; } else { $waiter->ready while $waiter = shift @{$_[0][3]}; } } 1; =back =head1 AUTHOR/SUPPORT/CONTACT Marc A. Lehmann http://software.schmorp.de/pkg/Coro.html =cut