def run_executable(*, path, argv, prefix=None): cmd = [path] + argv # on Windows Python scripts are invokable through the interpreter if os.name == 'nt' and path.endswith('.py'): cmd.insert(0, sys.executable) if prefix is not None: cmd = prefix + cmd process = subprocess.Popen(cmd) while process.returncode is None: try: process.communicate() except KeyboardInterrupt: # the subprocess will also receive the signal and should shut down # therefore we continue here until the process has finished pass if process.returncode != 0: if -process.returncode in signal.valid_signals() and os.name == 'posix': # a negative value -N indicates that the child was terminated by signal N. print(ROS2RUN_MSG_PREFIX, signal.strsignal(-process.returncode)) else: # print general failure message instead. print(ROS2RUN_MSG_PREFIX, 'Process exited with failure %d' % (process.returncode)) return process.returncode
def test_valid_signals(self): s = signal.valid_signals() self.assertIsInstance(s, set) self.assertIn(signal.Signals.SIGINT, s) self.assertIn(signal.Signals.SIGALRM, s) self.assertNotIn(0, s) self.assertNotIn(signal.NSIG, s) self.assertLess(len(s), signal.NSIG)
def test_valid_signals(self): s = signal.valid_signals() self.assertIsInstance(s, set) self.assertGreaterEqual(len(s), 6) self.assertIn(signal.Signals.SIGINT, s) self.assertNotIn(0, s) self.assertNotIn(signal.NSIG, s) self.assertLess(len(s), signal.NSIG)
def trace_signals(cls, sink: Writeable = sys.stderr) -> None: """ Registers signal handlers for all signals that log the traceback. Uses ``signal.signal``. """ for sig in signal.valid_signals(): handler = SignalHandler(sig.name, sig.value, signal.strsignal(sig), sink) signal.signal(sig.value, handler)
def _check_signal(self, sig): """Internal helper to validate a signal. Raise ValueError if the signal number is invalid or uncatchable. Raise RuntimeError if there is a problem setting up the handler. """ if not isinstance(sig, int): raise TypeError(f'sig must be an int, not {sig!r}') if sig not in signal.valid_signals(): raise ValueError(f'invalid signal number {sig}')
def _check_signal(self, sig): """Internal helper to validate a signal. Raise ValueError if the signal number is invalid or uncatchable. Raise RuntimeError if there is a problem setting up the handler. """ if not isinstance(sig, int): raise TypeError(f'sig must be an int, not {sig!r}') if sig not in signal.valid_signals(): raise ValueError(f'invalid signal number {sig}')
def __init__(self, root_config, job_config: DaemonProcessorConfig, prompter): super().__init__(root_config, job_config, prompter) signals_str = { s.name: s for s in signal.valid_signals() if isinstance(s, IntEnum) } signals_int = [s for s in signal.valid_signals()] if isinstance(job_config.signal, int): if job_config.signal not in signals_int: raise ValueError( f'Signal {job_config.signal} is not available.') self._signal = job_config.signal else: if job_config.signal not in signals_str: raise ValueError( f'Signal {job_config.signal} is not available.') self._signal = signals_str[job_config.signal]
def blocked_signals(): """Block all signals for e.g. starting a worker thread.""" # valid_signals() was added in Python 3.8 (and not using it results # in a warning on pthread_sigmask() call) try: mask = signal.valid_signals() except AttributeError: mask = set(range(1, signal.NSIG)) old_mask = signal.pthread_sigmask(signal.SIG_SETMASK, mask) try: yield finally: signal.pthread_sigmask(signal.SIG_SETMASK, old_mask)
def script() -> None: #!/usr/bin/env python3 import fcntl import os import sys import signal import time from typing import Any def handle_signal(sig: Any, frame: Any) -> None: sys.stderr.write(f'{os.getpid()} ignoring signal {sig}\n') if hasattr(signal, 'valid_signals'): # We can just ask about the signals all_signals = signal.valid_signals() else: # Fish them out by name all_signals = [ getattr(signal, n) for n in dir(signal) if n.startswith('SIG') and not n.startswith('SIG_') ] for sig in all_signals: # Set up to ignore all signals we can and generally be obstinate if sig != signal.SIGKILL and sig != signal.SIGSTOP: signal.signal(sig, handle_signal) if len(sys.argv) > 2: # Instructed to hide if os.fork(): # Try and hide the first process immediately so getting its # pgid won't work. sys.exit(0) for depth in range(3): # Bush out into a tree of processes os.fork() if len(sys.argv) > 1: fd = os.open(sys.argv[1], os.O_RDONLY) fcntl.lockf(fd, fcntl.LOCK_SH) sys.stderr.write(f'{os.getpid()} waiting...\n') while True: # Wait around forever time.sleep(60)
def _serve(self): if hasattr(signal, 'pthread_sigmask'): signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals()) while 1: try: with self._listener.accept() as conn: msg = conn.recv() if msg is None: break key, destination_pid = msg send, close = self._cache.pop(key) try: send(conn, destination_pid) finally: close() except: if not util.is_exiting(): sys.excepthook(*sys.exc_info())
def _serve(self): if hasattr(signal, 'pthread_sigmask'): signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals()) while 1: try: with self._listener.accept() as conn: msg = conn.recv() if msg is None: break key, destination_pid = msg send, close = self._cache.pop(key) try: send(conn, destination_pid) finally: close() except: if not util.is_exiting(): sys.excepthook(*sys.exc_info())
def _valid_signals() -> Set[signal.Signals]: """Returns all valid signals supported on the current platform. Behaves identically to :func:`signals.valid_signals` in Python 3.8+ and implements the equivalent behavior for older Python versions. """ if sys.version_info >= (3, 8): return signal.valid_signals() elif _IS_WINDOWS: # supported signals on Windows: https://docs.python.org/3/library/signal.html#signal.signal return { signal.SIGABRT, signal.SIGFPE, signal.SIGILL, signal.SIGINT, signal.SIGSEGV, signal.SIGTERM, signal.SIGBREAK, } return set(signal.Signals)
def blocked_signals() -> Iterator[None]: """Block all signals for e.g. starting a worker thread.""" # valid_signals() was added in Python 3.8 (and not using it results # in a warning on pthread_sigmask() call) mask: Iterable[int] try: mask = signal.valid_signals() except AttributeError: mask = set(range(1, signal.NSIG)) old_mask = signal.pthread_sigmask( # type: ignore[attr-defined] signal.SIG_SETMASK, # type: ignore[attr-defined] mask, ) try: yield finally: signal.pthread_sigmask( # type: ignore[attr-defined] signal.SIG_SETMASK, # type: ignore[attr-defined] old_mask, )
# signal.signal(signal.SIGXCPU, time_expired) # soft, hard = resource.getrlimit(resource.RLIMIT_CPU) # print('Soft limit starts as :', soft) # resource.setrlimit(resource.RLIMIT_CPU, (10, hard)) # print('Soft limit changed to : ', soft) # print() # print('Starting:', time.ctime()) # for i in range(200000): # for i in range(200000): # v = i * i # print('Exiting:', time.ctime()) valid_signals = signal.valid_signals() # print(valid_signals) """ A Signal Handler is a user defined function, where Python signals can be handled. If we take the signal SIGINT (Interrupt Signal), the default behavior would be to stop the current running program. We can, however, assign a signal handler to detect this signal and do our custom processing instead! """ def signal_handler(signum, frame): print("Signal Number:", signum, " Frame: ", frame)
def process_config(self): self.signal_lookup = {} # Collect all valid signals into a lookup dict for x in signal.valid_signals(): try: self.signal_lookup[x.name] = x self.signal_lookup[str(x.value)] = x except AttributeError: self.signal_lookup[str(x)] = x # Parse passthrough-input for signal passthrough mappings self.passthroughmap = {} if "passthrough" in self.config: for x in self.config["passthrough"].split(';'): y = x.split('=') if len(y) not in (1, 2): self.logger.critical( "Invalid signal passthrough configuration (syntax) -- exiting" ) sys.exit(1) if len(y) == 1: y.append(y[0]) sig_in, sig_out = y if sig_in in self.signal_lookup and sig_out in signal_lookup: self.passthroughmap[self.signal_lookup[ sig_in]] = self.signal_lookup[sig_out] else: self.logger.critical( "Invalid signal passthrough configuration (unknown signal) -- exiting" ) if self.signal_lookup[sig_in] == signal.SIGINT: self.exit_signals.remove(signal.SIGINT) self.logger.warn( "Passthrough for SIGINT defined -- you will not be able to stop this program with Ctrl-C" .format(sig_in)) if "stopcmd" in self.config: for sig in (signal.SIGTERM, signal.SIGINT): if sig not in self.passthroughmap.keys(): self.signal_commands[sig] = self.config["stopcmd"] else: self.logger.info( "Passthrough for {} defined together with stopcmd -- will use passthrough" .format(sig)) # Parse input for signals if "signals" in self.config: for x in self.config["signals"].split(';'): y = x.split('=') if len(y) != 2: self.logger.critical( "Invalid signal configuration -- exiting") sys.exit(1) sig, cmd = y if sig in self.signal_lookup: if self.signal_lookup[sig] in (signal.SIGKILL, signal.SIGTSTP): self.logger.critical( "Impossible to hook to signal {} -- exiting". format(sig)) sys.exit(1) if self.signal_lookup[ sig] == signal.SIGTERM and "stopcmd" in d: self.logger.warn( "Both stopcmd and signalcmd for {} defined -- will use stopcmd" .format(sig)) continue if self.signal_lookup[sig] == signal.SIGINT: exit_signals.remove(signal.SIGINT) self.logger.warn( "Command for SIGINT defined -- you will not be able to stop this program with Ctrl-C" .format(sig)) if self.signal_lookup[sig] in self.passthroughmap.keys(): self.logger.warn( "Both passthrough and signalcmd for {} defined -- will use passthrough" .format(sig)) continue self.signal_commands[self.signal_lookup[sig]] = cmd else: self.logger.critical( "Unknown signal {} -- exiting".format(sig)) sys.exit(1) # Register signals for sig, cmd in self.signal_commands.items(): signal.signal(sig, self.signal_handler) self.logger.info( "Registered signal {} with command '{}'".format( sig.name, cmd)) # Register passthrough mappings for sig_in, sig_out in self.passthroughmap.items(): signal.signal(sig_in, self.signal_handler) self.logger.info( "Registered signal {} with passthrough using signal {}". format(sig_in.name, sig_out.name))
def setup_signals(): for sig in signal.valid_signals(): try: signal.signal(sig, receiveSignal) except Exception: pass
def test_pthread_sigmask_valid_signals(self): s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals()) self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, s) # Get current blocked set s = signal.pthread_sigmask(signal.SIG_UNBLOCK, signal.valid_signals()) self.assertLessEqual(s, signal.valid_signals())
def test_pthread_sigmask_valid_signals(self): s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals()) self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, s) # Get current blocked set s = signal.pthread_sigmask(signal.SIG_UNBLOCK, signal.valid_signals()) self.assertLessEqual(s, signal.valid_signals())
distributed data parallel launcher as just a reference. https://github.com/pytorch/pytorch/blob/v1.8.2/torch/distributed/launch.py One main difference is this code focuses on launching simple function with given arguments. """ import multiprocessing import os import signal import socket import time if hasattr(signal, "valid_signals"): _signalno_name_map = { s.value: s.name for s in signal.valid_signals() if isinstance(s, signal.Signals) } else: # TODO(lazykyama): It should be deprecated # once Python 3.7 is removed from supported platform. _signalno_name_map = dict([ (1, "SIGHUP"), (2, "SIGINT"), (3, "SIGQUIT"), (4, "SIGILL"), (5, "SIGTRAP"), (6, "SIGABRT"), (7, "SIGBUS"), (8, "SIGFPE"), (9, "SIGKILL"), (10, "SIGUSR1"),
if not seccomp.is_available(): return try: with seccomp.SeccompFilter() as s: for syscall in _FORBIDDEN_SYSCALLS: s.add_rule(seccomp.SCMP_ACT_ENOSYS, syscall) # enable for debugging # _ s.print_to(1) s.activate() except OSError as e: logging.info( "Could not enable seccomp filter for container isolation: %s", e) try: _ALL_SIGNALS = signal.valid_signals() # pytype: disable=module-attr except AttributeError: # Only exists on Python 3.8+ _ALL_SIGNALS = range(1, signal.NSIG) def block_all_signals(): """Block asynchronous delivery of all signals to this process.""" signal.pthread_sigmask(signal.SIG_BLOCK, _ALL_SIGNALS) def _forward_signal(signum, target_pid, process_name): logging.debug("Forwarding signal %d to process %s.", signum, process_name) try: os.kill(target_pid, signum) except OSError as e:
def update_event(self, inp=-1): self.set_output_val(0, signal.valid_signals())
if not seccomp.is_available(): return try: with seccomp.SeccompFilter() as s: for syscall in _FORBIDDEN_SYSCALLS: s.add_rule(seccomp.SCMP_ACT_ENOSYS, syscall) # enable for debugging # _ s.print_to(1) s.activate() except OSError as e: logging.info( "Could not enable seccomp filter for container isolation: %s", e) try: _ALL_SIGNALS = signal.valid_signals() except AttributeError: # Only exists on Python 3.8+ _ALL_SIGNALS = range(1, signal.NSIG) _FORWARDABLE_SIGNALS = set(range(1, 32)).difference( [signal.SIGKILL, signal.SIGSTOP, signal.SIGCHLD]) _HAS_SIGWAIT = hasattr(signal, "sigwait") # Does not exist on Python 2 def block_all_signals(): """Block asynchronous delivery of all signals to this process.""" if _HAS_SIGWAIT: signal.pthread_sigmask(signal.SIG_BLOCK, _ALL_SIGNALS) def _forward_signal(signum, target_pid, process_name):