Linux信号处理浅析

news2024/11/20 20:42:41

一、信号从发送到被处理经历的过程

1、常见概念

(1) 信号阻塞

阻塞,即被进程拉黑,信号被发送后,分为两种情况,一种是被阻塞了(被拉黑了),一种是没有被阻塞。

(2) 信号未决

在信号被进程处理之前的过程,都可以称为信号未决

(3) 信号递达

信号被进程处理,我们称为信号递达

(4) 信号忽略

进程收到信号后直接忽略,不进行处理,是否还有默认处理呢?(忽略中断信号,验证是否会中断)

(5) 阻塞信号集

指一个进程中当前阻塞而不能够递送给该进程的信号集

(6) 未决信号集

指当前进程未处理的信号集,收到阻塞的信号,未决信号集该信号位会置1,解除阻塞后会置0。

2、信号保存的方式(内核级)

block表:对应的信号是否被阻塞,0表示不阻塞,1表示阻塞

pending表信号是否被收到,0表示未收到该信号,1表示收到该信号

handler表:表示对应信号的处理方式(函数),存放的是函数的地址(函数指针)

3、信号从发送到被处理

第一列表示第 N 号信号,以第二行为例,阻塞信号为 1 ,说明该信号被阻塞了(相当于在进程的黑名单里),后面的未决信号是0还是1都无所谓了

以第四行为例,阻塞信号为0,该信号没有被阻塞,未决信号为1,说明收到这个信号了,对应的处理方式是 sighandler函数,那就会执行该函数

注意:

SIG_DFL(signal default):信号默认处理方式

SIG_IGN(signal ignore):忽略信号
 

总结

先看block,如果block为1,即信号被拉黑,是否收到信号都不重要了

如果block不为1,那就再看pending是否为1,即是否收到信号

二、信号集操作(信号保存)

阻塞信号其实就是要修改block表,但是要怎么修改呢?如果只是传递单个信号,或许可以直接以某种方式告诉OS我希望阻塞哪个信号,但是,如果要修改多个信号呢??OS给出了一种方案来解决传递单个或者多个信号,那就是直接传递位图!!

收到一个信号之后执行信号处理函数,在执行信号处理函数的过程中如果又来了一个相同的信号,那么这个信号将会被阻塞,直到信号处理函数执行完之后,再响应被阻塞的信号,注意如果信号被阻塞期间又收到了该信号,那么多个信号的处理会被合并为1次。

信号集就是用来记录当前收到了哪个信号,会把当前信号的标志位置成“正在处理”,如果此时再收到该信号,那么信号就阻塞等待,使用数据类型sigset_t表示信号集,在Linux中该类型是一个32位无符号整数,这是因为在Linux中定义了32种信号,每一个信号用32位无符号整型变量中的一位来标志,如果该位置为1,那么表示正在处理该信号,如果置为0表示可以处理该信号。

未决信号集保存当前为处理的信号集。

信号屏蔽字又叫阻塞信号集,是指一个进程中当前阻塞而不能够递送给该进程的信号集。每个进程都有一个信号屏蔽字,它规定了当前要阻塞递达到该进程的信号集

1、特定的数据类型sigset_t

既然要传递位图,要用什么来表示位图呢?第一想法是int/uint32_t,不同的操作系统,实现位图的方式可能有所不同,Linux操作系统不光给我们提供了 保存位图的数据类型 sigset_t,还有对应的函数来操作位图(下面说)

——》sigset_t 可以看作是一个信号集,保存着1~31号信号的状态,0表示没收到,1表示收到了

2、操作信号集的函数

(1) sigemptyset函数,清空信号集,全部位置置0。GUN C库中的非标准函数

int  sigemptyset ( sigset_t  *set);

成功返回0,失败返回-1

(2) sigfillset函数:初始化信号集,全部置1。GUN C库中的非标准函数

int  sigfillset( sigset_t  *set);

成功返回0,失败返回-1

(3) sigaddset函数:向信号集中添加一个信号,将对应信号置1。标准函数

假设一开始所有的比特位都是 0(0000 0000 ...),如果我们希望把第二个信号阻塞,那么就需要先把信号集的第二个比特位设置为1(0100 0000....),然后再传给信号阻塞函数

int  sigaddset( sigset_t  *set, int  signum);

 第一个参数是传入信号集的地址,第二个参数是要把哪个位置(信号)设置成1,成功返回0,失败返回-1

(4) sigdelset函数:从信号集中删除一个信号,将对应信号置0。标准函数

(假设前面已经阻塞了2号信号)这个时候的比特位显示为0100 0000....,现在我们不希望阻塞2号信号,那么需要把第二个位置(信号)设置为 0 (0000 0000....)

int  sigdelset( sigset_t  *set, int  signum);

 第一个参数是传入信号集的地址,第二个参数是要把哪个位置(信号)设置成1,成功返回0,失败返回-1

(5) sigismember函数:判断某个信号是否为信号集的成员(判断是否在信号集中)。标准函数

