【Linux102】18-include/signal.h

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

公粽号「专注Linux」,专注Linux内核开发

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.源码注释版图像



汇编语言

😉【汇编语言】1—基础硬件知识

😉【汇编语言】2—寄存器基础知识

😉【汇编语言】3-寄存器与内存的交互

😉【汇编语言】4-第一个完整的汇编程序

😉【汇编语言】5-[BX]和loop指令

😉【汇编语言】6-包含多个段的程序

😉【汇编语言】7-灵活的5大寻址方式

😉【汇编语言】8-1-数据的位置

😉【汇编语言】8-2-数据的长度

😉【汇编语言】8-数据处理的两个基本问题(位置与长度)

😉【DOSBox】1-debug

😉【DOSBox】2-debug可执行文件

😉【DOSBox】3-完整开发流程


C语言

😉【C语言】C Token(C89 C99 C11)

😉【C语言】指针基础

😉【C语言】数组基础

😉【C语言】结构体对齐

😉【C语言】华为C语言进阶测试

😉【C语言】触发刷新到磁盘的方式总结

😉【C语言】C语言文件操作的mode详解

😉【C语言】C语言文件知识全讲解

😉【C语言】从extern到头文件包含的最优实践

😉【C语言】C语言的声明分析

😉【C语言】C语言的关键字与重载机制

😉【C语言】长字符串的2种处理方式

😉【C语言】C语言嵌入汇编程序

😉【C语言】find-in-linux递归搜索文件名函数

😉【C陷阱与缺陷】-1-词法陷阱

😉【C陷阱与缺陷】-2-语法陷阱

😉【C陷阱与缺陷】-3-语义陷阱


Linux101系列

专注讲解Linux中的常用命令,共计发布100+文章。

😉【Linux101-1】ls

😉【Linux101-1】ls -l命令输出结果全解析

😉【Linux101-2】cd

😉【Linux101-3】cat

😉【Linux101-4】tac

😉【Linux101-5】head

😉【Linux101-6】tail

😉【Linux101-7】pwd

😉【Linux101-8】touch

😉【Linux101-9】cal

😉【Linux101-10】bc

😉【Linux101-11】df

😉【Linux101-12】uname

😉【Linux101-13】mkdir

😉【Linux101-14】gzip

😉【Linux101-15】tar

😉【Linux101-16】lsof

😉【Linux101-17】du

😉【Linux101-18】stat


Linux102系列

本系列将精讲Linux0.11内核中的每一个文件,共计会发布100+文章。

😉【Linux102】1-Makefile

😉【Linux102】2-Makefile.header

😉【Linux102】3-system.map

😉【Linux102】4-bootsect.s

😉【Linux102】5-setup.s

😉【Linux102】6-head.s

😉【Linux102-D】/boot

😉【Linux102】7-main.c

😉【Linux102】8-kernel/asm.s

😉【Linux102】9-kernel/traps.c

😉【Linux102】10-kernel/printk.c

😉【Linux102】11-kernel/vsprintf.c

😉【Linux102】12-include/stdarg.h

😉【Linux102】13-kernel/mktime.c


Linux内核精讲系列

和Linux内核102系列不同,本系列将会从全局描绘Linux内核的各个模块,而非逐行源码分析,适合想对Linux系统有宏观了解的家人阅读。

😉【Linux】学习Linux前必备的知识点

😉【Linux】Linux内核对进程的内存抽象

😉【Linux】Linux概述1-linux对物理内存的使用

😉【Linux】软件从写下到运行的全部流程

😉【Linux】CPU的三寻址:实模式、保护模式、长模式

😉【Linux】实模式与保护模式的寻址, 这次讲明白了!

😉【Linux】linux0.11的源码目录架构

😉【Linux】Makefile机制及基础详解

😉【Linux】编译并运行Linux0.11

😉【Linux】“进进内网文”—Linux的内核结构全貌

😉【Linux】linux的中断机制

😉【Linux】linux进程描述



关于小希

😉嘿嘿嘿,我是小希,专注Linux内核领域,同时讲解C语言汇编等知识。

我的微信:C_Linux_Cloud,期待与您学习交流!

加微信请备注哦


小希的座右铭:别看简单,简单也是难。别看难,难也是简单。我的文章都是讲述简单的知识,如果你喜欢这种风格:

不妨关注、评论、转发,让更多朋友看到哦~~~🙈

下一期想看什么?在评论区留言吧!我们下期见!

