diff --git a/src/shared/linux-process-start-times.ts b/src/shared/linux-process-start-times.ts new file mode 100644 index 00000000000..534b10547ce --- /dev/null +++ b/src/shared/linux-process-start-times.ts @@ -0,0 +1,38 @@ +import { readFile } from 'node:fs/promises' +import type { ProcessTableRow } from './process-table-snapshot' + +/** Read Linux's stable PID start-time ticks without spawning another process. */ +export async function readLinuxProcessStartTimes( + rows: readonly ProcessTableRow[] +): Promise | undefined> { + if (process.platform !== 'linux') { + return undefined + } + const candidates = rows.filter((row) => row.tty !== undefined && row.tty !== '?') + const starts = await Promise.all( + candidates.map(async (row) => { + try { + const stat = await readFile(`/proc/${row.pid}/stat`, 'utf8') + const closingParen = stat.lastIndexOf(')') + if (closingParen === -1) { + return null + } + const tail = stat + .slice(closingParen + 1) + .trim() + .split(/\s+/) + const startTime = tail[19] + return startTime ? ([row.pid, startTime] as const) : null + } catch { + return null + } + }) + ) + const result = new Map() + for (const entry of starts) { + if (entry) { + result.set(entry[0], entry[1]) + } + } + return result +} diff --git a/src/shared/process-table-snapshot-reader.ts b/src/shared/process-table-snapshot-reader.ts index e89260b397a..7a3187df978 100644 --- a/src/shared/process-table-snapshot-reader.ts +++ b/src/shared/process-table-snapshot-reader.ts @@ -1,6 +1,6 @@ import { execFile as execFileCb } from 'node:child_process' -import { readFile } from 'node:fs/promises' import { promisify } from 'node:util' +import { readLinuxProcessStartTimes } from './linux-process-start-times' import { PS_ARGS, PS_MAX_BUFFER_BYTES, @@ -217,42 +217,6 @@ function assertWholeCapture(stdout: string): string { return stdout } -/** Read Linux's stable PID start-time ticks without spawning another process. */ -async function readLinuxProcessStartTimes( - rows: readonly ProcessTableRow[] -): Promise | undefined> { - if (process.platform !== 'linux') { - return undefined - } - const candidates = rows.filter((row) => row.tty !== undefined && row.tty !== '?') - const starts = await Promise.all( - candidates.map(async (row) => { - try { - const stat = await readFile(`/proc/${row.pid}/stat`, 'utf8') - const closingParen = stat.lastIndexOf(')') - if (closingParen === -1) { - return null - } - const tail = stat - .slice(closingParen + 1) - .trim() - .split(/\s+/) - const startTime = tail[19] - return startTime ? ([row.pid, startTime] as const) : null - } catch { - return null - } - }) - ) - const result = new Map() - for (const entry of starts) { - if (entry) { - result.set(entry[0], entry[1]) - } - } - return result -} - const processTableReader = createProcessTableSnapshotReader({ runPs: () => captureProcessTable(PS_ARGS), now: () => Date.now()