17db96d56Sopenharmony_ciimport os 27db96d56Sopenharmony_ciimport msvcrt 37db96d56Sopenharmony_ciimport signal 47db96d56Sopenharmony_ciimport sys 57db96d56Sopenharmony_ciimport _winapi 67db96d56Sopenharmony_ci 77db96d56Sopenharmony_cifrom .context import reduction, get_spawning_popen, set_spawning_popen 87db96d56Sopenharmony_cifrom . import spawn 97db96d56Sopenharmony_cifrom . import util 107db96d56Sopenharmony_ci 117db96d56Sopenharmony_ci__all__ = ['Popen'] 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ci# 147db96d56Sopenharmony_ci# 157db96d56Sopenharmony_ci# 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciTERMINATE = 0x10000 187db96d56Sopenharmony_ciWINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) 197db96d56Sopenharmony_ciWINSERVICE = sys.executable.lower().endswith("pythonservice.exe") 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_cidef _path_eq(p1, p2): 237db96d56Sopenharmony_ci return p1 == p2 or os.path.normcase(p1) == os.path.normcase(p2) 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ciWINENV = not _path_eq(sys.executable, sys._base_executable) 267db96d56Sopenharmony_ci 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_cidef _close_handles(*handles): 297db96d56Sopenharmony_ci for handle in handles: 307db96d56Sopenharmony_ci _winapi.CloseHandle(handle) 317db96d56Sopenharmony_ci 327db96d56Sopenharmony_ci 337db96d56Sopenharmony_ci# 347db96d56Sopenharmony_ci# We define a Popen class similar to the one from subprocess, but 357db96d56Sopenharmony_ci# whose constructor takes a process object as its argument. 367db96d56Sopenharmony_ci# 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_ciclass Popen(object): 397db96d56Sopenharmony_ci ''' 407db96d56Sopenharmony_ci Start a subprocess to run the code of a process object 417db96d56Sopenharmony_ci ''' 427db96d56Sopenharmony_ci method = 'spawn' 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ci def __init__(self, process_obj): 457db96d56Sopenharmony_ci prep_data = spawn.get_preparation_data(process_obj._name) 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci # read end of pipe will be duplicated by the child process 487db96d56Sopenharmony_ci # -- see spawn_main() in spawn.py. 497db96d56Sopenharmony_ci # 507db96d56Sopenharmony_ci # bpo-33929: Previously, the read end of pipe was "stolen" by the child 517db96d56Sopenharmony_ci # process, but it leaked a handle if the child process had been 527db96d56Sopenharmony_ci # terminated before it could steal the handle from the parent process. 537db96d56Sopenharmony_ci rhandle, whandle = _winapi.CreatePipe(None, 0) 547db96d56Sopenharmony_ci wfd = msvcrt.open_osfhandle(whandle, 0) 557db96d56Sopenharmony_ci cmd = spawn.get_command_line(parent_pid=os.getpid(), 567db96d56Sopenharmony_ci pipe_handle=rhandle) 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci python_exe = spawn.get_executable() 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci # bpo-35797: When running in a venv, we bypass the redirect 617db96d56Sopenharmony_ci # executor and launch our base Python. 627db96d56Sopenharmony_ci if WINENV and _path_eq(python_exe, sys.executable): 637db96d56Sopenharmony_ci cmd[0] = python_exe = sys._base_executable 647db96d56Sopenharmony_ci env = os.environ.copy() 657db96d56Sopenharmony_ci env["__PYVENV_LAUNCHER__"] = sys.executable 667db96d56Sopenharmony_ci else: 677db96d56Sopenharmony_ci env = None 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci cmd = ' '.join('"%s"' % x for x in cmd) 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ci with open(wfd, 'wb', closefd=True) as to_child: 727db96d56Sopenharmony_ci # start process 737db96d56Sopenharmony_ci try: 747db96d56Sopenharmony_ci hp, ht, pid, tid = _winapi.CreateProcess( 757db96d56Sopenharmony_ci python_exe, cmd, 767db96d56Sopenharmony_ci None, None, False, 0, env, None, None) 777db96d56Sopenharmony_ci _winapi.CloseHandle(ht) 787db96d56Sopenharmony_ci except: 797db96d56Sopenharmony_ci _winapi.CloseHandle(rhandle) 807db96d56Sopenharmony_ci raise 817db96d56Sopenharmony_ci 827db96d56Sopenharmony_ci # set attributes of self 837db96d56Sopenharmony_ci self.pid = pid 847db96d56Sopenharmony_ci self.returncode = None 857db96d56Sopenharmony_ci self._handle = hp 867db96d56Sopenharmony_ci self.sentinel = int(hp) 877db96d56Sopenharmony_ci self.finalizer = util.Finalize(self, _close_handles, 887db96d56Sopenharmony_ci (self.sentinel, int(rhandle))) 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci # send information to child 917db96d56Sopenharmony_ci set_spawning_popen(self) 927db96d56Sopenharmony_ci try: 937db96d56Sopenharmony_ci reduction.dump(prep_data, to_child) 947db96d56Sopenharmony_ci reduction.dump(process_obj, to_child) 957db96d56Sopenharmony_ci finally: 967db96d56Sopenharmony_ci set_spawning_popen(None) 977db96d56Sopenharmony_ci 987db96d56Sopenharmony_ci def duplicate_for_child(self, handle): 997db96d56Sopenharmony_ci assert self is get_spawning_popen() 1007db96d56Sopenharmony_ci return reduction.duplicate(handle, self.sentinel) 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci def wait(self, timeout=None): 1037db96d56Sopenharmony_ci if self.returncode is None: 1047db96d56Sopenharmony_ci if timeout is None: 1057db96d56Sopenharmony_ci msecs = _winapi.INFINITE 1067db96d56Sopenharmony_ci else: 1077db96d56Sopenharmony_ci msecs = max(0, int(timeout * 1000 + 0.5)) 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci res = _winapi.WaitForSingleObject(int(self._handle), msecs) 1107db96d56Sopenharmony_ci if res == _winapi.WAIT_OBJECT_0: 1117db96d56Sopenharmony_ci code = _winapi.GetExitCodeProcess(self._handle) 1127db96d56Sopenharmony_ci if code == TERMINATE: 1137db96d56Sopenharmony_ci code = -signal.SIGTERM 1147db96d56Sopenharmony_ci self.returncode = code 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci return self.returncode 1177db96d56Sopenharmony_ci 1187db96d56Sopenharmony_ci def poll(self): 1197db96d56Sopenharmony_ci return self.wait(timeout=0) 1207db96d56Sopenharmony_ci 1217db96d56Sopenharmony_ci def terminate(self): 1227db96d56Sopenharmony_ci if self.returncode is None: 1237db96d56Sopenharmony_ci try: 1247db96d56Sopenharmony_ci _winapi.TerminateProcess(int(self._handle), TERMINATE) 1257db96d56Sopenharmony_ci except OSError: 1267db96d56Sopenharmony_ci if self.wait(timeout=1.0) is None: 1277db96d56Sopenharmony_ci raise 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci kill = terminate 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci def close(self): 1327db96d56Sopenharmony_ci self.finalizer() 133