Fundamentals 16 min read

Mastering Unix Signals: From Basics to Custom Handlers

This article explains what Unix signals are, categorizes reliable and unreliable signals, describes how they are generated by hardware and software, and details registration, blocking, pending states, handling functions, and practical code examples for custom signal processing.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Mastering Unix Signals: From Basics to Custom Handlers

1. What is a signal?

A signal is essentially a software interrupt.

Example:

Enter a command to start a foreground process in the shell.

Press Ctrl‑C, generating a hardware interrupt.

If the CPU is executing the process, it switches from user mode to kernel mode to handle the interrupt.

The terminal driver translates Ctrl‑C into a SIGINT signal and records it in the process's PCB.

Before returning to user space, the kernel sees the pending SIGINT, whose default action is to terminate the process, so the process ends without returning to user code.

In this example, the hardware interrupt caused by Ctrl‑C is a signal that can only be sent to the foreground process; appending '&' runs a command in the background. The shell can run one foreground process and many background processes, but only the foreground process receives signals like Ctrl‑C.

2. Types of signals

Use the command kill -l to list signals.

Unreliable signals: numbers 1‑31 (may be lost). Reliable signals: numbers 34‑64 (cannot be lost).

Signal table
Signal table

SIGHUP (1): Hangup detected on controlling terminal or death of controlling process.

SIGINT (2): Interrupt from keyboard (Ctrl‑C).

SIGQUIT (3): Quit from keyboard (Ctrl‑\), generates a core dump.

SIGABRT (6): Abort signal from abort(3), generates a core dump.

SIGKILL (9): Kill signal, cannot be blocked, ignored, or caught.

SIGSEGV (11): Invalid memory reference, generates a core dump.

SIGPIPE (13): Broken pipe, terminates the process.

SIGCHLD (17): Child stopped or terminated (default ignored).

SIGSTOP (19): Stop process.

SIGTSTP (20): Stop typed at terminal (Ctrl‑Z).

For detailed actions, see man 7 signal.

3. Signal generation

3.1 Hardware-generated signals

Hardware generates signals via terminal key presses, e.g.:

Ctrl‑C → SIGINT (2)

Ctrl‑Z → SIGTSTP (20)

Ctrl‑\ → SIGQUIT (3)

3.2 Software-generated signals

Software generates signals by calling system functions.

kill function

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
/* pid: process ID, sig: signal number, returns 0 on success, -1 on error */

kill command: kill -[signal] pid abort: void abort(void); – sends signal 6 to the calling process.

alarm: unsigned int alarm(unsigned int seconds); – schedules SIGALRM after the given seconds.

4. Signal registration

Signal registration differs for reliable and unreliable signals and involves a bitmap and a sigqueue.

Signal registration diagram
Signal registration diagram

4.1 Unreliable signal registration

When a process receives an unreliable signal:

Set the corresponding bit in the signal bitmap to 1.

Add a sigqueue node to the sigqueue; if a node for that signal already exists, do not add another.

4.2 Reliable signal registration

When a process receives a reliable signal:

Set the corresponding bit in the bitmap to 1 and always add a sigqueue node, regardless of existing nodes.

5. Signal deregistration

5.1 Unreliable signal deregistration

Clear the signal’s bit in the bitmap and remove its node from the sigqueue.

5.2 Reliable signal deregistration

Remove the node from the sigqueue; if no other node for that signal remains, clear the bitmap bit, otherwise leave the bit set.

6. Signal blocking

6.1 How signals are blocked

Blocking a signal sets its bit in the block bitmap to 1. The signal can still be registered but will not be delivered until unblocked.

6.2 sigprocmask

Function prototype:

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how: operation type
SIG_BLOCK: set signals to blocked
SIG_UNBLOCK: unblock signals
SIG_SETMASK: replace the block bitmap
set: bitmap to apply
oldset: previous bitmap

Example: block all signals and then kill the process with kill -9:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void signcallback(int signumber){ printf("change the signal %d
", signumber); }
int main(){
    sigset_t set, oldset;
    sigfillset(&set); // block all signals
    sigprocmask(SIG_BLOCK, &set, &oldset);
    while(1){ sleep(1); }
    return 0;
}

Result: signals have no effect; the process must be killed with kill -9.

7. Pending signals

7.1 Concept of pending

After a signal is generated, it remains pending until delivered. A blocked signal stays pending until unblocked.

7.2 sigpending

Prototype: int sigpending(sigset_t *set); – retrieves the set of pending signals.

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void signalcallback(int signumber){ printf("change signumber %d
", signumber); }
void printsigset(sigset_t *set){
    for(int i=0;i<32;i++) putchar(sigismember(set,i)?'1':'0');
}
int main(){
    signal(2, signalcallback);
    signal(10, signalcallback);
    sigset_t set, oldset, pending;
    sigfillset(&set);
    sigprocmask(SIG_BLOCK, &set, &oldset);
    while(1){
        sigpending(&pending);
        printsigset(&pending);
        sleep(1);
    }
    return 0;
}

8. Signal handling methods

Signal handling diagram
Signal handling diagram

Each signal has two flags (blocked and pending) and a function pointer for its action.

8.1 signal function

Changes a signal’s handling action.

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
/* signum: signal number, handler: new action */

Internally, signal calls sigaction.

8.2 sigaction function

Gets or sets the action for a specific signal.

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

Structure:

void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);

8.3 Custom signal handling flow

Custom handler flow
Custom handler flow

The task_struct contains a struct sighand_struct.

The sighand_struct holds an array of struct k_sigaction actions.

The _sighandler_t sa_handler in the array stores the handling method; changing it customizes signal handling.

9. Signal catching

9.1 Conditions for catching

If a signal’s action is a user-defined function, the kernel calls it when the signal is delivered—this is signal catching.

9.2 Catching process

Catching flow
Catching flow

When returning from kernel to user mode, do_signal is invoked. If a signal is pending, the kernel executes the handler instead of the original user code, then returns via sigreturn.

10. Common signal set operations

int sigemptyset(sigset_t *set);   // clear all bits
int sigfillset(sigset_t *set);    // set all bits
int sigaddset(sigset_t *set, int signum);   // add a signal
int sigdelset(sigset_t *set, int signum);   // remove a signal
int sigismember(const sigset_t *set, int signum); // test membership

11. SIGCHLD signal

Sent to a parent when a child terminates; default action is ignore. Ignoring it can cause zombie processes. You can customize its handling:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
void signcallback(int signumber){ printf("change signal %d
", signumber); wait(NULL); }
int main(){
    signal(17, signcallback); // SIGCHLD
    pid_t pid = fork();
    if(pid < 0){ perror("fork"); return -1; }
    else if(pid == 0){
        printf("I am child
");
        sleep(1);
        exit(12);
    } else {
        while(1) sleep(1);
    }
    return 0;
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CLinuxSystem ProgrammingUnixsignals
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.