信号生产
关于信号篇,本只想写一篇,但发现把它想简单了,内容不多,难度极大.整理了好长时间,理解了为何<<深入理解linux内核>>要单独为它开一章,原因有二
- 信号相关的结构体多,而且还容易搞混.所以看本篇要注意结构体的名字和作用.
- 系统调用太多了,涉及面广,信号的来源分硬件和软件.相当于软中断和硬中断,这就会涉及到汇编代码,但信号的处理函数又在用户空间,CPU是禁止内核态执行用户态代码的,所以运行过程需在用户空间和内核空间来回的折腾,频繁的切换上下文.
信号思想来自Unix,它老人家已经五十多岁了,但很有活力,许多方面几乎没发生大的变化.信号可以由内核产生,也可以由用户进程产生,并由内核传送给特定的进程或线程(组),若这个进程定义了自己的信号处理程序,则调用这个程序去处理信号,否则则执行默认的程序或者忽略.
信号为系统提供了一种进程间异步通讯的方式,一个进程不必通过任何操作来等待信号的到达。事实上,进程也不可能知道信号到底什么时候到达。一般来说,只需用户进程提供信号处理函数,内核会想方设法调用信号处理函数,网上查阅了很多的关于信号的资料.个人想换个视角去看信号.把异步过程理解为生产者(安装和发送信号)和消费者(捕捉和处理信号)两个过程
信号分类
每个信号都有一个名字和编号,这些名字都以SIG
开头,例如SIGQUIT
、SIGCHLD
等等。
信号定义在signal.h头文件中,信号名都定义为正整数。
具体的信号名称可以使用kill -l
来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。不过kill
对于信号0有特殊的应用。啥用呢? 可用来查询进程是否还在. 敲下 kill 0 pid
就知道了.
信号分为两大类:可靠信号与不可靠信号,前32种信号为不可靠信号,后32种为可靠信号。
- 不可靠信号: 也称为非实时信号,不支持排队,信号可能会丢失, 比如发送多次相同的信号, 进程只能收到一次. 信号值取值区间为1~31;
- 可靠信号: 也称为实时信号,支持排队, 信号不会丢失, 发多少次, 就可以收到多少次. 信号值取值区间为32~64
信号来源
信号来源分为硬件类和软件类:
- 硬件类
- 用户输入:比如在终端上按下组合键
ctrl+C
,产生SIGINT
信号; - 硬件异常:CPU检测到内存非法访问等异常,通知内核生成相应信号,并发送给发生事件的进程;
- 软件类
- 通过系统调用,发送signal信号:
kill()
,raise()
,sigqueue()
,alarm()
,setitimer()
,abort()
-
kill
命令就是一个发送信号的工具,用于向进程或进程组发送信号.例如:kill 9 PID
(SIGKILL
)来杀死PID
进程. - sigqueue():只能向一个进程发送信号,不能向进程组发送信号;主要针对实时信号提出,与sigaction()组合使用,当然也支持非实时信号的发送;
- alarm():用于调用进程指定时间后发出SIGALARM信号;
- setitimer():设置定时器,计时达到后给进程发送SIGALRM信号,功能比alarm更强大;
- abort():向进程发送SIGABORT信号,默认进程会异常退出。
- raise():用于向进程自身发送信号;
信号与进程的关系
主要是通过系统调用 sigaction
将用户态信号处理函数注册到PCB保存.所有进程的任务都共用这个信号注册函数sigHandler
,在信号的消费阶段内核用一种特殊的方式’回调’它.
解读
- 每个信号都对应一个位. 信号从1开始编号 [1 ~ 64] 对应
sigShare
的[0 ~ 63]位,所以中间会差一个.记住这点,后续代码会提到. -
sigHandler
信号处理函数的注册过程,由系统调用sigaction
(用户空间) ->OsSigAction
(内核空间)完成绑定动作.
信号与任务的关系
解读
- 系列篇已多次说过,进程只是管理资源的容器,真正让cpu干活的是任务
task
,所以发给进程的信号最终还是需要分发给具体任务来处理.所以能想到的是关于任务部分会更复杂. -
context
信号处理很复杂的原因在于信号的发起在用户空间,发送需要系统调用,而处理信号的函数又是用户空间提供的, 所以需要反复的切换任务上下文.而且还有硬中断的问题,比如 ctrl + c ,需要从硬中断中回调用户空间的信号处理函数,处理完了再回到内核空间,最后回到用户空间.没听懂吧,我自己都说晕了,所以需要专门的一篇来说清楚信号的处理问题.本篇不展开说. -
sig_cb
结构体是任务处理信号的结构体,要响应,屏蔽哪些信号等等都由它完成,这个结构体虽不复杂,但是很绕,很难搞清楚它们之间的区别.笔者是经过一番痛苦的阅读理解后才明白各自的含义.并想通过用打比方的例子试图让大家明白. - 以下用追女孩打比方理解.任务相当于某个男,没错说的就是屏幕前的你,除了苦逼的码农谁会有耐心能坚持看到这里.64个信号对应64个女孩.允许一男同时追多个女孩,女孩也可同时被多个男追.女孩也可以主动追男的.理解如下:
-
waitList
等待信号的任务链表,上面挂的是因等待信号而被阻塞的任务.众男在排队追各自心爱的女孩们,处于无所事事的挂起的状态,等待女孩们的出现. -
sigwaitmask
任务在等待的信号集合,只有这些信号能唤醒任务.相当于列出喜欢的各位女孩,只要出现一位就能让你满血复活. -
sigprocmask
指任务对哪些信号不感冒.来了也不处理.相当于列出不喜欢的各位女孩,请她们别来骚扰你,嘚瑟. -
sigPendFlag
信号到达但并未唤醒任务.相当于喜欢你的女孩来追你,但她不在你喜欢的列表内,结果是不搭理人家继续等喜欢的出现. -
sigFlag
记录不屏蔽的信号集合,相当于你并不反感的女孩们.记录来过的那些女孩(除掉你不喜欢的).
信号发送过程
用户进程调用kill()
的过程如下:
流程
- 通过 系统调用
kill
陷入内核空间 - 因为是用户态进程,使用
OS_USER_KILL_PERMISSION
权限发送信号
- 鉴权之后进程轮询任务组,向目标任务发送信号.这里分三种情况:
-
SIGKILL
信号,将所有等待任务唤醒,拉入就绪队列等待被调度执行,并情况信号等待集 - 非
SIGKILL
信号时,将通过sigwaitmask
和sigprocmask
过滤,找到一个任务向它发送信号OsTcbDispatch
.
代码细节
- 如果是
SIGKILL
信号,让spcb
的所有任务执行SigProcessKillSigHandler
函数,查看旗下的所有任务是否又在等待这个信号的,如果有就将任务唤醒,放在就绪队列等待被调度执行.
- 非
SIGKILL
信号,让spcb
的所有任务执行SigProcessSignalHandler
函数
解读
- 函数的意思是,当进程中有多个任务在等待这个信号时,发送信号给第一个等待的任务
awakenedTcb
. - 如果没有任务在等待信号,那就从不屏蔽这个信号的任务集中随机找一个
receivedTcb
接受信号. - 只要不屏蔽
unblockedTcb
就有值,随机的. - 如果上面的都不满足,信号发送给
defaultTcb
. - 寻找发送任务的优先级是
awakenedTcb
>receivedTcb
>unblockedTcb
>defaultTcb
信号相关函数
信号集操作函数
- sigemptyset(sigset_t *set):信号集全部清0;
- sigfillset(sigset_t *set): 信号集全部置1,则信号集包含linux支持的64种信号;
- sigaddset(sigset_t *set, int signum):向信号集中加入signum信号;
- sigdelset(sigset_t *set, int signum):向信号集中删除signum信号;
- sigismember(const sigset_t *set, int signum):判定信号signum是否存在信号集中。
信号阻塞函数
- sigprocmask(int how, const sigset_t *set, sigset_t *oldset)); 不同how参数,实现不同功能
- SIG_BLOCK:将set指向信号集中的信号,添加到进程阻塞信号集;
- SIG_UNBLOCK:将set指向信号集中的信号,从进程阻塞信号集删除;
- SIG_SETMASK:将set指向信号集中的信号,设置成进程阻塞信号集;
- sigpending(sigset_t *set)):获取已发送到进程,却被阻塞的所有信号;
- sigsuspend(const sigset_t *mask)):用mask代替进程的原有掩码,并暂停进程执行,直到收到信号再恢复原有掩码并继续执行进程。
经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?
为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。
《鸿蒙 (Harmony OS)开发学习手册》(共计892页)
如何快速入门?
1.基本概念
2.构建第一个ArkTS应用
3.……
开发基础知识:
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……
基于ArkTS 开发
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……
鸿蒙开发面试真题(含参考答案)
OpenHarmony 开发环境搭建
《OpenHarmony源码解析》
- 搭建开发环境
- Windows 开发环境的搭建
- Ubuntu 开发环境搭建
- Linux 与 Windows 之间的文件共享
- ……
- 系统架构分析
- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ……
OpenHarmony 设备开发学习手册
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。