feat: supervise EXEC with guest liveness instead of a stopwatch
TCPAGENT는 system()이 도는 동안 통째로 얼어 있어 응답도 진행 보고도 못 한다. 그런데 호스트는 소켓에 30초 고정 타임아웃을 걸고, 만료되면 연결 자체를 버렸다. 그래서 35초짜리 컴파일이 "느린 명령"이 아니라 "죽은 에이전트"로 취급됐다. QEMU는 게스트가 얼어 있어도 계속 돈다. info blockstats의 idle_time_ns로 "작업 중"과 "멈춤"을 구분한다. 실측으로 확인했다: 에이전트가 완전히 벙어리인 동안에도 rd_operations가 7초당 47000씩 증가하고 idle은 0.00s를 유지한다. - EXEC은 짧은 간격으로 깨어나 감시만 하고 소켓은 절대 안 버린다. - --idle-timeout(기본 60s)과 --hard-timeout(기본 900s). 후자는 디스크를 안 쓰는 CPU 바운드 멈춤용 백스톱이다. - 중단은 QEMU 모니터로 Ctrl+C를 주입하고 COMMAND.COM의 "Terminate batch file (Y/N/A)?" 프롬프트에 답한다. - Ctrl+C는 DOS break check에서만 먹는다. FreeDOS 기본값 BREAK=OFF에서 출력을 파일로 돌린 CPU 바운드 자식은 거기 도달 안 할 수 있다. 그래서 중단은 보장이 아니라 요청으로 다루고, 명령이 안 멈춰도 RESULT를 끝까지 수거해 스트림을 깨뜨리지 않는다. - ferro-vm abort 추가. 실행 중에도 응답해야 하므로 파이프 서버를 요청당 스레드로 바꿨다. - 5558 바인딩을 SO_EXCLUSIVEADDRUSE로. Windows의 SO_REUSEADDR는 다른 프로세스가 같은 포트를 잡아 조용히 반쯤 동작하게 만든다. 검증 (QEMU FreeDOS 실측): - 32.4초 명령 정상 완료 (이전에는 30초에 실패) - 실행 중 abort가 0.1초에 응답, exit=95로 종료, 부분 출력 1805B 수거, 연결 유지 - pause처럼 디스크를 안 쓰는 명령을 idle 15s로 검출해 중단 시리얼 시절에 있다가 TCP 전환에서 사라진 TODO 3건을 복구한다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012PQm6oAvWX4Lp3iSN5AHGT
This commit is contained in:
@@ -61,9 +61,28 @@ are not interpreted on this FreeDOS console, so neither of the usual routes
|
||||
works. Elapsed times come from the BIOS tick counter at 18.2065 Hz (~55 ms
|
||||
resolution).
|
||||
|
||||
Note that mTCP is not driven while `system()` runs a child, so a DOS command
|
||||
lasting tens of seconds can drop the TCP connection. The agent logs `link lost`
|
||||
and reconnects on its own, but the host loses that command's result.
|
||||
## Long commands
|
||||
|
||||
mTCP is only driven when the agent calls it, and `system()` freezes the agent
|
||||
for the entire child command. So during a long `EXEC` the DOS side is mute: it
|
||||
cannot answer, cannot acknowledge, cannot report progress. Silence therefore
|
||||
proves nothing about whether the command is healthy.
|
||||
|
||||
The host must not read that silence as failure. `ferro-vm exec` waits on
|
||||
QEMU's own view of the guest instead: `info blockstats` keeps counting while
|
||||
the agent is frozen, and `idle_time_ns` distinguishes a slow command from a
|
||||
stuck one. See `--idle-timeout` and `--hard-timeout` in `ferro-vm exec --help`.
|
||||
|
||||
When the host does decide to stop a command it injects Ctrl+C through the QEMU
|
||||
monitor, then answers COMMAND.COM's `Terminate batch file (Y/N/A)?` prompt.
|
||||
That is a request, not a guarantee: Ctrl+C only lands at a DOS break check, and
|
||||
with `BREAK=OFF` (the FreeDOS default in `C:\FDCONFIG.SYS`) a compute-bound
|
||||
child whose output we redirected to a file may never reach one. The host keeps
|
||||
collecting the result either way rather than abandoning a stream that still
|
||||
owes it a `RESULT`.
|
||||
|
||||
Adding `BREAK=ON` to `C:\FDCONFIG.SYS` would make DOS check on every system
|
||||
call and so make Ctrl+C reliable, at a small cost to every DOS call.
|
||||
|
||||
## Rebuilding inside the VM
|
||||
|
||||
|
||||
Reference in New Issue
Block a user