blob: 222db2d90a31564bb94c1bb9ad1de918d4f3038f [file] [log] [blame]
Richard Oudkerk84ed9a62013-08-14 15:35:41 +01001import io
2import os
3
Davin Potts54586472016-09-09 18:03:10 -05004from .context import reduction, set_spawning_popen
Richard Oudkerk84ed9a62013-08-14 15:35:41 +01005if not reduction.HAVE_SEND_HANDLE:
6 raise ImportError('No support for sending fds between processes')
7from . import forkserver
Richard Oudkerk84ed9a62013-08-14 15:35:41 +01008from . import popen_fork
9from . import spawn
10from . import util
11
12
13__all__ = ['Popen']
14
15#
16# Wrapper for an fd used while launching a process
17#
18
19class _DupFd(object):
20 def __init__(self, ind):
21 self.ind = ind
22 def detach(self):
23 return forkserver.get_inherited_fds()[self.ind]
24
25#
26# Start child process using a server process
27#
28
29class Popen(popen_fork.Popen):
30 method = 'forkserver'
31 DupFd = _DupFd
32
33 def __init__(self, process_obj):
34 self._fds = []
35 super().__init__(process_obj)
36
37 def duplicate_for_child(self, fd):
38 self._fds.append(fd)
39 return len(self._fds) - 1
40
41 def _launch(self, process_obj):
42 prep_data = spawn.get_preparation_data(process_obj._name)
43 buf = io.BytesIO()
Davin Potts54586472016-09-09 18:03:10 -050044 set_spawning_popen(self)
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010045 try:
46 reduction.dump(prep_data, buf)
47 reduction.dump(process_obj, buf)
48 finally:
Davin Potts54586472016-09-09 18:03:10 -050049 set_spawning_popen(None)
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010050
51 self.sentinel, w = forkserver.connect_to_new_process(self._fds)
52 util.Finalize(self, os.close, (self.sentinel,))
53 with open(w, 'wb', closefd=True) as f:
54 f.write(buf.getbuffer())
55 self.pid = forkserver.read_unsigned(self.sentinel)
56
57 def poll(self, flag=os.WNOHANG):
58 if self.returncode is None:
Richard Oudkerkc3460602014-03-23 12:52:16 +000059 from multiprocessing.connection import wait
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010060 timeout = 0 if flag == os.WNOHANG else None
61 if not wait([self.sentinel], timeout):
62 return None
63 try:
64 self.returncode = forkserver.read_unsigned(self.sentinel)
65 except (OSError, EOFError):
66 # The process ended abnormally perhaps because of a signal
67 self.returncode = 255
68 return self.returncode