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:

  1. Sets m.pendingAction to the appropriate enum (e.g., actionKill, actionPause)
  2. Displays a confirmation prompt to prevent accidental termination
  3. Upon confirmation, invokes the corresponding helper from actions.go
  4. Captures errors in execErr and 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 sendSignal in internal/tui/actions.go, wrapping syscall.Kill for 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.go enforces confirmation dialogs via pendingAction before executing destructive actions
  • Renice functionality combines input rendering in view.go with priority adjustment via syscall.Setpriority in actions.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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →