popen_spawn_posix.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import io
  2. import os
  3. from .context import reduction, set_spawning_popen
  4. from . import popen_fork
  5. from . import spawn
  6. from . import util
  7. __all__ = ['Popen']
  8. #
  9. # Wrapper for an fd used while launching a process
  10. #
  11. class _DupFd(object):
  12. def __init__(self, fd):
  13. self.fd = fd
  14. def detach(self):
  15. return self.fd
  16. #
  17. # Start child process using a fresh interpreter
  18. #
  19. class Popen(popen_fork.Popen):
  20. method = 'spawn'
  21. DupFd = _DupFd
  22. def __init__(self, process_obj):
  23. self._fds = []
  24. super().__init__(process_obj)
  25. def duplicate_for_child(self, fd):
  26. self._fds.append(fd)
  27. return fd
  28. def _launch(self, process_obj):
  29. from . import resource_tracker
  30. tracker_fd = resource_tracker.getfd()
  31. self._fds.append(tracker_fd)
  32. prep_data = spawn.get_preparation_data(process_obj._name)
  33. fp = io.BytesIO()
  34. set_spawning_popen(self)
  35. try:
  36. reduction.dump(prep_data, fp)
  37. reduction.dump(process_obj, fp)
  38. finally:
  39. set_spawning_popen(None)
  40. parent_r = child_w = child_r = parent_w = None
  41. try:
  42. parent_r, child_w = os.pipe()
  43. child_r, parent_w = os.pipe()
  44. cmd = spawn.get_command_line(tracker_fd=tracker_fd,
  45. pipe_handle=child_r)
  46. self._fds.extend([child_r, child_w])
  47. self.pid = util.spawnv_passfds(spawn.get_executable(),
  48. cmd, self._fds)
  49. self.sentinel = parent_r
  50. with open(parent_w, 'wb', closefd=False) as f:
  51. f.write(fp.getbuffer())
  52. finally:
  53. fds_to_close = []
  54. for fd in (parent_r, parent_w):
  55. if fd is not None:
  56. fds_to_close.append(fd)
  57. self.finalizer = util.Finalize(self, util.close_fds, fds_to_close)
  58. for fd in (child_r, child_w):
  59. if fd is not None:
  60. os.close(fd)