Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 1 | import os |
| 2 | import sys |
| 3 | import signal |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 4 | |
| 5 | from . import util |
| 6 | |
| 7 | __all__ = ['Popen'] |
| 8 | |
| 9 | # |
| 10 | # Start child process using fork |
| 11 | # |
| 12 | |
| 13 | class Popen(object): |
| 14 | method = 'fork' |
| 15 | |
| 16 | def __init__(self, process_obj): |
Antoine Pitrou | daeefd2 | 2017-10-22 11:40:31 +0200 | [diff] [blame] | 17 | try: |
| 18 | sys.stdout.flush() |
| 19 | except (AttributeError, ValueError): |
| 20 | pass |
| 21 | try: |
| 22 | sys.stderr.flush() |
| 23 | except (AttributeError, ValueError): |
| 24 | pass |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 25 | self.returncode = None |
Antoine Pitrou | 13e96cc | 2017-06-24 19:22:23 +0200 | [diff] [blame] | 26 | self.finalizer = None |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 27 | self._launch(process_obj) |
| 28 | |
| 29 | def duplicate_for_child(self, fd): |
| 30 | return fd |
| 31 | |
| 32 | def poll(self, flag=os.WNOHANG): |
| 33 | if self.returncode is None: |
Antoine Pitrou | dfd5f34 | 2017-06-12 15:28:19 +0200 | [diff] [blame] | 34 | try: |
| 35 | pid, sts = os.waitpid(self.pid, flag) |
| 36 | except OSError as e: |
| 37 | # Child process not yet created. See #1731717 |
| 38 | # e.errno == errno.ECHILD == 10 |
| 39 | return None |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 40 | if pid == self.pid: |
| 41 | if os.WIFSIGNALED(sts): |
| 42 | self.returncode = -os.WTERMSIG(sts) |
| 43 | else: |
Allen W. Smith, Ph.D | bd73e72 | 2017-08-29 17:52:18 -0500 | [diff] [blame] | 44 | assert os.WIFEXITED(sts), "Status is {:n}".format(sts) |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 45 | self.returncode = os.WEXITSTATUS(sts) |
| 46 | return self.returncode |
| 47 | |
| 48 | def wait(self, timeout=None): |
| 49 | if self.returncode is None: |
| 50 | if timeout is not None: |
Richard Oudkerk | c346060 | 2014-03-23 12:52:16 +0000 | [diff] [blame] | 51 | from multiprocessing.connection import wait |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 52 | if not wait([self.sentinel], timeout): |
| 53 | return None |
| 54 | # This shouldn't block if wait() returned successfully. |
| 55 | return self.poll(os.WNOHANG if timeout == 0.0 else 0) |
| 56 | return self.returncode |
| 57 | |
Vitor Pereira | ba75af7 | 2017-07-18 16:34:23 +0100 | [diff] [blame] | 58 | def _send_signal(self, sig): |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 59 | if self.returncode is None: |
| 60 | try: |
Vitor Pereira | ba75af7 | 2017-07-18 16:34:23 +0100 | [diff] [blame] | 61 | os.kill(self.pid, sig) |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 62 | except ProcessLookupError: |
| 63 | pass |
| 64 | except OSError: |
| 65 | if self.wait(timeout=0.1) is None: |
| 66 | raise |
| 67 | |
Vitor Pereira | ba75af7 | 2017-07-18 16:34:23 +0100 | [diff] [blame] | 68 | def terminate(self): |
| 69 | self._send_signal(signal.SIGTERM) |
| 70 | |
| 71 | def kill(self): |
| 72 | self._send_signal(signal.SIGKILL) |
| 73 | |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 74 | def _launch(self, process_obj): |
| 75 | code = 1 |
Victor Stinner | daf4555 | 2013-08-28 00:53:59 +0200 | [diff] [blame] | 76 | parent_r, child_w = os.pipe() |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 77 | self.pid = os.fork() |
| 78 | if self.pid == 0: |
| 79 | try: |
| 80 | os.close(parent_r) |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 81 | code = process_obj._bootstrap() |
| 82 | finally: |
| 83 | os._exit(code) |
| 84 | else: |
| 85 | os.close(child_w) |
Antoine Pitrou | 13e96cc | 2017-06-24 19:22:23 +0200 | [diff] [blame] | 86 | self.finalizer = util.Finalize(self, os.close, (parent_r,)) |
Richard Oudkerk | 84ed9a6 | 2013-08-14 15:35:41 +0100 | [diff] [blame] | 87 | self.sentinel = parent_r |
Antoine Pitrou | 13e96cc | 2017-06-24 19:22:23 +0200 | [diff] [blame] | 88 | |
| 89 | def close(self): |
| 90 | if self.finalizer is not None: |
| 91 | self.finalizer() |