如果对应位置(信号)的比特位为1,说明在信号集中,如果为0,说明不在信号集中

int  sigismember( sigset_t  *set, int  signum);

成功返回1,失败返回0

如果使用sigemptyset()初始化信号集(信号集的所有位置0),此时可以接收到所有的信号

如果使用sigfillset()初始化信号集(信号集的所有位置1),此时屏蔽所有信号,当然SIGKILL和SIGQUIT信号是不能屏蔽的

sigaddset()和sigdelset()的意义在于指定屏蔽某信号或者接收某信号
 

int  sigprocmask (int  how,  const  sigset_t  *restrict set,  sigset_t  *restrict oset);

how取值有下列三个:

SIG_BLOCK :set中包含的是希望阻塞的附加信号,合并set中的信号集

SIG_UNBLOCK:set中包含的是希望解除阻塞的信号,删除set中的信号集

SIG_SETMASK:set中包含的是现有屏蔽字的代替值,替换set中的信号集

若oset是非空指针,则返回进程的当前信号屏蔽字。

若set为空,则进程信号屏蔽字不变,how值无意义。

另外,注意一点,不可以阻塞SIGKILL和SIGSTOP信号。

注意:调用该接口将信号设置为非阻塞时,若该信号已经是阻塞状态,则在该函数返回前马上会发给该线程

int  sigpending ( sigset_t  *set );

此函数通过set返回当前检查未决的信号集。其中的各个信号对于调用进程是阻塞的而不能递送,因而也一定是当前未决的。

signal 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受到了一定的限制。而 POSIX 标准定义的信号处理接口是 sigaction 函数。

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

signum:要操作的信号。

act:要设置的对信号的新处理方式。

oldact:原来对信号的处理方式。

返回值:0 表示成功,-1 表示有错误发生。

struct  sigaction
{
        void (*sa_handler)(int);
        void (*sa_sigaction)(int,  siginfo_t *,  void*);
        sigset_t  sa_mask;
        int  sa_flags;
        void (*sa_restorer)(void);
};

这个结构体中,成员 sa_handler 是一个函数指针,其含义与 signal 函数中的信号处理函数类似。成员sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理函数。在某些系统中,成员 sa_handler 与 sa_sigaction 被放在联合体中,因此使用时不要同时设置。

sa_mask 用来指定在信号处理函数执行期间需要被屏蔽的信号,特别是当某个信号被处理时,它自身会被自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。

sa_flags 用于指定信号处理的行为,它可以是一下值的“按位或”组合。

◆ SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
◆ SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
◆ SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。
◆ SA_NODEFER:一般情况下,当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记,那么在该信号处理函数运行时,内核将不会阻塞该信号。
◆ SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL。
◆ SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。

re_restorer 是一个已经废弃的数据域,不要使用。

可重入函数

一个函数被重入,表示这个函数没有执行完成,由于外部因素或内部调用,又一次进入该函数执行。一个函数要被重入,只有两种情况:

1、多线程同时执行这个函数

2、函数自身(可能经过多层调用之后)调用自身

一个函数可重入,表示这个函数被重入后不会产生任何不良后果。要成人可重入函数必须有以下特定:

1、不使用任何(局部)静态或全局的非const变量

2、不返回任何(局部)静态或全局的非const变量的指针

3、依赖调用方提供参数

4、不依赖任何单个资源的锁

5、不调用任何不可重入的函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1370838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

xilinix 7系列器件生成已加密文件和已经过身份验证的文件

注释 :如需了解更多信息,请参阅《使用加密确保 7 系列 FPGA 比特流的安全》(XAPP1239)。 要生成加密比特流,请在 Vivado IDE 中打开已实现的设计。在主工具栏中,依次选择“Flow” → “Bitstream Settings”(流程 >…

【elfboard linux开发板】11. 版本管理和修改设备树流程(点亮LED)

1. 版本管理 1.1 初始化git仓库 git init 生成一个.git 目录 git config --global user.name 用户名 git config --global user.email 邮箱 1.2 查看.gitignore vim .gitignore 1.3 添加删除到缓存区 git status 查看状态 git add 文件名 git rm 文件名 1.4 提交当前记录 …

.NET Framework 与 .NET Core 与 .NET Standard 之间的差异

介绍 在本文中,我们将探讨 .NET Framework、.NET Core 和 .NET Standard 之间的差异。 .NET Framework 与 .NET Core .NET框架.NET核心 历史 .NET Framework 是 .NET 的第一个实现。 .NET Core 是 .NET 的最新实现。 开源 .NET Framework 的某些组件是开源的。 .N…

在学习爬虫前的准备

1. 写一个爬虫程序需要分几步 获取网页内容。 我们会通过代码给一个网站服务器发送请求,它会返回给我们网页上的内容。 在我们平时使用浏览器访问服务器内容是,本质上也是向服务器发送一个请求,然后服务器返回网页上的内容。只不过浏览器还会…

Spark八:Spark性能优化

Spark性能调优 Spark调优的方法,包括RDD使用、文件读取,partition 学习资料:https://mp.weixin.qq.com/s/caCk3mM5iXy0FaXCLkDwYQ 一、Spark调优之RDD算子调优 1.1 RDD复用 在对RDD进行计算时,要避免相同的算子和计算逻辑下对…

高防服务器、高防 IP 和高防 CDN 之间有什么区别?

网络运营人员最头痛的是什么? 网络攻击无疑名列前茅。一旦企业遭受网络攻击,所面临的损失可能是无法估量的。那么,如何有效地抵御网络攻击呢? 高防 IP、高防 CDN 和高防服务器是当前主流的防御手段。那何为“高防”呢&#xff1…

unity小程序websocket:nginx配置https (wss)转http (ws)及其他问题解决

目录 前言 实际运用场景 处理流程如下 nginx配置ssl和wss 配置过程中遇到的问题 1、无法连接服务器 2、通过IP可以访问,域名却不行 问题描述 解决 3、如何判断该域名是否备案了 前言 为了服务器网络的通用性,我们在实现移动端的游戏转微信小程序…

植物大战僵尸小游戏抖音快手直播搭建弹幕插件教程

植物大战弹幕插件功能介绍 该插件由梦歌技术部团队支持开发,本插件软件通过监测抖音弹幕信息,获取礼物数据触发脚本插件对应的功能; 功能目前基本上已经完善,后期功能会陆续上线支持更新,全新的脚本监测稳定方便实用…

2024年1月9日学习总结

目录 学习目标学习内容联邦学习基础:why, what, howwhy?what?how? 联邦学习的例子——CIFAR-10数据集(分类问题)1、import libararies2、hyper-parameters3、加载并且划分数据4、创建神经网络模型5、helper…

易基因:ChIP-seq等揭示WWOX基因通过上调Myc促进骨肉瘤发生发展的表观调控机制|Cell Death Dis

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 骨肉瘤(Osteosarcoma, OS)是一种高侵袭性骨肿瘤,主要影响儿童和青少年。这种恶性肿瘤与不良临床结果相关,尤其是肺转移。由于其罕见性和生…

【7-zip密码】7-Zip如何取消文件加密的密码

7z压缩包设置了密码,解压的时候就需要输入正确的密码才能顺利解压出文件,正常当我们解压文件或者删除密码的时候,虽然方法多,但是都需要输入正确的密码才能完成。忘记密码就无法进行操作。 那么,忘记了7z压缩包的密码…

Ubuntu20二进制方式安装nginx

文章目录 1.下载nginx安装包2.安装nginx3.安装出现的问题及解决方案错误1:错误2:错误3: 4.常用命令5.知识扩展: 1.下载nginx安装包 nginx官网:http://nginx.org/en/download.html 选择稳定的nginx版本下载。 2.安装ngi…

SWM341系列之SWM34SRET6介绍

SWM341系列的介绍 本文介绍了华芯微特SWM341系列主要性能,和其系列之一的SWM34SRET6-50驱动4.3寸800*480 TFTLCD显示的例程应用。 SWM341系列性能 SWM341是一款基于ARM Cortex-M33的32位微控制器,片上包含精度为 1%以内的 20MHz/40MHz 时钟,最…

Java18:网络编程

一.对象序列化: 1.对象流: ObjectInputStream 和 ObjectOutputStream 2.作用: ObjectOutputSteam:内存中的对象-->存储中的文件,通过网络传输出去 ObjectInputStream:存储中的文件,通过网络传输出去…

状态管理小能手:Cookie 和 Session

1. 引言 大家好,我是小❤,一个漂泊江湖多年的 985 非科班程序员,曾混迹于国企、互联网大厂和创业公司的后台开发攻城狮。 假期抢票的尴尬事件 最近小❤在抢出行的高铁票时,发生了一件尴尬的事情。 这不是临近假期了嘛&#xf…

【数字图像处理】水平翻转、垂直翻转

图像翻转是常见的数字图像处理方式,分为水平翻转和垂直翻转。本文主要介绍 FPGA 实现图像翻转的基本思路,以及使用紫光同创 PGL22G 开发板实现数字图像水平翻转、垂直翻转的过程。 目录 1 水平翻转与垂直翻转 2 FPGA 布署与实现 2.1 功能与指标定义 …

SSM 基础知识点

1. IoC IoC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在 Java 开发中,IoC 意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。 谁控制谁,控制什么&…

Linux网络配置

一、查看网络配置 1、查看网络接口信息ifconfig 1.查看所有活动的网络接口信息 2.查看指定网络接口信息 ifconfig 网络接口 ifconfig -a #显示所有活动及非活动的连接 ifconfig网络接口 ifconfig -a #显示所有活动及非活动的连接 主机的网络接口卡(网卡)通常称为网络接口…

QT上位机开发(动态添加控件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 开发界面的时候,大多数情况下,我们都是推荐优先使用designer来进行界面开发。但凡事总有例外,如果控件本身数量…