Topic Overview

Signals: Concepts, Internals & Interview Use Cases

Learn Unix signals: software interrupts for inter-process communication and control.

Medium7 min read

Signals

Why This Matters

Think of signals like text messages between processes. One process sends a signal (like "stop" or "terminate") to another process, and the receiving process handles it (like handling a text message). Signals are a simple form of inter-process communication (IPC) used for process control and notification.

This matters because processes need to communicate and control each other. When you press Ctrl+C to stop a program, you're sending a SIGINT signal. When the OS needs to terminate a process, it sends a SIGTERM signal. Signals provide a simple way for processes to notify and control each other. Understanding signals helps you understand process control and write signal handlers.

In interviews, when someone asks "How do you stop a process?", they're testing whether you understand signals. Do you know what SIGTERM vs SIGKILL means? Do you understand signal handlers? Most engineers don't. They just kill processes and assume they stop.

What Engineers Usually Get Wrong

Most engineers think "signals are just kill commands." But signals are a communication mechanism. Processes can send signals to each other, and processes can handle signals (install signal handlers). SIGTERM can be caught and handled gracefully (cleanup, save state). SIGKILL cannot be caught (forced termination). Understanding this helps you write programs that handle termination gracefully.

Engineers also don't understand that signals are asynchronous. A signal can arrive at any time, interrupting the process's normal execution. Signal handlers must be careful not to do too much work (they can be interrupted by other signals) and must be re-entrant. Understanding this helps you write safe signal handlers.

How This Breaks Systems in the Real World

A service was using SIGKILL to stop processes. SIGKILL cannot be caught, so processes couldn't clean up (close files, release resources). This caused resource leaks and data corruption. The fix? Use SIGTERM first, which can be caught. Give processes time to clean up. Only use SIGKILL if SIGTERM doesn't work. Understanding signals helps you stop processes gracefully.

Another story: A service had a signal handler that did too much work (allocated memory, made system calls). When signals arrived frequently, the handler was interrupted by other signals, causing crashes. The fix? Keep signal handlers simple. Only set flags, don't do heavy work. Do heavy work in the main program after checking flags. Understanding signal handling helps you write safe programs.


Common Signals

Process Control Signals:

  • SIGTERM (15): Termination request (can be caught, graceful shutdown)
  • SIGKILL (9): Kill signal (cannot be caught, forced termination)
  • SIGINT (2): Interrupt (Ctrl+C, can be caught)
  • SIGHUP (1): Hangup (terminal closed, can be caught)
  • SIGSTOP (19): Stop process (cannot be caught, suspend)
  • SIGCONT (18): Continue process (resume stopped process)

Error Signals:

  • SIGSEGV (11): Segmentation fault (invalid memory access)
  • SIGBUS (7): Bus error (invalid memory access)
  • SIGFPE (8): Floating-point exception

Examples

Example 1: Graceful Shutdown with SIGTERM

// Signal handler for graceful shutdown
void signal_handler(int sig) {
    if (sig == SIGTERM) {
        // Set flag to stop main loop
        running = 0;
        // Cleanup: close files, release resources
        cleanup();
    }
}

int main() {
    // Install signal handler
    signal(SIGTERM, signal_handler);
    
    while (running) {
        // Main program loop
        process_data();
    }
    
    // Cleanup completed
    return 0;
}

Usage: kill -TERM <pid> sends SIGTERM, process can clean up gracefully

Example 2: Forced Termination with SIGKILL

# Process doesn't respond to SIGTERM
kill -TERM <pid>  # Try graceful shutdown
sleep 2
kill -KILL <pid>  # Force kill (cannot be caught)

SIGKILL cannot be caught: Process is terminated immediately, no cleanup

Example 3: Signal Handler Safety

// UNSAFE: Signal handler does too much work
void unsafe_handler(int sig) {
    // Allocates memory (not safe in signal handler)
    char *buf = malloc(1000);
    // Makes system call (not safe)
    write(log_fd, buf, 1000);
    // Can be interrupted by another signal!
}

// SAFE: Signal handler sets flag only
volatile sig_atomic_t flag = 0;

void safe_handler(int sig) {
    flag = 1;  // Just set flag
}

int main() {
    signal(SIGTERM, safe_handler);
    
    while (1) {
        if (flag) {
            // Do heavy work in main program
            cleanup();
            break;
        }
        process_data();
    }
}

Common Pitfalls

Pitfall 1: Using SIGKILL for normal shutdown

  • Problem: SIGKILL cannot be caught, process can't clean up
  • Solution: Use SIGTERM first, only use SIGKILL if SIGTERM fails
  • Example: Using kill -9 prevents processes from closing files, releasing resources

Pitfall 2: Signal handlers doing too much work

  • Problem: Signal handlers can be interrupted by other signals, causing crashes
  • Solution: Keep handlers simple (set flags only), do heavy work in main program
  • Example: Allocating memory or making system calls in signal handler can cause deadlocks

