File Coverage

blib/lib/IO/Event/Emulate.pm
Criterion Covered Total %
statement 191 288 66.3
branch 54 108 50.0
condition 19 40 47.5
subroutine 37 53 69.8
pod 0 10 0.0
total 301 499 60.3


line stmt bran cond sub pod time code
1              
2             #
3             # Use a pure-perl event handler that kinda emulates's Event
4             # for IO::Event's event handler.
5             #
6              
7             my $sdebug = 0;
8              
9             {
10             package IO::Event::Emulate;
11              
12 19     19   94 use strict;
  19         36  
  19         678  
13 19     19   98 use warnings;
  19         35  
  19         24731  
14              
15             our @ISA = qw(IO::Event::Common);
16              
17             my %want_read;
18             my %want_write;
19             my %want_exception;
20             my %active;
21              
22             my $rin = '';
23             my $win = '';
24             my $ein = '';
25              
26             my $unloop;
27              
28             sub import
29             {
30 0     0   0 require IO::Event;
31 0         0 IO::Event->import('emulate_Event');
32             }
33              
34             sub new
35             {
36 172     172 0 4068 my ($pkg, @stuff) = @_;
37 172         8550 $pkg->SUPER::new(@stuff);
38             }
39              
40             # a replacement for Event::loop
41             sub ie_loop
42             {
43 4     4 0 13 $unloop = 0;
44 4         8 my ($rout, $wout, $eout);
45 4         15 for(;;) {
46 82 50       255 print STDERR "EMULATE LOOP-TOP\n" if $sdebug;
47 82 100       194 last if $unloop;
48              
49 80         1313 my $timer_timeout = IO::Event::Emulate::Timer->get_time_to_timer;
50              
51 80   100     6894 my $timeout = $timer_timeout || IO::Event::Emulate::Idle->get_time_to_idle;
52              
53 80 50       203 if ($sdebug > 3) {
54 0         0 print STDERR "Readers:\n";
55 0         0 for my $ioe (values %want_read) {
56 0         0 print STDERR "\t${*$ioe}{ie_desc}\n";
  0         0  
57             }
58 0         0 print STDERR "Writers:\n";
59 0         0 for my $ioe (values %want_write) {
60 0         0 print STDERR "\t${*$ioe}{ie_desc}\n";
  0         0  
61             }
62 0         0 print STDERR "Exceptions:\n";
63 0         0 for my $ioe (values %want_exception) {
64 0         0 print STDERR "\t${*$ioe}{ie_desc}\n";
  0         0  
65             }
66             }
67 80         5878761 my ($nfound, $timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
68 80 50       377 print STDERR "SELECT: N$nfound\n" if $sdebug;
69 80 100       272 if ($nfound) {
70             EVENT:
71             {
72 70 50       118 if ($rout) {
  70         192  
73 70         264 for my $ioe (values %want_read) {
74 175 100       363 next unless vec($rout, ${*$ioe}{ie_fileno}, 1);
  175         1091  
75 85         151 my $ret = $ioe->ie_dispatch_read(${*$ioe}{ie_fh});
  85         715  
76 84 50 66     358 if ($ret && vec($wout, ${*$ioe}{ie_fileno}, 1)) {
  16         100  
77 0         0 vec($wout, ${*$ioe}{ie_fileno}, 1) = 0;
  0         0  
78 0         0 $nfound--;
79             }
80 84 50 66     366 if ($ret && vec($eout, ${*$ioe}{ie_fileno}, 1)) {
  16         90  
81 0         0 vec($eout, ${*$ioe}{ie_fileno}, 1) = 0;
  0         0  
82 0         0 $nfound--;
83             }
84 84         122 $nfound--;
85 84 100       357 last EVENT unless $nfound > 0;
86             }
87             }
88 0 0       0 if ($wout) {
89 0         0 for my $ioe (values %want_write) {
90 0 0       0 next unless vec($wout, ${*$ioe}{ie_fileno}, 1);
  0         0  
91 0         0 my $ret = $ioe->ie_dispatch_write(${*$ioe}{ie_fh});
  0         0  
92 0 0 0     0 if ($ret && vec($eout, ${*$ioe}{ie_fileno}, 1)) {
  0         0  
93 0         0 vec($eout, ${*$ioe}{ie_fileno}, 1) = 0;
  0         0  
94 0         0 $nfound--;
95             }
96 0         0 $nfound--;
97 0 0       0 last EVENT unless $nfound > 0;
98             }
99             }
100 0 0       0 if ($eout) {
101 0         0 for my $ioe (values %want_exception) {
102 0 0       0 next unless vec($eout, ${*$ioe}{ie_fileno}, 1);
  0         0  
103 0         0 $ioe->ie_dispatch_exception(${*$ioe}{ie_fh});
  0         0  
104 0         0 $nfound--;
105 0 0       0 last EVENT unless $nfound > 0;
106             }
107             }
108             }
109             }
110 79 100       477 IO::Event::Emulate::Timer->invoke_timers if $timer_timeout;
111 78         604 IO::Event::Emulate::Idle->invoke_idlers($nfound == 0);
112             }
113 2 50       11 die unless ref($unloop);
114 2         17 my @r = @$unloop;
115 2         8 shift(@r);
116 2 50       19 return $r[0] if @r == 1;
117 0         0 return @r;
118             }
119              
120             sub loop
121             {
122 4     4 0 40 ie_loop(@_);
123             }
124              
125             sub timer
126             {
127 3     3 0 7 shift;
128 3         70 IO::Event::Emulate::Timer->new(@_);
129             }
130              
131             sub idle
132             {
133 1     1 0 2 shift;
134 1         8 IO::Event::Emulate::Idle->new(@_);
135             }
136              
137             sub unloop_all
138             {
139 3     3 0 28 $unloop = [1, @_];
140             }
141              
142             sub set_write_polling
143             {
144 172     172 0 1340 my ($self, $new) = @_;
145 172         574 my $fileno = ${*$self}{ie_fileno};
  172         528  
146 172 50       692 if ($new) {
147 0         0 vec($win, $fileno, 1) = 1;
148 0         0 $want_write{$fileno} = $want_exception{$fileno} = $self;
149             } else {
150 172         2324 vec($win, $fileno, 1) = 0;
151 172         607 delete $want_write{$fileno};
152 172 50       848 delete $want_exception{$fileno}
153             unless $want_read{$fileno};
154             }
155 172         2628 $ein = $rin | $win;
156             }
157              
158             sub set_read_polling
159             {
160 332     332 0 1453 my ($self, $new) = @_;
161 332         441 my $fileno = ${*$self}{ie_fileno};
  332         1071  
162 332 100       1588 if ($new) {
163 172         2501 vec($rin, $fileno, 1) = 1;
164 172         2860 $want_read{$fileno} = $want_exception{$fileno} = $self;
165             } else {
166 160 50       1218 if (defined $fileno) {
167 160         2517 vec($rin, $fileno, 1) = 0;
168 160         2895 delete $want_read{$fileno};
169 160 50       1199 delete $want_exception{$fileno}
170             unless $want_write{$fileno}
171             }
172             }
173 332         2800 $ein = $rin | $win;
174             }
175              
176             sub ie_register
177             {
178 172     172 0 839 my ($self) = @_;
179 172         2401 my ($fh, $fileno) = $self->SUPER::ie_register();
180 172         2126 $active{$fileno} = $self;
181 172         950 $self->readevents(! ${*$self}{ie_readclosed});
  172         2482  
182 172         2080 $self->writeevents(0);
183             }
184              
185             sub ie_deregister
186             {
187 141     141 0 515 my ($self) = @_;
188 141         3054 $self->SUPER::ie_deregister();
189 141         774 delete $active{${*$self}{ie_fileno}};
  141         1867  
190             }
191              
192             }{package IO::Event::Emulate::Timer;
193              
194 19     19   130 use warnings;
  19         28  
  19         617  
195 19     19   79 use strict;
  19         21  
  19         582  
196 19     19   93 use Time::HiRes qw(time);
  19         37  
  19         218  
197 19     19   2762 use Carp qw(confess);
  19         22  
  19         1086  
198 19     19   80 use Scalar::Util qw(reftype);
  19         36  
  19         2065  
199              
200             our @ISA = qw(IO::Event);
201             our %timers = ();
202             our %levels = ();
203             our %next = ();
204              
205             BEGIN {
206 19     19   55 for $a (qw(at after interval hard cb desc prio repeat timeout)) {
207 171         196 my $attrib = $a;
208 19     19   78 no strict 'refs';
  19         35  
  19         2388  
209 171         20028 *{"IO::Event::Emulate::Timer::$a"} = sub {
210 0     0   0 my $self = shift;
211 0 0       0 return $self->{$attrib} unless @_;
212 0         0 my $val = shift;
213 0         0 $self->{$attrib} = $val;
214 0         0 return $val;
215 171         393 };
216             }
217             }
218              
219             my $tcount = 1;
220              
221             my @timers;
222              
223             sub get_time_to_timer
224             {
225 80     80   401 @timers = sort { $a <=> $b } keys %next;
  41         195  
226 80         352 my $t = time;
227 80 100       259 if (@timers) {
228 23 50       96 if ($timers[0] > $t) {
229 23         54 my $timeout = $timers[0] - $t;
230 23 50       70 $timeout = 0.01 if $timeout < 0.01;
231 23         68 return $timeout;
232             } else {
233 0         0 return 0.01;
234             }
235             }
236 57         176 return undef;
237             }
238              
239             sub invoke_timers
240             {
241 23   100 23   365 while (@timers && $timers[0] < time) {
242 13 50       52 print STDERR "Ti" if $sdebug;
243 13         45 my $t = shift(@timers);
244 13         89 my $te = delete $next{$t};
245 13         115 for my $tnum (keys %$te) {
246 13         43 my $timer = $te->{$tnum};
247 13 50       67 next unless $timer->{next};
248 13 100       257 next unless $timer->{next} eq $t;
249 11         142 $timer->now();
250             }
251             }
252             }
253              
254             sub new
255             {
256 3     3   52 my ($pkg, %param) = @_;
257 3 50       30 confess unless $param{cb};
258 3 50 33     15 die if $param{after} && $param{at};
259 3         50 my $timer = bless {
260             tcount => $tcount,
261             last_time => time,
262             %param
263             }, __PACKAGE__;
264 3         27 $timers{$tcount++} = $timer;
265 3         48 $timer->schedule;
266 3         37 return $timer;
267             }
268              
269             sub schedule
270             {
271 15     15   35 my ($self) = @_;
272 15         35 my $next;
273 15 100       118 if ($self->{invoked}) {
    50          
    50          
    50          
274 10 50       41 if ($self->{interval}) {
275 10         31 $next = $self->{last_time} + $self->{interval};
276 10 50 33     67 if ($self->{hard} && $self->{next}) {
277 0         0 $next = $self->{next} + $self->{interval};
278             }
279             } else {
280 0         0 $next = undef;
281             }
282             } elsif ($self->{at}) {
283 0         0 $next = $self->{at};
284             } elsif ($self->{after}) {
285 0         0 $next = $self->{after} + time;
286             } elsif ($self->{interval}) {
287 5         25 $next = $self->{interval} + time;
288             } else {
289 0         0 die;
290             }
291 15 50       64 if ($next) {
292 15         223 $next{$next}{$self->{tcount}} = $self;
293 15         185 $self->{next} = $next;
294             } else {
295 0         0 $self->{next} = 0;
296 0         0 $self->stop();
297             }
298             }
299              
300             sub start
301             {
302 2     2   3 my ($self) = @_;
303 2         6 $timers{$self->{tcount}} = $self;
304 2         5 delete $self->{stopped};
305 2         6 $self->schedule;
306             }
307              
308             sub again
309             {
310 2     2   14 my ($self) = @_;
311 2         9 $self->{last_time} = time;
312 2         9 $self->start;
313             }
314              
315             sub now
316             {
317 11     11   40 my ($self) = @_;
318 11         59 $self->{last_time} = time;
319 11   50     170 local($levels{$self->{tcount}}) = ($levels{$self->{tcount}} || 0)+1;
320 11         124 $self->{invoked}++;
321 11 100       144 if (reftype($self->{cb}) eq 'CODE') {
    50          
322 4         35 $self->{cb}->($self);
323             } elsif (reftype($self->{cb}) eq 'ARRAY') {
324 7         15 my ($o, $m) = @{$self->{cb}};
  7         31  
325 7         150 $o->$m($self);
326             } else {
327 0         0 die;
328             }
329 10         2077 $self->schedule;
330             }
331              
332              
333             sub stop
334             {
335 2     2   27 my ($self) = @_;
336 2         8 delete $timers{$self->{tcount}};
337 2         29 $self->{stopped} = time;
338             }
339              
340             sub cancel
341             {
342 0     0   0 my ($self) = @_;
343 0         0 $self->{cancelled} = time;
344 0         0 delete $timers{$self->{tcount}};
345             }
346              
347             sub is_cancelled
348             {
349 0     0   0 my ($self) = @_;
350 0         0 return $self->{cancelled};
351             }
352              
353             sub is_active
354             {
355 0     0   0 my ($self) = @_;
356 0         0 return exists $timers{$self->{tcount}};
357             }
358              
359             sub is_running
360             {
361 0     0   0 my ($self) = @_;
362 0         0 return $levels{$self->{tcount}};
363             }
364              
365             sub is_suspended
366             {
367 0     0   0 my ($self) = @_;
368 0         0 return 0;
369             }
370              
371             sub pending
372             {
373 0     0   0 return;
374             }
375              
376              
377             }{package IO::Event::Emulate::Idle;
378              
379 19     19   104 use warnings;
  19         21  
  19         397  
380 19     19   159 use strict;
  19         43  
  19         677  
381 19     19   94 use Carp qw(confess);
  19         21  
  19         866  
382 19     19   114 use Scalar::Util qw(reftype);
  19         21  
  19         724  
383 19     19   94 use Time::HiRes qw(time);
  19         99  
  19         85  
384              
385             our @ISA = qw(IO::Event);
386             our %timers = ();
387             our %levels = ();
388             our %next = ();
389              
390             my $icount = 0;
391             my %idlers;
392              
393             our $time_to_idle_timeout = 1;
394              
395             sub new
396             {
397 1     1   4 my ($pkg, %param) = @_;
398 1 50       4 confess unless $param{cb};
399 1 50 33     4 die if $param{after} && $param{at};
400 1         10 my $idler = bless {
401             icount => $icount,
402             last_time => time,
403             %param
404             }, __PACKAGE__;
405 1         3 $idlers{$icount++} = $idler;
406 1         4 return $idler;
407             }
408              
409             sub get_time_to_idle
410             {
411 57 100   57   280 return undef unless %idlers;
412 1         5 return $time_to_idle_timeout;
413             }
414              
415             sub start
416             {
417 0     0   0 my ($self) = @_;
418 0         0 $idlers{$self->{icount}} = $self;
419 0         0 delete $self->{stopped};
420 0         0 $self->schedule;
421             }
422              
423             sub again
424             {
425 0     0   0 my ($self) = @_;
426 0         0 $self->{last_time} = time;
427 0         0 $self->start;
428             }
429              
430             sub invoke_idlers
431             {
432 78     78   200 my ($pkg, $is_idle) = @_;
433 78         411 for my $idler (values %idlers) {
434 1 50 33     36 if ($idler->{min} && (time - $idler->{last_time}) < $idler->{min}) {
435 0         0 next;
436             }
437 1 50       18 unless ($is_idle) {
438 0 0       0 next unless $idler->{max};
439 0 0       0 next unless (time - $idler->{last_time}) > $idler->{max};
440             }
441 1         7 $idler->now;
442             }
443             }
444              
445             sub now
446             {
447 1     1   4 my ($self) = @_;
448 1         15 $self->{last_time} = time;
449 1   50     16 local($levels{$self->{icount}}) = ($levels{$self->{icount}} || 0)+1;
450 1 50 33     13 if (defined($self->{reentrant}) && ! $self->{reentrant} && $self->{icount}) {
      33        
451 0         0 return;
452             }
453 1         4 $self->{invoked}++;
454 1 50 33     17 if (defined($self->{repeat}) && ! $self->{repeat}) {
455 1         5 $self->cancel;
456             }
457 1 50       14 if (reftype($self->{cb}) eq 'CODE') {
    0          
458 1         10 $self->{cb}->($self);
459             } elsif (reftype($self->{cb}) eq 'ARRAY') {
460 0         0 my ($o, $m) = @{$self->{cb}};
  0         0  
461 0         0 $o->$m($self);
462             } else {
463 0         0 die;
464             }
465 1         26 $self->{last_time} = time;
466             }
467              
468              
469             sub stop
470             {
471 0     0   0 my ($self) = @_;
472 0         0 delete $idlers{$self->{icount}};
473 0         0 $self->{stopped} = time;
474             }
475              
476             sub cancel
477             {
478 1     1   3 my ($self) = @_;
479 1         14 $self->{cancelled} = time;
480 1         7 delete $idlers{$self->{icount}};
481             }
482              
483             sub is_cancelled
484             {
485 0     0     my ($self) = @_;
486 0           return $self->{cancelled};
487             }
488              
489             sub is_active
490             {
491 0     0     my ($self) = @_;
492 0           return exists $idlers{$self->{icount}};
493             }
494              
495             sub is_running
496             {
497 0     0     my ($self) = @_;
498 0           return $levels{$self->{icount}};
499             }
500              
501             sub is_suspended
502             {
503 0     0     my ($self) = @_;
504 0           return 0;
505             }
506              
507             sub pending
508             {
509 0     0     return;
510             }
511              
512              
513             }#end package
514             1;