diff --git a/pyk/src/pyk/kore/rpc.py b/pyk/src/pyk/kore/rpc.py index 647e6e4fcb9..3bbfdb68620 100644 --- a/pyk/src/pyk/kore/rpc.py +++ b/pyk/src/pyk/kore/rpc.py @@ -12,7 +12,8 @@ from enum import Enum, auto from pathlib import Path from signal import SIGINT -from subprocess import Popen +from subprocess import DEVNULL, PIPE, Popen +from threading import Thread from time import sleep from typing import ClassVar # noqa: TC003 from typing import TYPE_CHECKING, ContextManager, NamedTuple, TypedDict, final @@ -26,7 +27,7 @@ if TYPE_CHECKING: from collections.abc import Iterable, Mapping - from typing import Any, Final, TextIO, TypeVar + from typing import IO, Any, Final, TypeVar from typing_extensions import Required @@ -115,7 +116,7 @@ class SingleSocketTransport(Transport): _host: str _port: int _sock: socket.socket - _file: TextIO + _file: IO[str] def __init__( self, @@ -1129,6 +1130,8 @@ class KoreServerInfo(NamedTuple): class KoreServer(ContextManager['KoreServer']): _proc: Popen + _stdout_reader: Thread + _stderr_reader: Thread _info: KoreServerInfo _kompiled_dir: Path @@ -1208,7 +1211,7 @@ def start(self) -> None: new_env['GHCRTS'] = f'-N{self._haskell_threads}' _LOGGER.info(f'Starting KoreServer: {" ".join(cli_args)}') - self._proc = Popen(cli_args, env=new_env) + self._proc, self._stdout_reader, self._stderr_reader = self._create_proc(cli_args, new_env) pid = self._proc.pid host, port = self._get_host_and_port(pid) if self._port: @@ -1216,6 +1219,24 @@ def start(self) -> None: self._info = KoreServerInfo(pid=pid, host=host, port=port) _LOGGER.info(f'KoreServer started: {self.host}:{self.port}, pid={self.pid}') + @staticmethod + def _create_proc(args: list[str], env: dict[str, str]) -> tuple[Popen, Thread, Thread]: + popen = Popen(args, env=env, stdin=DEVNULL, stdout=PIPE, stderr=PIPE, text=True) + + def reader(fh: IO[str], prefix: str) -> None: + for line in fh: + _LOGGER.info(f'[PID={popen.pid}][{prefix}] {line.rstrip()}') + + stdout_reader = Thread(target=reader, args=(popen.stdout, 'stdo')) + stdout_reader.daemon = True + stdout_reader.start() + + stderr_reader = Thread(target=reader, args=(popen.stderr, 'stde')) + stderr_reader.daemon = True + stderr_reader.start() + + return popen, stdout_reader, stderr_reader + def close(self) -> None: _LOGGER.info(f'Stopping KoreServer: {self.host}:{self.port}, pid={self.pid}') if '--solver-transcript' in self._command: @@ -1223,6 +1244,8 @@ def close(self) -> None: else: self._proc.terminate() self._proc.wait() + self._stdout_reader.join() + self._stderr_reader.join() _LOGGER.info(f'KoreServer stopped: {self.host}:{self.port}, pid={self.pid}') def _validate(self) -> None: