def exited(self, status): # Log last output for line in self.readlines(): pass # Display exit code if status is not None: log_func = self.warning info = [] if WCOREDUMP(status): info.append("core.%s dumped!" % self._pid) log_func = self.error if WIFSIGNALED(status): signal = WTERMSIG(status) signal = SIGNAME.get(signal, signal) info.append("signal %s" % signal) if WIFEXITED(status): info.append("exitcode=%s" % WEXITSTATUS(status)) if info: log_func("Exit (%s)" % ", ".join(info)) else: log_func("Exit") else: self.error("Process exited (ECHILD error)") # Delete process self.process = None self._pid = None
def wait_and_reap_zombies(pid): _, status = waitpid(pid, 0) try: while True: waitpid(-1, WNOHANG) except ChildProcessError: pass if WIFSIGNALED(status): return -WTERMSIG(status) return WEXITSTATUS(status)
def execute(self, *args): process = Popen4([self.facility.path] + self.facility.args + list(args)) timers = [ Timer(time, self.kill, [process.pid, signal]) for time, signal in self.facility.wait.iteritems() ] for timer in timers: timer.start() status = process.wait() for timer in timers: # No penalty, btw, for cancelling a dead timer if timer.isAlive(): timer.cancel() process.tochild.close() if __debug__: while True: line = process.fromchild.readline() if line: syslog(line) else: break process.fromchild.close() command = basename(self.facility.path) if WIFEXITED(status): exit_status = WEXITSTATUS(status) if exit_status != EX_OK: raise ExecutionError( EX_SOFTWARE, '`%(command)s\' exited with \ error-code %(exit_status)d' % { 'command': command, 'exit_status': exit_status }) elif WIFSIGNALED(status): raise ExecutionError( EX_SOFTWARE, '`%(command)s\' terminated \ with signal %(signal)d' % { 'command': command, 'signal': WTERMSIG(status) }) elif WIFSTOPPED(status): raise ExecutionError( EX_SOFTWARE, '`%(command)s\' stopped with \ signal %(signal)d' % { 'command': command, 'signal': WSTOPSIG(status) }) else: # Failsafe: timers should have killed the process by this point, or # it should have ended naturally. kill(process.pid, SIGKILL) raise ExecutionError( EX_SOFTWARE, 'Failed timer on `%(command)s\'; \ terminating the process extraordinarily.' % {'command': command})
def formatProcessStatus(status, title="Process"): if WIFSTOPPED(status): signum = WSTOPSIG(status) return "%s stopped by signal %s" % (title, signalName(signum)) if WIFSIGNALED(status): signum = WTERMSIG(status) return "%s killed by signal %s" % (title, signalName(signum)) if not WIFEXITED(status): raise ValueError("Invalid status: %r" % status) exitcode = WEXITSTATUS(status) if exitcode: return "%s exited with code %s" % (title, exitcode) else: return "%s exited normally" % title
def _waitpid(pid): """Convenience wrapper around the original waitpid invocation.""" # 0 and -1 trigger a different behavior in waitpid. We disallow those # values. assert pid > 0 while True: pid_, status = waitpid_(pid, 0) assert pid_ == pid if WIFEXITED(status): return WEXITSTATUS(status) elif WIFSIGNALED(status): # Signals are usually represented as the negated signal number. return -WTERMSIG(status) elif WIFSTOPPED(status) or WIFCONTINUED(status): # In our current usage scenarios we can simply ignore SIGSTOP and # SIGCONT by restarting the wait. continue else: assert False return 1
def formatProcessStatus(status, title="Process"): """ Format a process status (integer) as a string. """ if WIFSTOPPED(status): signum = WSTOPSIG(status) text = "%s stopped by signal %s" % (title, signalName(signum)) elif WIFSIGNALED(status): signum = WTERMSIG(status) text = "%s killed by signal %s" % (title, signalName(signum)) else: if not WIFEXITED(status): raise ValueError("Invalid status: %r" % status) exitcode = WEXITSTATUS(status) if exitcode: text = "%s exited with code %s" % (title, exitcode) else: text = "%s exited normally" % title if WCOREDUMP(status): text += " (core dumped)" return text
def processStatus(self, status): # Process exited? if WIFEXITED(status): code = WEXITSTATUS(status) event = self.processExited(code) # Process killed by a signal? elif WIFSIGNALED(status): signum = WTERMSIG(status) event = self.processKilled(signum) # Invalid process status? elif not WIFSTOPPED(status): raise ProcessError(self, "Unknown process status: %r" % status) # Ptrace event? elif HAS_PTRACE_EVENTS and WPTRACEEVENT(status): event = WPTRACEEVENT(status) event = self.ptraceEvent(event) else: signum = WSTOPSIG(status) event = self.processSignal(signum) return event
def _event_handle_process_kill(self, status, pid): signum = WTERMSIG(status) logger.debug('process killed by a signal:%d, pid=%d' % (signum, pid)) self.pid_dict.pop(pid) if len(self.pid_dict) == 0: self.process_exist = True