|
import os |
|
import signal |
|
|
|
from . import util |
|
|
|
__all__ = ['Popen'] |
|
|
|
|
|
|
|
|
|
|
|
class Popen(object): |
|
method = 'fork' |
|
|
|
def __init__(self, process_obj): |
|
util._flush_std_streams() |
|
self.returncode = None |
|
self.finalizer = None |
|
self._launch(process_obj) |
|
|
|
def duplicate_for_child(self, fd): |
|
return fd |
|
|
|
def poll(self, flag=os.WNOHANG): |
|
if self.returncode is None: |
|
try: |
|
pid, sts = os.waitpid(self.pid, flag) |
|
except OSError: |
|
|
|
|
|
return None |
|
if pid == self.pid: |
|
self.returncode = os.waitstatus_to_exitcode(sts) |
|
return self.returncode |
|
|
|
def wait(self, timeout=None): |
|
if self.returncode is None: |
|
if timeout is not None: |
|
from multiprocessing.connection import wait |
|
if not wait([self.sentinel], timeout): |
|
return None |
|
|
|
return self.poll(os.WNOHANG if timeout == 0.0 else 0) |
|
return self.returncode |
|
|
|
def _send_signal(self, sig): |
|
if self.returncode is None: |
|
try: |
|
os.kill(self.pid, sig) |
|
except ProcessLookupError: |
|
pass |
|
except OSError: |
|
if self.wait(timeout=0.1) is None: |
|
raise |
|
|
|
def terminate(self): |
|
self._send_signal(signal.SIGTERM) |
|
|
|
def kill(self): |
|
self._send_signal(signal.SIGKILL) |
|
|
|
def _launch(self, process_obj): |
|
code = 1 |
|
parent_r, child_w = os.pipe() |
|
child_r, parent_w = os.pipe() |
|
self.pid = os.fork() |
|
if self.pid == 0: |
|
try: |
|
os.close(parent_r) |
|
os.close(parent_w) |
|
code = process_obj._bootstrap(parent_sentinel=child_r) |
|
finally: |
|
os._exit(code) |
|
else: |
|
os.close(child_w) |
|
os.close(child_r) |
|
self.finalizer = util.Finalize(self, util.close_fds, |
|
(parent_r, parent_w,)) |
|
self.sentinel = parent_r |
|
|
|
def close(self): |
|
if self.finalizer is not None: |
|
self.finalizer() |
|
|