| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import signal | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from . import util | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __all__ = ['Popen'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Start child process using fork | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Popen(object): | 
					
						
							|  |  |  |     method = 'fork' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, process_obj): | 
					
						
							| 
									
										
										
										
											2018-03-11 19:21:38 +01:00
										 |  |  |         util._flush_std_streams() | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         self.returncode = None | 
					
						
							| 
									
										
										
										
											2017-06-24 19:22:23 +02:00
										 |  |  |         self.finalizer = None | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         self._launch(process_obj) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def duplicate_for_child(self, fd): | 
					
						
							|  |  |  |         return fd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def poll(self, flag=os.WNOHANG): | 
					
						
							|  |  |  |         if self.returncode is None: | 
					
						
							| 
									
										
										
										
											2017-06-12 15:28:19 +02:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 pid, sts = os.waitpid(self.pid, flag) | 
					
						
							|  |  |  |             except OSError as e: | 
					
						
							|  |  |  |                 # Child process not yet created. See #1731717 | 
					
						
							|  |  |  |                 # e.errno == errno.ECHILD == 10 | 
					
						
							|  |  |  |                 return None | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             if pid == self.pid: | 
					
						
							|  |  |  |                 if os.WIFSIGNALED(sts): | 
					
						
							|  |  |  |                     self.returncode = -os.WTERMSIG(sts) | 
					
						
							|  |  |  |                 else: | 
					
						
							| 
									
										
										
										
											2017-08-29 17:52:18 -05:00
										 |  |  |                     assert os.WIFEXITED(sts), "Status is {:n}".format(sts) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |                     self.returncode = os.WEXITSTATUS(sts) | 
					
						
							|  |  |  |         return self.returncode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def wait(self, timeout=None): | 
					
						
							|  |  |  |         if self.returncode is None: | 
					
						
							|  |  |  |             if timeout is not None: | 
					
						
							| 
									
										
										
										
											2014-03-23 12:52:16 +00:00
										 |  |  |                 from multiprocessing.connection import wait | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |                 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 16:34:23 +01:00
										 |  |  |     def _send_signal(self, sig): | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         if self.returncode is None: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2017-07-18 16:34:23 +01:00
										 |  |  |                 os.kill(self.pid, sig) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             except ProcessLookupError: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |             except OSError: | 
					
						
							|  |  |  |                 if self.wait(timeout=0.1) is None: | 
					
						
							|  |  |  |                     raise | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 16:34:23 +01:00
										 |  |  |     def terminate(self): | 
					
						
							|  |  |  |         self._send_signal(signal.SIGTERM) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def kill(self): | 
					
						
							|  |  |  |         self._send_signal(signal.SIGKILL) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |     def _launch(self, process_obj): | 
					
						
							|  |  |  |         code = 1 | 
					
						
							| 
									
										
										
										
											2013-08-28 00:53:59 +02:00
										 |  |  |         parent_r, child_w = os.pipe() | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |         self.pid = os.fork() | 
					
						
							|  |  |  |         if self.pid == 0: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 os.close(parent_r) | 
					
						
							|  |  |  |                 code = process_obj._bootstrap() | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 os._exit(code) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             os.close(child_w) | 
					
						
							| 
									
										
										
										
											2017-06-24 19:22:23 +02:00
										 |  |  |             self.finalizer = util.Finalize(self, os.close, (parent_r,)) | 
					
						
							| 
									
										
										
										
											2013-08-14 15:35:41 +01:00
										 |  |  |             self.sentinel = parent_r | 
					
						
							| 
									
										
										
										
											2017-06-24 19:22:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							|  |  |  |         if self.finalizer is not None: | 
					
						
							|  |  |  |             self.finalizer() |