How witr Handles Signal Operations in the TUI: Kill, Terminate, Pause, and Renice
witr implements process control signals directly in its TUI layer through platform-agnostic syscall wrappers located in internal/tui/actions.go, using syscall.Kill for POSIX signals and syscall.Setpriority for niceness adjustments.
The open-source process monitor witr (pranshuparmar/witr) provides terminal-based process management through an intuitive Text User Interface (TUI). Understanding how witr handles signal operations reveals a lightweight architecture that leverages Go's standard library to deliver cross-platform process control without external dependencies.
Core Signal Implementation in actions.go
The foundation of witr's signal operations resides in internal/tui/actions.go, where dedicated helper functions map user commands to POSIX signals. Each operation uses the internal sendSignal helper to deliver signals via Go's syscall package.
Signal Dispatch Functions
The file defines specific wrappers for each destructive operation at the following locations:
killProcess(pid int)– Sends SIGKILL (actions.go L13-L14)termProcess(pid int)– Sends SIGTERM (actions.go L13-L14)pauseProcess(pid int)– Sends SIGSTOP (actions.go L15)resumeProcess(pid int)– Sends SIGCONT (actions.go L16)
These functions delegate to a unified sendSignal(pid int, sig syscall.Signal) implementation that invokes syscall.Kill to transmit the signal to the target process. This abstraction ensures compatibility across Linux, macOS, and BSD systems by handling platform-specific system call details internally.
Renice Implementation
For priority adjustment, setNice(pid, value int) (actions.go L30-L35) handles renice operations. Rather than sending a signal, this function calls syscall.Setpriority (or the equivalent setpriority syscall) to modify the process's niceness value within the standard -20 to 19 range.
// Simplified representation of the actions.go implementation
func sendSignal(pid int, sig syscall.Signal) error {
return syscall.Kill(pid, sig)
}
func setNice(pid, value int) error {
// Validation and syscall.Setpriority logic
return syscall.Setpriority(syscall.PRIO_PROCESS, pid, value)
}
TUI State Management and User Interaction
The signal workflow integrates with the TUI through internal/tui/update.go, which manages confirmation dialogs and action state to prevent accidental process termination.
Action Confirmation Flow
When a user initiates a destructive operation (pressing k for kill, t for terminate, p for pause, or r for resume), the update loop follows this sequence:
- Sets
m.pendingActionto the appropriate enum (e.g.,actionKill,actionPause) - Displays a confirmation prompt to prevent accidental termination
- Upon confirmation, invokes the corresponding helper from
actions.go - Captures errors in
execErrand surfaces status messages
The pause implementation at line 1293 demonstrates this pattern: execErr = pauseProcess(pid) executes only after explicit user confirmation (update.go L1290-L1295).
Renice Input Handling
Unlike instantaneous signals, renice requires user input for the new priority value. The internal/tui/view.go file renders an input prompt (view.go L421-L425) requesting a niceness value. After validation through validateNiceValue, update.go executes setNice(pid, val) (update.go L1249-L1264), displaying confirmation messages like "PID 123 reniced to -5" upon success.
Cross-Platform Syscall Architecture
witr's signal operations rely on Go's syscall package for direct kernel communication. The sendSignal function uses syscall.Kill for immediate signal delivery, while setNice leverages syscall.Setpriority for scheduling adjustments. This design eliminates CGO dependencies while maintaining native performance characteristics across POSIX-compliant operating systems.
Summary
- Signal dispatch occurs through
sendSignalininternal/tui/actions.go, wrappingsyscall.Killfor POSIX compliance - Individual operations (kill, terminate, pause, resume) use dedicated helpers that map to SIGKILL, SIGTERM, SIGSTOP, and SIGCONT respectively
- State management in
internal/tui/update.goenforces confirmation dialogs viapendingActionbefore executing destructive actions - Renice functionality combines input rendering in
view.gowith priority adjustment viasyscall.Setpriorityinactions.go - Cross-platform support comes from Go's standard library abstraction of system calls across Linux, macOS, and BSD
Frequently Asked Questions
What signals does witr use for process termination?
witr implements two termination methods: termProcess sends SIGTERM for graceful shutdown, while killProcess sends SIGKILL for immediate termination. Both functions reside in internal/tui/actions.go and utilize syscall.Kill for signal delivery.
How does witr prevent accidental process kills?
The TUI requires explicit confirmation through the pendingAction state machine in internal/tui/update.go. When a user presses a destructive key, the interface displays a confirmation prompt and only executes killProcess or termProcess after receiving affirmative input, preventing accidental signal transmission.
Can witr adjust process priority on macOS and Linux?
Yes. The setNice function in internal/tui/actions.go uses syscall.Setpriority, which works on both Linux and macOS (as well as other BSD variants). The implementation handles the standard Unix niceness range of -20 (highest priority) to 19 (lowest priority).
Where does witr handle the UI rendering for signal operations?
Signal confirmation prompts and renice input fields are rendered in internal/tui/view.go, while the state transitions and business logic execute in internal/tui/update.go. This separation follows the Model-View-Update pattern common in TUI applications.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →