popen_fork.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import os
  2. import signal
  3. from . import util
  4. __all__ = ['Popen']
  5. #
  6. # Start child process using fork
  7. #
  8. class Popen(object):
  9. method = 'fork'
  10. def __init__(self, process_obj):
  11. util._flush_std_streams()
  12. self.returncode = None
  13. self.finalizer = None
  14. self._launch(process_obj)
  15. def duplicate_for_child(self, fd):
  16. return fd
  17. def poll(self, flag=os.WNOHANG):
  18. if self.returncode is None:
  19. try:
  20. pid, sts = os.waitpid(self.pid, flag)
  21. except OSError:
  22. # Child process not yet created. See #1731717
  23. # e.errno == errno.ECHILD == 10
  24. return None
  25. if pid == self.pid:
  26. self.returncode = os.waitstatus_to_exitcode(sts)
  27. return self.returncode
  28. def wait(self, timeout=None):
  29. if self.returncode is None:
  30. if timeout is not None:
  31. from multiprocessing.connection import wait
  32. if not wait([self.sentinel], timeout):
  33. return None
  34. # This shouldn't block if wait() returned successfully.
  35. return self.poll(os.WNOHANG if timeout == 0.0 else 0)
  36. return self.returncode
  37. def _send_signal(self, sig):
  38. if self.returncode is None:
  39. try:
  40. os.kill(self.pid, sig)
  41. except ProcessLookupError:
  42. pass
  43. except OSError:
  44. if self.wait(timeout=0.1) is None:
  45. raise
  46. def terminate(self):
  47. self._send_signal(signal.SIGTERM)
  48. def kill(self):
  49. self._send_signal(signal.SIGKILL)
  50. def _launch(self, process_obj):
  51. code = 1
  52. parent_r, child_w = os.pipe()
  53. child_r, parent_w = os.pipe()
  54. self.pid = os.fork()
  55. if self.pid == 0:
  56. try:
  57. os.close(parent_r)
  58. os.close(parent_w)
  59. code = process_obj._bootstrap(parent_sentinel=child_r)
  60. finally:
  61. os._exit(code)
  62. else:
  63. os.close(child_w)
  64. os.close(child_r)
  65. self.finalizer = util.Finalize(self, util.close_fds,
  66. (parent_r, parent_w,))
  67. self.sentinel = parent_r
  68. def close(self):
  69. if self.finalizer is not None:
  70. self.finalizer()