File Coverage

blib/lib/IO/Async/Loop/Poll.pm
Criterion Covered Total %
statement 129 141 91.4
branch 55 66 83.3
condition 11 25 44.0
subroutine 20 20 100.0
pod 5 6 83.3
total 220 258 85.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, 2007-2024 -- leonerd@leonerd.org.uk
5              
6             package IO::Async::Loop::Poll 0.805;
7              
8 85     85   2691 use v5.14;
  85         390  
9 85     85   538 use warnings;
  85         261  
  85         6539  
10              
11 85     85   509 use constant API_VERSION => '0.49';
  85         181  
  85         8508  
12              
13 85     85   553 use base qw( IO::Async::Loop );
  85         182  
  85         25728  
14              
15 85     85   615 use Carp;
  85         158  
  85         8357  
16              
17 85     85   47889 use IO::Poll qw( POLLIN POLLOUT POLLPRI POLLHUP POLLERR );
  85         460100  
  85         8240  
18              
19 85     85   2370 use Errno qw( EINTR );
  85         2168  
  85         14754  
20 85     85   571 use Fcntl qw( S_ISREG );
  85         173  
  85         8257  
21              
22             # Only Linux, or FreeBSD 8.0 and above, are known always to be able to report
23             # EOF conditions on filehandles using POLLHUP
24             use constant _CAN_ON_HANGUP =>
25             ( $^O eq "linux" ) ||
26 85   33 85   534 ( $^O eq "freebsd" and do { no warnings 'numeric'; (POSIX::uname)[2] >= 8.0 } );
  85     85   202  
  85         7345  
  85         548  
  85         206  
  85         9515  
27              
28             # poll() on most platforms claims that ISREG files are always read- and
29             # write-ready, but not on MSWin32. We need to fake this
30 85     85   685 use constant FAKE_ISREG_READY => IO::Async::OS->HAVE_FAKE_ISREG_READY;
  85         182  
  85         7345  
31             # poll() on most platforms indicates POLLOUT when connect() fails, but not on
32             # MSWin32. Have to poll also for POLLPRI in that case
33 85     85   621 use constant POLL_CONNECT_POLLPRI => IO::Async::OS->HAVE_POLL_CONNECT_POLLPRI;
  85         222  
  85         6018  
34              
35 85     85   511 use constant _CAN_WATCHDOG => 1;
  85         177  
  85         6039  
36 85     85   484 use constant WATCHDOG_ENABLE => IO::Async::Loop->WATCHDOG_ENABLE;
  85         168  
  85         128271  
