File Coverage

blib/lib/IO/Async/Loop/IO/Async.pm
Criterion Covered Total %
statement 119 124 95.9
branch 21 32 65.6
condition 6 9 66.6
subroutine 25 26 96.1
pod 14 14 100.0
total 185 205 90.2


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2010 -- leonerd@leonerd.org.uk
5              
6             package IO::Async::Loop::IO::Async;
7              
8 11     11   14600 use strict;
  11         24  
  11         478  
9 11     11   64 use warnings;
  11         30  
  11         753  
10              
11             our $VERSION = '0.02';
12 11     11   79 use constant API_VERSION => '0.33';
  11         17  
  11         1005  
13              
14 11     11   64 use base qw( IO::Async::Loop );
  11         20  
  11         14039  
15              
16 11     11   173987 use Carp;
  11         39  
  11         932  
17              
18 11     11   64 use Scalar::Util qw( weaken );
  11         26  
  11         559  
19              
20 11     11   13481 use IO::Async::Notifier;
  11         33839  
  11         374  
21 11     11   11609 use IO::Async::Handle;
  11         143013  
  11         403  
22 11     11   11298 use IO::Async::Timer::Absolute;
  11         23151  
  11         325  
23 11     11   10562 use IO::Async::Signal;
  11         7173  
  11         290  
24 11     11   11438 use IO::Async::PID;
  11         8558  
  11         15825  
