Project 4: Signal Laboratory
Build a set of programs that send, catch, and escalate signals for graceful shutdown.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Intermediate |
| Time Estimate | Weekend |
| Language | C (Alternatives: Rust, Go, Python) |
| Prerequisites | Basic C, process basics |
| Key Topics | signals, handlers, graceful shutdown |
1. Learning Objectives
By completing this project, you will:
- Install signal handlers with
sigaction. - Demonstrate SIGTERM vs SIGKILL behavior.
- Build a graceful shutdown sequence.
- Avoid common async-signal-safety bugs.
2. Theoretical Foundation
2.1 Core Concepts
- Signals as interrupts: Signals are asynchronous events delivered by the kernel.
- Signal disposition: Default, ignore, or custom handler; SIGKILL/SIGSTOP cannot be caught.
- Async-signal safety: Only a small set of functions are safe inside handlers.
2.2 Why This Matters
Production daemons must shut down cleanly. Signal handling is the contract for safe termination.
2.3 Historical Context / Background
Signals date back to early Unix, providing a uniform method for process control and job management.
2.4 Common Misconceptions
- “kill -9 is normal”: It bypasses cleanup and should be a last resort.
- “printf in handlers is fine”: It is not async-signal-safe.
3. Project Specification
3.1 What You Will Build
A small suite: a signal receiver with handlers, a sender tool, and a manager that gracefully shuts down child workers.
3.2 Functional Requirements
- Register handlers for SIGINT, SIGTERM, SIGHUP.
- Demonstrate SIGKILL and SIGSTOP cannot be handled.
- Implement a graceful shutdown flow for children.
3.3 Non-Functional Requirements
- Reliability: Cleanup happens outside handlers.
- Safety: No unsafe calls in signal handlers.
- Clarity: Logs show signal flow.
3.4 Example Usage / Output
$ ./signal-receiver
[PID 1234] Ready
$ kill -SIGTERM 1234
[PID 1234] SIGTERM received, shutting down...
3.5 Real World Outcome
You will send signals to your receiver and see clean shutdown logs and proper child cleanup. Example:
$ ./signal-receiver
[PID 1234] Ready
$ kill -SIGTERM 1234
[PID 1234] SIGTERM received, shutting down...
4. Solution Architecture
4.1 High-Level Design
Sender -> kernel delivers signal -> handler sets flag -> main loop cleans up
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Receiver | Handle signals | Use sigaction |
| Manager | Spawn/stop workers | SIGTERM then SIGKILL |
| Sender | Send signals | Use kill(2) |
4.3 Data Structures
volatile sig_atomic_t shutdown_requested = 0;
4.4 Algorithm Overview
Key Algorithm: Graceful Shutdown
- Handler sets a flag.
- Main loop detects flag.
- Stop workers and wait.
Complexity Analysis:
- Time: O(n) workers
- Space: O(n) PIDs
5. Implementation Guide
5.1 Development Environment Setup
gcc --version
5.2 Project Structure
project-root/
├── receiver.c
├── manager.c
├── sender.c
└── README.md
5.3 The Core Question You’re Answering
“How do I shut down a process safely when the OS tells it to stop?”
5.4 Concepts You Must Understand First
Stop and research these before coding:
- Signal Disposition
- Default actions and which signals cannot be caught.
- sigaction
- Using
sa_handler,sa_flags, andsigemptyset.
- Using
- SIGCHLD
- Reaping children to avoid zombies.
5.5 Questions to Guide Your Design
Before implementing, think through these:
- What cleanup is safe to do inside the handler?
- How long should a worker have to exit before SIGKILL?
- How will you confirm a worker exited?
5.6 Thinking Exercise
Write a Safe Handler
Write a handler that only sets a flag. Move real cleanup into the main loop.
5.7 The Interview Questions They’ll Ask
Prepare to answer these:
- “Why is SIGKILL different from SIGTERM?”
- “Why is printf unsafe in a signal handler?”
- “How do you prevent zombie processes?”
5.8 Hints in Layers
Hint 1: Use sigaction It is more reliable than signal().
Hint 2: Use a flag Set a volatile sig_atomic_t flag and exit cleanly in the main loop.
Hint 3: Reap children
Use waitpid with WNOHANG.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Signals | “TLPI” | Ch. 20-22 |
| Process control | “APUE” | Ch. 10 |
| Daemon patterns | “Linux System Programming” | Ch. 6 |
5.10 Implementation Phases
Phase 1: Foundation (1 day)
Goals:
- Catch SIGINT and SIGTERM.
Tasks:
- Create receiver with sigaction.
- Print a message on shutdown.
Checkpoint: Receiver exits cleanly on SIGTERM.
Phase 2: Core Functionality (1 day)
Goals:
- Manage workers.
Tasks:
- Spawn child processes.
- Send SIGTERM then SIGKILL if needed.
Checkpoint: Workers exit and are reaped.
Phase 3: Polish & Edge Cases (Half day)
Goals:
- Improve logs and handle SIGCHLD.
Tasks:
- Add SIGCHLD handler.
- Summarize shutdown results.
Checkpoint: No zombies after shutdown.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Handler API | signal vs sigaction | sigaction | Portable and robust |
| Escalation | immediate kill vs grace | grace then kill | Safe cleanup |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Handler | Catch signals | SIGINT, SIGTERM |
| Escalation | SIGKILL fallback | Unresponsive worker |
| Reaping | No zombies | ps -o stat |
6.2 Critical Test Cases
- SIGTERM triggers graceful shutdown.
- SIGKILL stops a stuck worker.
- No zombies remain after exit.
6.3 Test Data
Worker PIDs list
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Unsafe handler calls | Deadlocks/crashes | Only set flags |
| Ignoring SIGCHLD | Zombies | Call waitpid |
| Short timeouts | Forced kills | Increase grace period |
7.2 Debugging Strategies
- Use
strace -e signalto view signal delivery. - Inspect process states with
ps -o pid,ppid,stat,cmd.
7.3 Performance Traps
Overly aggressive signal loops can spin; use sleeps between checks.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add SIGHUP reload behavior.
- Add configurable timeouts.
8.2 Intermediate Extensions
- Add a supervisor that restarts crashed workers.
- Add signal masking for critical sections.
8.3 Advanced Extensions
- Implement a small daemon with PID file handling.
- Integrate with systemd service unit signals.
9. Real-World Connections
9.1 Industry Applications
- Graceful shutdown is required for systemd, Kubernetes, and service managers.
9.2 Related Open Source Projects
- systemd: https://systemd.io
- supervisord: http://supervisord.org
9.3 Interview Relevance
- Signals and process cleanup are core Unix topics.
10. Resources
10.1 Essential Reading
- signal(7) -
man 7 signal - sigaction(2) -
man 2 sigaction
10.2 Video Resources
- Unix signals overview (search “Unix signals sigaction”)
10.3 Tools & Documentation
- kill(1) -
man 1 kill
10.4 Related Projects in This Series
- Zombie Hunter: focus on SIGCHLD handling.
11. Self-Assessment Checklist
11.1 Understanding
- I can explain signal delivery.
- I can describe SIGTERM vs SIGKILL.
- I can explain async-signal safety.
11.2 Implementation
- Handlers are installed with sigaction.
- Shutdown is graceful and reliable.
- Children are reaped.
11.3 Growth
- I can apply this to a production daemon.
- I can explain shutdown semantics in interviews.
12. Submission / Completion Criteria
Minimum Viable Completion:
- Signal receiver handles SIGINT/SIGTERM safely.
Full Completion:
- Manager shuts down child processes gracefully.
Excellence (Going Above & Beyond):
- Add reload behavior and integrate with service manager patterns.
This guide was generated from LINUX_SYSTEM_TOOLS_MASTERY.md. For the complete learning path, see the parent directory.