1# Plain Perl signal handling is something shared by several event 2# loops. The invariant code has moved out here so that each loop may 3# use it without reinventing it. This will save maintenance and 4# shrink the distribution. Yay! 5 6package POE::Loop::PerlSignals; 7 8use strict; 9 10use vars qw($VERSION); 11$VERSION = '1.368'; # NOTE - Should be #.### (three decimal places) 12 13# Everything plugs into POE::Kernel. 14package POE::Kernel; 15 16use strict; 17use POE::Kernel; 18 19# Flag so we know which signals are watched. Used to reset those 20# signals during finalization. 21my %signal_watched; 22 23#------------------------------------------------------------------------------ 24# Signal handlers/callbacks. 25 26sub _loop_signal_handler_generic { 27 if( USE_SIGNAL_PIPE ) { 28 POE::Kernel->_data_sig_pipe_send( $_[0] ); 29 } 30 else { 31 _loop_signal_handler_generic_bottom( $_[0] ); 32 } 33} 34 35sub _loop_signal_handler_generic_bottom { 36 if (TRACE_SIGNALS) { 37 POE::Kernel::_warn "<sg> Enqueuing generic SIG$_[0] event"; 38 } 39 40 $poe_kernel->_data_ev_enqueue( 41 $poe_kernel, $poe_kernel, EN_SIGNAL, ET_SIGNAL, [ $_[0] ], 42 __FILE__, __LINE__, undef 43 ); 44 $SIG{$_[0]} = \&_loop_signal_handler_generic; 45} 46 47## 48 49sub _loop_signal_handler_pipe { 50 if( USE_SIGNAL_PIPE ) { 51 POE::Kernel->_data_sig_pipe_send( $_[0] ); 52 } 53 else { 54 _loop_signal_handler_pipe_bottom( $_[0] ); 55 } 56} 57 58sub _loop_signal_handler_pipe_bottom { 59 if (TRACE_SIGNALS) { 60 POE::Kernel::_warn "<sg> Enqueuing PIPE-like SIG$_[0] event"; 61 } 62 63 $poe_kernel->_data_ev_enqueue( 64 $poe_kernel, $poe_kernel, EN_SIGNAL, ET_SIGNAL, [ $_[0] ], 65 __FILE__, __LINE__, undef 66 ); 67 $SIG{$_[0]} = \&_loop_signal_handler_pipe; 68} 69 70## only used under USE_SIGCHLD 71 72sub _loop_signal_handler_chld { 73 if( USE_SIGNAL_PIPE ) { 74 POE::Kernel->_data_sig_pipe_send( 'CHLD' ); 75 } 76 else { 77 _loop_signal_handler_chld_bottom( $_[0] ); 78 } 79} 80 81sub _loop_signal_handler_chld_bottom { 82 if (TRACE_SIGNALS) { 83 POE::Kernel::_warn "<sg> Enqueuing CHLD-like SIG$_[0] event"; 84 } 85 86 $poe_kernel->_data_sig_enqueue_poll_event($_[0]); 87} 88 89#------------------------------------------------------------------------------ 90# Signal handler maintenance functions. 91 92sub loop_watch_signal { 93 my ($self, $signal) = @_; 94 95 $signal_watched{$signal} = 1; 96 97 # Child process has stopped. 98 if ($signal eq 'CHLD' or $signal eq 'CLD') { 99 if ( USE_SIGCHLD ) { 100 # Poll once for signals. Will set the signal handler when done. 101 # It would be more efficient to set $SIG{$signal} here and reap 102 # processes, but that would synchronously set the signal 103 # handler, and subsequent system() calls within the callback 104 # could fail with a -1 return value. The polling event defers 105 # the setup until the current callback returns. 106 $self->_data_sig_enqueue_poll_event($signal); 107 } else { 108 # We should never twiddle $SIG{CH?LD} under POE, unless we want to 109 # override system() and friends. --hachi 110 # $SIG{$signal} = "DEFAULT"; 111 $self->_data_sig_begin_polling($signal); 112 } 113 return; 114 } 115 116 # Broken pipe. 117 if ($signal eq 'PIPE') { 118 $SIG{$signal} = \&_loop_signal_handler_pipe; 119 return; 120 } 121 122 # Everything else. 123 $SIG{$signal} = \&_loop_signal_handler_generic; 124} 125 126sub loop_ignore_signal { 127 my ($self, $signal) = @_; 128 129 delete $signal_watched{$signal}; 130 131 if ($signal eq 'CHLD' or $signal eq 'CLD') { 132 if ( USE_SIGCHLD ) { 133 if ($self->_data_sig_kernel_awaits_pids()) { 134 # We need SIGCHLD to stay around after shutdown, so that 135 # child processes may be reaped and kr_child_procs=0 136 if (TRACE_SIGNALS) { 137 POE::Kernel::_warn "<sg> Keeping SIG$signal anyway!"; 138 } 139 return; 140 } 141 } else { 142 $self->_data_sig_cease_polling(); 143 # We should never twiddle $SIG{CH?LD} under poe, unless we want to 144 # override system() and friends. --hachi 145 # $SIG{$signal} = "IGNORE"; 146 return; 147 } 148 } 149 150 delete $signal_watched{$signal}; 151 152 my $state = 'DEFAULT'; 153 if ($signal eq 'PIPE') { 154 $state = "IGNORE"; 155 } 156 157 if (TRACE_SIGNALS) { 158 POE::Kernel::_warn "<sg> $state SIG$signal"; 159 } 160 $SIG{$signal} = $state; 161} 162 163sub loop_ignore_all_signals { 164 my $self = shift; 165 foreach my $signal (keys %signal_watched) { 166 $self->loop_ignore_signal($signal); 167 } 168} 169 1701; 171 172__END__ 173 174=head1 NAME 175 176POE::Loop::PerlSignals - common signal handling routines for POE::Loop bridges 177 178=head1 SYNOPSIS 179 180See L<POE::Loop>. 181 182=head1 DESCRIPTION 183 184POE::Loop::PerlSignals implements common code to handle signals for 185many different event loops. Most loops don't handle signals natively, 186so this code has been abstracted into a reusable mix-in module. 187 188POE::Loop::PerlSignals follows POE::Loop's public interface for signal 189handling. Therefore, please see L<POE::Loop> for more details. 190 191=head1 SEE ALSO 192 193L<POE>, L<POE::Loop> 194 195=head1 AUTHORS & LICENSING 196 197Please see L<POE> for more information about authors, contributors, 198and POE's licensing. 199 200=cut 201 202# rocco // vim: ts=2 sw=2 expandtab 203# TODO - Edit. 204