def spawn(specs, pipe_fd, tty_fd): # We do not want to get killed by Ctrl-C. We should only exit # when the child processes have exited. signal.signal(signal.SIGINT, signal.SIG_IGN) # We can get these signals when setting the status of child # processes. Ignore them otherwise we'll get wedged! signal.signal(signal.SIGTTIN, signal.SIG_IGN) signal.signal(signal.SIGTTOU, signal.SIG_IGN) pipe = os.fdopen(pipe_fd, "w", 0) # Detach from controlling tty and create new session. os.setsid() # Set controlling tty. fcntl.ioctl(tty_fd, termios.TIOCSCTTY, 0) pgroup = shell_spawn.ProcessGroup(True, NonOwningFDWrapper(tty_fd)) pids = [] for spec in specs: spec["pgroup"] = pgroup spec["fds"] = dict((dest_fd, NonOwningFDWrapper(fd)) for dest_fd, fd in spec["fds"].iteritems()) pids.append(shell_spawn.spawn_subprocess(spec)) shell_spawn.close_fds([pipe_fd]) os.chdir("/") # Don't keep directory FD alive via cwd. pipe.write("%s\n" % repr(pids)) while True: try: pid, status = os.waitpid(-1, os.WUNTRACED) except OSError: break pipe.write("%s\n" % repr((pid, status)))
def start_job(self, job_procs, is_foreground, cmd_text): pgroup = shell_spawn.ProcessGroup(is_foreground, self._tty_fd) pids = [] for spec in job_procs: spec["pgroup"] = pgroup pids.append(shell_spawn.spawn_subprocess(spec)) del spec # We must ensure that FDs are dropped before any waiting. job_procs[:] = [] procs = [ChildProcess(self._dispatcher, proc) for proc in pids] pgid = pgroup.get_pgid() def to_foreground(): os.tcsetpgrp(self._tty_fd.fileno(), pgid) job = Job(procs, pgroup.get_pgid(), cmd_text, to_foreground) self._job_controller.add_job(job, is_foreground)