Signals in UNIX/Linux
Signals are asynchronous software notifications sent to a process to inform it that an event has occurred. They provide a mechanism for the kernel, other processes, or the process itself to interrupt normal execution and request immediate attention.
Learning Objectives
- Understand what a signal is.
- Learn why signals are needed.
- Understand signal generation and delivery.
- Learn the signal life cycle.
- Understand default signal actions.
- Prepare for signal programming using POSIX APIs.
1. What is a Signal?
A signal is an asynchronous notification sent to a process to indicate that a particular event has occurred. Signals may be generated by:
- The operating system kernel.
- Another process.
- The process itself.
When a signal is delivered, the process may terminate, ignore the signal, stop execution, continue execution, or invoke a signal handler, depending on the signal's disposition.
2. Why are Signals Needed?
Signals provide a mechanism for responding to asynchronous events without requiring continuous polling by the application. Common situations include:
- User interrupts a program using the keyboard.
- A child process terminates.
- A timer expires.
- An invalid memory access occurs.
- An illegal instruction is executed.
3. What is an Asynchronous Event?
An asynchronous event occurs independently of the normal sequence of instructions being executed by a process. Unlike an ordinary function call, a signal may arrive at almost any point during program execution.
4. Signal Life Cycle
A signal passes through several stages before it affects a process.
5. Signal Generation
A signal may be generated in several ways.
| Source | Example |
|---|---|
| Kernel | Invalid memory access |
| User | Ctrl+C |
| Process | kill() |
| Self | raise() |
6. Signal Delivery
Once generated, a signal becomes pending until it is delivered. Delivery occurs when the process is eligible to receive the signal and the signal is not blocked.
7. Signal Disposition
Every signal has a disposition, which determines how the receiving process responds.
| Disposition | Description |
|---|---|
| Default | Kernel performs the predefined action. |
| Ignore | Signal is discarded. |
| Catch | User-defined signal handler executes. |
8. Common UNIX Signals
| Signal | Typical Cause |
|---|---|
| SIGINT | User presses Ctrl+C |
| SIGTERM | Termination request |
| SIGKILL | Forced process termination |
| SIGSTOP | Stop process execution |
| SIGSEGV | Invalid memory access |
| SIGALRM | Timer expiration |
9. Signals vs Function Calls
| Function Call | Signal |
|---|---|
| Synchronous | Asynchronous |
| Called explicitly | Generated by an event |
| Returns normally | Interrupts execution |
| Program controlled | Event controlled |
10. Interview Questions
- What is a signal in UNIX/Linux?
- Why are signals considered asynchronous?
- Name four sources that can generate a signal.
- What is meant by signal disposition?
- What are the three possible signal dispositions?
- Explain the signal life cycle.
- What is the difference between a function call and a signal?
11. Standard UNIX Signals
UNIX defines a standard set of signals used to notify processes about
various events.
Each signal has a symbolic name beginning with SIG and is
associated with an implementation-defined signal number.
Applications should use symbolic names such as
SIGINT instead of numeric signal values because signal
numbers may differ across UNIX-like operating systems.
12. Frequently Used Signals
| Signal | Typical Meaning | Common Source |
|---|---|---|
| SIGINT | Interrupt process | Ctrl+C |
| SIGTERM | Request graceful termination | kill command |
| SIGKILL | Force immediate termination | Kernel / kill -9 |
| SIGSTOP | Stop execution | Kernel / debugger |
| SIGCONT | Resume stopped process | kill -CONT |
| SIGSEGV | Invalid memory reference | Memory protection fault |
| SIGFPE | Arithmetic exception | Divide by zero, overflow |
| SIGILL | Illegal instruction | Invalid CPU instruction |
| SIGALRM | Alarm timer expired | alarm() |
| SIGCHLD | Child process state changed | Kernel |
13. Signal Numbers
Every signal has an associated numeric value. However, applications should avoid depending on specific signal numbers, because they are implementation dependent.
14. Listing Signals in Linux
Linux provides the following command to display the signals supported by the system.
Example output includes signal names such as
SIGHUP,
SIGINT,
SIGTERM,
and many others.
15. Default Signal Actions
Each signal has a predefined default action if the process does not install a signal handler or ignore the signal (where ignoring is permitted).
| Default Action | Description |
|---|---|
| Terminate | Process exits. |
| Terminate + Core Dump | Process exits and a core dump may be generated. |
| Stop | Process execution is suspended. |
| Continue | Previously stopped process resumes execution. |
| Ignore | Signal is discarded. |
16. Signals That Cannot Be Caught or Ignored
Two signals have special behavior defined by POSIX.
| Signal | Purpose |
|---|---|
| SIGKILL | Immediate process termination |
| SIGSTOP | Stop process execution |
Applications cannot install handlers for these signals, block them, or ignore them.
17. Sending Signals with kill
Signals can be sent from the shell using the
kill command.
The command above requests graceful termination of the process whose process ID (PID) is 1234.
The second command sends SIGKILL, which immediately
terminates the process.
18. raise()
A process can send a signal to itself using raise().
The specified signal is generated for the calling process.
19. abort()
The abort() library function causes abnormal program termination.
Calling abort() generates SIGABRT for the
calling process.
If the signal is not caught and handled appropriately, the process
terminates and may produce a core dump.
20. Interview Questions
- Why should programs use signal names instead of signal numbers?
- Which command lists all supported Linux signals?
- What are the five possible default signal actions?
- Which two signals cannot be caught, blocked, or ignored?
- What is the difference between
kill -TERMandkill -9? - What is the purpose of
raise()? - How does
abort()terminate a program?
21. signal()
The signal() function installs a signal disposition for a specified signal. A process may:
- Use the default action.
- Ignore the signal (when permitted).
- Install a user-defined signal handler.
22. Parameters of signal()
| Parameter | Description |
|---|---|
| signum | Signal to modify |
| handler | Default action, ignore, or handler function |
23. Signal Handler
A signal handler is a function executed automatically when the specified signal is delivered.
The handler receives the signal number as its only argument.
24. Installing a Handler
After installation, pressing Ctrl+C causes the handler to execute instead of performing the default action.
25. Complete Example
26. Signal Handler Execution Flow
27. Returning from a Signal Handler
When a signal handler returns normally, program execution resumes at the point determined by the operating system after signal handling is complete.
If the signal's default action terminates the process, execution does not continue unless a handler has been installed.
28. SIG_DFL
SIG_DFL requests the default action for a signal.
The kernel performs the predefined action associated with the signal.
29. SIG_IGN
SIG_IGN instructs the process to ignore a signal when ignoring that signal is permitted.
After installation, pressing Ctrl+C no longer causes the default interrupt action.
30. SIG_ERR
If signal() fails, it returns
SIG_ERR.
Applications should check for this return value when installing signal handlers.
31. Limitations of signal()
Historically, the behavior of signal() differed across UNIX
implementations.
POSIX defines consistent semantics, but modern applications generally
prefer sigaction(), which provides more precise and
portable control over signal handling.
32. Interview Questions
- What is the purpose of
signal()? - What argument does a signal handler receive?
- What happens when a signal handler returns?
- What is the purpose of
SIG_DFL? - What does
SIG_IGNdo? - When does
signal()returnSIG_ERR? - Why is
sigaction()generally preferred oversignal()?
33. sigaction()
The sigaction() function provides a reliable and
portable mechanism for installing signal handlers.
Unlike signal(), it offers greater control over signal
handling behavior and is the preferred POSIX interface.
34. Why Use sigaction()?
- Provides consistent POSIX behavior.
- Allows signal masking during handler execution.
- Supports configurable handler behavior through flags.
- Can retrieve the previous signal disposition.
- Preferred for new UNIX/Linux applications.
35. struct sigaction
The structure specifies how a process should respond when a particular signal is delivered.
36. sa_handler
The sa_handler member specifies the function to execute when
the signal is delivered.
It may also be assigned SIG_DFL or
SIG_IGN.
37. sa_mask
The sa_mask member specifies additional signals that are
temporarily blocked while the signal handler is executing.
The delivered signal itself is normally blocked during execution of its
handler unless the SA_NODEFER flag is used.
38. sa_flags
The sa_flags field controls optional signal-handling
behavior.
| Flag | Purpose |
|---|---|
| SA_RESTART | Restart certain interrupted system calls when possible. |
| SA_SIGINFO | Use an extended signal handler with additional information. |
| SA_NODEFER | Do not automatically block the delivered signal during its handler. |
| SA_RESETHAND | Restore the default disposition after one handler invocation. |
39. sigemptyset()
The sigemptyset() function initializes a signal set so that it contains no signals.
This is commonly used before selectively adding signals to the set.
40. sigfillset()
The sigfillset() function initializes a signal set so that it contains all blockable signals.
This causes all blockable signals to be added to the signal set.
41. Installing a sigaction() Handler
The example installs a handler for SIGINT using the POSIX
signal interface.
42. sigaction() Execution Flow
43. Interview Questions
- Why is
sigaction()preferred oversignal()? - What is the purpose of
sa_handler? - What does
sa_maskcontrol? - What is the purpose of
sa_flags? - What is the difference between
sigemptyset()andsigfillset()? - What does
SA_RESTARTdo? - When would
SA_SIGINFObe useful?
44. Signal Sets (sigset_t)
A signal set is a collection of signals represented by
the sigset_t data type.
Signal sets are used to block, unblock, and manipulate groups of
signals.
45. Why are Signal Sets Needed?
Many signal-related operations require working with multiple signals at the same time. Instead of manipulating signals individually, UNIX uses signal sets.
46. sigemptyset()
The sigemptyset() function initializes a signal set so that it contains no signals.
47. sigfillset()
The sigfillset() function initializes a signal set with all blockable signals.
48. sigaddset()
The sigaddset() function adds a signal to an existing signal set.
49. sigdelset()
The sigdelset() function removes a signal from a signal set.
50. sigismember()
The sigismember() function determines whether a signal belongs to a signal set.
51. What is a Signal Mask?
Every process has a signal mask. The signal mask specifies which signals are currently blocked from being delivered to the process. Blocked signals become pending until they are later unblocked (except for signals that cannot be blocked).
52. sigprocmask()
The sigprocmask() function examines or changes the calling thread's signal mask. In a single-threaded process, this is effectively the process signal mask.
53. Blocking Signals
The example blocks delivery of SIGINT.
54. Unblocking Signals
Previously blocked signals become eligible for delivery after they are unblocked. If a pending signal is no longer blocked, it may be delivered according to the POSIX signal rules.
55. Replacing the Signal Mask
The existing signal mask can be completely replaced.
SIG_SETMASK replaces the current signal mask with the
specified signal set.
56. Signal Mask Execution Flow
57. Interview Questions
- What is a
sigset_t? - Why are signal sets used?
- What is the purpose of
sigaddset()? - What does
sigdelset()do? - How does
sigismember()work? - What is a signal mask?
- What is the difference between
SIG_BLOCK,SIG_UNBLOCK, andSIG_SETMASK? - What happens when a blocked signal is generated?
58. Pending Signals
When a signal is generated but cannot be delivered immediately because it is currently blocked, it becomes a pending signal. The signal remains pending until it is unblocked and eligible for delivery.
59. Why Do Pending Signals Exist?
Pending signals allow a process to temporarily delay signal delivery while executing critical sections of code. This prevents interruption during operations that must complete without interference.
60. sigpending()
The sigpending() function retrieves the set of signals that are currently pending for the calling process or thread.
The returned signal set can be examined using
sigismember().
61. Example: Checking Pending Signals
This example checks whether SIGINT is currently pending.
62. pause()
The pause() function suspends the calling process until a signal is delivered whose disposition causes execution of a signal handler or terminates the process.
63. Limitation of pause()
Using pause() directly can introduce race conditions.
A signal may be delivered after a program checks for an event but before
it calls pause(), causing the process to wait indefinitely
for another signal.
64. sigsuspend()
The sigsuspend() function temporarily replaces the
calling thread's signal mask and suspends execution until a signal is
delivered.
It provides an atomic operation that avoids the race condition
associated with separately changing the signal mask and calling
pause().
65. Why is sigsuspend() Safer?
The signal mask replacement and suspension occur as one atomic operation. No signal can be delivered in the small interval between unblocking signals and entering the waiting state.
66. Typical sigsuspend() Sequence
This sequence allows a program to safely wait for a signal after finishing a critical section.
67. pause() vs sigsuspend()
| pause() | sigsuspend() |
|---|---|
| Simply waits for a signal | Atomically changes mask and waits |
| Can suffer race conditions | Avoids the race window |
| No temporary signal mask | Uses a temporary signal mask |
| Simple interface | Preferred for reliable waiting |
68. Pending Signal Execution Flow
69. Interview Questions
- What is a pending signal?
- Why do pending signals exist?
- What is the purpose of
sigpending()? - How can a program determine whether a signal is pending?
- What does
pause()do? - Why can
pause()introduce race conditions? - How does
sigsuspend()avoid race conditions? - What happens to the original signal mask after
sigsuspend()returns?
70. Reliable Signals
Modern POSIX systems provide reliable signal handling
through interfaces such as sigaction().
Reliable signals ensure predictable behavior when installing handlers,
blocking signals, and restoring signal dispositions.
Applications should use sigaction() instead of
signal() for portable and reliable signal handling.
71. Interrupted System Calls
A signal may be delivered while a process is blocked inside a system
call such as read(), write(), or
accept().
Depending on the signal handling configuration and the specific system
call, the call may return early with an error instead of completing.
72. EINTR Error
If a system call is interrupted by a signal and is not automatically
restarted, it may fail with the error code
EINTR (Interrupted system call).
Applications should detect this condition and determine whether to retry
the operation.
73. SA_RESTART
The SA_RESTART flag requests that certain interrupted
system calls be automatically restarted after the signal handler
returns, when supported by the implementation.
74. Reentrant Functions
A reentrant function can safely be interrupted and called again before the previous invocation has completed. Signal handlers should avoid calling functions that are not reentrant, because doing so can lead to undefined behavior.
75. Async-Signal-Safe Functions
POSIX defines a set of functions that are safe to call from within a signal handler. These are known as async-signal-safe functions. Only these functions should be called directly from a signal handler.
| Generally Safe Examples |
|---|
| _exit() |
| write() |
| kill() |
| signal-safe POSIX functions |
Functions such as printf() are generally not
async-signal-safe and should be avoided inside signal handlers.
76. alarm()
The alarm() function schedules the delivery of
SIGALRM after a specified number of seconds.
The example schedules a SIGALRM approximately five seconds
later unless the alarm is cancelled or replaced.
77. Cancelling an Alarm
An outstanding alarm can be cancelled by passing zero to
alarm().
This cancels any previously scheduled alarm for the process.
78. sleep()
The sleep() function suspends execution for up to the requested number of seconds.
If a signal is caught before the requested interval expires,
sleep() returns early and reports the number of seconds
remaining.
79. alarm() vs sleep()
| alarm() | sleep() |
|---|---|
| Schedules SIGALRM | Suspends execution |
| Returns immediately | Blocks the caller |
| Generates a signal later | No signal generated by the function itself |
| Used for timers | Used for delays |
80. alarm() Execution Flow
81. Interview Questions
- What are reliable signals?
- What happens when a signal interrupts a system call?
- What does
EINTRindicate? - What is the purpose of
SA_RESTART? - What is a reentrant function?
- Why should only async-signal-safe functions be called from a signal handler?
- What signal is generated by
alarm()? - How can a pending alarm be cancelled?
- How does
sleep()behave when interrupted by a signal?
82. kill()
The kill() system call sends a specified signal to a
process or a group of processes.
Despite its name, kill() can send any signal, not only
termination signals.
83. Parameters of kill()
| Parameter | Description |
|---|---|
| pid | Target process or process group |
| sig | Signal to send |
The meaning of pid depends on its value. For example, a
positive PID targets a specific process, while certain special values
target process groups as defined by POSIX.
84. Example: Sending SIGTERM
This requests that the target process terminate gracefully using its
current disposition for SIGTERM.
85. Example: Sending SIGKILL
This sends SIGKILL, which immediately terminates the target
process. The process cannot catch, ignore, or block this signal.
86. Signals Between Processes
Signals provide a lightweight mechanism for one process to notify another process that an event has occurred. Unlike pipes or message queues, signals carry notification rather than general-purpose data.
87. Signal Permissions
A process may send signals only when permitted by the operating system's access control rules. Generally, a process must have appropriate permission to signal the target process.
Permission checks help prevent unauthorized processes from interfering with others.
88. pause() Review
The pause() function suspends execution until a signal is
caught or the process is terminated by a signal.
89. POSIX Real-Time Signals
POSIX defines an additional range of real-time signals beyond the traditional UNIX signal set.
- Queued instead of merged.
- Delivered in priority order defined by POSIX.
- Can carry application-defined values using POSIX interfaces.
Detailed real-time signal programming is beyond the core APUE signal chapter and is typically covered in advanced POSIX programming references.
90. sigqueue() (POSIX Extension)
The POSIX sigqueue() function allows a process to send a
real-time signal together with application-defined data.
This interface is part of the POSIX real-time extensions and is not covered in detail by APUE.
91. Traditional Signals vs Real-Time Signals
| Traditional Signals | Real-Time Signals |
|---|---|
| Multiple identical pending signals may be merged | Each queued signal is retained |
| Limited notification information | Can include application-defined data |
| Classic UNIX mechanism | POSIX real-time extension |
92. Interview Questions
- Why is the function named
kill()even though it can send many different signals? - What is the purpose of
kill()? - What is the difference between sending
SIGTERMandSIGKILL? - Can every process send signals to every other process?
- What is the purpose of
pause()? - What are real-time signals?
- How do traditional signals differ from real-time signals?
- What additional capability does
sigqueue()provide?
93. Signal Programming Best Practices
- Prefer
sigaction()oversignal(). - Keep signal handlers as short as possible.
- Call only async-signal-safe functions inside handlers.
- Use
volatile sig_atomic_tfor variables shared between normal code and signal handlers. - Block signals while updating critical shared data.
- Check for
EINTRwhen calling blocking system calls. - Use
sigsuspend()instead ofpause()when waiting for signals after modifying the signal mask.
94. Common Signal Programming Mistakes
| Mistake | Consequence |
|---|---|
| Calling printf() inside a handler | Undefined behavior |
| Ignoring EINTR | Unexpected system call failures |
| Using signal() for portable applications | Less predictable behavior than sigaction() |
| Long-running signal handlers | Reduced responsiveness |
| Sharing ordinary global variables with handlers | Race conditions |
| Forgetting to initialize signal sets | Incorrect signal masking |
95. Debugging Signals
Several standard UNIX utilities help observe and test signal behavior.
| Command | Purpose |
|---|---|
| ps | Display running processes |
| kill | Send signals to processes |
| kill -l | List supported signals |
| strace | Trace system calls and signal delivery (Linux) |
96. Complete Signal Lifecycle
97. Important Signal APIs
| Function | Purpose |
|---|---|
| signal() | Install a basic signal disposition |
| sigaction() | Install a reliable POSIX signal handler |
| kill() | Send a signal to a process or process group |
| raise() | Send a signal to the calling process |
| abort() | Generate SIGABRT |
| alarm() | Schedule delivery of SIGALRM |
| pause() | Wait until a signal is delivered |
| sigpending() | Retrieve pending signals |
| sigprocmask() | Modify the calling thread's signal mask |
| sigsuspend() | Atomically replace the signal mask and wait |
99. Advanced Interview Questions
- Explain the complete lifecycle of a UNIX signal.
- Why is
sigaction()preferred oversignal()? - What is the difference between pending and blocked signals?
- How does
sigsuspend()prevent race conditions? - What is
EINTR, and how should applications handle it? - What is the purpose of
SA_RESTART? - Why should only async-signal-safe functions be called from a signal handler?
- Explain the purpose of
sigprocmask(). - What is the role of
sigpending()? - Compare
SIGTERMandSIGKILL. - Can every signal be ignored? Explain.
- What is the difference between traditional and POSIX real-time signals?
- How does
alarm()differ fromsleep()? - What happens if multiple identical traditional signals are generated while blocked?
- Describe the purpose of
volatile sig_atomic_tin signal handling.
Concept Mastery Assessment — Module 21
Verify your conceptual understanding with 12 targeted technical assessment questions. Instant feedback and explanations are provided for every choice.