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