--- Coro/Coro/Semaphore.pm 2007/07/25 14:22:33 1.56 +++ Coro/Coro/Semaphore.pm 2008/11/19 11:11:10 1.82 @@ -33,11 +33,11 @@ package Coro::Semaphore; -BEGIN { eval { require warnings } && warnings->unimport ("uninitialized") } +no warnings; use Coro (); -$VERSION = 1.9; +$VERSION = 5.0; =item new [inital count] @@ -46,129 +46,93 @@ negative values) are also allowed, in which case the semaphore is locked by default. -=cut - -sub new { - bless [defined $_[1] ? $_[1] : 1], $_[0]; -} - =item $sem->count Returns the current semaphore count. -=cut - -sub count { - $_[0][0] -} - =item $sem->adjust ($diff) Atomically adds the amount given to the current semaphore count. If the count becomes positive, wakes up any waiters. Does not block if the count becomes negative, however. -=cut - -sub adjust { - # basically a weird copy of up - if (($_[0][0] += $_[1]) > 0) { - (shift @{$_[0][1]})->ready if @{$_[0][1]}; - } -} - =item $sem->down Decrement the counter, therefore "locking" the semaphore. This method waits until the semaphore is available if the counter is zero. -=item $status = $sem->timed_down($timeout) +=item $sem->wait -Like C, but returns false if semaphore couldn't be acquired within -$timeout seconds, otherwise true. +Similar to C, but does not actually decrement the counter. Instead, +when this function returns, a following call to C or C is +guaranteed to succeed without blocking, until the next coroutine switch +(C etc.). + +Note that using C is much less efficient than using C, so try +to prefer C whenever possible. + +=item $sem->wait ($callback) + +If you pass a callback argument to C, it will not wait, but +immediately return. The callback will be called as soon as the semaphore +becomes available (which might be instantly), and gets passed the +semaphore as first argument. + +The callback might C the semaphore exactly once, might wake up other +coroutines, but is I allowed to block (switch to other coroutines). + +This is considered a rather experimental interface, and is subject to +change. =cut -sub down { - while ($_[0][0] <= 0) { - push @{$_[0][1]}, $Coro::current; - &Coro::schedule; - } - --$_[0][0]; -} - -sub timed_down { - require Coro::Timer; - my $timeout = Coro::Timer::timeout($_[1]); - - while ($_[0][0] <= 0) { - push @{$_[0][1]}, $Coro::current; - &Coro::schedule; - if ($timeout) { - # ugly as hell. slow, too, btw! - for (0..$#{$_[0][1]}) { - if ($_[0][1][$_] == $Coro::current) { - splice @{$_[0][1]}, $_, 1; - return; - } - } - die; - } - } - - --$_[0][0]; - return 1; -} +#=item $status = $sem->timed_down ($timeout) +# +#Like C, but returns false if semaphore couldn't be acquired within +#$timeout seconds, otherwise true. + +#sub timed_down { +# require Coro::Timer; +# my $timeout = Coro::Timer::timeout ($_[1]); +# +# while ($_[0][0] <= 0) { +# push @{$_[0][1]}, $Coro::current; +# &Coro::schedule; +# if ($timeout) { +# # ugly as hell. slow, too, btw! +# for (0..$#{$_[0][1]}) { +# if ($_[0][1][$_] == $Coro::current) { +# splice @{$_[0][1]}, $_, 1; +# return; +# } +# } +# die; +# } +# } +# +# --$_[0][0]; +# return 1; +#} =item $sem->up Unlock the semaphore again. -=cut - -sub up { - if (++$_[0][0] > 0) { - (shift @{$_[0][1]})->ready if @{$_[0][1]}; - } -} - =item $sem->try Try to C the semaphore. Returns true when this was possible, otherwise return false and leave the semaphore unchanged. -=cut - -sub try { - if ($_[0][0] > 0) { - --$_[0][0]; - return 1; - } else { - return 0; - } -} - =item $sem->waiters In scalar context, returns the number of coroutines waiting for this semaphore. -=cut - -sub waiters { - @{$_[0][1]}; -} - =item $guard = $sem->guard This method calls C and then creates a guard object. When the guard object is destroyed it automatically calls C. -=item $guard = $sem->timed_guard($timeout) - -Like C, but returns undef if semaphore couldn't be acquired within -$timeout seconds, otherwise the guard object. - =cut sub guard { @@ -178,11 +142,16 @@ bless \\$_[0], Coro::Semaphore::guard::; } -sub timed_guard { - &timed_down - ? bless \\$_[0], Coro::Semaphore::guard:: - : (); -} +#=item $guard = $sem->timed_guard ($timeout) +# +#Like C, but returns undef if semaphore couldn't be acquired within +#$timeout seconds, otherwise the guard object. + +#sub timed_guard { +# &timed_down +# ? bless \\$_[0], Coro::Semaphore::guard:: +# : (); +#} sub Coro::Semaphore::guard::DESTROY { &up(${${$_[0]}});