Pitfall 3: Not handling signal race conditions

  • Problem: Signals can arrive at any time, causing race conditions
  • Solution: Use proper synchronization, make signal handlers re-entrant
  • Example: Signal arriving during critical section can corrupt data

Pitfall 4: Ignoring signal delivery semantics

  • Problem: Signals are asynchronous, delivery not guaranteed
  • Solution: Understand that signals can be lost, use proper IPC for reliable communication
  • Example: Relying on signals for critical synchronization can fail

Pitfall 5: Not restoring signal handlers

  • Problem: Signal handlers should be restored after handling
  • Solution: Re-install signal handler after handling, or use sigaction with SA_RESTART
  • Example: Signal handler not restored, subsequent signals use default handler

Interview Questions

Beginner

Q: What is the difference between SIGTERM and SIGKILL?

A: SIGTERM is a termination request that can be caught by the process. The process can install a signal handler to perform cleanup (close files, release resources) before terminating. SIGKILL is a kill signal that cannot be caught—the process is terminated immediately with no opportunity for cleanup. SIGTERM should be used first for graceful shutdown, and SIGKILL should only be used if SIGTERM doesn't work (process is hung or unresponsive).


Intermediate

Q: Why must signal handlers be simple and re-entrant?

A: Signal handlers must be simple and re-entrant because:

  1. Asynchronous delivery: Signals can arrive at any time, even during handler execution
  2. Interruption: A signal handler can be interrupted by another signal
  3. Limited context: Signal handlers run in a limited context (not full process context)
  4. Re-entrancy: If a handler is interrupted and re-entered, it must handle this safely

Safe practices:

  • Set flags only (volatile sig_atomic_t)
  • Don't allocate memory
  • Don't make system calls (except async-signal-safe ones)
  • Don't access shared data without proper synchronization
  • Do heavy work in main program after checking flags

Example: A signal handler that allocates memory can cause deadlocks if interrupted during allocation.


Senior

Q: How would you design a process management system that handles process termination gracefully while ensuring processes can be forcefully killed when needed?

A: I would design a multi-level termination system:

  1. Graceful shutdown protocol:

    • Send SIGTERM first (allows cleanup)
    • Wait for graceful shutdown (timeout: 5-30 seconds)
    • Monitor process state (check if process exited)
    • Only use SIGKILL if process doesn't terminate
  2. Signal handler design:

    • Install SIGTERM handler that sets shutdown flag
    • Handler must be simple (set flag only)
    • Main program checks flag and performs cleanup
    • Use sigaction with proper flags (SA_RESTART for system calls)
  3. Cleanup coordination:

    • Implement cleanup state machine (in-progress, completed)
    • Use synchronization to prevent race conditions
    • Ensure cleanup is idempotent (safe to call multiple times)
  4. Timeout mechanism:

    • Set alarm/timeout for graceful shutdown
    • If timeout expires, escalate to SIGKILL
    • Log timeout events for debugging
  5. Process monitoring:

    • Track process state (running, shutting down, terminated)
    • Monitor for hung processes (not responding to SIGTERM)
    • Implement health checks to detect unresponsive processes
  6. Force kill handling:

    • Use SIGKILL only as last resort
    • Log force kill events (for debugging)
    • Handle orphaned resources (cleanup by parent/init)
  7. Error handling:

    • Handle signal delivery failures
    • Handle process already terminated
    • Handle permission errors (can't send signal)

This design ensures graceful shutdown when possible while allowing forceful termination when needed.


  • Signals: Software interrupts for inter-process communication and process control

  • Signal types: SIGTERM (terminate, catchable), SIGKILL (kill, non-catchable), SIGINT (interrupt), SIGHUP (hangup)

  • Signal handlers: Processes can catch signals (except SIGKILL) for graceful shutdown

  • Signal delivery: Asynchronous (can arrive at any time), handlers must be re-entrant and simple

  • Best practices: Use SIGTERM for graceful shutdown, SIGKILL only if needed, keep handlers simple

  • Process vs Thread - Understanding processes that send and receive signals

  • Interrupts and Traps - How signals relate to interrupts and traps in the OS

  • System Calls - How signal operations are implemented through system calls

  • Shared Memory vs Message Passing - Signals as a form of inter-process communication

  • PCB (Process Control Block) - How signals are delivered to processes using PCB information

Key Takeaways

Signals: Software interrupts for inter-process communication and process control

Signal types: SIGTERM (terminate, catchable), SIGKILL (kill, non-catchable), SIGINT (interrupt), SIGHUP (hangup)

Signal handlers: Processes can catch signals (except SIGKILL) for graceful shutdown

Signal delivery: Asynchronous (can arrive at any time), handlers must be re-entrant and simple

Best practices: Use SIGTERM for graceful shutdown, SIGKILL only if needed, keep handlers simple


About the author

InterviewCrafted helps you master system design with patience. We believe in curiosity-led engineering, reflective writing, and designing systems that make future changes feel calm.