mirror of https://github.com/openclaw/openclaw.git
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import fsSync from "node:fs";
|
|
|
|
function isValidPid(pid: number): boolean {
|
|
return Number.isInteger(pid) && pid > 0;
|
|
}
|
|
|
|
/**
|
|
* Check if a process is a zombie on Linux by reading /proc/<pid>/status.
|
|
* Returns false on non-Linux platforms or if the proc file can't be read.
|
|
*/
|
|
function isZombieProcess(pid: number): boolean {
|
|
if (process.platform !== "linux") {
|
|
return false;
|
|
}
|
|
try {
|
|
const status = fsSync.readFileSync(`/proc/${pid}/status`, "utf8");
|
|
const stateMatch = status.match(/^State:\s+(\S)/m);
|
|
return stateMatch?.[1] === "Z";
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function isPidAlive(pid: number): boolean {
|
|
if (!isValidPid(pid)) {
|
|
return false;
|
|
}
|
|
try {
|
|
process.kill(pid, 0);
|
|
} catch {
|
|
return false;
|
|
}
|
|
if (isZombieProcess(pid)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Read the process start time (field 22 "starttime") from /proc/<pid>/stat.
|
|
* Returns the value in clock ticks since system boot, or null on non-Linux
|
|
* platforms or if the proc file can't be read.
|
|
*
|
|
* This is used to detect PID recycling: if two readings for the same PID
|
|
* return different starttimes, the PID has been reused by a different process.
|
|
*/
|
|
export function getProcessStartTime(pid: number): number | null {
|
|
if (process.platform !== "linux") {
|
|
return null;
|
|
}
|
|
if (!isValidPid(pid)) {
|
|
return null;
|
|
}
|
|
try {
|
|
const stat = fsSync.readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
const commEndIndex = stat.lastIndexOf(")");
|
|
if (commEndIndex < 0) {
|
|
return null;
|
|
}
|
|
// The comm field (field 2) is wrapped in parens and can contain spaces,
|
|
// so split after the last ")" to get fields 3..N reliably.
|
|
const afterComm = stat.slice(commEndIndex + 1).trimStart();
|
|
const fields = afterComm.split(/\s+/);
|
|
// field 22 (starttime) = index 19 after the comm-split (field 3 is index 0).
|
|
const starttime = Number(fields[19]);
|
|
return Number.isInteger(starttime) && starttime >= 0 ? starttime : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|