Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 197 lines (152 sloc) 4.703 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
# Plain Perl signal handling is something shared by several event
# loops. The invariant code has moved out here so that each loop may
# use it without reinventing it. This will save maintenance and
# shrink the distribution. Yay!

package POE::Loop::PerlSignals;

use strict;

use vars qw($VERSION);
$VERSION = '1.281'; # NOTE - Should be #.### (three decimal places)

# Everything plugs into POE::Kernel.
package POE::Kernel;

use strict;
use POE::Kernel;

# Flag so we know which signals are watched. Used to reset those
# signals during finalization.
my %signal_watched;

#------------------------------------------------------------------------------
# Signal handlers/callbacks.

sub _loop_signal_handler_generic {
  if( USE_SIGNAL_PIPE ) {
    POE::Kernel->_data_sig_pipe_send( $_[0] );
  }
  else {
    _loop_signal_handler_generic_bottom( $_[0] );
  }
}

sub _loop_signal_handler_generic_bottom {
  if (TRACE_SIGNALS) {
    POE::Kernel::_warn "<sg> Enqueuing generic SIG$_[0] event";
  }

  $poe_kernel->_data_ev_enqueue(
    $poe_kernel, $poe_kernel, EN_SIGNAL, ET_SIGNAL, [ $_[0] ],
    __FILE__, __LINE__, undef, time()
  );
  $SIG{$_[0]} = \&_loop_signal_handler_generic;
}

##
sub _loop_signal_handler_pipe {
  if( USE_SIGNAL_PIPE ) {
    POE::Kernel->_data_sig_pipe_send( $_[0] );
  }
  else {
    _loop_signal_handler_pipe_bottom( $_[0] );
  }
}

sub _loop_signal_handler_pipe_bottom {
  if (TRACE_SIGNALS) {
    POE::Kernel::_warn "<sg> Enqueuing PIPE-like SIG$_[0] event";
  }

  $poe_kernel->_data_ev_enqueue(
    $poe_kernel, $poe_kernel, EN_SIGNAL, ET_SIGNAL, [ $_[0] ],
    __FILE__, __LINE__, undef, time()
  );
  $SIG{$_[0]} = \&_loop_signal_handler_pipe;
}

## only used under USE_SIGCHLD
sub _loop_signal_handler_chld {
  if( USE_SIGNAL_PIPE ) {
    POE::Kernel->_data_sig_pipe_send( 'CHLD' );
  }
  else {
    _loop_signal_handler_chld_bottom( $_[0] );
  }
}

sub _loop_signal_handler_chld_bottom {
  if (TRACE_SIGNALS) {
    POE::Kernel::_warn "<sg> Enqueuing CHLD-like SIG$_[0] event";
  }

  $poe_kernel->_data_sig_enqueue_poll_event($_[0]);
}

#------------------------------------------------------------------------------
# Signal handler maintenance functions.

sub loop_watch_signal {
  my ($self, $signal) = @_;

  $signal_watched{$signal} = 1;

  # Child process has stopped.
  if ($signal eq 'CHLD' or $signal eq 'CLD') {
    if ( USE_SIGCHLD ) {
      # Poll once for signals. Will set the signal handler when done.
      $self->_data_sig_enqueue_poll_event($signal);
    } else {
      # We should never twiddle $SIG{CH?LD} under POE, unless we want to
      # override system() and friends. --hachi
      # $SIG{$signal} = "DEFAULT";
      $self->_data_sig_begin_polling($signal);
    }
    return;
  }

  # Broken pipe.
  if ($signal eq 'PIPE') {
    $SIG{$signal} = \&_loop_signal_handler_pipe;
    return;
  }

  # Everything else.
  $SIG{$signal} = \&_loop_signal_handler_generic;
}

sub loop_ignore_signal {
  my ($self, $signal) = @_;

  delete $signal_watched{$signal};

  if ($signal eq 'CHLD' or $signal eq 'CLD') {
    if ( USE_SIGCHLD ) {
      if( $self->_data_sig_child_procs) {
        # We need SIGCHLD to stay around after shutdown, so that
        # child processes may be reaped and kr_child_procs=0
        if (TRACE_SIGNALS) {
          POE::Kernel::_warn "<sg> Keeping SIG$signal anyway!";
        }
        return;
      }
    } else {
      $self->_data_sig_cease_polling();
      # We should never twiddle $SIG{CH?LD} under poe, unless we want to
      # override system() and friends. --hachi
      # $SIG{$signal} = "IGNORE";
      return;
    }
  }

  delete $signal_watched{$signal};

  my $state = 'DEFAULT';
  if ($signal eq 'PIPE') {
    $state = "IGNORE";
  }

  if (TRACE_SIGNALS) {
    POE::Kernel::_warn "<sg> $state SIG$signal";
  }
  $SIG{$signal} = $state;
}

sub loop_ignore_all_signals {
  my $self = shift;
  foreach my $signal (keys %signal_watched) {
    $self->loop_ignore_signal($signal);
  }
}

1;

__END__

=head1 NAME

POE::Loop::PerlSignals - common signal handling routines for POE::Loop bridges

=head1 SYNOPSIS

See L<POE::Loop>.

=head1 DESCRIPTION

POE::Loop::PerlSignals implements common code to handle signals for
many different event loops. Most loops don't handle signals natively,
so this code has been abstracted into a reusable mix-in module.

POE::Loop::PerlSignals follows POE::Loop's public interface for signal
handling. Therefore, please see L<POE::Loop> for more details.

=head1 SEE ALSO

L<POE>, L<POE::Loop>

=head1 AUTHORS & LICENSING

Please see L<POE> for more information about authors, contributors,
and POE's licensing.

=cut

# rocco // vim: ts=2 sw=2 expandtab
# TODO - Edit.
Something went wrong with that request. Please try again.