College-Level Course Module | RHEL System Administration
Learning Objectives
1
Understand processes
Process concepts, states, and the process hierarchy
2
Investigate processes
Use ps, top, and other tools to view process information
3
Control job execution
Manage foreground and background processes
4
Send signals to processes
Use kill and related commands to control processes
5
Adjust process priority
Use nice and renice to manage CPU scheduling
What is a Process?
A process is a running instance of a program. When you execute a command, the kernel creates a process, assigns it resources, and schedules it for execution.
Process Attributes:
PID - Unique Process ID
PPID - Parent Process ID
UID/GID - User/Group ownership
Priority - Scheduling priority
State - Current execution state
Memory - Allocated memory space
Program vs Process:
Program - Executable file on disk
Process - Running program in memory
One program can spawn many processes
Each process has isolated memory
Processes share CPU time
# Every process has a unique PID[user@host ~]$ echo $$
1234# Current shell's PID
Process States
Processes move between states as they execute. Understanding states helps diagnose process behavior.
State
Code
Description
Running
R
Currently executing on CPU or waiting in run queue
Sleeping (Interruptible)
S
Waiting for event (I/O, signal) - can be interrupted
Sleeping (Uninterruptible)
D
Waiting for I/O - cannot be interrupted (disk wait)
Stopped
T
Suspended by signal (Ctrl+Z) or debugger
Zombie
Z
Terminated but parent hasn't read exit status
Created
→
Ready
↔
Running
→
Terminated
Process Hierarchy
Processes form a parent-child hierarchy. Every process (except PID 1) has a parent. When processes create new processes, they become children.
# View process tree[user@host ~]$ pstree
systemd─┬─NetworkManager───3*[{NetworkManager}]
├─agetty
├─auditd───{auditd}
├─crond
├─sshd───sshd───sshd───bash───pstree
└─systemd-journal# Show PIDs in tree[user@host ~]$ pstree -p
systemd(1)─┬─sshd(1234)───sshd(5678)───sshd(5680)───bash(5681)───pstree(5700)# Show tree for specific process[user@host ~]$ pstree -p 1234
PID 1 (systemd): The first process started at boot. It is the ancestor of all other processes and adopts orphaned processes.
Viewing Processes: ps
ps (process status) displays a snapshot of current processes. Different options show different information.
# Basic ps - shows processes in current terminal[user@host ~]$ ps
PID TTY TIME CMD
5681 pts/0 00:00:00 bash
5700 pts/0 00:00:00 ps# Show all processes (BSD style - most common)[user@host ~]$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.3 171820 13256 ? Ss 09:00 0:02 /usr/lib/systemd/systemd
root 2 0.0 0.0 0 0 ? S 09:00 0:00 [kthreadd]
apache 1234 0.2 1.5 550000 62000 ? S 09:15 0:45 /usr/sbin/httpd
student 5681 0.0 0.1 27000 4500 pts/0 Ss 10:30 0:00 -bash# Show all processes (Unix style)[user@host ~]$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 09:00 ? 00:00:02 /usr/lib/systemd/systemd
student 5681 5680 0 10:30 pts/0 00:00:00 -bash
Understanding ps Output
Column
Description
Example
USER
Process owner
root, apache, student
PID
Process ID
1, 1234, 5681
%CPU
CPU usage percentage
0.0, 25.5, 99.9
%MEM
Memory usage percentage
0.1, 5.2, 15.0
VSZ
Virtual memory size (KB)
Total addressable memory
RSS
Resident Set Size (KB)
Actual physical RAM used
TTY
Controlling terminal
pts/0, tty1, ? (none)
STAT
Process state
S, R, D, T, Z (+ modifiers)
START
When process started
09:00, Jan15
TIME
Cumulative CPU time
0:00, 5:32
COMMAND
Command that started process
/usr/sbin/httpd
# STAT column modifiers:s - session leader l - multi-threaded
+ - foreground process < - high priority
N - low priority L - pages locked in memory
Filtering ps Output
# Find processes by name using grep[user@host ~]$ ps aux | grep httpd
root 1234 0.0 0.5 275000 20000 ? Ss 09:15 0:00 /usr/sbin/httpd
apache 1235 0.0 0.3 275500 12000 ? S 09:15 0:01 /usr/sbin/httpd
apache 1236 0.0 0.3 275500 12000 ? S 09:15 0:01 /usr/sbin/httpd
student 5720 0.0 0.0 12000 1000 pts/0 S+ 10:45 0:00 grep httpd# Exclude grep from results[user@host ~]$ ps aux | grep [h]ttpd
[user@host ~]$ ps aux | grep httpd | grep -v grep
# Find processes by user[user@host ~]$ ps -u apache
[user@host ~]$ ps aux | grep ^apache
# Find process by PID[user@host ~]$ ps -p 1234
# Custom output format[user@host ~]$ ps -eo pid,user,%cpu,%mem,cmd --sort=-%cpu | head
PID USER %CPU %MEM CMD
3456 mysql 45.2 12.5 /usr/libexec/mysqld
1234 apache 8.3 2.1 /usr/sbin/httpd
Real-time Monitoring: top
top provides a dynamic, real-time view of processes. It updates continuously and allows interactive sorting and filtering.
[user@host ~]$ top
top - 10:45:23 up 1 day, 2:30, 2 users, load average: 0.15, 0.10, 0.05
Tasks: 156 total, 1 running, 155 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.3 us, 1.0 sy, 0.0 ni, 96.5 id, 0.1 wa, 0.0 hi, 0.1 si
MiB Mem : 3936.0 total, 1524.0 free, 1200.0 used, 1212.0 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 2500.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3456 mysql 20 0 1256000 512000 15000 S 12.3 12.7 5:23.45 mysqld
1234 apache 20 0 275000 62000 12000 S 2.5 1.5 0:45.12 httpd
1 root 20 0 171820 13256 8500 S 0.0 0.3 0:02.35 systemd
Key metrics in header: Load average (1, 5, 15 min), CPU breakdown (user, system, idle, wait), Memory usage
Interactive top Commands
Key
Action
Key
Action
h or ?
Help screen
q
Quit top
M
Sort by memory
P
Sort by CPU (default)
N
Sort by PID
T
Sort by time
u
Filter by user
c
Toggle full command
k
Kill a process
r
Renice a process
1
Toggle per-CPU stats
m
Toggle memory display
Space
Refresh immediately
d
Change refresh delay
# Start top sorted by memory[user@host ~]$ top -o %MEM
# Show only specific user's processes[user@host ~]$ top -u apache
# Batch mode (for scripting, non-interactive)[user@host ~]$ top -bn1 | head -20
# Set refresh interval to 1 second[user@host ~]$ top -d 1
Other Monitoring Tools
# htop - enhanced interactive process viewer (if installed)[user@host ~]$ htop
# Better visual interface, mouse support, easier to use# pidof - find PID by process name[user@host ~]$ pidof httpd
1236 1235 1234# pgrep - search processes by pattern[user@host ~]$ pgrep -l http
1234 httpd
1235 httpd# pgrep with more details[user@host ~]$ pgrep -a httpd
1234 /usr/sbin/httpd -DFOREGROUND# lsof - list open files by process[user@host ~]$ lsof -p 1234 | head
# What process is using a file?[user@host ~]$ lsof /var/log/messages
# What process is using a port?[user@host ~]$ lsof -i :80
Foreground and Background
Foreground processes receive keyboard input and block the terminal. Background processes run without blocking, freeing the terminal for other work.
# Run command in foreground (default)[user@host ~]$ sleep 60
# Terminal is blocked for 60 seconds...# Run command in background (add &)[user@host ~]$ sleep 60 &
[1] 5800# [job number] PID[user@host ~]$# Terminal available immediately# Suspend foreground process (Ctrl+Z)[user@host ~]$ sleep 60
^Z
[1]+ Stopped sleep 60# Resume in background[user@host ~]$ bg
[1]+ sleep 60 &# Bring to foreground[user@host ~]$ fg
sleep 60
Managing Jobs
# List current jobs[user@host ~]$ jobs
[1]- Running sleep 100 &
[2]+ Stopped vim file.txt# Jobs with PIDs[user@host ~]$ jobs -l
[1]- 5800 Running sleep 100 &
[2]+ 5810 Stopped vim file.txt# Bring specific job to foreground[user@host ~]$ fg %1 # Job number 1[user@host ~]$ fg %vim # Job starting with "vim"# Resume specific job in background[user@host ~]$ bg %2
# The + and - indicate:# + current job (default for fg/bg)# - previous job# Disown - remove job from shell's job table[user@host ~]$ disown %1
# Process continues but shell doesn't track it
Keeping Processes Running
Normally, background processes terminate when you log out. Use nohup to keep them running.
# nohup - "no hangup" - ignore SIGHUP signal[user@host ~]$ nohup long-running-script.sh &
nohup: ignoring input and appending output to 'nohup.out'[1] 5850# Output goes to nohup.out (or redirect explicitly)[user@host ~]$ nohup ./backup.sh > backup.log 2>&1 &
# Now safe to log out - process continues[user@host ~]$ exit
# Later, check if still running[user@host ~]$ ps aux | grep backup
# Alternative: screen or tmux for interactive sessions[user@host ~]$ screen -S mysession
# Work in screen session...# Detach with Ctrl+A, D# Reattach later:[user@host ~]$ screen -r mysession
Understanding Signals
Signals are software interrupts sent to processes. They notify processes of events and can request termination, reload, or other actions.
Signal
Number
Default Action
Description
SIGHUP
1
Terminate
Hangup - terminal closed, often used to reload config
SIGINT
2
Terminate
Interrupt - Ctrl+C pressed
SIGQUIT
3
Core dump
Quit - Ctrl+\ pressed
SIGKILL
9
Terminate
Kill - cannot be caught or ignored, immediate death
SIGTERM
15
Terminate
Terminate - polite request to exit (default for kill)
SIGSTOP
19
Stop
Stop - cannot be caught, pauses process
SIGCONT
18
Continue
Continue - resume stopped process
SIGTSTP
20
Stop
Terminal stop - Ctrl+Z pressed
Key distinction: SIGTERM asks nicely (process can clean up). SIGKILL forces immediately (no cleanup possible).
Sending Signals: kill
kill sends signals to processes. Despite the name, it can send any signal, not just termination signals.
# Default: send SIGTERM (signal 15)[root@host ~]# kill 1234
# Specify signal by name[root@host ~]# kill -SIGTERM 1234
[root@host ~]# kill -TERM 1234
# Specify signal by number[root@host ~]# kill -15 1234
# Force kill (cannot be caught - use as last resort)[root@host ~]# kill -9 1234
[root@host ~]# kill -SIGKILL 1234
# Send to multiple processes[root@host ~]# kill 1234 1235 1236
# List available signals[user@host ~]$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
9) SIGKILL 15) SIGTERM 18) SIGCONT 19) SIGSTOP ...
Best practice: Try SIGTERM first. Only use SIGKILL (-9) if SIGTERM fails after a few seconds.
killall and pkill
# killall - kill by exact process name[root@host ~]# killall httpd
# Sends SIGTERM to all processes named exactly "httpd"# killall with specific signal[root@host ~]# killall -9 httpd
[root@host ~]# killall -SIGHUP httpd # Reload config# pkill - kill by pattern (more flexible)[root@host ~]# pkill http
# Matches any process containing "http"# pkill by user[root@host ~]# pkill -u student
# Kill all processes owned by student# pkill with signal[root@host ~]# pkill -9 -u baduser
# Preview what would be killed (like pgrep)[user@host ~]$ pgrep -l http
1234 httpd
1235 httpd# Then: pkill http
Caution: pkill matches patterns - pkill user might kill more than intended. Preview with pgrep first!
Process Priority
The Linux scheduler uses nice values to determine CPU priority. Lower nice values = higher priority. Range: -20 (highest) to 19 (lowest).
-20 Highest
→
-10
→
0 Default
→
+10
→
+19 Lowest
# View process nice values (NI column)[user@host ~]$ ps -eo pid,ni,cmd
PID NI CMD
1 0 /usr/lib/systemd/systemd
1234 0 /usr/sbin/httpd
5000 10 /usr/local/bin/backup.sh# Also visible in top (NI column)[user@host ~]$ top
Naming: A "nice" process is considerate of others. Higher nice value = nicer = lower priority. Negative = not nice = higher priority.
nice and renice
# Start process with specific nice value[user@host ~]$ nice -n 10 ./long-task.sh
# Runs with nice value 10 (lower priority)# Default nice value is 10 if not specified[user@host ~]$ nice ./long-task.sh
# Only root can set negative nice values[root@host ~]# nice -n -5 ./important-task.sh
# Change nice value of running process[root@host ~]# renice -n 15 -p 1234
1234 (process ID) old priority 0, new priority 15# Renice by user (all processes owned by user)[root@host ~]# renice -n 10 -u student
# Regular users can only increase nice (lower priority)[user@host ~]$ renice -n 5 -p 5678 # Works (lowering priority)[user@host ~]$ renice -n -5 -p 5678 # Fails (raising priority)renice: failed to set priority for 5678: Permission denied
Best Practices
Do
Use ps/top to investigate before killing
Try SIGTERM before SIGKILL
Use pgrep to preview pkill targets
Use nohup for long-running tasks
Nice background jobs to reduce impact
Monitor with top for real-time issues
Check process owner before killing
Understand why a process is misbehaving
Do Not
Jump straight to kill -9
Kill processes you don't understand
Use pkill without previewing matches
Kill system processes carelessly
Ignore zombie process accumulation
Assume process names are unique
Forget that kill sends signals, not just kills
Neglect to check if process actually stopped
Troubleshooting order: Investigate (ps, top) → Understand the problem → Try gentle solutions first → Escalate if needed
Key Takeaways
1
Investigate: Use ps aux for snapshots, top for real-time monitoring. Understand PID, state, CPU, memory.
2
Jobs: Background with &, suspend with Ctrl+Z, resume with bg/fg. Use nohup to survive logout.