ProcessLookup Module
Standalone, identity-safe process lookup and reuse-safe liveness for a pid the caller holds **outside** any `ProcessGroup` (T-385) — a pid saved to disk across runs, a launch registry, or an external probe watching a process this library never itself contained. `ProcessGroup.MembersInfo` answers the same questions for a group's own membership; this module is the companion for a bare pid nothing here has ever tracked, so it needs no group and creates nothing. Reuses exactly the same per-platform readers `ProcessGroup.MembersInfo` uses (`Native.Windows` / `Native.Posix`) — no second, parallel identity-reading mechanism for this entry point — and keeps every standing rule those readers already enforce: never reads a process's argv or environment, and every enriching `MemberInfo` field stays an honest `option`, `None` wherever the platform cannot report it, never fabricated.
Functions and values
| Function or value |
Description
|
Full Usage:
ProcessLookup.processInfo pid
Parameters:
int
Returns: Result<MemberInfo option, ProcessError>
|
Look up the identity and best-effort metadata of an **arbitrary** process by pid — the standalone
companion to `ProcessGroup.MembersInfo`, for a pid the caller holds outside any group.
Three honest outcomes, never confused with one another:
- `Ok(Some info)` — the process exists; `info` carries the same fields `MemberInfo` always does
(`Ppid` / `ExeName` / `StartTime`, each `None` where the platform cannot honestly report it).
- `Ok None` — the pid names **no** process: an honest negative, not an error — the "it's gone"
answer a liveness check wants.
- `Error` — the process may well exist, but its state could not be determined (denied permission,
an OS read failure). **Never** read this as "dead" — that is the whole reason it is an error
rather than `Ok None`.
`pid <= 0` is refused up front with `Ok None`, before any native call: `0` names Windows' own
unopenable System Idle Process, and on POSIX `0`/a negative number addresses "the caller's own
process group" / a process GROUP rather than an individual process — neither is a meaning this
read-only query exists to act on. This process's own pid is not special-cased further: unlike
`ProcessGroup.AdoptByPid` (which would enlist the caller in its own group's teardown), a read-only
lookup has nothing to enlist it into, so querying yourself is an entirely ordinary, exercised case.
Never reads the process's command line or environment, on any platform — the same exclusion
`MemberInfo` documents. A snapshot taken now: the process may exit immediately afterwards, and the
pid is only as stable as the OS's reuse policy — to tell a *recycled* number apart from the
original process later, pair the returned `StartTime` with the pid and use `processIsAlive`.
See `docs/platform-support.md` ("Standalone process lookup") for the per-platform existence/
permission oracle each reader uses (Windows: `OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION)`;
Linux: `/proc/
|
Full Usage:
ProcessLookup.processIsAlive pid startTime
Parameters:
int
startTime : DateTime option
Returns: Result<bool, ProcessError>
|
Reuse-safe liveness: is the process at `pid` **still the same instance** you saw earlier — the one whose `MemberInfo.StartTime` you saved (from an earlier `processInfo`, or `ProcessGroup .MembersInfo`)? Because the OS reuses pid *numbers*, a bare pid check would answer "alive" for a stranger that recycled the number after your process exited; pairing it with the start time — fixed at creation and distinct for a later occupant — tells the original apart from a recycled number. This is the same anti-reuse discipline `ProcessGroup.AdoptByPid` applies internally to its own kills and stats reads, exposed here for a pid you merely hold. - `Ok true` — the process at `pid` exists **and**, when both start-time tokens are known, they agree: your process is still running. - `Ok false` — the process is gone: either the pid names nothing, or it names a **different** process now (a recycled number — the start times differ), so *your* process is no longer alive. - `Error` — either the pid may name a live process but it could not be inspected (the same permission/OS-error surface as `processInfo`), or the caller passed `Some` token but the CURRENT process's start time could not be read, so the recycle check cannot be answered honestly (see the degradation rule below). Never read this as "dead". **Reuse protection degrades honestly — never into a false "alive".** The recycle check needs a start-time token on **both** sides. - `startTime = None` (the caller saved no token — e.g. an earlier `processInfo` did not report one for that pid): this is an ordinary, deliberate bare-pid liveness check. A live process at the number reads as `Ok true`, exactly the number-only liveness a caller would otherwise write by hand — no weaker, and never a false "dead". - `startTime = Some _` (the caller wants reuse protection) but the CURRENT process's start time cannot be read right now: this is **not** treated as "still the original process" just because the number exists — that is precisely the false positive this API exists to prevent (a PID recycled by a stranger would read the same way). It is a typed refusal instead: `ProcessError.Io` — `readProcessStartTime` (the SAME reader `processInfo`/`MembersInfo` use, on every platform this library targets, `other` BSDs included via a best-effort `Process.StartTime`) simply did not answer for THIS pid right now — never `Unsupported`, because there is no platform where the start-time reader is categorically absent rather than momentarily unable to answer for one pid. So passing the saved `Some token` gives reuse protection on every platform, honestly refused rather than guessed when it cannot be verified.
|
ProcessKit API Reference