blob: 98f8f0ab334d2ff3f04753019a208bb56f03b061 [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 +01005from . import popen_fork
Richard Oudkerk84ed9a62013-08-14 15:35:41 +01006from . import spawn
7from . import util
8
Richard Oudkerk84ed9a62013-08-14 15:35:41 +01009__all__ = ['Popen']
10
11
12#
13# Wrapper for an fd used while launching a process
14#
15
16class _DupFd(object):
17 def __init__(self, fd):
18 self.fd = fd
19 def detach(self):
20 return self.fd
21
22#
23# Start child process using a fresh interpreter
24#
25
26class Popen(popen_fork.Popen):
27 method = 'spawn'
28 DupFd = _DupFd
29
30 def __init__(self, process_obj):
31 self._fds = []
32 super().__init__(process_obj)
33
34 def duplicate_for_child(self, fd):
35 self._fds.append(fd)
36 return fd
37
38 def _launch(self, process_obj):
Richard Oudkerk7d2d43c2013-08-22 11:38:57 +010039 from . import semaphore_tracker
Richard Oudkerkb1694cf2013-10-16 16:41:56 +010040 tracker_fd = semaphore_tracker.getfd()
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010041 self._fds.append(tracker_fd)
42 prep_data = spawn.get_preparation_data(process_obj._name)
43 fp = 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, fp)
47 reduction.dump(process_obj, fp)
48 finally:
Davin Potts54586472016-09-09 18:03:10 -050049 set_spawning_popen(None)
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010050
51 parent_r = child_w = child_r = parent_w = None
52 try:
Victor Stinnerdaf45552013-08-28 00:53:59 +020053 parent_r, child_w = os.pipe()
54 child_r, parent_w = os.pipe()
Richard Oudkerk7d2d43c2013-08-22 11:38:57 +010055 cmd = spawn.get_command_line(tracker_fd=tracker_fd,
56 pipe_handle=child_r)
Richard Oudkerk84ed9a62013-08-14 15:35:41 +010057 self._fds.extend([child_r, child_w])
58 self.pid = util.spawnv_passfds(spawn.get_executable(),
59 cmd, self._fds)
60 self.sentinel = parent_r
61 with open(parent_w, 'wb', closefd=False) as f:
62 f.write(fp.getbuffer())
63 finally:
64 if parent_r is not None:
65 util.Finalize(self, os.close, (parent_r,))
66 for fd in (child_r, child_w, parent_w):
67 if fd is not None:
68 os.close(fd)