17db96d56Sopenharmony_ciimport io 27db96d56Sopenharmony_ciimport os 37db96d56Sopenharmony_ci 47db96d56Sopenharmony_cifrom .context import reduction, set_spawning_popen 57db96d56Sopenharmony_ciif not reduction.HAVE_SEND_HANDLE: 67db96d56Sopenharmony_ci raise ImportError('No support for sending fds between processes') 77db96d56Sopenharmony_cifrom . import forkserver 87db96d56Sopenharmony_cifrom . import popen_fork 97db96d56Sopenharmony_cifrom . import spawn 107db96d56Sopenharmony_cifrom . import util 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ci__all__ = ['Popen'] 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci# 167db96d56Sopenharmony_ci# Wrapper for an fd used while launching a process 177db96d56Sopenharmony_ci# 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ciclass _DupFd(object): 207db96d56Sopenharmony_ci def __init__(self, ind): 217db96d56Sopenharmony_ci self.ind = ind 227db96d56Sopenharmony_ci def detach(self): 237db96d56Sopenharmony_ci return forkserver.get_inherited_fds()[self.ind] 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci# 267db96d56Sopenharmony_ci# Start child process using a server process 277db96d56Sopenharmony_ci# 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ciclass Popen(popen_fork.Popen): 307db96d56Sopenharmony_ci method = 'forkserver' 317db96d56Sopenharmony_ci DupFd = _DupFd 327db96d56Sopenharmony_ci 337db96d56Sopenharmony_ci def __init__(self, process_obj): 347db96d56Sopenharmony_ci self._fds = [] 357db96d56Sopenharmony_ci super().__init__(process_obj) 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci def duplicate_for_child(self, fd): 387db96d56Sopenharmony_ci self._fds.append(fd) 397db96d56Sopenharmony_ci return len(self._fds) - 1 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci def _launch(self, process_obj): 427db96d56Sopenharmony_ci prep_data = spawn.get_preparation_data(process_obj._name) 437db96d56Sopenharmony_ci buf = io.BytesIO() 447db96d56Sopenharmony_ci set_spawning_popen(self) 457db96d56Sopenharmony_ci try: 467db96d56Sopenharmony_ci reduction.dump(prep_data, buf) 477db96d56Sopenharmony_ci reduction.dump(process_obj, buf) 487db96d56Sopenharmony_ci finally: 497db96d56Sopenharmony_ci set_spawning_popen(None) 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ci self.sentinel, w = forkserver.connect_to_new_process(self._fds) 527db96d56Sopenharmony_ci # Keep a duplicate of the data pipe's write end as a sentinel of the 537db96d56Sopenharmony_ci # parent process used by the child process. 547db96d56Sopenharmony_ci _parent_w = os.dup(w) 557db96d56Sopenharmony_ci self.finalizer = util.Finalize(self, util.close_fds, 567db96d56Sopenharmony_ci (_parent_w, self.sentinel)) 577db96d56Sopenharmony_ci with open(w, 'wb', closefd=True) as f: 587db96d56Sopenharmony_ci f.write(buf.getbuffer()) 597db96d56Sopenharmony_ci self.pid = forkserver.read_signed(self.sentinel) 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci def poll(self, flag=os.WNOHANG): 627db96d56Sopenharmony_ci if self.returncode is None: 637db96d56Sopenharmony_ci from multiprocessing.connection import wait 647db96d56Sopenharmony_ci timeout = 0 if flag == os.WNOHANG else None 657db96d56Sopenharmony_ci if not wait([self.sentinel], timeout): 667db96d56Sopenharmony_ci return None 677db96d56Sopenharmony_ci try: 687db96d56Sopenharmony_ci self.returncode = forkserver.read_signed(self.sentinel) 697db96d56Sopenharmony_ci except (OSError, EOFError): 707db96d56Sopenharmony_ci # This should not happen usually, but perhaps the forkserver 717db96d56Sopenharmony_ci # process itself got killed 727db96d56Sopenharmony_ci self.returncode = 255 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci return self.returncode 75