process-manager
Child process lifecycle management with Wayland socket binding.
Overview
Provides a ProcessManager for spawning, tracking, and terminating child processes. Supports label-based grouping, forked/detached processes, and an optional reaper thread for zombie prevention and exit notifications.
This crate is used by both smearor-wrot (to spawn compositor clients like panels, wallpapers, and widgets) and smearor-swipe-launcher (to launch terminal commands and desktop applications). It replaces the ad-hoc launch_application() function in wrot and the duplicated TrackedProcess struct in swipe-launcher.
Types
ProcessConfig- Unified configuration viaTypedBuilder(command, args, env, working_dir, shell, forked, terminate_on_exit, kill_signal, restart_on_exit, stdio, socket)ProcessManager- Concurrent process tracking viaDashMap, label-based grouping, optional reaper threadProcess/ProcessId/ProcessInfo- Process handle, unique identifier, and lightweight snapshot typeProcessState- Explicit lifecycle state enum (Starting,Running,Stopping,Stopped,Crashed,Restarting,Failed)ProcessExitEvent- Reaper exit notification withid,pid,label,restart_on_exit,exit_status,stateStdioConfig- Inherit/Null/Piped enum for standard streamsKillSignal- Sigterm/Sigkill enum for termination configSignal- Broader signal enum (SIGHUP, SIGUSR1, SIGSTOP, etc.) for general process controlProcessManagerError/ProcessConfigError- Error types
Architecture
graph TD
classDef default fill: #1e1e1e, stroke: #333333, stroke-width: 1px, color: #ffffff
classDef config fill: #00a1e4, stroke: #ffffff, stroke-width: 2px, color: #ffffff
classDef manager fill: #f5b700, stroke: #333333, stroke-width: 2px, color: #000000
classDef reaper fill: #dc0073, stroke: #333333, stroke-width: 2px, color: #ffffff
classDef process fill: #89fc00, stroke: #333333, stroke-width: 1px, color: #000
classDef event fill: #04e762, stroke: #333333, stroke-width: 1px, color: #000
A["ProcessConfig<br/><small>TypedBuilder</small>"] --> B["ProcessManager::start()"]
B --> C["Process<br/><small>stored in DashMap</small>"]
B --> D{"forked?"}
D -->|Yes| E["setsid() in pre_exec"]
D -->|No| F["Normal spawn"]
E --> C
F --> C
G["Reaper Thread<br/><small>optional</small>"] -->|"try_wait() poll"| C
C -->|exited| H["ProcessExitEvent<br/>via mpsc channel"]
H --> I["Consumer<br/>restart/status logic"]
class A config
class B manager
class C process
class D manager
class E manager
class F manager
class G reaper
class H event
class I event
Features
ProcessConfigwithTypedBuilder- Compile-time enforcement of required fields, ergonomic optional fields- Label-based grouping - Start/stop multiple processes under a shared label
- Forked/detached processes -
setsid()viapre_execfor terminal detachment - Reaper thread - Non-blocking
try_wait()polling withProcessExitEventchannel - Signal escalation -
SIGTERMwith configurable timeout, automaticSIGKILLescalation - Wayland socket binding - Sets
WAYLAND_DISPLAYfromSocket StdioConfig- Inherit/Null/Piped with reader threads for output captureKillSignal-Sigterm/Sigkillwith serde support for termination configSignal- Broader signal enum for general process control viasend_signal()- Restart -
restart()/restart_label()preserve config and label across restarts - Serde -
ProcessConfig,StdioConfig,KillSignal, andSignalimplementSerialize/Deserialize - Executable resolution -
whichintegration for PATH lookup - Graceful shutdown -
terminate_on_exitflag kills processes on drop #[must_use]- All public structs and enums are#[must_use]
Dependencies
| Crate | Purpose |
|---|---|
dashmap | Concurrent process tracking |
nix | Signal handling (SIGTERM, SIGKILL) |
libc | setsid() for forked processes |
typed-builder | ProcessConfig builder pattern |
which | Executable path resolution |
process-manager-socket | Wayland socket binding |
thiserror | Error types |
tracing | Logging |
See the individual pages for detailed documentation: