Commit 3ac2df6
committed
Address review: Process owns its handle; fix wait timeout, kill, sb-method aliasing
Handle ownership (load-bearing): a popen() Process now owns its handle for
its lifetime instead of resolving sandbox._handle at call time. Previously
every Process method (kill/wait/__del__/pid) read the sandbox's current
handle, so a stale Process aliased whatever child the sandbox ran next:
`p1.kill()` after the sandbox was reused SIGKILLed p2, and a stale
`p1.wait()` reaped p2 and left it "not running".
- Process takes and stores the handle (and caches its pid); all methods
act on self._handle and set it to None once freed. The handle/pid are
taken only AFTER the fds are wrapped, so an fdopen failure leaves
ownership with popen()'s caller — no double free via __del__.
- Sandbox keeps only a weak busy marker (self._process, a weakref) so
the one-process-per-sandbox rule and pid/is_running/ports still see
the live child, while abandoning the Process still triggers its
__del__ reap rather than the sandbox pinning it alive.
- Sandbox.wait/pause/resume/kill fail loudly when a popen() Process owns
the handle (manage it through the Process).
Concurrency: Process guards its handle with a lock and a `waiting` flag.
wait() runs the blocking native wait without the lock; kill() signals the
process group by cached pid (like the sandbox and the Go binding), not
through the handle, so the documented "kill from another thread while
wait() blocks" pattern is race-free — no kill on a handle wait() is
freeing. kill() raises OSError on a genuine failure (ProcessLookupError,
i.e. already-exited, is a no-op) and is a silent no-op once reaped.
Also: Process.wait / Sandbox.run clamp a finite timeout up to 1ms so
`timeout=0` and sub-millisecond values don't collapse to 0 (= wait
forever); None still waits forever.
Tests: stale-Process-does-not-alias-reused-sandbox; sandbox lifecycle
methods reject a popen Process; wait(timeout=0) returns instead of
hanging; kill from another thread interrupts a blocked wait.1 parent 1afb6e6 commit 3ac2df6
2 files changed
Lines changed: 259 additions & 48 deletions
0 commit comments