mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 04:47:03 -06:00
fix: treat EPERM as alive in isPidAlive (#110235)
* fix(pid): treat EPERM as alive in isPidAlive Match isPidDefinitelyDead: process.kill(pid, 0) throwing EPERM means the PID exists but cannot be signaled, so it should not look dead. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(pid): check Linux zombies after EPERM existence probe EPERM means the PID exists but cannot be signaled; still run the zombie check so Linux zombies are not reported as alive. Co-authored-by: Cursor <cursoragent@cursor.com> * test(pid): isolate EPERM liveness probe Co-authored-by: stantheman0128 <stanshih888@gmail.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -42,6 +42,45 @@ describe("isPidAlive", () => {
|
||||
expect(isPidAlive(Number.POSITIVE_INFINITY)).toBe(false);
|
||||
});
|
||||
|
||||
it("returns true when process probing reports EPERM", () => {
|
||||
const error = Object.assign(new Error("permission denied"), { code: "EPERM" });
|
||||
vi.spyOn(process, "kill").mockImplementation(() => {
|
||||
throw error;
|
||||
});
|
||||
mockProcReads({
|
||||
"/proc/42/status": "Name:\tnode\nState:\tS (sleeping)\nPid:\t42\n",
|
||||
});
|
||||
|
||||
expect(isPidAlive(42)).toBe(true);
|
||||
expect(process["kill"]).toHaveBeenCalledWith(42, 0);
|
||||
});
|
||||
|
||||
it("returns false for Linux zombies even when probing reports EPERM", async () => {
|
||||
const error = Object.assign(new Error("permission denied"), { code: "EPERM" });
|
||||
vi.spyOn(process, "kill").mockImplementation(() => {
|
||||
throw error;
|
||||
});
|
||||
mockProcReads({
|
||||
"/proc/42/status": "Name:\tnode\nUmask:\t0022\nState:\tZ (zombie)\nTgid:\t42\nPid:\t42\n",
|
||||
});
|
||||
|
||||
await withMockedPlatform("linux", async () => {
|
||||
expect(isPidAlive(42)).toBe(false);
|
||||
});
|
||||
|
||||
expect(process["kill"]).toHaveBeenCalledWith(42, 0);
|
||||
});
|
||||
|
||||
it("returns false when process probing reports ESRCH", () => {
|
||||
const error = Object.assign(new Error("missing process"), { code: "ESRCH" });
|
||||
vi.spyOn(process, "kill").mockImplementation(() => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
expect(isPidAlive(42)).toBe(false);
|
||||
expect(process["kill"]).toHaveBeenCalledWith(42, 0);
|
||||
});
|
||||
|
||||
it("returns false for zombie processes on Linux", async () => {
|
||||
const zombiePid = process.pid;
|
||||
|
||||
|
||||
@@ -32,8 +32,13 @@ export function isPidAlive(pid: number): boolean {
|
||||
}
|
||||
try {
|
||||
process.kill(pid, 0);
|
||||
} catch {
|
||||
return false;
|
||||
} catch (err) {
|
||||
// EPERM means the PID exists but we cannot signal it. Treat that as a
|
||||
// successful existence probe, then still apply the Linux zombie check.
|
||||
// Keep parity with isPidDefinitelyDead (EPERM is not "definitely dead").
|
||||
if ((err as NodeJS.ErrnoException).code !== "EPERM") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isZombieProcess(pid)) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user