popen_fork.py 2.3 KB

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