def _signal_int(self, signum, frame): """Signal handler for SIGINT - Ctrl+C may have been pressed.""" self.send_signal(signal.CTRL_C_EVENT if xp.ON_WINDOWS else signum) if self.proc is not None and self.proc.poll() is not None: self._restore_sigint(frame=frame) if xt.on_main_thread() and not xp.ON_WINDOWS: signal.pthread_kill(threading.get_ident(), signal.SIGINT)
def _restore_sigquit(self, frame=None): old = self.old_quit_handler if old is not None: if xt.on_main_thread(): signal.signal(signal.SIGQUIT, old) self.old_quit_handler = None if frame is not None: self._disable_cbreak_stdin()
def _restore_sigtstp(self, frame=None): old = self.old_tstp_handler if old is not None: if xt.on_main_thread(): signal.signal(signal.SIGTSTP, old) self.old_tstp_handler = None if frame is not None: self._disable_cbreak_stdin() self._restore_suspend_keybind()
def _restore_sigint(self, frame=None): old = self.old_int_handler if old is not None: if xt.on_main_thread(): signal.signal(signal.SIGINT, old) self.old_int_handler = None if frame is not None: self._disable_cbreak_stdin() if old is not None and old is not self._signal_int: old(signal.SIGINT, frame)
def _restore_sigint(self, frame=None): old = self.old_int_handler if old is not None: if xt.on_main_thread(): signal.signal(signal.SIGINT, old) self.old_int_handler = None if frame is not None: if old is not None and old is not self._signal_int: old(signal.SIGINT, frame) if self._interrupted: self.returncode = 1
def wait(self, timeout=None): """Dispatches to Popen.wait(), but also does process cleanup such as joining this thread and replacing the original window size signal handler. """ self._disable_cbreak_stdin() rtn = self.proc.wait(timeout=timeout) self.join() # need to replace the old signal handlers somewhere... if self.old_winch_handler is not None and xt.on_main_thread(): signal.signal(signal.SIGWINCH, self.old_winch_handler) self.old_winch_handler = None self._clean_up() return rtn
def _signal_int(self, signum, frame): """Signal handler for SIGINT - Ctrl+C may have been pressed.""" # Check if we have already been interrupted. This should prevent # the possibility of infinite recursion. if self._interrupted: return self._interrupted = True # close file handles here to stop an processes piped to us. handles = ( self.p2cread, self.p2cwrite, self.c2pread, self.c2pwrite, self.errread, self.errwrite, ) for handle in handles: safe_fdclose(handle) if self.poll() is not None: self._restore_sigint(frame=frame) if xt.on_main_thread() and not xp.ON_WINDOWS: signal.pthread_kill(threading.get_ident(), signal.SIGINT)
def __init__( self, f, args, stdin=None, stdout=None, stderr=None, universal_newlines=False, close_fds=False, env=None, ): """Parameters ---------- f : function The function to be executed. args : list A (possibly empty) list containing the arguments that were given on the command line stdin : file-like, optional A file-like object representing stdin (input can be read from here). If `stdin` is not provided or if it is explicitly set to `None`, then an instance of `io.StringIO` representing an empty file is used. stdout : file-like, optional A file-like object representing stdout (normal output can be written here). If `stdout` is not provided or if it is explicitly set to `None`, then `sys.stdout` is used. stderr : file-like, optional A file-like object representing stderr (error output can be written here). If `stderr` is not provided or if it is explicitly set to `None`, then `sys.stderr` is used. universal_newlines : bool, optional Whether or not to use universal newlines. close_fds : bool, optional Whether or not to close file descriptors. This is here for Popen compatability and currently does nothing. env : Mapping, optional Environment mapping. """ self.orig_f = f self.f = partial_proxy(f) self.args = args self.pid = None self.returncode = None self._closed_handle_cache = {} handles = self._get_handles(stdin, stdout, stderr) ( self.p2cread, self.p2cwrite, self.c2pread, self.c2pwrite, self.errread, self.errwrite, ) = handles # default values self.stdin = stdin self.stdout = stdout self.stderr = stderr self.close_fds = close_fds self.env = env or builtins.__xonsh__.env self._interrupted = False if xp.ON_WINDOWS: if self.p2cwrite != -1: self.p2cwrite = xli.msvcrt.open_osfhandle( self.p2cwrite.Detach(), 0) if self.c2pread != -1: self.c2pread = xli.msvcrt.open_osfhandle( self.c2pread.Detach(), 0) if self.errread != -1: self.errread = xli.msvcrt.open_osfhandle( self.errread.Detach(), 0) if self.p2cwrite != -1: self.stdin = io.open(self.p2cwrite, "wb", -1) if universal_newlines: self.stdin = io.TextIOWrapper(self.stdin, write_through=True, line_buffering=False) elif isinstance(stdin, int) and stdin != 0: self.stdin = io.open(stdin, "wb", -1) if self.c2pread != -1: self.stdout = io.open(self.c2pread, "rb", -1) if universal_newlines: self.stdout = io.TextIOWrapper(self.stdout) if self.errread != -1: self.stderr = io.open(self.errread, "rb", -1) if universal_newlines: self.stderr = io.TextIOWrapper(self.stderr) # Set some signal handles, if we can. Must come before process # is started to prevent deadlock on windows self.old_int_handler = None if xt.on_main_thread(): self.old_int_handler = signal.signal(signal.SIGINT, self._signal_int) # start up the proc super().__init__() self.start()
def __init__(self, *args, stdin=None, stdout=None, stderr=None, **kwargs): super().__init__() self.daemon = True self.lock = threading.RLock() env = XSH.env # stdin setup self.orig_stdin = stdin if stdin is None: self.stdin_fd = 0 elif isinstance(stdin, int): self.stdin_fd = stdin else: self.stdin_fd = stdin.fileno() self.store_stdin = env.get("XONSH_STORE_STDIN") self.timeout = env.get("XONSH_PROC_FREQUENCY") self.in_alt_mode = False self.stdin_mode = None self._tc_cc_vsusp = b"\x1a" # default is usually ^Z self._disable_suspend_keybind() # stdout setup self.orig_stdout = stdout self.stdout_fd = 1 if stdout is None else stdout.fileno() self._set_pty_size() # stderr setup self.orig_stderr = stderr # Set some signal handles, if we can. Must come before process # is started to prevent deadlock on windows self.proc = None # has to be here for closure for handles self.old_int_handler = self.old_winch_handler = None self.old_tstp_handler = self.old_quit_handler = None if xt.on_main_thread(): self.old_int_handler = signal.signal(signal.SIGINT, self._signal_int) if xp.ON_POSIX: self.old_tstp_handler = signal.signal(signal.SIGTSTP, self._signal_tstp) self.old_quit_handler = signal.signal(signal.SIGQUIT, self._signal_quit) if xp.CAN_RESIZE_WINDOW: self.old_winch_handler = signal.signal(signal.SIGWINCH, self._signal_winch) # start up process if xp.ON_WINDOWS and stdout is not None: os.set_inheritable(stdout.fileno(), False) try: self.proc = proc = subprocess.Popen(*args, stdin=stdin, stdout=stdout, stderr=stderr, **kwargs) except Exception: self._clean_up() raise self.pid = proc.pid self.universal_newlines = uninew = proc.universal_newlines if uninew: self.encoding = enc = env.get("XONSH_ENCODING") self.encoding_errors = err = env.get("XONSH_ENCODING_ERRORS") self.stdin = io.BytesIO() # stdin is always bytes! self.stdout = io.TextIOWrapper(io.BytesIO(), encoding=enc, errors=err) self.stderr = io.TextIOWrapper(io.BytesIO(), encoding=enc, errors=err) else: self.encoding = self.encoding_errors = None self.stdin = io.BytesIO() self.stdout = io.BytesIO() self.stderr = io.BytesIO() self.suspended = False self.prevs_are_closed = False # This is so the thread will use the same swapped values as the origin one. self.original_swapped_values = XSH.env.get_swapped_values() self.start()