专家
公告
财富商城
电子网
旗下网站
登录
免费注册
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux信号机制分析
写评论
嵌入式
【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux信号机制分析
2019-07-13 09:20
发布
生成海报
站内文章
/
嵌入式Linux
17271
0
1028
roserouge
男 |
私信
[复制链接]
举报
写评论
生成海报
Linux
信号机制分析
Sailor_forever
sailing_9806@163.com
转载请注明
http://blog.csdn.net/sailor_8318/archive/2008/09/27/2990077.aspx
【摘要】本文分析了
Linux
内核对于信号的实现机制和应用层的相关处理。首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理。接着分析了内核对于信号的处理流程包括信号的触发
/
注册
/
执行及注销等。最后介绍了应用层的相关处理,主要包括信号处理函数的安装、信号的发送、屏蔽阻塞等,最后给了几个简单的应用实例。
【关键字】软中断信号,
signal
,
sigaction
,
kill
,
sigqueue
,
settimer
,
sigmask
,
sigprocmask
,
sigset_t
1
信号本质
软中断信号(
signal
,又简称为信号)用来通知进程发生了异步事件。在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。
信号是进程间通信机制中唯一的异步通信机制
,
一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。进程之间可以互相通过系统调用
kill
发送软中断信号
。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。信号机制除了基本通知功能外,
还可以传递附加信息。
收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:
第一种是类似中断的处理程序,
对于需要处理的信号,进程可以指定处理函
数,由该函数来处理。
第二种方法是,
忽略某个信号
,对该信号不做任何处理,就象未发生过一样。
第三种方法是,对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止。
进程通过系统调用
signal
来指定进程对某个信号的处理行为。
2
信号的种类
可以从两个不同的分类角度对信号进行分类:
可靠性方面:可靠信号与不可靠信号;
与时间的关系上:实时信号与非实时信号。
2.1
可靠信号与不可靠信号
Linux
信号机制基本上是从
Unix
系统中继承过来的。早期
Unix
系统中的信号机制比较简单和原始,
信号值小于
SIGRTMIN
的信号都是不可靠信号。
这就是
"
不可靠信号
"
的来源。它的主要问题是信号可能丢失。
随着时间的发展,实践证明了
有必要对信号的原始机制加以改进和扩充
。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为
可靠信号,这些信号支持排队,不会丢失
。
信号值位于
SIGRTMIN
和
SIGRTMAX
之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。
Linux
在支持新版本的信号安装函数
sigation()
以及信号发送函数
sigqueue()
的同时,仍然支持早期的
signal()
信号安装函数,支持信号发送函数
kill()
。
信号的可靠与不可靠只与信号值有关,与信号的发送及安装函数无关
。目前
linux
中的
signal()
是通过
sigation()
函数实现的,因此,即使通过
signal()
安装的信号,在信号处理函数的结尾也不必再调用一次信号安装函数。同时,由
signal()
安装的实时信号支持排队,同样不会丢失。
对于目前
linux
的两个信号安装函数:
signal()
及
sigaction()
来说,它们都不能把
SIGRTMIN
以前的信号变成可靠信号(都不支持排队,仍有可能丢失,仍然是不可靠信号)
,而且对
SIGRTMIN
以后的信号都支持排队。这两个函数的最大区别在于,经过
sigaction
安装的信号都能传递信息给信号处理函数,而经过
signal
安装的信号不能向信号处理函数传递信息。对于信号发送函数来说也是一样的。
2.2
实时信号与非实时信号
早期
Unix
系统只定义了
32
种信号,前
32
种信号已经有了预定义值,每个信号有了确定的用途及含义,
并且每种信号都有各自的缺省动作。如按键盘的
CTRL ^C
时
,会产生
SIGINT
信号,对该信号的默认反应就是进程终止。后
32
个信号表示实时信号,等同于前面阐述的可靠信号。这保证了发送的多个实时信号都被接收。
非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。
3
信号处理流程
对于一个完整的信号生命周期
(
从信号发送到相应的处理函数执行完毕
)
来说,可以分为三个阶段:
信号诞生
信号在进程中注册
信号的执行和注销
3.1
信号诞生
信号事件的发生有两个来源:
硬件来源
(
比如我们按下了键盘或者其它硬件故障
)
;软件来源,
最常用发送信号的系统函数是
kill, raise, alarm
和
setitimer
以及
sigqueue
函数,
软件来源还包括一些非法运算等操作。
这里按发出信号的原因简单分类,以了解各种信号:
(
1
)
与进程终止相关的信号。当进程退出,或者子进程终止时,发出这类信号。
(
2
)
与进程例外事件相关的信号。如进程越界,或企图写一个只读的内存区域(如程序正文区),或执行一个特权指令及其他各种硬件错误。
(
3
)
与在系统调用期间遇到不可恢复条件相关的信号。如执行系统调用
exec
时,原有资源已经释放,而目前系统资源又已经耗尽。
(
4
)
与执行系统调用时遇到非预测错误条件相关的信号。如执行一个并不存在的系统调用。
(
5
)
在用户态下的进程发出的信号。如进程调用系统调用
kill
向其他进程发送信号
。
(
6
)
与终端交互相关的信号。如用户关闭一个终端,或按下
break
键等情况。
(
7
)
跟踪进程执行的信号。
Linux
支持的信号列表如下。很多信号是与机器的体系结构相关的
信号值
默认处理动作
发出信号的原因
SIGHUP
1 A
终端挂起或者控制进程终止
SIGINT
2 A
键盘中断(如
break
键被按下)
SIGQUIT
3 C
键盘的退出键被按下
SIGILL
4 C
非法指令
SIGABRT
6 C
由
abort(3)
发出的退出指令
SIGFPE
8 C
浮点异常
SIGKILL 9 AEF Kill
信号
SIGSEGV
11 C
无效的内存引用
SIGPIPE
13 A
管道破裂
:
写一个没有读端口的管道
SIGALRM
14 A
由
alarm(2)
发出的信号
SIGTERM
15 A
终止信号
SIGUSR1 30,10,
16 A
用户自定义信号
1
SIGUSR2 31,12,
17 A
用户自定义信号
2
SIGCHLD 20,17,18 B
子进程结束信号
SIGCONT 19,18,25
进程继续(曾被停止的进程)
SIGSTOP 17,19,23 DEF
终止进程
SIGTSTP 18,20,24 D
控制终端(
tty
)上按下停止键
SIGTTIN 21,21,26 D
后台进程企图从控制终端读
SIGTTOU 22,22,27 D
后台进程企图从控制终端写
处理动作一项中的字母含义如下
A
缺省的动作是终止进程
B
缺省的动作是忽略此信号,将该信号丢弃,不做处理
C
缺省的动作是终止进程并进行内核映像转储(
dump core
),内核映像转储是指将进程数据在内存的映像和进程在内核结构中的部分内容以一定格式转储到文件系统,并且进程退出执行,这样做的好处是为程序员提供了方便,使得他们可以得到进程当时执行时的数据值,允许他们确定转储的原因,并且可以调试他们的程序。
D
缺省的动作是停止进程,进入停止状况以后还能重新进行下去,一般是在调试的过程中(例如
ptrace
系统调用)
E
信号不能被捕获
F
信号不能被忽略
3.2
信号在目标进程中注册
在
进程表的表项中有一个软中断信号域
,该域中每一位对应一个信号。内核给一个进程发送软中断信号的方法,
是在进程所在的进程表项的信号域设置对应于该信号的位。
如果信号发送给一个正在睡眠的进程,
如果进程睡眠在可被中断的优先级上,则唤醒进程;
否则仅设置进程表中信号域相应的位,而不唤醒进程。如果发送给一个处于可运行状态的进程,则只置相应的域即可。
进程的
task_struct
结构中有关于
本进程中未决信号的数据成员:
struct sigpending pending
:
struct sigpending{
struct sigqueue *head, *tail;
sigset_t signal;
};
第三个成员是进程中所有未决信号集
,第一、第二个成员分别指向一个
sigqueue
类型的结构链(称之为
"
未决信号信息链
"
)的首尾,信息链中的每个
sigqueue
结构刻画一个特定信号所携带的信息,并指向下一个
sigqueue
结构
:
struct sigqueue{
struct sigqueue *next;
siginfo_t info;
}
信号在进程中注册指的就是信号值加入到进程的未决信号集
sigset_t signal
(每个信号占用一位)中,并且信号所携带的信息被保留到未决信号信息链的某个
sigqueue
结构中。
只要信号在进程的未决信号集中,表明进程已经知道这些信号的存在,但还没来得及处理,或者该信号被进程阻塞。
当一个实时信号发送给一个进程时,不管该信号是否已经在进程中注册,都会被再注册一次
,因此,信号不会丢失,因此,实时信号又叫做
"
可靠信号
"
。这意味着同一个实时信号可以在同一个进程的未决信号信息链中占有多个
sigqueue
结构(进程每收到一个实时信号,都会为它分配一个结构来登记该信号信息,并把该结构添加在未决信号链尾,即所有诞生的实时信号都会在目标进程中注册)。
当一个非实时信号发送给一个进程时,
如果该信号已经在进程中注册(通过
sigset_t signal
指示
),则该信号将被丢弃,造成信号丢失。
因此,非实时信号又叫做
"
不可靠信号
"
。这意味着
同一个非实时信号在进程的未决信号信息链中,至多占有一个
sigqueue
结构
。
总之信号注册与否,与发送信号的函数(如
kill()
或
sigqueue()
等)以及信号安装函数(
signal()
及
sigaction()
)无关,只与信号值有关(
信号值小于
SIGRTMIN
的信号最多只注册一次
,信号值在
SIGRTMIN
及
SIGRTMAX
之间的信号,只要被进程接收到就被注册)
登录
后发表评论
0条评论
还没有人评论过~
Ta的文章
更多
>>
N76E003 PWM程序及分析2(互补模式&死区插入)
0 个评论
【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux信号机制分析
0 个评论
热门文章
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