File Coverage

blib/lib/IO/Async/Loop/IO/Async.pm
Criterion Covered Total %
statement 119 125 95.2
branch 24 36 66.6
condition 7 12 58.3
subroutine 24 25 96.0
pod 13 13 100.0
total 187 211 88.6


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-2020 -- leonerd@leonerd.org.uk
5              
6             package IO::Async::Loop::IO::Async;
7              
8 12     12   5494 use strict;
  12         25  
  12         296  
9 12     12   51 use warnings;
  12         21  
  12         410  
10              
11             our $VERSION = '0.03';
12 12     12   52 use constant API_VERSION => '0.76';
  12         22  
  12         742  
13              
14 12     12   61 use base qw( IO::Async::Loop );
  12         21  
  12         7817  
15             IO::Async::Loop->VERSION( 0.49 );
16              
17 12     12   149068 use Carp;
  12         26  
  12         678  
18              
19 12     12   68 use Scalar::Util qw( weaken );
  12         23  
  12         423  
20              
21 12     12   5866 use IO::Async::Notifier;
  12         143111  
  12         319  
22 12     12   5162 use IO::Async::Handle;
  12         63534  
  12         396  
23 12     12   4861 use IO::Async::Timer::Absolute;
  12         15536  
  12         318  
24 12     12   4393 use IO::Async::Signal;
  12         6365  
  12         275  
25 12     12   4527 use IO::Async::PID;
  12         6940  
  12         11436  
26              
27             =head1 NAME
28              
29             C - use C with C
30              
31             =head1 SYNOPSIS
32              
33             use IO::Async::Loop::IO::Async;
34              
35             my $loop = IO::Async::Loop::IO::Async->new();
36              
37             $loop->add( ... );
38              
39             $loop->add( IO::Async::Signal->new(
40             name => 'HUP',
41             on_receipt => sub { ... },
42             ) );
43              
44             $loop->run;
45              
46             =head1 DESCRIPTION
47              
48             This subclass of L uses another instance of an
49             C object as its underlying implementation. While this at
50             first appears to be pointless, this module distribution is not primarily
51             intended to serve a useful purpose for end-users. Rather, it stands as a real
52             code example, for authors of other modules to use for reference.
53              
54             =head2 For C Authors
55              
56             Authors of other subclasses to implement C subclasses may
57             find this distribution useful as a template. By copying the code and replacing
58             the contents of the various C and C methods, a Loop
59             implementation can be built making use of some other event system or
60             underlying kernel blocking primative.
61              
62             =head2 For Authors of Other Event Systems
63              
64             Authors of implementations in other event systems wishing to support running
65             their event system on top of L may find this distribution useful to
66             read a way to implement the various underlying behaviours, such as watching
67             filehandles and timers. Examples in each of the C and C
68             methods may be useful to demonstrate the sort of code that might be required
69             to attach some other event system on top of C.
70              
71             =head1 CONSTRUCTOR
72              
73             =cut
74              
75             =head2 new
76              
77             $loop = IO::Async::Loop::IO::Async->new()
78              
79             This function returns a new instance of a C object.
80              
81             =cut
82              
83             sub new
84             {
85 11     11 1 143 my $class = shift;
86 11         169 my ( %args ) = @_;
87              
88 11         85 my $self = $class->SUPER::__new( %args );
89              
90 11         514 $self->{root_notifier} = IO::Async::Notifier->new;
91              
92 11         271 return $self;
93             }
94              
95             =head1 METHODS
96              
97             =cut
98              
99             =head2 parent_loop
100              
101             $loop->parent_loop( $parent )
102              
103             $parent = $loop->parent_loop
104              
105             Accessor for the underlying C that this loop will use. If one
106             is not provided by the time that C is first invoked, one will be
107             constructed using the normal C<< IO::Async::Loop->new >> constructor. This
108             method may be used to access it after that.
109              
110             =cut
111              
112             sub parent_loop
113             {
114 70     70 1 117 my $self = shift;
115 70         122 my ( $loop ) = @_;
116              
117 70 50       221 $self->{parent_loop} = $loop if $loop;
118              
119 70   66     259 $self->{parent_loop} ||= do {
120 10         83 my $loop = IO::Async::Loop->new;
121 10         46959 $loop->add( $self->{root_notifier} );
122 10         43405 $loop;
123             };
124              
125 70         423 return $self->{parent_loop};
126             }
127              
128             sub loop_once
129             {
130 58     58 1 1942717 my $self = shift;
131 58         128 my ( $timeout ) = @_;
132              
133 58         162 $self->parent_loop->loop_once( $timeout );
134             }
135              
136             sub watch_io
137             {
138 9     9 1 19765 my $self = shift;
139 9         32 my %params = @_;
140              
141 9 50       28 my $handle = $params{handle} or die "Need a handle";
142              
143 9   66     33 my $ioa_handle = $self->{handles}{$handle} ||= do {
144 8         46 my $h = IO::Async::Handle->new;
145 8         306 $self->{root_notifier}->add_child( $h );
146 8         759 $h;
147             };
148              
149 9 100       24 if( my $on_read_ready = $params{on_read_ready} ) {
150 6         18 $ioa_handle->configure(
151             read_handle => $handle,
152             on_read_ready => $on_read_ready,
153             );
154 6         1227 $ioa_handle->want_readready( 1 );
155             }
156              
157 9 100       62 if( my $on_write_ready = $params{on_write_ready} ) {
158 5         14 $ioa_handle->configure(
159             write_handle => $handle,
160             on_write_ready => $on_write_ready,
161             );
162 5         243 $ioa_handle->want_writeready( 1 );
163             }
164             }
165              
166             sub unwatch_io
167             {
168 9     9 1 4577 my $self = shift;
169 9         29 my %params = @_;
170              
171 9 50       28 my $handle = $params{handle} or die "Need a handle";
172              
173 9 50       29 my $ioa_handle = $self->{handles}{$handle} or return;
174              
175 9 100       23 if( $params{on_read_ready} ) {
176 6         29 $ioa_handle->want_readready( 0 );
177 6         535 $ioa_handle->configure(
178             read_handle => undef,
179             on_read_ready => undef,
180             );
181             }
182              
183 9 100       336 if( $params{on_write_ready} ) {
184 5         15 $ioa_handle->want_writeready( 0 );
185 5         335 $ioa_handle->configure(
186             write_handle => undef,
187             on_write_ready => undef,
188             );
189             }
190              
191 9 100 66     225 if( !$ioa_handle->want_readready and !$ioa_handle->want_writeready ) {
192 8         119 $self->{root_notifier}->remove_child( $ioa_handle );
193 8         1074 delete $self->{handles}{$handle};
194             }
195             }
196              
197             sub watch_time
198             {
199 30     30 1 12428577 my $self = shift;
200 30         320 my %params = @_;
201              
202 30 50       192 my $code = $params{code} or croak "Expected 'code' as CODE ref";
203              
204 30         54 my $time;
205 30 100       146 if( defined $params{at} ) {
    50          
206 1         3 $time = $params{at};
207             }
208             elsif( defined $params{after} ) {
209 29   33     482 my $now = $params{now} || $self->time;
210 29         325 $time = $now + $params{after};
211             }
212             else {
213 0         0 croak "Expected one of 'at' or 'after'; got @_";
214             }
215              
216 30         602 my $timer = IO::Async::Timer::Absolute->new(
217             time => $time,
218             on_expire => $code,
219             );
220              
221 30         3702 $self->{root_notifier}->add_child( $timer );
222              
223 30         29338 return $timer;
224             }
225              
226             sub unwatch_time
227             {
228 19     19 1 1219656 my $self = shift;
229 19         43 my ( $timer ) = @_;
230              
231 19 50       179 $timer->stop if $timer->get_loop;
232 19         1820 $self->{root_notifier}->remove_child( $timer );
233             }
234              
235             sub watch_signal
236             {
237 4     4 1 2650 my $self = shift;
238 4         7 my ( $signal, $code ) = @_;
239              
240 4         18 my $ioa_signal = IO::Async::Signal->new(
241             name => $signal,
242             on_receipt => $code,
243             );
244              
245 4         235 $self->{signals}{$signal} = $ioa_signal;
246              
247 4         10 $self->{root_notifier}->add_child( $ioa_signal );
248             }
249              
250             sub unwatch_signal
251             {
252 2     2 1 1775 my $self = shift;
253 2         4 my ( $signal ) = @_;
254              
255 2         11 $self->{root_notifier}->remove_child( delete $self->{signals}{$signal} );
256             }
257              
258             sub watch_idle
259             {
260 6     6 1 1005872 my $self = shift;
261 6         20 my %params = @_;
262              
263 6 50       16 my $code = $params{code} or croak "Expected 'code' as CODE ref";
264              
265 6 50       14 my $when = $params{when} or croak "Expected 'when'";
266              
267 6 50       13 $when eq "later" or croak "Expected 'when' to be 'later'";
268              
269             # TODO: Find a nice way to do this that isn't cheating
270 6         13 return $self->parent_loop->watch_idle(
271             when => "later",
272             code => $code,
273             );
274             }
275              
276             sub unwatch_idle
277             {
278 1     1 1 17 my $self = shift;
279 1         2 my ( $id ) = @_;
280              
281 1         3 $self->parent_loop->unwatch_idle( $id );
282             }
283              
284             sub watch_process
285             {
286 16     16 1 31069 my $self = shift;
287 16         154 my ( $pid, $code ) = @_;
288              
289             # Some more cheating
290 16 100       178 if( $pid == 0 ) {
291 5         55 $self->parent_loop->watch_process( 0, $code );
292 5         525 return;
293             }
294              
295 11         165 weaken( my $weakself = $self );
296              
297             my $ioa_pid = IO::Async::PID->new(
298             pid => $pid,
299             on_exit => sub {
300 11     11   1134899 my ( undef, $exitstatus ) = @_;
301              
302 11         56 $code->( $pid, $exitstatus );
303              
304 11         67 delete $weakself->{pids}{$pid};
305             }
306 11         1070 );
307              
308 11         2155 $self->{pids}{$pid} = $ioa_pid;
309              
310 11         165 $self->{root_notifier}->add_child( $ioa_pid );
311             }
312              
313             sub unwatch_process
314             {
315 0     0 1   my $self = shift;
316 0           my ( $pid ) = @_;
317              
318 0 0         if( $pid == 0 ) {
319 0           $self->parent_loop->unwatch_process( 0 );
320             }
321              
322 0           $self->{root_notifier}->remove_child( delete $self->{pids}{$pid} );
323             }
324              
325             =head1 AUTHOR
326              
327             Paul Evans
328              
329             =cut
330              
331             0x55AA;