Linux102系列会详细讲解Linux0.11版本中的102个文件,本文讲解linux0.11的第18个文件
include/signal.h的文件源码。
一、信号基础扫盲
说人话:我是操作系统发出的信号,我来了,进程要先停下工作处理我,再处理其他工作。
0.什么是计算机信号?
在开启源码阅读之前,我们要明白什么是计算机信号?
在计算机领域,信号(Signal) 是一种由操作系统或进程发出的异步通知机制,用于告知目标进程发生了某个特定事件,需要其暂停当前工作并处理该事件。
1.核心本质
信号是进程间(或操作系统与进程间)的 “极简通信方式”—— 它不传递复杂数据,仅传递 “某个事件发生” 的 “通知编号”,类似现实中的 **“紧急暗号”**或 “中断提醒”。
2.关键特性
①异步性:
信号的产生和传递是 “突发” 的,目标进程无法预知信号何时到来,只能提前注册 “信号处理函数” 以应对。
例如,用户按下 Ctrl+C 时,操作系统会立即向当前前台进程发送信号,进程会暂停当前代码执行,转而去执行对应的处理逻辑。
②有限的事件集合:
操作系统定义了一组固定的信号类型(每个信号对应一个整数编号),每个编号代表一种特定事件。例如 Linux/UNIX 中:
| 信号 | 对应事件 |
|---|---|
| SIGINT(编号 2) | 用户按下 Ctrl+C,请求进程中断。 |
| SIGKILL(编号 9) | 强制终止进程(进程无法忽略或自定义处理)。 |
| SIGSEGV(编号 11) | “段错误”,进程访问了非法内存地址(如空指针 dereference)。 |
| SIGALRM(编号 14) | 定时器到期通知(如 alarm() 函数设置的定时)。 |
③进程的处理方式:
进程收到信号后,默认有 3 种处理行为(可通过代码自定义部分行为):
| 默认处理(SIG_DFL) | 执行操作系统预设的动作,如 SIGINT 默认终止进程、SIGSEGV 默认终止并生成 “核心转储文件”(用于调试)。 |
| 忽略信号(SIG_IGN) | 对信号不做任何处理(少数信号如 SIGKILL、SIGSTOP 无法忽略)。 |
| 自定义处理(信号处理函数) | 进程提前注册一个函数,收到信号时自动执行该函数(如捕获 SIGINT 后,先保存数据再终止,而非直接退出)。 |
二、源码中的信号实现
1.include/signal.h 的主要作用
本文件定义了信号处理相关数据结构,是理解Linux内核的信号机制的必知前提。
2.源码注释版本
在阅读源码之前,可以先看看这篇针对C语言声明分析的经典好文: 😉【C语言】C语言的声明分析 ,抽丝剖茧,循序渐进,并给出完整的signal的声明分析实例,不然第一次遇到signal函数的声明很抽象:
#ifndef _SIGNAL_H
#define _SIGNAL_H
#include <sys/types.h>
// 基础类型定义(符合 POSIX 信号处理规范)
typedef int sig_atomic_t; // 原子信号类型(保证读写原子性)
typedef unsigned int sigset_t;// 信号集合类型(32位,对应常见32种信号) /* 32 bits */
#define _NSIG 32 // 系统支持的最大信号数(0~31,共32个)
#define NSIG _NSIG // 暴露给用户的信号数量宏
// 常用信号宏(POSIX 标准信号,1~31 为常规信号)
#define SIGHUP 1 // 挂起信号(终端断开)
#define SIGINT 2 // 中断信号(Ctrl+C)
#define SIGQUIT 3 // 退出信号(Ctrl+\,带 core dump)
#define SIGILL 4 // 非法指令
#define SIGTRAP 5 // 调试陷阱
#define SIGABRT 6 // 异常终止(abort() 触发)
#define SIGIOT 6 // 同 SIGABRT(历史兼容)
#define SIGUNUSED 7 // 未使用(保留)
#define SIGFPE 8 // 浮点异常
#define SIGKILL 9 // 强制杀死(无法捕获/忽略)
#define SIGUSR1 10 // 用户自定义信号1
#define SIGSEGV 11 // 段错误(非法内存访问)
#define SIGUSR2 12 // 用户自定义信号2
#define SIGPIPE 13 // 管道断裂(写已关闭的管道)
#define SIGALRM 14 // 定时器信号(alarm() 触发)
#define SIGTERM 15 // 终止信号(优雅退出,可捕获)
#define SIGSTKFLT 16 // 栈溢出(特定架构)
#define SIGCHLD 17 // 子进程状态变化(退出/停止)
#define SIGCONT 18 // 继续执行(之前被暂停)
#define SIGSTOP 19 // 暂停执行(无法捕获/忽略)
#define SIGTSTP 20 // 终端暂停(Ctrl+Z,可捕获)
#define SIGTTIN 21 // 后台进程读终端(非法操作)
#define SIGTTOU 22 // 后台进程写终端(非法操作)
/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
// sigaction 标志宏(部分实现,贴近 POSIX 头文件规范)
#define SA_NOCLDSTOP 1 // 子进程停止时不触发 SIGCHLD
#define SA_NOMASK 0x40000000 // 旧版掩码标志(部分系统兼容)
#define SA_ONESHOT 0x80000000 // 信号处理函数仅生效一次
// sigprocmask 操作宏(控制信号掩码)
#define SIG_BLOCK 0 // 阻塞指定信号/* for blocking signals */
#define SIG_UNBLOCK 1 // 解除阻塞指定信号/* for unblocking signals */
#define SIG_SETMASK 2 // 直接设置信号掩码/* for setting the signal mask */
// 默认处理(系统默认逻辑)
#define SIG_DFL ((void (*)(int))0) /* default signal handling */
// 忽略信号(不做处理)
#define SIG_IGN ((void (*)(int))1) /* ignore signal */
// sigaction 结构体(POSIX 标准结构,用于高级信号处理)
struct sigaction {
void (*sa_handler)(int);// 信号处理函数(或 SIG_DFL/SIG_IGN)
sigset_t sa_mask; // 信号掩码(处理信号时额外阻塞的信号)
int sa_flags; // 标志位(如 SA_NOCLDSTOP)
void (*sa_restorer)(void);// 历史兼容字段(现代系统少用)
};
// 注册信号处理函数
// 这是最经典的信号声明了,之前专门写过一篇文章来分析这个声明
// signal是一个参数依次为int、返回void类型的,参数为int的函数指针的,
// 返回值为返回void类型的、参数为int的函数指针的函数。
void (*signal(int _sig, void (*_func)(int)))(int);
// 显然返回值类型为:去掉函数名和紧跟在其后的参数列表,即void (*)(int);,那显然是一个函数指针!
// void (*a())(int);
// int a();
// 信号处理核心函数声明(符合 POSIX 接口)
int raise(int sig);// 向自身发送信号
int kill(pid_t pid, int sig);// 向指定进程/进程组发信号
int sigaddset(sigset_t *mask, int signo);// 向信号集合添加信号
int sigdelset(sigset_t *mask, int signo);// 从信号集合删除信号
int sigemptyset(sigset_t *mask);// 清空信号集合
int sigfillset(sigset_t *mask); // 填满信号集合(包含所有信号)
// 检查信号是否在集合中(1=是,0=否,-1=错) /* 1 - is, 0 - not, -1 error */
int sigismember(sigset_t *mask, int signo);
int sigpending(sigset_t *set);// 获取当前pending(待处理)的信号集合
int sigprocmask(int how, sigset_t *set, sigset_t *oldset);// 控制信号掩码
int sigsuspend(sigset_t *sigmask);// 临时替换掩码并等待信号
int sigaction(int sig, struct sigaction *act, struct sigaction *oldact); // 高级信号处理
#endif /* _SIGNAL_H */
3.源码完整版
#ifndef _SIGNAL_H
#define _SIGNAL_H
#include <sys/types.h>
typedef int sig_atomic_t;
typedef unsigned int sigset_t; /* 32 bits */
#define _NSIG 32
#define NSIG _NSIG
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGUNUSED 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
#define SA_NOCLDSTOP 1
#define SA_NOMASK 0x40000000
#define SA_ONESHOT 0x80000000
#define SIG_BLOCK 0 /* for blocking signals */
#define SIG_UNBLOCK 1 /* for unblocking signals */
#define SIG_SETMASK 2 /* for setting the signal mask */
#define SIG_DFL ((void (*)(int))0) /* default signal handling */
#define SIG_IGN ((void (*)(int))1) /* ignore signal */
struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
void (*signal(int _sig, void (*_func)(int)))(int);
int raise(int sig);
int kill(pid_t pid, int sig);
int sigaddset(sigset_t *mask, int signo);
int sigdelset(sigset_t *mask, int signo);
int sigemptyset(sigset_t *mask);
int sigfillset(sigset_t *mask);
int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */
int sigpending(sigset_t *set);
int sigprocmask(int how, sigset_t *set, sigset_t *oldset);
int sigsuspend(sigset_t *sigmask);
int sigaction(int sig, struct sigaction *act, struct sigaction *oldact);
#endif /* _SIGNAL_H */
4.源码图像版

6.源码注释版图像


专注讲解Linux中的常用命令,共计发布100+文章。
本系列将精讲Linux0.11内核中的每一个文件,共计会发布100+文章。
😉【Linux102】11-kernel/vsprintf.c
😉【Linux102】12-include/stdarg.h
和Linux内核102系列不同,本系列将会从全局描绘Linux内核的各个模块,而非逐行源码分析,适合想对Linux系统有宏观了解的家人阅读。
😉【Linux】Linux概述1-linux对物理内存的使用
关于小希
😉嘿嘿嘿,我是小希,专注Linux内核领域,同时讲解C语言、汇编等知识。
我的微信:C_Linux_Cloud,期待与您学习交流!

加微信请备注哦
小希的座右铭:
别看简单,简单也是难。别看难,难也是简单。我的文章都是讲述简单的知识,如果你喜欢这种风格:
下一期想看什么?在评论区留言吧!我们下期见!

Linux0.11中include/signal.h源码解析
790

被折叠的 条评论
为什么被折叠?



