File Coverage

blib/lib/AnyEvent/Semaphore.pm
Criterion Covered Total %
statement 15 59 25.4
branch 0 10 0.0
condition 0 5 0.0
subroutine 5 12 41.6
pod 4 4 100.0
total 24 90 26.6


line stmt bran cond sub pod time code
1             package AnyEvent::Semaphore;
2              
3             our $VERSION = '0.01';
4              
5 1     1   28801 use strict;
  1         4  
  1         63  
6 1     1   7 use warnings;
  1         3  
  1         40  
7              
8 1     1   991 use AE;
  1         11289  
  1         29  
9 1     1   10 use Scalar::Util ();
  1         2  
  1         21  
10 1     1   846 use Method::WeakCallback qw(weak_method_callback);
  1         6235  
  1         973  
11              
12             # internal representation of watcher is an array [$semaphore, $cb]
13              
14             sub new {
15 0     0 1   my ($class, $size) = @_;
16 0   0       my $sem = { size => $size || 1,
17             holes => 0,
18             running => 0,
19             watchers => [] };
20 0           $sem->{schedule_cb} = weak_method_callback($sem, '_schedule'),
21             bless $sem, $class;
22             }
23              
24             sub size {
25 0     0 1   my $sem = shift;
26 0 0         if (@_) {
27 0           $sem->{size} = shift;
28 0           &AE::postpone($sem->{schedule_cb});
29             }
30 0           $sem->{size};
31             }
32              
33 0     0 1   sub running { shift->{running} }
34              
35             sub down {
36 0 0   0 1   return unless defined $_[1];
37 0           my ($sem) = @_;
38 0           my $watchers = $sem->{watchers};
39 0           my $w = [@_];
40 0           bless $w, 'AnyEvent::Semaphore::Watcher';
41 0           push @{$watchers}, $w;
  0            
42 0           Scalar::Util::weaken($watchers->[-1]);
43 0           &AE::postpone($sem->{schedule_cb});
44 0           $w;
45             }
46              
47             sub _schedule {
48 0     0     my $sem = shift;
49 0           my $watchers = $sem->{watchers};
50 0           while ($sem->{size} > $sem->{running}) {
51 0 0         if (defined (my $w = shift @$watchers)) {
52 0           $sem->{running}++;
53 0           my ($cb, @args) = splice @$w, 1;
54 0           bless $w, 'AnyEvent::Semaphore::Down';
55 0           $cb->(@args);
56             }
57             else {
58 0 0         @$watchers or return;
59             }
60             }
61             }
62              
63             sub AnyEvent::Semaphore::Watcher::DESTROY {
64 0     0     local ($!, $@, $SIG{__DIE__});
65 0           eval {
66 0           my $watcher = shift;
67 0           my $sem = $watcher->[0];
68 0           my $holes = ++$sem->{holes};
69 0           my $watchers = $sem->{watchers};
70 0 0 0       if ($holes > 100 and $holes * 2 > @$watchers) {
71 0           @{$sem->{watchers}} = grep defined, @$watchers;
  0            
72 0           Scalar::Util::weaken $_ for @$watchers;
73 0           $sem->{holes} = 0;
74             }
75             }
76             }
77              
78             sub AnyEvent::Semaphore::Down::DESTROY {
79 0     0     local ($!, $@, $SIG{__DIE__});
80 0           eval {
81 0           my $sem = shift->[0];
82 0           $sem->{running}--;
83 0           &AE::postpone($sem->{schedule_cb})
84             }
85             }
86              
87             1;
88              
89             __END__