|
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'] |
|
|
|
|
|
|
|
|
|
|
|
class _DupFd(object): |
|
def __init__(self, ind): |
|
self.ind = ind |
|
def detach(self): |
|
return forkserver.get_inherited_fds()[self.ind] |
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
_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): |
|
|
|
|
|
self.returncode = 255 |
|
|
|
return self.returncode |
|
|