POE

 view release on metacpan or  search on metacpan

lib/POE/Resource/Signals.pm  view on Meta::CPAN

    }
    # Per https://rt.cpan.org/Ticket/Display.html?id=45109 setting the
    # signal handler must be done after reaping the outstanding child
    # processes, at least on SysV systems like HP-UX.
    $SIG{$signal} = \&_loop_signal_handler_chld;
  }
  else {
    # The poll loop is over.  Resume slowly polling for signals.

    if ($polling_for_signals) {
      if (TRACE_SIGNALS) {
        _warn("<sg> POE::Kernel will poll again after a delay");
      }
      $self->_data_sig_enqueue_poll_event($signal);
    }
    else {
      if (TRACE_SIGNALS) {
        _warn("<sg> POE::Kernel SIGCHLD poll loop paused");
      }
      $self->_idle_queue_shrink();
    }
  }
}

sub _data_sig_reap_pids {
  my $self = shift();

  # Reap children for as long as waitpid(2) says something
  # interesting has happened.
  # TODO This has a possibility of an infinite loop, but so far it
  # hasn't hasn't happened.

  my $pid;
  while ($pid = waitpid(-1, WNOHANG)) {
    # waitpid(2) returned a process ID.  Emit an appropriate SIGCHLD
    # event and loop around again.

    if (($pid > 0) or (RUNNING_IN_HELL and $pid < -1)) {
      if (RUNNING_IN_HELL or WIFEXITED($?) or WIFSIGNALED($?)) {

        if (TRACE_SIGNALS) {
          _warn("<sg> POE::Kernel detected SIGCHLD (pid=$pid; exit=$?)");
        }

        # Check for explicit SIGCHLD watchers, and enqueue explicit
        # events for them.

        if (exists $kr_pids_to_events{$pid}) {
          my @sessions_to_clear;
          while (my ($sid, $ses_rec) = each %{$kr_pids_to_events{$pid}}) {
            $self->_data_ev_enqueue(
              $ses_rec->[PID_SESSION], $self, $ses_rec->[PID_EVENT], ET_SIGCLD,
              [ 'CHLD', $pid, $?, @{$ses_rec->[PID_ARGS]} ],
              __FILE__, __LINE__, undef
            );
            push @sessions_to_clear, $sid;
          }
          $self->_data_sig_pid_ignore($_, $pid) foreach @sessions_to_clear;
        }

        # Kick off a SIGCHLD cascade.
        $self->_data_ev_enqueue(
          $self, $self, EN_SIGNAL, ET_SIGNAL, [ 'CHLD', $pid, $? ],
          __FILE__, __LINE__, undef
        );
      }
      elsif (TRACE_SIGNALS) {
        _warn("<sg> POE::Kernel detected strange exit (pid=$pid; exit=$?");
      }

      if (TRACE_SIGNALS) {
        _warn("<sg> POE::Kernel will poll again immediately");
      }

      next;
    }

    # The only other negative value waitpid(2) should return is -1.
    # This is highly unlikely, but it's necessary to catch
    # portability problems.
    #
    # TODO - Find a way to test this.

    _trap "internal consistency error: waitpid returned $pid" if $pid != -1;

    # If the error is an interrupted syscall, poll again right away.

    if ($! == EINTR) {
      if (TRACE_SIGNALS) {
        _warn(
          "<sg> POE::Kernel's waitpid(2) was interrupted.\n",
          "POE::Kernel will poll again immediately.\n"
        );
      }
      next;
    }

    # No child processes exist.  TODO This is different than
    # children being present but running.  Maybe this condition
    # could halt polling entirely, and some UNIVERSAL::fork wrapper
    # could restart polling when processes are forked.

    if ($! == ECHILD) {
      if (TRACE_SIGNALS) {
        _warn("<sg> POE::Kernel has no child processes");
      }
      last;
    }

    # Some other error occurred.

    if (TRACE_SIGNALS) {
      _warn("<sg> POE::Kernel's waitpid(2) got error: $!");
    }
    last;
  }

  # Remember whether there are more processes to reap.

  $kr_has_child_procs = !$pid;
}



( run in 0.661 second using v1.01-cache-2.11-cpan-f56aa216473 )