Which of the Following Represents a Signal in Linux?
Ever typed kill -9 1234 and wondered what the “‑9” actually means? Or stared at a list of names like SIGTERM, SIGSEGV, and thought, “Are these all signals, or am I mixing them up with something else?Day to day, ” You’re not alone. Signals are one of those low‑level concepts that pop up whenever you dig into Linux internals, yet they stay hidden until something goes wrong.
It sounds simple, but the gap is usually here.
In this post we’ll peel back the mystery, walk through the most common signals, explain why they matter, and give you a cheat‑sheet you can actually use the next time you’re debugging a misbehaving process Small thing, real impact..
What Is a Linux Signal?
Think of a signal as a tiny, asynchronous interrupt that the kernel sends to a process. Worth adding: it’s the OS’s way of saying, “Hey, something’s up—pay attention. ” The process can either handle the signal, ignore it, or let the default action run (which is often to terminate).
Unlike a function call, a signal can arrive at any point in the program’s execution, even in the middle of a system call. That’s why you’ll see code that sets up a signal handler—a small routine that runs when a particular signal arrives.
No fluff here — just what actually works.
The Core Idea
- A signal is a numeric identifier (an integer) paired with a symbolic name like
SIGINT. - The kernel delivers it to a process’s signal queue.
- The process decides what to do: catch, block, or ignore.
That’s it in practice. No fancy data structures, just a simple notification mechanism that’s been part of Unix since the ’70s Worth keeping that in mind..
Why It Matters / Why People Care
If you’ve ever been stuck with a hung program, you’ve probably tried Ctrl‑C. That keystroke sends SIGINT to the foreground job. If the program ignores it, you might resort to kill -9 (which sends SIGKILL). Knowing which signal does what can be the difference between a graceful shutdown and a corrupted state.
In production, signals are used for:
- Graceful reloads –
SIGHUPtells a daemon to reread its config without dropping connections. - Resource limits –
SIGXCPUfires when a process exceeds its CPU quota. - Debugging –
SIGTRAPis used by debuggers to break execution.
When you understand the signal set, you can script smarter restarts, build more resilient services, and avoid the dreaded “kill -9 and hope for the best” habit.
How It Works (or How to Do It)
Below is the step‑by‑step of how signals travel from the kernel to your code, plus a quick guide to the most common ones you’ll see in the wild.
1. Generating a Signal
Signals can originate from several sources:
| Source | Example | Typical Signal |
|---|---|---|
| Keyboard | Pressing Ctrl‑C |
SIGINT |
| Terminal | Closing a terminal window | SIGHUP |
| System call failure | Division by zero | SIGFPE |
| Explicit request | kill -SIGTERM 1234 |
SIGTERM |
| Kernel watchdog | Out‑of‑memory | SIGKILL (or SIGSEGV for illegal memory) |
The kill command (despite its name) is just a generic way to send any signal you choose.
2. Delivering the Signal
When the kernel decides a signal should go to a process, it:
- Looks up the target’s signal mask (which signals are blocked).
- If the signal is blocked, it’s queued.
- If not blocked, the kernel interrupts the process’s current flow and arranges for the signal handler (if any) to run.
If the process has no handler and the default action is “terminate,” the process dies instantly—except for SIGKILL and SIGSTOP, which cannot be caught or ignored.
3. Handling a Signal in Code
In C you’d typically do:
#include
void handler(int sig) {
// cleanup, log, etc.
}
int main() {
signal(SIGINT, handler); // catch Ctrl-C
while (1) pause(); // wait for signals
}
In higher‑level languages (Python, Go, Rust) the same idea applies, just with language‑specific APIs.
4. Common Signals and What They Represent
Below is the cheat‑sheet you asked for. The left column shows the symbolic name, the middle column the numeric value on most Linux distros, and the right column the typical meaning Small thing, real impact..
| Symbol | Number | Meaning (short) |
|---|---|---|
SIGHUP |
1 | Hangup – terminal closed or daemon reload |
SIGINT |
2 | Interrupt – Ctrl‑C |
SIGQUIT |
3 | Quit – Ctrl‑\ (core dump) |
SIGILL |
4 | Illegal instruction |
SIGABRT |
6 | Abort – abort() call |
SIGFPE |
8 | Floating‑point exception (divide by zero) |
SIGKILL |
9 | Kill – cannot be caught/ignored |
SIGUSR1 |
10 | User‑defined signal 1 |
SIGSEGV |
11 | Segmentation fault |
SIGUSR2 |
12 | User‑defined signal 2 |
SIGPIPE |
13 | Broken pipe – write to closed pipe |
SIGALRM |
14 | Timer alarm (alarm() expires) |
SIGTERM |
15 | Termination request – default for kill |
SIGCHLD |
17 | Child stopped/terminated |
SIGCONT |
18 | Continue a stopped process |
SIGSTOP |
19 | Stop (pause) – cannot be caught |
SIGTSTP |
20 | Terminal stop – Ctrl‑Z |
SIGTTIN |
21 | Background read from tty |
SIGTTOU |
22 | Background write to tty |
SIGBUS |
7 | Bus error – misaligned memory |
SIGPOLL |
29 | Pollable event (rare) |
SIGPROF |
27 | Profiling timer expired |
SIGSYS |
31 | Bad system call |
SIGTRAP |
5 | Trace/breakpoint trap |
SIGURG |
23 | Urgent condition on socket |
SIGXCPU |
24 | CPU time limit exceeded |
SIGXFSZ |
25 | File size limit exceeded |
That’s the core set you’ll see in most kill -l output. Anything not listed is either a real‑time signal (SIGRTMIN‑SIGRTMAX) or architecture‑specific Practical, not theoretical..
5. Sending a Signal from the Command Line
The syntax is simple:
# Send SIGTERM (default) to PID 1234
kill 1234
# Send SIGINT explicitly
kill -SIGINT 1234
# Use the numeric shortcut
kill -2 1234 # -2 == SIGINT
If you need to broadcast to a whole process group, prepend a minus sign to the PGID:
kill -SIGTERM -1234 # sends to every process in group 1234
Common Mistakes / What Most People Get Wrong
-
Assuming
killalways terminates –killwithout-9sendsSIGTERM. Many daemons catchSIGTERMto clean up, so the process may stay alive for a while. -
Confusing
SIGKILLwith “force quit” –SIGKILLis uncatchable, but it can still leave temporary files behind. A graceful shutdown (SIGTERM→ cleanup) is usually safer. -
Using the wrong signal for a reload – Some admins send
SIGTERMto Nginx expecting a reload. Nginx actually usesSIGHUP. The result? The server restarts instead of reloading config Most people skip this — try not to.. -
Blocking signals unintentionally – If a program masks
SIGINTearly on and never unmasks it,Ctrl‑Cappears to do nothing Small thing, real impact.. -
Ignoring real‑time signals – Linux supports up to 64 real‑time signals (
SIGRTMIN‑SIGRTMAX). They’re queued, ordered, and can carry extra data. Most tutorials skip them, but they’re handy for custom IPC.
Practical Tips / What Actually Works
- Always try a graceful signal first.
kill -TERM $pidgives the process a chance to shut down cleanly. Reserve-9for when it truly hangs. - Check the default action before you send. Run
kill -land look up the signal; you’ll see if it’s ignored, terminates, or core‑dumps. - Use
pkillorkillallfor name‑based targeting – they accept signal names, e.g.,pkill -SIGUSR1 mydaemon. - Log signal handling in production. Add a small handler that writes to syslog; you’ll know exactly which signal caused a restart.
- take advantage of
SIGHUPfor config reloads – most well‑behaved daemons listen for it. If you’re writing your own service, makeSIGHUPdo a reload, not a full exit. - Don’t block
SIGCHLDunless you have a reason. It’s the kernel’s way of telling you a child exited; ignoring it can lead to zombie processes. - Test your handlers. A simple script that traps
SIGINTandSIGTERMand prints a message can save you hours of debugging later.
FAQ
Q: How do I find out which signal a process received?
A: Use strace -e trace=signal -p <pid> or check the process’s /proc/<pid>/status for the SigQ field, which shows pending signals.
Q: Can I send a signal to a process that I don’t own?
A: Only if you’re root or the target process has the same UID. Normal users can’t signal arbitrary processes for security reasons.
Q: What’s the difference between SIGTERM and SIGINT?
A: Functionally they both request termination, but SIGINT is generated by the terminal (Ctrl‑C) and is often used for interactive aborts, while SIGTERM is the generic “please exit” signal used by scripts and service managers No workaround needed..
Q: Are real‑time signals (SIGRTMIN‑SIGRTMAX) safe to use?
A: Yes, they’re queued and won’t be lost if multiple instances arrive quickly. Just remember they’re not portable across all Unix flavors.
Q: Why does kill -0 <pid> sometimes return success?
A: Signal 0 is a special “ping” that performs error checking without delivering a signal. It’s a quick way to test if a PID exists and you have permission to signal it Surprisingly effective..
Wrapping It Up
Signals are the Linux kernel’s lightweight messenger system, and they’re more than just a list of cryptic names. Knowing which of the following actually represents a signal—SIGINT, SIGKILL, SIGHUP, SIGTERM, and the rest—lets you control processes with confidence, avoid accidental data loss, and write daemons that behave nicely when the world tells them to stop.
Next time you see a kill -9 on a log file, pause and ask yourself: could a gentler signal have done the job? With the cheat‑sheet and tips above, you’ve got the tools to make that call. Happy signaling!
Advanced Patterns for Real‑World Daemons
1. Graceful Shutdown Pipelines
When a service needs to wind down—think a web server draining connections or a database flushing caches—you’ll often see a two‑stage approach:
- First signal (
SIGTERMorSIGHUP) – tells the process “stop accepting new work.” - Second signal (
SIGINTor a custom real‑time signal) – after a timeout, forces termination if the graceful path hangs.
Implement this in a script that mirrors what systemd does internally:
#!/usr/bin/env bash
PID=$(cat /run/myapp.pid)
# Stage 1 – ask nicely
kill -TERM "$PID"
# Give the app 30 seconds to finish what it’s doing
timeout=30
while [ $timeout -gt 0 ] && kill -0 "$PID" 2>/dev/null; do
sleep 1
((timeout--))
done
# Stage 2 – be firm if needed
if kill -0 "$PID" 2>/dev/null; then
echo "Force‑killing $PID"
kill -KILL "$PID"
fi
The pattern is reusable across any service that must preserve in‑flight transactions Nothing fancy..
2. Using SIGUSR1/SIGUSR2 for Application‑Specific Control
POSIX reserves two user‑defined signals. They’re perfect for:
| Signal | Typical Use‑Case | Example Implementation |
|---|---|---|
SIGUSR1 |
Rotate logs, dump diagnostics, toggle debug mode | trap 'logger "Rotating logs…"; kill -HUP $(cat $PIDFILE)' SIGUSR1 |
SIGUSR2 |
Trigger a hot‑swap of configuration, start a profiling run | trap 'profiler start' SIGUSR2 |
Because they’re not interpreted by the kernel, you can give them any semantic meaning you want, provided you document the contract for anyone who will be sending them Simple, but easy to overlook..
3. Real‑Time Signals for Queued Events
Unlike the standard set, real‑time signals (SIGRTMIN … SIGRTMAX) are queued. If your daemon needs to react to a burst of events—e.g Easy to understand, harder to ignore..
/* C example */
#include
#include
static void rt_handler(int sig, siginfo_t *info, void *ucontext) {
printf("Received real‑time signal %d, value=%d\n", sig, info->si_value.sival_int);
}
int main(void) {
struct sigaction sa = { .sa_sigaction = rt_handler,
.sa_flags = SA_SIGINFO };
sigaction(SIGRTMIN, &sa, NULL); // listen on the first real‑time signal
while (1) pause();
}
The kernel guarantees delivery order, which is essential when the sequence of events matters Not complicated — just consistent..
4. Coordinating Multiple Processes with SIGCHLD
A parent that spawns workers often uses SIGCHLD to reap children without blocking:
#!/usr/bin/env bash
child_pids=()
handle_sigchld() {
while true; do
# -n prevents blocking if no child has exited yet
wait -n 2>/dev/null || break
done
}
trap 'handle_sigchld' SIGCHLD
# Launch a few workers
for i in {1..5}; do
./worker "$i" &
child_pids+=($!)
done
# Main loop – do something useful while children run
while kill -0 "${child_pids[0]}" 2>/dev/null; do
sleep 1
done
echo "All workers finished."
The wait -n builtin (available in Bash 4.3+) pulls the next terminated child off the wait queue, keeping the parent responsive Practical, not theoretical..
5. Signal Masking in Multi‑Threaded Programs
When you move from a single‑process script to a multi‑threaded C/C++ application, you must decide which thread receives which signals. The usual strategy:
- Block all signals in every thread at startup.
- Create a dedicated “signal‑handling thread.”
- Unmask the signals you care about only in that thread using
pthread_sigmask().
void *sig_thread(void *arg) {
sigset_t set;
int sig;
sigemptyset(&set);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGHUP);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
while (1) {
sigwait(&set, &sig);
if (sig == SIGTERM) graceful_shutdown();
else if (sig == SIGHUP) reload_config();
}
}
This design eliminates race conditions where a signal lands in an unexpected thread and makes the handling logic deterministic.
Debugging Signals in Production
| Symptom | Likely Cause | Quick Test |
|---|---|---|
| Process dies silently after a reload | Received SIGKILL from an out‑of‑memory (OOM) killer |
Check `dmesg |
| Daemon restarts repeatedly | A watchdog (systemd, monit) keeps sending SIGTERM because the service never reports “ready” |
Inspect systemctl status mysvc and look at ExecStartPost/TimeoutStartSec |
| Log files show “Received signal 0” | A monitoring script is using kill -0 for health checks; the daemon mistakenly treats it as a real signal |
Ensure the handler ignores signal 0 (it never arrives, but stray code can misinterpret it) |
| Child processes become zombies | Parent ignored or blocked SIGCHLD |
Run `ps -ef |
Tip: strace -e trace=signal -p <pid> prints every signal the kernel delivers to a running process, including the origin (kernel vs. user). Pair it with lsof -p <pid> to see which files are still open when a signal arrives—useful for spotting resources that need explicit cleanup.
Integrating with Modern Service Managers
Most Linux distributions ship with systemd, which abstracts many of the manual signal steps:
| systemd directive | Underlying signal | What it does |
|---|---|---|
KillSignal=SIGTERM |
SIGTERM |
Sent when systemctl stop is invoked. |
WatchdogSec= |
SIGABRT (by default) |
If the daemon fails to “ping” the watchdog, systemd sends the configured signal. |
RestartKillSignal=SIGKILL |
SIGKILL |
Force‑kill after RestartForceExitStatus. |
SuccessExitStatus= |
– | Treats specific exit codes as “clean” even if the process was killed. |
When you write a daemon, declare the signals you expect:
[Service]
ExecStart=/usr/local/bin/mydaemon
Restart=on-failure
KillSignal=SIGINT # prefer a graceful interrupt
WatchdogSec=30
Now the service manager handles the heavy lifting, and you only need to implement the corresponding handlers The details matter here..
Security Considerations
- Never trust user‑supplied signal numbers. A malicious user could try
kill -9 $(cat /etc/passwd); always validate that the target PID belongs to the same UID or that the caller is root. - Avoid
SIGKILLfor normal shutdowns. It bypasses cleanup, leaving sockets inTIME_WAITor files in inconsistent states, which can be exploited for denial‑of‑service. - Limit
ptraceaccess. Debuggers can inject signals; ensure/proc/sys/kernel/yama/ptrace_scopeis set appropriately for production hosts.
TL;DR Checklist
- ✅ Know the default actions for each POSIX signal.
- ✅ Use
kill -lto list names;kill -s NAME PIDfor readability. - ✅ Prefer
SIGTERM→ graceful →SIGKILLas a fallback. - ✅ Reserve
SIGUSR1/2for application‑specific commands; document them. - ✅ make use of real‑time signals when you need queuing.
- ✅ In multi‑threaded code, centralize handling in a dedicated thread.
- ✅ When using systemd, set
KillSignal,WatchdogSec, and related directives. - ✅ Log every signal receipt in production; it’s priceless for post‑mortems.
Conclusion
Signals are the Unix kernel’s minimalist inter‑process mailbox, and mastering them turns a collection of noisy processes into a well‑orchestrated ensemble. By internalizing the semantics of each signal, employing the right tools (kill, pkill, systemd), and embedding reliable handlers in your code, you gain fine‑grained control over startup, reload, shutdown, and error‑recovery pathways.
The practical patterns outlined above—graceful shutdown pipelines, user‑defined signals for diagnostics, real‑time queuing, disciplined SIGCHLD handling, and thread‑safe masking—bridge the gap between theory and daily operations. Coupled with vigilant logging and a security‑first mindset, they empower you to keep services alive, responsive, and maintainable even under heavy load or unexpected failure.
So the next time you see a kill command, pause and ask: Which signal is truly appropriate? Choose wisely, implement a clear handler, and let the kernel do what it does best—deliver a lightweight, reliable notification that keeps your Linux ecosystem humming. Happy signaling!
Not the most exciting part, but easily the most useful Surprisingly effective..
Debugging and Monitoring Signals in Production
-
strace -p <pid>
Attach to a running process and watch forSIG*entries Simple, but easy to overlook. Nothing fancy..strace -p 1234 -e trace=signalThis shows the exact moment the kernel delivers a signal and the system call that receives it Simple as that..
-
journalctl -u <service>
For systemd‑managed units, the unit’s logs will contain anySIGTERM/SIGKILLevents you explicitly log. Combine withsystemd-analyze blameto see if slow shutdowns are due to signal handling. -
pstackorgdb -p <pid>
When a process is stuck after a signal, a backtrace can reveal whether the handler is blocking, deadlocking, or mis‑managing shared resources No workaround needed.. -
Custom Metrics
Emit Prometheus counters such asprocess_received_signal_total{signal="SIGTERM"}. A sudden spike can indicate an attack or mis‑configured load‑balancer. -
Audit Trails
Useauditdrules to logexecveandkillsyscalls.auditctl -a always,exit -F arch=b64 -S kill -k signal‑auditThis gives you a forensic trail for security reviews.
Advanced Patterns
| Pattern | When to Use | Key Considerations |
|---|---|---|
| Signal‑driven configuration reload | Dynamic feature toggles | Ensure idempotent reload; avoid race conditions. On top of that, |
| Signal‑based self‑healing | Daemon watchdogs | Combine with systemd WatchdogSec; restart only after a timeout. |
| Signal‑based graceful degradation | High‑traffic thresholds | Use a dedicated thread to throttle; avoid blocking critical paths. |
| Signal‑based inter‑process coordination | Micro‑service clusters | Use SIGRTMIN family for reliable message queues. |
| Signal‑based process fencing | High‑availability clusters | Pair with shared storage flags to prevent split‑brain. |
TL;DR – One‑Page Cheat Sheet
| Action | Typical Signal | Typical Usage | Notes |
|---|---|---|---|
| Start service | N/A | systemd or init.d |
Use ExecStart= |
| Graceful stop | SIGTERM |
kill -TERM <pid> |
Wait for cleanup |
| Force stop | SIGKILL |
kill -KILL <pid> |
No cleanup |
| Reload config | SIGHUP |
kill -HUP <pid> |
Re-read files |
| Child exit | SIGCHLD |
Handled by waitpid() |
Reap zombies |
| User command | SIGUSR1/2 |
Custom | Document per app |
| Queue event | SIGRTMIN… |
Real‑time | Ordered delivery |
| Watchdog | SIGALRM |
Timer | Use setitimer() |
Final Thoughts
Signals are not merely a relic of early Unix; they remain the kernel’s most efficient, low‑overhead mechanism for inter‑process communication. When wielded with care—validating targets, respecting default semantics, and centralizing complex logic—signals become a powerful tool in your ops arsenal Worth keeping that in mind..
Easier said than done, but still worth knowing.
A solid signal strategy blends:
- Clear documentation of what each signal does in your codebase.
- Graceful shutdown pipelines that honor both user intent and system health.
- Security hardening to prevent accidental or malicious misuse.
- Observability hooks that surface signal activity to monitoring systems.
By building these practices into your development lifecycle, you transform sporadic kill invocations into predictable, auditable events that keep services running smoothly, even under pressure.
So next time you’re about to send a kill, remember that signals are a language—use it wisely, and the rest of your ecosystem will speak back in kind. Happy signaling!
To wrap this up, understanding and utilizing signals effectively is crucial for any system administrator or developer working with Unix-like systems. By leveraging the power of signals, you can create more resilient, responsive, and secure applications and services.
Remember to always handle signals appropriately in your code, ensuring that your application can gracefully respond to external events and requests. Be mindful of the potential security implications of signal handling, and take steps to mitigate any risks.
As you continue to work with signals, keep exploring advanced patterns and techniques to optimize your system's performance and reliability. Stay up-to-date with best practices and emerging trends in signal handling to see to it that your skills remain sharp and relevant.
By mastering the art of signal handling, you'll be well-equipped to tackle even the most complex system administration challenges with confidence and finesse. So embrace the power of signals, and use them to your advantage in building solid, efficient, and secure systems Most people skip this — try not to. Still holds up..