(self, runtests: WorkerRunTests, output_fd: int,
tmp_dir: StrPath | None = None)
| 176 | self._kill() |
| 177 | |
| 178 | def _run_process(self, runtests: WorkerRunTests, output_fd: int, |
| 179 | tmp_dir: StrPath | None = None) -> int | None: |
| 180 | popen = create_worker_process(runtests, output_fd, tmp_dir) |
| 181 | self._popen = popen |
| 182 | self._killed = False |
| 183 | |
| 184 | try: |
| 185 | if self._stopped: |
| 186 | # If kill() has been called before self._popen is set, |
| 187 | # self._popen is still running. Call again kill() |
| 188 | # to ensure that the process is killed. |
| 189 | self._kill() |
| 190 | raise ExitThread |
| 191 | |
| 192 | try: |
| 193 | # gh-94026: stdout+stderr are written to tempfile |
| 194 | retcode = popen.wait(timeout=self.timeout) |
| 195 | assert retcode is not None |
| 196 | return retcode |
| 197 | except subprocess.TimeoutExpired: |
| 198 | if self._stopped: |
| 199 | # kill() has been called: communicate() fails on reading |
| 200 | # closed stdout |
| 201 | raise ExitThread |
| 202 | |
| 203 | # On timeout, kill the process |
| 204 | self._kill() |
| 205 | |
| 206 | # None means TIMEOUT for the caller |
| 207 | retcode = None |
| 208 | # bpo-38207: Don't attempt to call communicate() again: on it |
| 209 | # can hang until all child processes using stdout |
| 210 | # pipes completes. |
| 211 | except OSError: |
| 212 | if self._stopped: |
| 213 | # kill() has been called: communicate() fails |
| 214 | # on reading closed stdout |
| 215 | raise ExitThread |
| 216 | raise |
| 217 | return None |
| 218 | except: |
| 219 | self._kill() |
| 220 | raise |
| 221 | finally: |
| 222 | self._wait_completed() |
| 223 | self._popen = None |
| 224 | |
| 225 | def create_stdout(self, stack: contextlib.ExitStack) -> TextIO: |
| 226 | """Create stdout temporary file (file descriptor).""" |
no test coverage detected