Skip to content

perf(macos): replace pgrep/lsof/ps with libproc for process introspection#146

Merged
matej21 merged 1 commit into
mainfrom
perf/libproc-process-introspection
Jun 19, 2026
Merged

perf(macos): replace pgrep/lsof/ps with libproc for process introspection#146
matej21 merged 1 commit into
mainfrom
perf/libproc-process-introspection

Conversation

@matej21

@matej21 matej21 commented Jun 18, 2026

Copy link
Copy Markdown
Member

Why

On macOS, several process-introspection paths forked subprocesses:

Use Was (macOS) Now
child pids (busy check, idle detection) pgrep -P proc_listpids(PPID)
dtach socket → pid lsof <socket> (×2) socket-fd scan
listening ports (services) lsof -iTCP -sTCP:LISTEN socket-fd scan
process tree (port detection) ps -eo pid,ppid proc_pidinfo/BSDInfo

Each fork+exec on macOS costs tens of ms (dyld + AMFI/codesign). Linux already does all of this via /proc reads; this brings macOS to parity with in-process libproc syscalls — no subprocesses.

Companion to #145 (which moved the busy check off the GPUI thread). #145 fixes the perceived close lag regardless of backend; this removes the underlying fork+exec cost so the same introspection is cheap everywhere it's used (close path, idle detection, services panel).

What

New macOS-only module okena_terminal::macos_proc wrapping libproc:

  • child_pids / has_children / first_child_pid — replaces pgrep -P
  • process_nameproc_name; also gives the soft-close toast a foreground-command hint on macOS (was Linux-only)
  • process_tree — replaces ps -eo pid,ppid
  • pids_holding_unix_sockets — matches bound sockaddr_un paths; replaces lsof <socket>
  • listening_port_pairs — TCP LISTEN sockets → (pid, port); replaces lsof -iTCP -sTCP:LISTEN

Wired into child_processes.rs, pty_manager.rs (dtach lookup + dtach-daemon→shell walk) and okena-services::port_detect.

libproc is a macOS-only dependency. Linux and Windows paths are untouched; other Unix (BSD) keeps the pgrep/lsof fallback (libproc is darwin-only).

⚠️ Verification note

libproc generates its bindings via bindgen against the macOS SDK at build time, so the new module only compiles on macOS. It is cfg'd out on Linux, which means:

  • A Linux build does not compile it.
  • The PR check job (Linux-only clippy -D warnings + tests) does not exercise it.

It needs a macOS build before merge — either locally (cargo build --target aarch64-apple-darwin) or via the multi-platform build workflow (tag / workflow_dispatch). The code follows libproc's documented API, but the FFI/union/struct-field access is unverified by CI until then.

Linux side (integration, cfg gating, BSD fallback) passes cargo clippy --workspace --all-targets -- -D warnings.

🤖 Generated with Claude Code

On macOS the close path, idle detection and port detection forked subprocesses
to inspect processes: `pgrep -P` (child pids), `lsof` (dtach socket → pid, and
listening ports) and `ps -eo pid,ppid` (process tree). Each fork+exec costs
tens of ms on macOS (dyld + AMFI/codesign). Linux does the same via `/proc`
reads; this brings macOS to parity with in-process `libproc` syscalls.

New `okena_terminal::macos_proc` (macOS-only) wraps libproc:
- `child_pids` / `has_children` / `first_child_pid` — `proc_listpids(PPID)`,
  replacing `pgrep -P`.
- `process_name` — `proc_name`, gives the soft-close toast a foreground-command
  hint on macOS too (was Linux-only).
- `process_tree` — `proc_pidinfo`/BSDInfo ppid, replacing `ps -eo pid,ppid`.
- `pids_holding_unix_sockets` — scans each process's socket fds and matches the
  bound `sockaddr_un` path, replacing `lsof <socket>`.
- `listening_port_pairs` — TCP sockets in LISTEN state → (pid, port), replacing
  `lsof -iTCP -sTCP:LISTEN`.

Wired into `child_processes.rs`, `pty_manager.rs` (dtach lookup + first child)
and `okena-services::port_detect`. libproc is a macOS-only dependency; Linux and
Windows paths are unchanged, and other Unix (BSD) keeps the pgrep/lsof fallback.

NOTE: the macOS code only compiles on macOS (libproc generates bindings via
bindgen against the macOS SDK at build time). It is cfg'd out on Linux, so
neither a Linux build nor the PR `check` job exercises it — it must be built on
macOS (locally or via the tag/workflow_dispatch build matrix) before merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019JZRfqVneyJnKjdrtSp3ro
@matej21 matej21 merged commit df89224 into main Jun 19, 2026
8 checks passed
@matej21 matej21 deleted the perf/libproc-process-introspection branch June 19, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant