| import io |
| import os |
| |
| from .context import reduction, set_spawning_popen |
| if not reduction.HAVE_SEND_HANDLE: |
| raise ImportError('No support for sending fds between processes') |
| from . import forkserver |
| from . import popen_fork |
| from . import spawn |
| from . import util |
| |
| |
| __all__ = ['Popen'] |
| |
| # |
| # Wrapper for an fd used while launching a process |
| # |
| |
| class _DupFd(object): |
| def __init__(self, ind): |
| self.ind = ind |
| def detach(self): |
| return forkserver.get_inherited_fds()[self.ind] |
| |
| # |
| # Start child process using a server process |
| # |
| |
| class Popen(popen_fork.Popen): |
| method = 'forkserver' |
| DupFd = _DupFd |
| |
| def __init__(self, process_obj): |
| self._fds = [] |
| super().__init__(process_obj) |
| |
| def duplicate_for_child(self, fd): |
| self._fds.append(fd) |
| return len(self._fds) - 1 |
| |
| def _launch(self, process_obj): |
| prep_data = spawn.get_preparation_data(process_obj._name) |
| buf = io.BytesIO() |
| set_spawning_popen(self) |
| try: |
| reduction.dump(prep_data, buf) |
| reduction.dump(process_obj, buf) |
| finally: |
| set_spawning_popen(None) |
| |
| self.sentinel, w = forkserver.connect_to_new_process(self._fds) |
| # Keep a duplicate of the data pipe's write end as a sentinel of the |
| # parent process used by the child process. |
| _parent_w = os.dup(w) |
| self.finalizer = util.Finalize(self, util.close_fds, |
| (_parent_w, self.sentinel)) |
| with open(w, 'wb', closefd=True) as f: |
| f.write(buf.getbuffer()) |
| self.pid = forkserver.read_signed(self.sentinel) |
| |
| def poll(self, flag=os.WNOHANG): |
| if self.returncode is None: |
| from multiprocessing.connection import wait |
| timeout = 0 if flag == os.WNOHANG else None |
| if not wait([self.sentinel], timeout): |
| return None |
| try: |
| self.returncode = forkserver.read_signed(self.sentinel) |
| except (OSError, EOFError): |
| # This should not happen usually, but perhaps the forkserver |
| # process itself got killed |
| self.returncode = 255 |
| |
| return self.returncode |