File Coverage

blib/lib/AnyEvent/Strict.pm
Criterion Covered Total %
statement 27 90 30.0
branch 5 50 10.0
condition 1 12 8.3
subroutine 8 17 47.0
pod 0 8 0.0
total 41 177 23.1


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             AnyEvent::Strict - force strict mode on for the whole process
4              
5             =head1 SYNOPSIS
6              
7             use AnyEvent::Strict;
8             # strict mode now switched on
9              
10             =head1 DESCRIPTION
11              
12             This module implements AnyEvent's strict mode.
13              
14             Loading it makes AnyEvent check all arguments to AnyEvent-methods, at the
15             expense of being slower (often the argument checking takes longer than the
16             actual function). It also wraps all callbacks to check for modifications
17             of C<$_>, which indicates a programming bug inside the watcher callback.
18              
19             Normally, you don't load this module yourself but instead use it
20             indirectly via the C environment variable (see
21             L). However, this module can be loaded manually at any time.
22              
23             =cut
24              
25             package AnyEvent::Strict;
26              
27 1     1   682 use Carp qw(confess);
  1         3  
  1         51  
28 1     1   6 use Errno ();
  1         2  
  1         15  
29 1     1   12 use POSIX ();
  1         3  
  1         34  
30              
31             $Carp::Internal{AE} = 1;
32             $Carp::Internal{AnyEvent::Strict} = 1;
33              
34 1     1   6 use AnyEvent (); BEGIN { AnyEvent::common_sense }
  1     1   2  
  1         28  
  1         6  