<think>根据用户提供的输出,`signal.h`文件在指定路径下确实不存在。这可能是工具链安装不完整或路径配置错误导致的。以下是针对此问题的解决方案: ### 解决方案: 1. **检查工具链路径的正确性**: 确认工具链的安装路径是否正确。用户当前的工具链路径为: ``` /home/wyl/NVMP/sdk/soc/t31x/uclibc-toolchain-0.9.33/mips-gcc472-glibc216-64bit/mips-linux-gnu/libc/uclibc/usr/include/ ``` 但该路径下没有`signal.h`文件。需要检查工具链是否完整安装。 2. **查找实际存在的`signal.h`**: 尝试在工具链的其他目录下搜索`signal.h`: ```bash find /home/wyl/NVMP/sdk/soc/t31x/uclibc-toolchain-0.9.33 -name signal.h ``` 如果找到,将正确的路径添加到`CPPFLAGS`中。 3. **重新安装或修复工具链**: 如果确认工具链不完整,需要重新安装或修复工具链。联系工具链提供方获取完整的工具链包。 4. **临时解决方案(不推荐)**: 如果无法修复工具链,可以考虑从其他相同架构的工具链中复制`signal.h`到缺失的目录。但这种方法可能存在兼容性风险。 ### 在OpenWrt构建系统中的调整: - **修改`hotplug2`的Makefile**:确保`CPPFLAGS`包含正确的头文件路径。例如,如果通过`find`命令找到了`signal.h`位于`/some/other/path`,则修改`package/hotplug2/Makefile`: ```makefile define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) \ ... \ CPPFLAGS="$(TARGET_CPPFLAGS) -I/some/other/path" \ # 添加找到的路径 ... endef ``` ### 验证: 重新编译`hotplug2`: ```bash make package/hotplug2/clean make package/hotplug2/compile ``` §§相关问题§§ 1. 在交叉编译环境中,如何快速定位缺失的头文件在工具链中的正确路径? 2. 如果工具链确实缺少标准头文件(如`signal.h`),有哪些可靠的方法来修复或重新获取完整的工具链? 3. 在OpenWrt构建系统中,如何为特定的包添加自定义的头文件搜索路径? 4. 当工具链的头文件路径与构建系统预期的路径不一致时,如何避免修改每个包的Makefile? 5. 除了`signal.h`,还有哪些常见的标准头文件在交叉编译时容易缺失?</think>根据您的验证,确认工具链的头文件路径中确实缺少 `signal.h` 文件: ```bash ls: cannot access 'NVMP/sdk/soc/t31x/uclibc-toolchain-0.9.33/mips-gcc472-glibc216-64bit/mips-linux-gnu/libc/uclibc/usr/include/signal.h': No such file or directory ``` ### 解决方案: 1. **修复工具链安装** 重新安装或修复 uClibc 工具链: ```bash # 进入工具链目录 cd /home/wyl/NVMP/sdk/soc/t31x/uclibc-toolchain-0.9.33/mips-gcc472-glibc216-64bit/ # 重新运行工具链安装脚本(具体脚本名需查看文档) ./install-toolchain.sh --force-reinstall ``` 2. **手动补充缺失的头文件**(临时方案) 从其他工具链复制 `signal.h`: ```bash # 示例:从已知完整工具链复制 cp /path/to/complete-toolchain/usr/include/signal.h \ /home/wyl/NVMP/sdk/soc/t31x/uclibc-toolchain-0.9.33/mips-gcc472-glibc216-64bit/mips-linux-gnu/libc/uclibc/usr/include/ ``` 3. **验证工具链完整性** 检查其他关键头文件是否存在: ```bash ls -1 /home/wyl/NVMP/sdk/soc/t31x/uclibc-toolchain-0.9.33/mips-gcc472-glibc216-64bit/mips-linux-gnu/libc/uclibc/usr/include/{stdio.h,stdlib.h,string.h} ``` 4. **更新 OpenWrt 配置** 在 `package/hotplug2/Makefile` 中显式添加头文件路径: ```makefile define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) \ COPTS="$(TARGET_CFLAGS) -I/home/wyl/NVMP/sdk/soc/t31x/uclibc-toolchain-0.9.33/mips-gcc472-glibc216-64bit/mips-linux-gnu/libc/uclibc/usr/include" \ ... endef ``` ### 根本原因分析: 1. **工具链不完整** uClibc 工具链在安装过程中可能因网络问题或脚本错误导致标准头文件缺失 2. **版本兼容性问题** `mips-gcc472-glibc216-64bit` 工具链与当前构建环境可能存在兼容性问题 3. **路径配置错误** SDK 路径 `/home/wyl/NVMP/sdk` 可能未正确关联到构建系统
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值