25              
26             =head1 NAME
27              
28             L - use C with C
29              
30             =head1 SYNOPSIS
31              
32             use IO::Async::Loop::IO::Async;
33              
34             my $loop = IO::Async::Loop::IO::Async->new();
35              
36             $loop->add( ... );
37              
38             $loop->add( IO::Async::Signal->new(
39             name => 'HUP',
40             on_receipt => sub { ... },
41             ) );
42              
43             $loop->loop_forever();
44              
45             =head1 DESCRIPTION
46              
47             This subclass of L uses another instance of an
48             C object as its underlying implementation. While this at
49             first appears to be pointless, this module distribution is not primarily
50             intended to serve a useful purpose for end-users. Rather, it stands as a real
51             code example, for authors of other modules to use for reference.
52              
53             =head2 For C Authors
54              
55             Authors of other subclasses to implement C subclasses may
56             find this distribution useful as a template. By copying the code and replacing
57             the contents of the various C and C methods, a Loop
58             implementation can be built making use of some other event system or
59             underlying kernel blocking primative.
60              
61             =head2 For Authors of Other Event Systems
62              
63             Authors of implementations in other event systems wishing to support running
64             their event system on top of L may find this distribution useful to
65             read a way to implement the various underlying behaviours, such as watching
66             filehandles and timers. Examples in each of the C and C
67             methods may be useful to demonstrate the sort of code that might be required
68             to attach some other event system on top of C.
69              
70             =head1 CONSTRUCTOR
71              
72             =cut
73              
74             =head2 $loop = IO::Async::Loop::IO::Async->new()
75              
76             This function returns a new instance of a C object.
77              
78             =cut
79              
80             sub new
81             {
82 10     10 1 207 my $class = shift;
83 10         31 my ( %args ) = @_;
84              
85 10         134 my $self = $class->SUPER::__new( %args );
86              
87 10         6336 $self->{root_notifier} = IO::Async::Notifier->new;
88              
89 10         295 return $self;
90             }
91              
92             =head1 METHODS
93              
94             =cut
95              
96             =head2 $loop->parent_loop( $parent )
97              
98             =head2 $parent = $loop->parent_loop
99              
100             Accessor for the underlying C that this loop will use. If one
101             is not provided by the time that C is first invoked, one will be
102             constructed using the normal C<< IO::Async::Loop->new >> constructor. This
103             method may be used to access it after that.
104              
105             =cut
106              
107             sub parent_loop
108             {
109 56     56 1 91 my $self = shift;
110 56         319 my ( $loop ) = @_;
111              
112 56 50       289 $self->{parent_loop} = $loop if $loop;
113              
114 56   66     330 $self->{parent_loop} ||= do {
115 9         144 my $loop = IO::Async::Loop->new;
116 9         57902 $loop->add( $self->{root_notifier} );
117 9         49171 $loop;
118             };
119              
120 56         398 return $self->{parent_loop};
121             }
122              
123             sub loop_once
124             {
125 45     45 1 1692450 my $self = shift;
126 45         94 my ( $timeout ) = @_;
127              
128 45         195 $self->parent_loop->loop_once( $timeout );
129             }
130              
131             sub watch_io
132             {
133 3     3 1 104230 my $self = shift;
134 3         14 my %params = @_;
135              
136 3 50       15 my $handle = $params{handle} or die "Need a handle";
137              
138 3   66     18 my $ioa_handle = $self->{handles}{$handle} ||= do {
139 1         15 my $h = IO::Async::Handle->new;
140 1         44 $self->{root_notifier}->add_child( $h );
141 1         29 $h;
142             };
143              
144 3 100       15 if( my $on_read_ready = $params{on_read_ready} ) {
145 2         7 $ioa_handle->configure(
146             read_handle => $handle,
147             on_read_ready => $on_read_ready,
148             );
149 2         169 $ioa_handle->want_readready( 1 );
150             }
151              
152 3 100       24 if( my $on_write_ready = $params{on_write_ready} ) {
153 1         9 $ioa_handle->configure(
154             write_handle => $handle,
155             on_write_ready => $on_write_ready,
156             );
157 1         74 $ioa_handle->want_writeready( 1 );
158             }
159             }
160              
161             sub unwatch_io
162             {
163 3     3 1 207286 my $self = shift;
164 3         21 my %params = @_;
165              
166 3 50       18 my $handle = $params{handle} or die "Need a handle";
167              
168 3 50       69 my $ioa_handle = $self->{handles}{$handle} or return;
169              
170 3 100       16 if( $params{on_read_ready} ) {
171 2         14 $ioa_handle->want_readready( 0 );
172 2         159 $ioa_handle->configure(
173             read_handle => undef,
174             on_read_ready => undef,
175             );
176             }
177              
178 3 100       133 if( $params{on_write_ready} ) {
179 1         11 $ioa_handle->want_writeready( 0 );
180 1         46 $ioa_handle->configure(
181             write_handle => undef,
182             on_write_ready => undef,
183             );
184             }
185              
186 3 100 66     92 if( !$ioa_handle->want_readready and !$ioa_handle->want_writeready ) {
187 2         51 $self->{root_notifier}->remove_child( $ioa_handle );
188             }
189             }
190              
191             sub enqueue_timer
192             {
193 25     25 1 12434569 my $self = shift;
194 25         131 my %params = @_;
195              
196 25         1091 my $time = $self->_build_time( %params );
197              
198 25 50       1099 my $code = $params{code} or croak "Expected 'code' as CODE ref";
199              
200 25         965 my $timer = IO::Async::Timer::Absolute->new(
201             time => $time,
202             on_expire => $code,
203             );
204              
205 25         3918 $self->{root_notifier}->add_child( $timer );
206              
207 25         13717 return $timer;
208             }
209              
210             sub cancel_timer
211             {
212 14     14 1 1154174 my $self = shift;
213 14         59 my ( $timer ) = @_;
214              
215 14 50       192 $timer->stop if $timer->get_loop;
216 14         838 $self->{root_notifier}->remove_child( $timer );
217             }
218              
219             sub requeue_timer
220             {
221 1     1 1 7 my $self = shift;
222 1         3 my ( $timer, %params ) = @_;
223              
224 1         4 my $time = $self->_build_time( %params );
225              
226 1         17 $timer->configure( time => $time );
227              
228 1         120 return $timer;
229             }
230              
231             sub watch_signal
232             {
233 3     3 1 3949 my $self = shift;
234 3         6 my ( $signal, $code ) = @_;
235              
236 3         27 my $ioa_signal = IO::Async::Signal->new(
237             name => $signal,
238             on_receipt => $code,
239             );
240              
241 3         198 $self->{signals}{$signal} = $ioa_signal;
242              
243 3         14 $self->{root_notifier}->add_child( $ioa_signal );
244             }
245              
246             sub unwatch_signal
247             {
248 2     2 1 1634 my $self = shift;
249 2         4 my ( $signal ) = @_;
250              
251 2         1504 $self->{root_notifier}->remove_child( delete $self->{signals}{$signal} );
252             }
253              
254             sub watch_idle
255             {
256 6     6 1 1007663 my $self = shift;
257 6         25 my %params = @_;
258              
259 6 50       23 my $code = $params{code} or croak "Expected 'code' as CODE ref";
260              
261 6 50       21 my $when = $params{when} or croak "Expected 'when'";
262              
263 6 50       23 $when eq "later" or croak "Expected 'when' to be 'later'";
264              
265             # TODO: Find a nice way to do this that isn't cheating
266 6         20 return $self->parent_loop->watch_idle(
267             when => "later",
268             code => $code,
269             );
270             }
271              
272             sub unwatch_idle
273             {
274 1     1 1 20 my $self = shift;
275 1         26 my ( $id ) = @_;
276              
277 1         4 $self->parent_loop->unwatch_idle( $id );
278             }
279              
280             sub watch_child
281             {
282 12     12 1 42360 my $self = shift;
283 12         168 my ( $pid, $code ) = @_;
284              
285             # Some more cheating
286 12 100       100 if( $pid == 0 ) {
287 4         44 $self->parent_loop->watch_child( 0, $code );
288 4         800 return;
289             }
290              
291 8         188 weaken( my $weakself = $self );
292              
293             my $ioa_pid = IO::Async::PID->new(
294             pid => $pid,
295             on_exit => sub {
296 8     8   1176568 my ( undef, $exitstatus ) = @_;
297              
298 8         1356 $code->( $pid, $exitstatus );
299              
300 8         108 delete $weakself->{pids}{$pid};
301             }
302 8         1616 );
303              
304 8         2972 $self->{pids}{$pid} = $ioa_pid;
305              
306 8         124 $self->{root_notifier}->add_child( $ioa_pid );
307             }
308              
309             sub unwatch_child
310             {
311 0     0 1   my $self = shift;
312 0           my ( $pid ) = @_;
313              
314 0 0         if( $pid == 0 ) {
315 0           $self->parent_loop->unwatch_child( 0 );
316             }
317              
318 0           $self->{root_notifier}->remove_child( delete $self->{pids}{$pid} );
319             }
320              
321             # Keep perl happy; keep Britain tidy
322             1;
323              
324             __END__