35              
36             AnyEvent::_isa_hook 1 => "AnyEvent::Strict", 1;
37              
38             BEGIN {
39 1 50   1   9 if (defined &Internals::SvREADONLY) {
40             # readonly available (at least 5.8.9+, working better in 5.10.1+)
41             *wrap = sub {
42 1     1   2 my $cb = shift;
43              
44             sub {
45 0     0   0 local $_;
46 0         0 Internals::SvREADONLY $_, 1;
47 0         0 &$cb;
48             }
49 1         1283 };
  1         3  
50             } else {
51             # or not :/
52 0         0 my $magic = []; # a unique magic value
53              
54             *wrap = sub {
55 0         0 my $cb = shift;
56              
57             sub {
58 0         0 local $_ = $magic;
59              
60 0         0 &$cb;
61              
62 0 0 0     0 if (!ref $_ || $_ != $magic) {
63 0         0 require AnyEvent::Debug;
64 0         0 die "callback $cb (" . AnyEvent::Debug::cb2str ($cb) . ") modified \$_ without restoring it.\n";
65             }
66             }
67 0         0 };
  0         0  
68             }
69             }
70              
71             our (@FD_INUSE, $FD_I);
72             our $FD_CHECK_W = AE::timer 4, 4, sub {
73             my $cnt = (@FD_INUSE < 100 * 10 ? int @FD_INUSE * 0.1 : 100) || 10;
74              
75             if ($FD_I <= 0) {
76             #pop @FD_INUSE while @FD_INUSE && !$FD_INUSE[-1];
77             $FD_I = @FD_INUSE
78             or return; # empty
79             }
80              
81             $cnt = $FD_I if $cnt > $FD_I;
82              
83             eval {
84             do {
85             !$FD_INUSE[--$FD_I]
86             or (POSIX::lseek $FD_I, 0, 1) != -1
87             or $! != Errno::EBADF
88             or die;
89             } while --$cnt;
90             1
91             } or AE::log crit => "File descriptor $FD_I registered with AnyEvent but prematurely closed, event loop might malfunction.";
92             };
93              
94             sub io {
95 0     0 0 0 my $class = shift;
96 0         0 my (%arg, $fh, $cb, $fd) = @_;
97              
98             ref $arg{cb}
99 0 0       0 or confess "AnyEvent->io called with illegal cb argument '$arg{cb}'";
100 0         0 $cb = wrap delete $arg{cb};
101            
102 0 0       0 $arg{poll} =~ /^[rw]$/
103             or confess "AnyEvent->io called with illegal poll argument '$arg{poll}'";
104              
105 0         0 $fh = delete $arg{fh};
106              
107 0 0       0 if ($fh =~ /^\s*\d+\s*$/) {
108 0         0 $fd = $fh;
109 0         0 ($fh) = AnyEvent::_dupfh $arg{poll}, $fh;
110             } else {
111 0 0       0 defined eval { $fd = fileno $fh }
  0         0  
112             or confess "AnyEvent->io called with illegal fh argument '$fh'";
113             }
114              
115 0 0       0 -f $fh
116             and confess "AnyEvent->io called with fh argument pointing to a file";
117              
118 0         0 delete $arg{poll};
119            
120 0 0       0 confess "AnyEvent->io called with unsupported parameter(s) " . join ", ", keys %arg
121             if keys %arg;
122              
123 0         0 ++$FD_INUSE[$fd];
124              
125 0         0 bless [
126             $fd,
127             $class->SUPER::io (@_, cb => $cb)
128             ], "AnyEvent::Strict::io";
129             }
130              
131             sub AnyEvent::Strict::io::DESTROY {
132 0     0   0 --$FD_INUSE[$_[0][0]];
133             }
134              
135             sub timer {
136 1     1 0 3 my $class = shift;
137 1         4 my %arg = @_;
138              
139             ref $arg{cb}
140 1 50       4 or confess "AnyEvent->timer called with illegal cb argument '$arg{cb}'";
141 1         4 my $cb = wrap delete $arg{cb};
142            
143             exists $arg{after}
144 1 50       4 or confess "AnyEvent->timer called without mandatory 'after' parameter";
145 1         1 delete $arg{after};
146            
147 1 50 33     6 !$arg{interval} or $arg{interval} > 0
148             or confess "AnyEvent->timer called with illegal interval argument '$arg{interval}'";
149 1         2 delete $arg{interval};
150            
151 1 50       4 confess "AnyEvent->timer called with unsupported parameter(s) " . join ", ", keys %arg
152             if keys %arg;
153              
154 1         6 $class->SUPER::timer (@_, cb => $cb)
155             }
156              
157             sub signal {
158 0     0 0   my $class = shift;
159 0           my %arg = @_;
160              
161             ref $arg{cb}
162 0 0         or confess "AnyEvent->signal called with illegal cb argument '$arg{cb}'";
163 0           my $cb = wrap delete $arg{cb};
164            
165 0 0 0       defined AnyEvent::Base::sig2num $arg{signal} and $arg{signal} == 0
166             or confess "AnyEvent->signal called with illegal signal name '$arg{signal}'";
167 0           delete $arg{signal};
168            
169 0 0         confess "AnyEvent->signal called with unsupported parameter(s) " . join ", ", keys %arg
170             if keys %arg;
171              
172 0           $class->SUPER::signal (@_, cb => $cb)
173             }
174              
175             sub child {
176 0     0 0   my $class = shift;
177 0           my %arg = @_;
178              
179             ref $arg{cb}
180 0 0         or confess "AnyEvent->child called with illegal cb argument '$arg{cb}'";
181 0           my $cb = wrap delete $arg{cb};
182            
183 0 0         $arg{pid} =~ /^-?\d+$/
184             or confess "AnyEvent->child called with malformed pid value '$arg{pid}'";
185 0           delete $arg{pid};
186            
187 0 0         confess "AnyEvent->child called with unsupported parameter(s) " . join ", ", keys %arg
188             if keys %arg;
189              
190 0           $class->SUPER::child (@_, cb => $cb)
191             }
192              
193             sub idle {
194 0     0 0   my $class = shift;
195 0           my %arg = @_;
196              
197             ref $arg{cb}
198 0 0         or confess "AnyEvent->idle called with illegal cb argument '$arg{cb}'";
199 0           my $cb = wrap delete $arg{cb};
200            
201 0 0         confess "AnyEvent->idle called with unsupported parameter(s) " . join ", ", keys %arg
202             if keys %arg;
203              
204 0           $class->SUPER::idle (@_, cb => $cb)
205             }
206              
207             sub condvar {
208 0     0 0   my $class = shift;
209 0           my %arg = @_;
210              
211             !exists $arg{cb} or ref $arg{cb}
212 0 0 0       or confess "AnyEvent->condvar called with illegal cb argument '$arg{cb}'";
213 0 0         my @cb = exists $arg{cb} ? (cb => wrap delete $arg{cb}) : ();
214            
215 0 0         confess "AnyEvent->condvar called with unsupported parameter(s) " . join ", ", keys %arg
216             if keys %arg;
217              
218 0           $class->SUPER::condvar (@cb);
219             }
220              
221             sub time {
222 0     0 0   my $class = shift;
223              
224             @_
225 0 0         and confess "AnyEvent->time wrongly called with paramaters";
226              
227 0           $class->SUPER::time (@_)
228             }
229              
230             sub now {
231 0     0 0   my $class = shift;
232              
233             @_
234 0 0         and confess "AnyEvent->now wrongly called with paramaters";
235              
236 0           $class->SUPER::now (@_)
237             }
238              
239             =head1 AUTHOR
240              
241             Marc Lehmann
242             http://anyevent.schmorp.de
243              
244             =cut
245              
246             1
247