popen_forkserver.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import io
  2. import os
  3. from .context import reduction, set_spawning_popen
  4. if not reduction.HAVE_SEND_HANDLE:
  5. raise ImportError('No support for sending fds between processes')
  6. from . import forkserver
  7. from . import popen_fork
  8. from . import spawn
  9. from . import util
  10. __all__ = ['Popen']
  11. #
  12. # Wrapper for an fd used while launching a process
  13. #
  14. class _DupFd(object):
  15. def __init__(self, ind):
  16. self.ind = ind
  17. def detach(self):
  18. return forkserver.get_inherited_fds()[self.ind]
  19. #
  20. # Start child process using a server process
  21. #
  22. class Popen(popen_fork.Popen):
  23. method = 'forkserver'
  24. DupFd = _DupFd
  25. def __init__(self, process_obj):
  26. self._fds = []
  27. super().__init__(process_obj)
  28. def duplicate_for_child(self, fd):
  29. self._fds.append(fd)
  30. return len(self._fds) - 1
  31. def _launch(self, process_obj):
  32. prep_data = spawn.get_preparation_data(process_obj._name)
  33. buf = io.BytesIO()
  34. set_spawning_popen(self)
  35. try:
  36. reduction.dump(prep_data, buf)
  37. reduction.dump(process_obj, buf)
  38. finally:
  39. set_spawning_popen(None)
  40. self.sentinel, w = forkserver.connect_to_new_process(self._fds)
  41. self.finalizer = util.Finalize(self, os.close, (self.sentinel,))
  42. with open(w, 'wb', closefd=True) as f:
  43. f.write(buf.getbuffer())
  44. self.pid = forkserver.read_signed(self.sentinel)
  45. def poll(self, flag=os.WNOHANG):
  46. if self.returncode is None:
  47. from multiprocessing.connection import wait
  48. timeout = 0 if flag == os.WNOHANG else None
  49. if not wait([self.sentinel], timeout):
  50. return None
  51. try:
  52. self.returncode = forkserver.read_signed(self.sentinel)
  53. except (OSError, EOFError):
  54. # This should not happen usually, but perhaps the forkserver
  55. # process itself got killed
  56. self.returncode = 255
  57. return self.returncode