mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	Capturing exceptions into names can lead to reference cycles though the __traceback__ attribute of the exceptions in some obscure cases that have been reported previously and fixed individually. As these variables are not used anyway, we can remove the binding to reduce the chances of creating reference cycles. See for example GH-13135
		
			
				
	
	
		
			87 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import os
 | 
						|
import signal
 | 
						|
 | 
						|
from . import util
 | 
						|
 | 
						|
__all__ = ['Popen']
 | 
						|
 | 
						|
#
 | 
						|
# Start child process using fork
 | 
						|
#
 | 
						|
 | 
						|
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:
 | 
						|
                # Child process not yet created. See #1731717
 | 
						|
                # e.errno == errno.ECHILD == 10
 | 
						|
                return None
 | 
						|
            if pid == self.pid:
 | 
						|
                if os.WIFSIGNALED(sts):
 | 
						|
                    self.returncode = -os.WTERMSIG(sts)
 | 
						|
                else:
 | 
						|
                    assert os.WIFEXITED(sts), "Status is {:n}".format(sts)
 | 
						|
                    self.returncode = os.WEXITSTATUS(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
 | 
						|
            # This shouldn't block if wait() returned successfully.
 | 
						|
            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()
 |