Linux Process Management: Signals, Priorities, and Service Control

Every running program on a Linux system is a process. Understanding how to inspect, control, prioritize, and terminate processes is a core system administration skill. This guide covers the essential tools and techniques for process management, from basic inspection commands to service orchestration with systemctl.

Part of the Linux System Administration guide. See also: Systemd Guide | Performance Monitoring

Inspecting Processes

ps: Process Snapshots

The ps command provides a snapshot of currently running processes. The most common invocation is ps aux, which shows all processes with detailed information:

$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
root         1  0.0  0.1 169436 13092 ?     Ss   Mar10   0:15 /sbin/init
root         2  0.0  0.0      0     0 ?     S    Mar10   0:00 [kthreadd]
www-data  1542  0.2  1.5 456320 125440 ?    Sl   09:00   1:22 /usr/sbin/apache2
postgres  1987  0.1  2.3 398712 189248 ?    Ss   09:01   0:45 postgres: writer

Key columns: PID (process ID), %CPU and %MEM (resource usage), STAT (process state), COMMAND (the executable and arguments).

Process states in STAT: S sleeping, R running, D uninterruptible sleep (usually I/O), Z zombie, T stopped. Additional characters: s session leader, l multi-threaded, + foreground process group.

Useful ps variations:

# Show process tree (parent-child relationships)
ps auxf

# Show processes for a specific user
ps -u postgres

# Show specific columns
ps -eo pid,ppid,user,%cpu,%mem,cmd --sort=-%cpu | head -20

# Find processes by name
ps aux | grep nginx
# Or more precisely:
pgrep -a nginx

top and htop: Real-Time Monitoring

top provides a continuously updating view of system processes sorted by CPU usage:

$ top
# Key commands inside top:
#   M     - sort by memory usage
#   P     - sort by CPU usage
#   k     - kill a process (enter PID)
#   r     - renice a process
#   1     - show individual CPU cores
#   q     - quit

htop is an enhanced, more user-friendly alternative. It provides color-coded output, mouse support, tree view, and easier process management. Install it with your package manager (apt install htop or dnf install htop):

$ htop
# Key commands inside htop:
#   F5    - tree view
#   F6    - choose sort column
#   F9    - kill menu (select signal)
#   F2    - setup/configuration
#   /     - search for process
#   u     - filter by user

Signals: Communicating with Processes

Signals are the primary mechanism for communicating with running processes. The kill command sends signals despite its name; termination is just one possibility.

Common Signals

Signal Number Default Action Purpose
SIGHUP 1 Terminate Hangup; many daemons reload config on SIGHUP
SIGINT 2 Terminate Interrupt (same as Ctrl+C)
SIGQUIT 3 Core dump Quit with core dump
SIGKILL 9 Terminate Force kill; cannot be caught or ignored
SIGTERM 15 Terminate Graceful termination (default signal)
SIGSTOP 19 Stop Pause process; cannot be caught
SIGCONT 18 Continue Resume a stopped process

Sending Signals

# Send SIGTERM (default, graceful shutdown)
kill 1542
kill -15 1542
kill -SIGTERM 1542

# Send SIGHUP (reload configuration)
kill -1 1542
kill -SIGHUP 1542

# Force kill (last resort; process cannot clean up)
kill -9 1542
kill -SIGKILL 1542

# Kill all processes by name
killall nginx
pkill -f "python app.py"

# Send signal to all processes of a user
pkill -u baduser

Best practice: Always try SIGTERM first. Give the process a few seconds to shut down gracefully. Only use SIGKILL if SIGTERM fails, because SIGKILL prevents cleanup (temporary files, lock files, database connections may be left in a dirty state).

Handling Zombie Processes

A zombie process (Z state) is a child process that has finished but whose parent has not yet read its exit status. Zombies consume a PID but no other resources. You cannot kill a zombie directly; you must either signal the parent to reap it or kill the parent:

# Find zombies
ps aux | awk '$8 ~ /Z/'

# Find the parent of a zombie
ps -o ppid= -p <zombie_pid>

Process Priority: nice and renice

Linux uses a priority system from -20 (highest priority) to 19 (lowest priority). The default nice value is 0. Only root can set negative nice values.

# Start a process with low priority
nice -n 10 tar czf backup.tar.gz /data

# Start with high priority (root only)
nice -n -5 /opt/critical-app/run.sh

# Change priority of a running process
renice 15 -p 1542

# Renice all processes of a user
renice 10 -u developer

Low-priority tasks like backups and batch jobs should be niced to avoid impacting interactive or customer-facing workloads.

Job Control: bg, fg, and jobs

The shell provides built-in job control for managing multiple processes within a terminal session.

# Start a process in the background
./long_running_task.sh &

# Suspend the current foreground process
# Press Ctrl+Z

# List background and stopped jobs
$ jobs
[1]+  Stopped                 vim config.yaml
[2]-  Running                 ./compile.sh &

# Resume job 1 in the foreground
fg %1

# Resume job 1 in the background
bg %1

# Bring the most recent background job to the foreground
fg

nohup: Surviving Logout

When you log out, your shell sends SIGHUP to all its child processes, which typically terminates them. nohup makes a process immune to SIGHUP:

# Run a process that survives logout
nohup ./data_migration.sh &

# Output goes to nohup.out by default; redirect if preferred
nohup ./data_migration.sh > /var/log/migration.log 2>&1 &

# Alternatively, use disown to detach an already-running job
./long_task.sh &
disown %1

For long-running tasks on remote servers, consider using screen or tmux instead of nohup for better session management.

Managing Services with systemctl

On modern Linux distributions using systemd, services are managed with systemctl. This is the primary interface for starting, stopping, enabling, and inspecting system services.

# Start, stop, and restart a service
systemctl start nginx
systemctl stop nginx
systemctl restart nginx

# Reload configuration without full restart (if supported)
systemctl reload nginx

# Enable a service to start at boot
systemctl enable nginx

# Disable a service from starting at boot
systemctl disable nginx

# Check service status
systemctl status nginx

# View all running services
systemctl list-units --type=service --state=running

# View all failed services
systemctl --failed

# Show service dependencies
systemctl list-dependencies nginx

Inspecting Service Logs

Systemd integrates with journalctl for centralized logging:

# View logs for a specific service
journalctl -u nginx

# Follow logs in real time
journalctl -u nginx -f

# Show logs since last boot
journalctl -u nginx -b

# Show logs from the last hour
journalctl -u nginx --since "1 hour ago"

Practical Tips

  • Use pgrep and pkill instead of ps | grep pipelines for reliability
  • Monitor for zombie processes in your alerting system; a growing count indicates a buggy parent process
  • Set appropriate nice values for batch jobs and backups
  • Use systemctl rather than direct process management for services; it handles dependencies, logging, restart policies, and resource limits
  • When a process is stuck in D state (uninterruptible sleep), it is usually waiting on I/O; investigate the storage subsystem rather than trying to kill the process