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