diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-02 11:44:31 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-02 11:44:31 -0400 |
| commit | 1c99bfbeffff04529f6f669601fdf835a73778da (patch) | |
| tree | 5867bab46e5848541df36c703f6fd8d6d0256e54 /debug/risc-v-gsp-rm-vm/greeneye/target.py | |
| parent | 2fd653044127a665e4677a2cdfb58120d7b3e16b (diff) | |
| download | open-iov-1c99bfbeffff04529f6f669601fdf835a73778da.tar.gz open-iov-1c99bfbeffff04529f6f669601fdf835a73778da.zip | |
rename (cosmetic): green-eye -> risc-v-gsp-rm-debugger in user-facing names, docs, CLI, launcher and CI workflow; internal greeneye package/module identifiers unchanged (includes in-flight greeneye module edits present in the tree)
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/greeneye/target.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/greeneye/target.py | 35 |
1 files changed, 23 insertions, 12 deletions
diff --git a/debug/risc-v-gsp-rm-vm/greeneye/target.py b/debug/risc-v-gsp-rm-vm/greeneye/target.py index 273f216..669a55d 100644 --- a/debug/risc-v-gsp-rm-vm/greeneye/target.py +++ b/debug/risc-v-gsp-rm-vm/greeneye/target.py @@ -1,4 +1,4 @@ -"""QEMU target lifecycle for green-eye. +"""QEMU target lifecycle for risc-v-gsp-rm-debugger. Owns the ``qemu-system-riscv64`` process, the gdbstub endpoint, the serial capture and the QEMU trace log. Both firmware paths are supported: @@ -76,8 +76,10 @@ class QemuTarget: os.makedirs(self.workdir, exist_ok=True) self.uart_log = uart_log or os.path.join(self.workdir, "uart.log") self.qemu_log = qemu_log or os.path.join(self.workdir, "qemu.log") + self.stderr_log = os.path.join(self.workdir, "qemu.stderr.log") self.keep_alive = keep_alive self.process: subprocess.Popen | None = None + self._stderr_fh = None self._segment_files: list[str] = [] self._cmd: list[str] = [] @@ -118,15 +120,19 @@ class QemuTarget: def start(self, paused: bool = True, timeout: float = 15.0) -> "QemuTarget": self._cmd = self._build_command(paused) + # Never use an undrained stderr=PIPE: a chatty QEMU would block once + # the pipe buffer fills and then stop answering the gdbstub. + self._stderr_fh = open(self.stderr_log, "ab") try: self.process = subprocess.Popen( self._cmd, stdout=subprocess.DEVNULL, - stderr=subprocess.PIPE, + stderr=self._stderr_fh, cwd=self.workdir, start_new_session=True, ) except OSError as exc: + self._close_stderr() raise TargetError(f"cannot start QEMU: {exc}") from exc try: self.wait_for_port(timeout=timeout) @@ -140,11 +146,11 @@ class QemuTarget: while time.monotonic() < deadline: if self.process is not None and self.process.poll() is not None: stderr = b"" - if self.process.stderr is not None: - try: - stderr = self.process.stderr.read() or b"" - except OSError: - pass + try: + with open(self.stderr_log, "rb") as fh: + stderr = fh.read() + except OSError: + pass raise TargetError( f"QEMU exited early rc={self.process.returncode}: " f"{stderr.decode('utf-8', 'replace')[-2000:]}" @@ -159,8 +165,17 @@ class QemuTarget: def alive(self) -> bool: return self.process is not None and self.process.poll() is None + def _close_stderr(self) -> None: + if self._stderr_fh is not None: + try: + self._stderr_fh.close() + except OSError: + pass + self._stderr_fh = None + def kill(self, timeout: float = 5.0) -> None: if self.process is None: + self._close_stderr() return if self.process.poll() is None: try: @@ -181,11 +196,7 @@ class QemuTarget: except ProcessLookupError: pass self.process.wait(timeout=timeout) - if self.process.stderr is not None: - try: - self.process.stderr.close() - except OSError: - pass + self._close_stderr() self.process = None # -- observation ------------------------------------------------------- |
