| 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; |