File Coverage

blib/lib/POE/Loop/PerlSignals.pm
Criterion Covered Total %
statement 51 52 98.0
branch 10 10 100.0
condition 5 6 83.3
subroutine 13 13 100.0
pod 0 3 0.0
total 79 84 94.0


line stmt bran cond sub pod time code
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              
6             package POE::Loop::PerlSignals;
7              
8 175     175   874 use strict;
  175         264  
  175         6447  
9              
10 175     175   792 use vars qw($VERSION);
  175         239  
  175         9714  
11             $VERSION = '1.365'; # NOTE - Should be #.### (three decimal places)
12              
13             # Everything plugs into POE::Kernel.
14             package POE::Kernel;
15              
16 175     175   801 use strict;
  175         258  
  175         4167  
17 175     175   2448 use POE::Kernel;
  175         256  
  175         1561  
18              
19             # Flag so we know which signals are watched. Used to reset those
20             # signals during finalization.
21             my %signal_watched;
22              
23             #------------------------------------------------------------------------------
24             # Signal handlers/callbacks.
25              
26             sub _loop_signal_handler_generic {
27 16     16   427 if( USE_SIGNAL_PIPE ) {
28 16         163 POE::Kernel->_data_sig_pipe_send( $_[0] );
29             }
30             else {
31             _loop_signal_handler_generic_bottom( $_[0] );
32             }
33             }
34              
35             sub _loop_signal_handler_generic_bottom {
36 16     16   29 if (TRACE_SIGNALS) {
37             POE::Kernel::_warn " Enqueuing generic SIG$_[0] event";
38             }
39              
40             $poe_kernel->_data_ev_enqueue(
41 16         83 $poe_kernel, $poe_kernel, EN_SIGNAL, ET_SIGNAL, [ $_[0] ],
42             __FILE__, __LINE__, undef
43             );
44 16         395 $SIG{$_[0]} = \&_loop_signal_handler_generic;
45             }
46              
47             ##
48              
49             sub _loop_signal_handler_pipe {
50 28     12   340 if( USE_SIGNAL_PIPE ) {
51 12         68 POE::Kernel->_data_sig_pipe_send( $_[0] );
52             }
53             else {
54             _loop_signal_handler_pipe_bottom( $_[0] );
55             }
56             }
57              
58             sub _loop_signal_handler_pipe_bottom {
59 12     12   18 if (TRACE_SIGNALS) {
60             POE::Kernel::_warn " Enqueuing PIPE-like SIG$_[0] event";
61             }
62              
63             $poe_kernel->_data_ev_enqueue(
64 12         58 $poe_kernel, $poe_kernel, EN_SIGNAL, ET_SIGNAL, [ $_[0] ],
65             __FILE__, __LINE__, undef
66             );
67 12         95 $SIG{$_[0]} = \&_loop_signal_handler_pipe;
68             }
69              
70             ## only used under USE_SIGCHLD
71              
72             sub _loop_signal_handler_chld {
73 205     193   22739 if( USE_SIGNAL_PIPE ) {
74 193         2539 POE::Kernel->_data_sig_pipe_send( 'CHLD' );
75             }
76             else {
77             _loop_signal_handler_chld_bottom( $_[0] );
78             }
79             }
80              
81             sub _loop_signal_handler_chld_bottom {
82 193     193   278 if (TRACE_SIGNALS) {
83             POE::Kernel::_warn " Enqueuing CHLD-like SIG$_[0] event";
84             }
85              
86 193         1103 $poe_kernel->_data_sig_enqueue_poll_event($_[0]);
87             }
88              
89             #------------------------------------------------------------------------------
90             # Signal handler maintenance functions.
91              
92             sub loop_watch_signal {
93 246     219 0 915 my ($self, $signal) = @_;
94              
95 219         842 $signal_watched{$signal} = 1;
96              
97             # Child process has stopped.
98 219 100 66     1028 if ($signal eq 'CHLD' or $signal eq 'CLD') {
99 203         258 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 203         1649 $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 203         668 return;
114             }
115              
116             # Broken pipe.
117 16 100       222 if ($signal eq 'PIPE') {
118 4         34 $SIG{$signal} = \&_loop_signal_handler_pipe;
119 4         18 return;
120             }
121              
122             # Everything else.
123 12         168 $SIG{$signal} = \&_loop_signal_handler_generic;
124             }
125              
126             sub loop_ignore_signal {
127 7417     7417 0 8961 my ($self, $signal) = @_;
128              
129 7417         7749 delete $signal_watched{$signal};
130              
131 7417 100 100     28328 if ($signal eq 'CHLD' or $signal eq 'CLD') {
132 1086         1066 if ( USE_SIGCHLD ) {
133 1086 100       3336 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 7         16 if (TRACE_SIGNALS) {
137             POE::Kernel::_warn " Keeping SIG$signal anyway!";
138             }
139 34         30 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 4161         3495 delete $signal_watched{$signal};
151              
152 7410         6869 my $state = 'DEFAULT';
153 7379 100       9446 if ($signal eq 'PIPE') {
154 3532         5677 $state = "IGNORE";
155             }
156              
157 4369         3294 if (TRACE_SIGNALS) {
158             POE::Kernel::_warn " $state SIG$signal";
159             }
160 7377         22057 $SIG{$signal} = $state;
161             }
162              
163             sub loop_ignore_all_signals {
164 3438     189 0 8953 my $self = shift;
165 3438         40141 foreach my $signal (keys %signal_watched) {
166 0           $self->loop_ignore_signal($signal);
167             }
168             }
169              
170             1;
171              
172             __END__