๐ Advanced Signals and Job Control
Deep dive into signal handling, job control interfaces, and process communication mechanisms.
๐งญ Signal Fundamentals
Signals are asynchronous notifications sent to processes for various events.
Standard Signals
| Signal |
Number |
Description |
Default Action |
| SIGHUP |
1 |
Hangup (terminal closed) |
Terminate |
| SIGINT |
2 |
Interrupt (Ctrl+C) |
Terminate |
| SIGQUIT |
3 |
Quit (Ctrl+) |
Core dump |
| SIGILL |
4 |
Illegal instruction |
Core dump |
| SIGTRAP |
5 |
Trace/breakpoint trap |
Core dump |
| SIGABRT |
6 |
Abort signal |
Core dump |
| SIGBUS |
7 |
Bus error |
Core dump |
| SIGFPE |
8 |
Floating point exception |
Core dump |
| SIGKILL |
9 |
Kill (cannot trap) |
Terminate |
| SIGUSR1 |
10 |
User-defined signal 1 |
Terminate |
| SIGSEGV |
11 |
Invalid memory reference |
Core dump |
| SIGUSR2 |
12 |
User-defined signal 2 |
Terminate |
| SIGPIPE |
13 |
Broken pipe |
Terminate |
| SIGALRM |
14 |
Alarm clock |
Terminate |
| SIGTERM |
15 |
Termination request |
Terminate |
| SIGSTOP |
17 |
Stop process (cannot trap) |
Stop |
| SIGTSTP |
18 |
Terminal stop (Ctrl+Z) |
Stop |
| SIGCONT |
19 |
Continue if stopped |
Continue |
๐งช Signal Handling with trap
Basic Signal Trapping
| # Handle Ctrl+C gracefully
trap 'echo "Interrupted!"; exit 1' INT
# Ignore termination signals
trap '' TERM
# Reset to default behavior
trap - INT
|
Advanced Trap Patterns
1
2
3
4
5
6
7
8
9
10
11
12 | # Multiple signals with same handler
trap 'cleanup_and_exit' INT TERM HUP
# Trap all signals except KILL and STOP
trap 'log_signal_received' $(kill -l | grep -v KILL | grep -v STOP)
# Conditional trapping
if [ "$INTERACTIVE" = true ]; then
trap 'echo "Use quit command to exit"' INT
else
trap 'exit 1' INT
fi
|
Signal Listing
| # List all signals
kill -l
# Show signal numbers
kill -L
# Signal description
man 7 signal
|
Signal Sending
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | # By name
kill -TERM $PID
# By number
kill -15 $PID
# To process group
kill -TERM -$PGID
# To all processes with name
pkill -TERM process_name
# To processes matching pattern
killall -TERM pattern
|
Signal Queueing
| # Send multiple signals
for i in {1..10}; do
kill -USR1 $PID
done
# Process handles them sequentially
|
๐งช Job Control Interface
Interactive Job Control
| # Suspend current job (Ctrl+Z equivalent)
kill -TSTP $$
# Resume in background
kill -CONT $$
# Resume in foreground (requires terminal control)
fg %1
|
Programmatic Job Control
1
2
3
4
5
6
7
8
9
10
11
12 | # List jobs programmatically
jobs -p # PIDs only
jobs -l # Detailed info
# Bring job to foreground
fg %1
# Send job to background
bg %1
# Disown job (remove from job table)
disown %1
|
Job Status Checking
| # Check if job exists
jobs %1 >/dev/null 2>&1 && echo "Job 1 exists"
# Wait for specific job
wait %1
# Wait for any background job
wait
|
๐ง Advanced Signal Patterns
Signal-Based Communication
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | # Parent process
child_pid=0
start_worker() {
(
# Worker process
trap 'echo "Worker stopping"; exit 0' TERM
trap 'echo "Reloading config"' USR1
while true; do
do_work
sleep 1
done
) &
child_pid=$!
}
# Send signals to worker
kill -USR1 $child_pid # Reload config
kill -TERM $child_pid # Graceful shutdown
|
Signal Masking
| # Block signals temporarily
trap '' INT TERM
# Critical section
perform_critical_operation
# Restore signal handling
trap - INT TERM
|
Signal Timing Issues
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | # Race condition example
trap 'flag=true' USR1
# This might miss signals
while [ "$flag" != true ]; do
: # Busy wait - inefficient and unreliable
done
# Better approach - use self-pipe trick
mkfifo /tmp/signal_pipe.$$
trap "echo > /tmp/signal_pipe.$$" USR1
# Wait for signal
read < /tmp/signal_pipe.$$
rm /tmp/signal_pipe.$$
|
๐งช Process Group Signaling
Send to Process Group
1
2
3
4
5
6
7
8
9
10
11
12 | # Start process group
(
setpgid 0 0 # Create new process group
worker1 &
worker2 &
wait
) &
PGID=$!
# Send signal to entire group
kill -TERM -$PGID
|
Session-Wide Signaling
| # Send to all processes in session
kill -HUP 0 # 0 means current session
# Exclude self
kill -HUP -$$ # Negative PID means process group
|
๐ง Signal Handling Best Practices
Robust Signal Handlers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | # Reentrant signal handlers
sig_handler() {
local sig=$1
echo "Received signal $sig" >&2
# Set flag for main loop to check
signal_received=$sig
}
trap 'sig_handler INT' INT
trap 'sig_handler TERM' TERM
# Main loop checks flag
while [ "$signal_received" != "TERM" ]; do
do_main_work
sleep 1
done
|
Cleanup on Exit
| cleanup() {
echo "Cleaning up..." >&2
rm -rf "$TEMP_DIR"
unlink "$LOCK_FILE"
}
trap cleanup EXIT INT TERM
|
Signal Safety
Unsafe in signal handlers:
- Memory allocation (malloc)
- I/O operations
- Most library functions
Safe operations:
- Setting global flags
- write(), _exit()
- Simple arithmetic
๐งช Debugging Signal Issues
Signal Tracing
| # Trace signal delivery
strace -e trace=signal ./myscript.sh
# Monitor specific signals
watch -n 1 'kill -l | head -10'
|
Signal Statistics
| # View pending signals
cat /proc/$PID/status | grep -E "Sig"
# Check signal masks
cat /proc/$PID/status | grep Sig
|
Testing Signal Handling
| # Automated signal testing
test_signals() {
local pid=$1
for sig in INT TERM HUP USR1 USR2; do
echo "Testing signal $sig..."
kill -$sig $pid
sleep 1
done
}
|
๐งพ Summary
- Understand standard signal meanings and behaviors
- Use
trap for custom signal handling
- Master job control with
fg, bg, jobs, wait
- Implement robust signal communication patterns
- Handle race conditions with proper synchronization
- Debug signal issues with
strace and /proc
- Follow signal safety guidelines in handlers
- Design graceful shutdown mechanisms
- Test signal handling thoroughly
๐ Continue to: Shell in CI/CD