(root)/
Python-3.12.0/
Lib/
multiprocessing/
popen_spawn_win32.py
       1  import os
       2  import msvcrt
       3  import signal
       4  import sys
       5  import _winapi
       6  
       7  from .context import reduction, get_spawning_popen, set_spawning_popen
       8  from . import spawn
       9  from . import util
      10  
      11  __all__ = ['Popen']
      12  
      13  #
      14  #
      15  #
      16  
      17  TERMINATE = 0x10000
      18  WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
      19  WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
      20  
      21  
      22  def _path_eq(p1, p2):
      23      return p1 == p2 or os.path.normcase(p1) == os.path.normcase(p2)
      24  
      25  WINENV = not _path_eq(sys.executable, sys._base_executable)
      26  
      27  
      28  def _close_handles(*handles):
      29      for handle in handles:
      30          _winapi.CloseHandle(handle)
      31  
      32  
      33  #
      34  # We define a Popen class similar to the one from subprocess, but
      35  # whose constructor takes a process object as its argument.
      36  #
      37  
      38  class ESC[4;38;5;81mPopen(ESC[4;38;5;149mobject):
      39      '''
      40      Start a subprocess to run the code of a process object
      41      '''
      42      method = 'spawn'
      43  
      44      def __init__(self, process_obj):
      45          prep_data = spawn.get_preparation_data(process_obj._name)
      46  
      47          # read end of pipe will be duplicated by the child process
      48          # -- see spawn_main() in spawn.py.
      49          #
      50          # bpo-33929: Previously, the read end of pipe was "stolen" by the child
      51          # process, but it leaked a handle if the child process had been
      52          # terminated before it could steal the handle from the parent process.
      53          rhandle, whandle = _winapi.CreatePipe(None, 0)
      54          wfd = msvcrt.open_osfhandle(whandle, 0)
      55          cmd = spawn.get_command_line(parent_pid=os.getpid(),
      56                                       pipe_handle=rhandle)
      57  
      58          python_exe = spawn.get_executable()
      59  
      60          # bpo-35797: When running in a venv, we bypass the redirect
      61          # executor and launch our base Python.
      62          if WINENV and _path_eq(python_exe, sys.executable):
      63              cmd[0] = python_exe = sys._base_executable
      64              env = os.environ.copy()
      65              env["__PYVENV_LAUNCHER__"] = sys.executable
      66          else:
      67              env = None
      68  
      69          cmd = ' '.join('"%s"' % x for x in cmd)
      70  
      71          with open(wfd, 'wb', closefd=True) as to_child:
      72              # start process
      73              try:
      74                  hp, ht, pid, tid = _winapi.CreateProcess(
      75                      python_exe, cmd,
      76                      None, None, False, 0, env, None, None)
      77                  _winapi.CloseHandle(ht)
      78              except:
      79                  _winapi.CloseHandle(rhandle)
      80                  raise
      81  
      82              # set attributes of self
      83              self.pid = pid
      84              self.returncode = None
      85              self._handle = hp
      86              self.sentinel = int(hp)
      87              self.finalizer = util.Finalize(self, _close_handles,
      88                                             (self.sentinel, int(rhandle)))
      89  
      90              # send information to child
      91              set_spawning_popen(self)
      92              try:
      93                  reduction.dump(prep_data, to_child)
      94                  reduction.dump(process_obj, to_child)
      95              finally:
      96                  set_spawning_popen(None)
      97  
      98      def duplicate_for_child(self, handle):
      99          assert self is get_spawning_popen()
     100          return reduction.duplicate(handle, self.sentinel)
     101  
     102      def wait(self, timeout=None):
     103          if self.returncode is None:
     104              if timeout is None:
     105                  msecs = _winapi.INFINITE
     106              else:
     107                  msecs = max(0, int(timeout * 1000 + 0.5))
     108  
     109              res = _winapi.WaitForSingleObject(int(self._handle), msecs)
     110              if res == _winapi.WAIT_OBJECT_0:
     111                  code = _winapi.GetExitCodeProcess(self._handle)
     112                  if code == TERMINATE:
     113                      code = -signal.SIGTERM
     114                  self.returncode = code
     115  
     116          return self.returncode
     117  
     118      def poll(self):
     119          return self.wait(timeout=0)
     120  
     121      def terminate(self):
     122          if self.returncode is None:
     123              try:
     124                  _winapi.TerminateProcess(int(self._handle), TERMINATE)
     125              except OSError:
     126                  if self.wait(timeout=1.0) is None:
     127                      raise
     128  
     129      kill = terminate
     130  
     131      def close(self):
     132          self.finalizer()