chrome guard: a zombie counts as ended (an orphan's new parent in a container whose PID 1 is no init never reaps it, and kill(pid, 0) still succeeds), so the reaper reports it and the real-process test passes on the Linux runner
This commit is contained in:
parent
c3b1e8c370
commit
cdaecc2afb
2 changed files with 11 additions and 3 deletions
|
|
@ -63,8 +63,16 @@ export function staleChromes(rows: PsRow[], markers: string[] = PROFILE_MARKERS)
|
|||
return { reap, windows };
|
||||
}
|
||||
|
||||
/** A zombie has ended: it only waits for its parent to reap it. An orphan's new parent may never do that (a container
|
||||
* whose PID 1 is not an init), and kill(pid, 0) still succeeds on it. */
|
||||
export function isZombie(pid: number): boolean {
|
||||
if (process.platform === 'win32') return false;
|
||||
try { return /^Z/.test(rt.spawnSync(['ps', '-o', 'stat=', '-p', String(pid)], { stdout: 'pipe', stderr: 'ignore', timeout: 5000 }).stdout.toString().trim()); } catch { return false; }
|
||||
}
|
||||
|
||||
function alive(pid: number): boolean {
|
||||
try { process.kill(pid, 0); return true; } catch (e) { return (e as NodeJS.ErrnoException).code === 'EPERM'; }
|
||||
try { process.kill(pid, 0); } catch (e) { return (e as NodeJS.ErrnoException).code === 'EPERM'; }
|
||||
return !isZombie(pid);
|
||||
}
|
||||
|
||||
/** SIGTERM (Chromium's clean shutdown), then SIGKILL after `graceMs`. True when the process is gone. */
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// standing in for Chrome (sh + sleep, no browser, about a second): the watchdog ends the child when its parent dies and
|
||||
// never touches a reused pid; the reaper ends a real orphan with a storebound profile on its command line.
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { guardChrome, guardedPids, isOrphan, parsePs, reapStaleChromes, staleChromes, startWatchdog, userDataDirOf, watchdogArgv } from '../cli/console/chrome-guard';
|
||||
import { guardChrome, guardedPids, isOrphan, isZombie, parsePs, reapStaleChromes, staleChromes, startWatchdog, userDataDirOf, watchdogArgv } from '../cli/console/chrome-guard';
|
||||
import { persistentExecutable } from '../cli/shots/browser';
|
||||
import * as rt from '../cli/lib/rt';
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ describe('headless runs on macOS never use Google Chrome.app when another Chromi
|
|||
// ---- real processes (sh + sleep stand in for Chrome and its run) ----
|
||||
|
||||
const posix = process.platform !== 'win32';
|
||||
const alive = (pid: number) => { try { process.kill(pid, 0); return true; } catch { return false; } };
|
||||
const alive = (pid: number) => { try { process.kill(pid, 0); } catch { return false; } return !isZombie(pid); };
|
||||
async function until(what: string, ok: () => boolean, ms = 5000): Promise<void> {
|
||||
const end = Date.now() + ms;
|
||||
while (!ok()) { if (Date.now() > end) throw new Error(`timed out after ${ms} ms waiting for: ${what}`); await rt.sleep(50); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue