File Coverage

blib/lib/IO/Async/Loop/Ppoll.pm
Criterion Covered Total %
statement 73 73 100.0
branch 7 10 70.0
condition 7 11 63.6
subroutine 16 16 100.0
pod 4 4 100.0
total 107 114 93.8


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-2011 -- leonerd@leonerd.org.uk
5              
6             package IO::Async::Loop::Ppoll;
7              
8 11     11   29578 use strict;
  11         21  
  11         451  
9 11     11   68 use warnings;
  11         23  
  11         651  
10              
11             our $VERSION = '0.09';
12 11     11   67 use constant API_VERSION => '0.49';
  11         23  
  11         1805  
13              
14 11     11   10301 use IO::Async::Loop::Poll 0.18;
  11         406573  
  11         398  
15 11     11   2210 use base qw( IO::Async::Loop::Poll );
  11         30  
  11         1154  
16              
17 11     11   57 use Carp;
  11         33  
  11         1122  
18              
19 11     11   13532 use IO::Ppoll qw( POLLIN POLLOUT POLLHUP );
  11         33299  
  11         1044  
20              
21 11     11   97 use POSIX qw( EINTR SIG_BLOCK SIG_UNBLOCK sigprocmask sigaction );
  11         19  
  11         101  
22              
23 11     11   1083 use constant _CAN_WATCHDOG => 1;
  11         23  
  11         766  
24 11     11   57 use constant WATCHDOG_ENABLE => IO::Async::Loop->WATCHDOG_ENABLE;
  11         24  
  11         14216  
25              
26             =head1 NAME
27              
28             C - use C with C
29              
30             =head1 SYNOPSIS
31              
32             use IO::Async::Loop::Ppoll;
33              
34             my $loop = IO::Async::Loop::Ppoll->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 C uses an C object instead
48             of a C to perform read-ready and write-ready tests so that they can
49             be mixed with signal handling.
50              
51             The C system call atomically switches the process's signal mask,
52             performs a wait exactly as C would, then switches it back. This allows
53             a process to block the signals it cares about, but switch in an empty signal
54             mask during the poll, allowing it to handle file IO and signals concurrently.
55              
56             =head1 CONSTRUCTOR
57              
58             =cut
59              
60             =head2 $loop = IO::Async::Loop::Ppoll->new( %args )
61              
62             This function returns a new instance of a C object.
63             It takes the following named arguments:
64              
65             =over 8
66              
67             =item C
68              
69             The C object to use for notification. Optional; if a value is not
70             given, a new C object will be constructed.
71              
72             =back
73              
74             =cut
75              
76             sub new
77             {
78 10     10 1 148 my $class = shift;
79 10         36 my ( %args ) = @_;
80              
81 10         32 my $poll = delete $args{poll};
82              
83 10   33     105 $poll ||= IO::Ppoll->new();
84              
85 10         429 my $self = $class->SUPER::new( %args, poll => $poll );
86              
87 10         836 $self->{signals} = {};
88              
89 10         38 return $self;
90             }
91              
92             =head1 METHODS
93              
94             As this is a subclass of L, all of its methods are
95             inherited. Expect where noted below, all of the class's methods behave
96             identically to C.
97              
98             =cut
99              
100             sub DESTROY
101             {
102 10     10   49286 my $self = shift;
103              
104 10         144 foreach my $signal ( keys %{ $self->{signals} } ) {
  10         740  
105 4         305 $self->unwatch_signal( $signal );
106             }
107             }
108              
109             =head2 $count = $loop->loop_once( $timeout )
110              
111             This method calls the C method on the stored C object,
112             passing in the value of C<$timeout>, and processes the results of that call.
113             It returns the total number of C callbacks invoked, or
114             C if the underlying C method returned an error. If the
115             C was interrupted by a signal, then 0 is returned instead.
116              
117             =cut
118              
119             sub loop_once
120             {
121 52     52 1 134310 my $self = shift;
122 52         118 my ( $timeout ) = @_;
123              
124 52         458 $self->_adjust_timeout( \$timeout );
125              
126 52         1259 my $poll = $self->{poll};
127              
128 52         402 my $pollret = $poll->poll( $timeout );
129              
130 52 50 66     17013718 return undef if ( !defined $pollret or $pollret == -1 ) and $! != EINTR;
      66        
131              
132 52         122 my $count = 0;
133              
134 52         102 alarm( IO::Async::Loop->WATCHDOG_INTERVAL ) if WATCHDOG_ENABLE;
135              
136 52         205 my $signals = $self->{signals};
137 52         548 foreach my $sigslot ( values %$signals ) {
138 16 100       115 if( $sigslot->[1] ) {
139 15         105 $sigslot->[0]->();
140 15         1149 $sigslot->[1] = 0;
141 15         774 $count++;
142             }
143             }
144              
145 52         605 return $count + $self->post_poll();
146             }
147              
148             # override
149             sub watch_signal
150             {
151 7     7 1 41536 my $self = shift;
152 7         78 my ( $signal, $code ) = @_;
153              
154 7 100       412 exists $SIG{$signal} or croak "Unrecognised signal name $signal";
155              
156             # We cannot simply set $SIG{$signal} = $code here, because of perl bug
157             # http://rt.perl.org/rt3/Ticket/Display.html?id=82040
158             # Instead, we'll store a tiny piece of code that just sets a flag, and
159             # check the flags on return from the epoll_pwait call.
160              
161 6         154 $self->{signals}{$signal} = [ $code, 0, $SIG{$signal} ];
162 6         64 my $pending = \$self->{signals}{$signal}[1];
163              
164 6         193 my $signum = $self->signame2num( $signal );
165 6         32184 sigprocmask( SIG_BLOCK, POSIX::SigSet->new( $signum ) );
166              
167             # Note this is an unsafe signal handler, and as such it should do as little
168             # as possible.
169 6     15   231 my $sigaction = POSIX::SigAction->new( sub { $$pending = 1 } );
  15         1623448  
170 6 50       672 sigaction( $signum, $sigaction ) or croak "Unable to sigaction - $!";
171             }
172              
173             # override
174             sub unwatch_signal
175             {
176 6     6 1 2626 my $self = shift;
177 6         38 my ( $signal ) = @_;
178              
179 6 50       128 exists $SIG{$signal} or croak "Unrecognised signal name $signal";
180              
181             # When we saved the original value, we might have got an undef. But %SIG
182             # doesn't like having undef assigned back in, so we need to translate
183 6   100     268 $SIG{$signal} = $self->{signals}{$signal}[2] || 'DEFAULT';
184              
185 6         345 delete $self->{signals}{$signal};
186            
187 6         152 my $signum = $self->signame2num( $signal );
188              
189 6         4018 sigprocmask( SIG_UNBLOCK, POSIX::SigSet->new( $signum ) );
190             }
191              
192             =head1 SEE ALSO
193              
194             =over 4
195              
196             =item *
197              
198             L - Object interface to Linux's C call
199              
200             =item *
201              
202             L - a set using an C object
203              
204             =back
205              
206             =head1 AUTHOR
207              
208             Paul Evans
209              
210             =cut
211              
212             0x55AA;