37              
38             =head1 NAME
39              
40             C - use C with C
41              
42             =head1 SYNOPSIS
43              
44             =for highlighter language=perl
45              
46             Normally an instance of this class would not be directly constructed by a
47             program. It may however, be useful for runinng L with an existing
48             program already using an C object.
49              
50             use IO::Poll;
51             use IO::Async::Loop::Poll;
52              
53             my $poll = IO::Poll->new;
54             my $loop = IO::Async::Loop::Poll->new( poll => $poll );
55              
56             $loop->add( ... );
57              
58             while(1) {
59             my $timeout = ...
60             my $ret = $poll->poll( $timeout );
61             $loop->post_poll;
62             }
63              
64             =head1 DESCRIPTION
65              
66             This subclass of L uses the C system call to perform
67             read-ready and write-ready tests.
68              
69             By default, this loop will use the underlying C system call directly,
70             bypassing the usual L object wrapper around it because of a number
71             of bugs and design flaws in that class; namely
72              
73             =over 2
74              
75             =item *
76              
77             L - IO::Poll relies on
78             stable stringification of IO handles
79              
80             =item *
81              
82             L - IO::Poll->poll() with no
83             handles always returns immediately
84              
85             =back
86              
87             However, to integrate with existing code that uses an C object, a
88             C can be called immediately after the C method that
89             C object. The appropriate mask bits are maintained on the
90             C object when notifiers are added or removed from the loop, or when
91             they change their C status. The C method inspects the
92             result bits and invokes the C or C methods on
93             the notifiers.
94              
95             =cut
96              
97             =head1 CONSTRUCTOR
98              
99             =cut
100              
101             =head2 new
102              
103             $loop = IO::Async::Loop::Poll->new( %args );
104              
105             This function returns a new instance of a C object. It
106             takes the following named arguments:
107              
108             =over 8
109              
110             =item C
111              
112             The C object to use for notification. Optional; if a value is not
113             given, the underlying C function is invoked directly,
114             outside of the object wrapping.
115              
116             =back
117              
118             =cut
119              
120             sub new
121             {
122 84     84 1 327620 my $class = shift;
123 84         251 my ( %args ) = @_;
124              
125 84         220 my $poll = delete $args{poll};
126              
127 84         1191 my $self = $class->__new( %args );
128              
129 84         474 $self->{poll} = $poll;
130 84         755 $self->{pollmask} = {};
131              
132 84         1806 return $self;
133             }
134              
135             =head1 METHODS
136              
137             =cut
138              
139             =head2 post_poll
140              
141             $count = $loop->post_poll;
142              
143             This method checks the returned event list from a C call,
144             and calls any of the notification methods or callbacks that are appropriate.
145             It returns the total number of callbacks that were invoked; that is, the
146             total number of C and C callbacks for
147             C, and C event callbacks.
148              
149             =cut
150              
151             sub post_poll
152             {
153 1375     1375 1 4980 my $self = shift;
154              
155 1375         6919 my $iowatches = $self->{iowatches};
156 1375         3155 my $poll = $self->{poll};
157              
158 1375         2660 my $count = 0;
159              
160 1375         2083 alarm( IO::Async::Loop->WATCHDOG_INTERVAL ) if WATCHDOG_ENABLE;
161              
162 1375         7915 foreach my $fd ( keys %$iowatches ) {
163 3044 100       9326 my $watch = $iowatches->{$fd} or next;
164              
165             my $events = $poll ? $poll->events( $watch->[0] )
166 3043 100       8597 : $self->{pollevents}{$fd};
167 3043         12005 if( FAKE_ISREG_READY and $self->{fake_isreg}{$fd} ) {
168             $events |= $self->{fake_isreg}{$fd} & ( POLLIN|POLLOUT );
169             }
170              
171             # We have to test separately because kernel doesn't report POLLIN when
172             # a pipe gets closed.
173 3043 100       8087 if( $events & (POLLIN|POLLHUP|POLLERR) ) {
174 1285 100       7685 $count++, $watch->[1]->() if defined $watch->[1];
175             }
176              
177 3043 100       9169 if( $events & (POLLOUT|POLLPRI|POLLHUP|POLLERR) ) {
178 671 100       3526 $count++, $watch->[2]->() if defined $watch->[2];
179             }
180              
181 3043 100       10411 if( $events & (POLLHUP|POLLERR) ) {
182 578 100       12327 $count++, $watch->[3]->() if defined $watch->[3];
183             }
184             }
185              
186             # Since we have no way to know if the timeout occurred, we'll have to
187             # attempt to fire any waiting timeout events anyway
188 1375         9909 $count += $self->_manage_queues;
189              
190 1373         5701 alarm( 0 ) if WATCHDOG_ENABLE;
191              
192 1373         10262 return $count;
193             }
194              
195             sub is_running
196             {
197 1     1 0 3 my $self = shift;
198 1         26 return $self->{running};
199             }
200              
201             =head2 loop_once
202              
203             $count = $loop->loop_once( $timeout );
204              
205             This method calls the C method on the stored C object,
206             passing in the value of C<$timeout>, and then runs the C method
207             on itself. It returns the total number of callbacks invoked by the
208             C method, or C if the underlying C method returned
209             an error.
210              
211             =cut
212              
213             sub loop_once
214             {
215 1373     1373 1 23318 my $self = shift;
216 1373         3619 my ( $timeout ) = @_;
217              
218 1373         13526 $self->_adjust_timeout( \$timeout );
219              
220 1373         2904 $timeout = 0 if FAKE_ISREG_READY and keys %{ $self->{fake_isreg} };
221              
222             # Round up to nearest millisecond
223 1373 100       4100 if( $timeout ) {
224 1223         2774 my $mils = $timeout * 1000;
225 1223         3023 my $fraction = $mils - int $mils;
226 1223 100       8449 $timeout += ( 1 - $fraction ) / 1000 if $fraction;
227             }
228              
229 1373 50       4489 if( my $poll = $self->{poll} ) {
230 0         0 my $pollret;
231              
232 0         0 $self->pre_wait;
233             # There is a bug in IO::Poll at least version 0.07, where poll with no
234             # registered masks returns immediately, rather than waiting for a timeout
235             # This has been reported:
236             # http://rt.cpan.org/Ticket/Display.html?id=25049
237 0 0       0 if( $poll->handles ) {
238 0         0 $pollret = $poll->poll( $timeout );
239              
240 0 0 0     0 if( ( $pollret == -1 and $! == EINTR ) or $pollret == 0
      0        
      0        
241             and defined $self->{sigproxy} ) {
242             # A signal occurred and we have a sigproxy. Allow one more poll
243             # call with zero timeout. If it finds something, keep that result.
244             # If it finds nothing, keep -1
245              
246             # Preserve $! whatever happens
247 0         0 local $!;
248              
249 0         0 my $secondattempt = $poll->poll( 0 );
250 0 0       0 $pollret = $secondattempt if $secondattempt > 0;
251             }
252             }
253             else {
254             # Workaround - we'll use select to fake a millisecond-accurate sleep
255 0         0 $pollret = select( undef, undef, undef, $timeout );
256             }
257              
258 0         0 $self->post_wait;
259              
260 0 0       0 return undef unless defined $pollret;
261 0         0 return $self->post_poll;
262             }
263             else {
264 1373         4721 my @pollmasks = %{ $self->{pollmask} };
  1373         11584  
265              
266 1373         8130 $self->pre_wait;
267              
268             # Perl 5.8.x's IO::Poll::_poll gets confused with no masks
269 1373         42227 my $pollret;
270 1373 100       5990 if( @pollmasks ) {
271 1278 100       3623 my $msec = defined $timeout ? $timeout * 1000 : -1;
272 1278         351078842 $pollret = IO::Poll::_poll( $msec, @pollmasks );
273 1278 100 66     23234 if( $pollret == -1 and $! == EINTR or
      66        
      66        
274             $pollret == 0 and $self->{sigproxy} ) {
275 55         730 local $!;
276              
277 55         309 @pollmasks = %{ $self->{pollmask} };
  55         1081  
278 55         828 my $secondattempt = IO::Poll::_poll( $msec, @pollmasks );
279 55 50       570 $pollret = $secondattempt if $secondattempt > 0;
280             }
281              
282             }
283             else {
284             # Workaround - we'll use select to fake a millisecond-accurate sleep
285 95         65325042 $pollret = select( undef, undef, undef, $timeout );
286             }
287              
288 1373         12603 $self->post_wait;
289              
290 1373 50       18988 return undef unless defined $pollret;
291              
292 1373         13233 $self->{pollevents} = { @pollmasks };
293 1373         8372 return $self->post_poll;
294             }
295             }
296              
297             sub watch_io
298             {
299 778     778 1 11239 my $self = shift;
300 778         12710 my %params = @_;
301              
302 778         11662 $self->__watch_io( %params );
303              
304 778         2410 my $poll = $self->{poll};
305              
306 778         1406 my $handle = $params{handle};
307 778         2298 my $fileno = $handle->fileno;
308              
309             my $curmask = $poll ? $poll->mask( $handle )
310 778 100       6074 : $self->{pollmask}{$fileno};
311 778   100     8338 $curmask ||= 0;
312              
313 778         2065 my $mask = $curmask;
314 778 100       3023 $params{on_read_ready} and $mask |= POLLIN;
315 778 100       2084 $params{on_write_ready} and $mask |= POLLOUT | (POLL_CONNECT_POLLPRI ? POLLPRI : 0);
316 778 100       1877 $params{on_hangup} and $mask |= POLLHUP;
317              
318 778         1532 if( FAKE_ISREG_READY and S_ISREG +(stat $handle)[2] ) {
319             $self->{fake_isreg}{$fileno} = $mask;
320             }
321              
322 778 100       2449 return if $mask == $curmask;
323              
324 777 100       2441 if( $poll ) {
325 4         11 $poll->mask( $handle, $mask );
326             }
327             else {
328 773         12132 $self->{pollmask}{$fileno} = $mask;
329             }
330             }
331              
332             sub unwatch_io
333             {
334 704     704 1 5701 my $self = shift;
335 704         5550 my %params = @_;
336              
337 704         59489 $self->__unwatch_io( %params );
338              
339 704         2503 my $poll = $self->{poll};
340              
341 704         1388 my $handle = $params{handle};
342 704         3041 my $fileno = $handle->fileno;
343              
344             my $curmask = $poll ? $poll->mask( $handle )
345 704 100       9965 : $self->{pollmask}{$fileno};
346 704   100     2354 $curmask ||= 0;
347              
348 704         1303 my $mask = $curmask;
349 704 100       2249 $params{on_read_ready} and $mask &= ~POLLIN;
350 704 100       1963 $params{on_write_ready} and $mask &= ~(POLLOUT | (POLL_CONNECT_POLLPRI ? POLLPRI : 0));
351 704 100       1788 $params{on_hangup} and $mask &= ~POLLHUP;
352              
353 704         1174 if( FAKE_ISREG_READY and S_ISREG +(stat $handle)[2] ) {
354             if( $mask ) {
355             $self->{fake_isreg}{$handle->fileno} = $mask;
356             }
357             else {
358             delete $self->{fake_isreg}{$handle->fileno};
359             }
360             }
361              
362 704 100       2091 return if $mask == $curmask;
363              
364 669 100       1607 if( $poll ) {
365 3         8 $poll->mask( $handle, $mask );
366             }
367             else {
368             $mask ? ( $self->{pollmask}{$fileno} = $mask )
369 666 100       4009 : ( delete $self->{pollmask}{$fileno} );
370             }
371             }
372              
373             =head1 AUTHOR
374              
375             Paul Evans
376              
377             =cut
378              
379             0x55AA;