linux进程实时信号处理,linux信号处理总结

中断是硬件与操作系统之间的一种通信方式;信号是进程间(内核进程+用户进程)的一种通信方式。信号的实现类似中断,所以很多人都称其为软中断

标准信号与实时信号

0-31 这 32 个信号称为标准信号。

从 32 到 63 之间的 32 个信号称为实时信号。

可以通过 man 7

signal 查看对“标准信号”和“实时信号”详细的描述。

信号排队

每个进程拥有一个信号等待队列。在 task_struct 中有一个 struct sigpending pending 域,

就是进程的信号等待队列。

当向一个进程发送信号时,信号会先被送入进程的信号等待队列,然后等到进程被调度到去处理信号的时候,会从信号

等待队列中依次取出信号进行处理。

标准信号不能排队,而实时信号可以排队:

假设进程屏蔽了一个标准信号,当给它连续发送多个相同

的标准信号,则只有第一个被放入进程的信号等待队列中,后续的都被丢弃。

假设进程屏蔽了一个实时信号,当给它连续发送多个相同的实时信号,则所有

的信号都被放入进程的信号接收队列中。

实时信号是在 POSIX.4 实时信号扩展中定义的。

信号屏蔽

进程可以屏蔽它不想接收的信号。

在 task_struct 中有一个 block 域,指定了进程要屏蔽的信号集合。

屏蔽信号

带来的影响:

1、

当向一个进程投递信号时,如果发现进程屏蔽了此信号,则即使此进程处于睡眠状态,也不唤醒它。(否则睡眠的进程会被唤醒)。

2、

当进程开始处理它的信号等待队列的时候,对于被屏蔽的信号,不做处理。所以这些信号会一直待在等待队列中,直到进程解开对相应信号的屏蔽,才能被处

理。(按照以上理解,也就是虽说某些信号被屏蔽,但是这个信号会被保存在pending里,只是在进程从内核返回处理信号时不处理被阻塞(屏蔽)的信号,

直到该信号被解除屏蔽)

是 KILL 和 TERM 这两种信号是不能屏蔽的。

发送信号的处理过程

用户空间可以通过 kill()  或 sigqueue() 两个系统调用来向一个进程发送信号。

内核空间的入口是 sys_kill():

sys_kill()

==>  kill_something_info()  ==>  kill_proc_info()  ==>

send_sig_info()  ==>  deliver_signal() ==> send_signal()

1、    首先,根据 PID 找到对应的目标进程。 这是通过

find_task_by_pid() 实现的。

2、    如果目标进程对信号的处理行为是“忽略”,则无需投递

3、    对于标准信号,如果前面已经有一个相同信号到达,进程还没来得及处理,则不再投递,信号丢失。

4、

否则,信号被挂在进程的信号等待队列中。

5、    如果进程屏蔽了此信号,则不唤醒此进程

6、

否则,如果此进程处于 INTERUPABLE 状态,则唤醒此进程。

signal_wake_up()

==>  wake_up_process()

7、    如果进程处于其它状态,则不做处理。

执行信号处理函数

进程检测信号的时机

1、    从系统调用、中断处理或者异常处理返回到用户空间的前夕。这和进程调度是同一个时机

arch/i386/kernel/entry.S 中,有如下汇编代码:

ENTRY(ret_from_sys_call)

cli                # need_resched and signals atomic test

cmpl $

0

,need_resched(

%

ebx)

jne reschedule

cmpl $

0

,sigpending(

%

ebx)

jne signal_return

可以看到,在返回到用户空间前夕,会检查 task_struct 中的 sigpending

域,如果非0,说明有信号需要处理,转而去处理信号。

2、

给进程投递完信号后,如果发现进程处于睡眠(INTERUPABLE)状态,则唤醒此进程,而进程会检查是否有信号等待处理。

signal_wake_up()

{

if (t->state &

TASK_INTERRUPTIBLE) {

wake_up_process(t);

return;

}

}

问题

1、    在执行信号处理程序的时候,是否要屏蔽此信号?

在进入某个信号处理 函数前,必须暂时屏蔽掉此信号。

当handle_signal() 执行完以后,堆栈已经被更换,接下来就会进入用户空间,执行信号处理函数。

在handle_signal() 的最后,通过sigaddset(&current->blocked,sig);

暂时屏蔽了对此信号。

2、我们知道,当进程进入睡眠(可打断)状态,在此期间收到另一个信号,那么,进程会被唤醒,执行新的信号处理程

序。

但是,如果进程处于运行状态,且不执行任何系统调用,在此期间向它发送信号,则此进程不会立刻处理此信号。那么此进程什么时候能检查到有信号要处理了?

答案是在时钟中断返回的时候!!!

前面说了,检查信号的时机是从系统调用、中断或异常处理返回用户空间的前夕,因此,时钟中断返回的时候,也是检查信号的时机。

由于时钟中断频繁发生,因此信号总会及时得到处理。

3、

在执行信号处理程序期间,虽然不会再被相同的信号打断,但仍然可能被其它信号打断。

假设进程处理 A 信号,那么它首先需要把 A

信号从信号队列中取出,然后再去执行相应的信号处理函数,在执行过程中,如果又被另一个信号B打断,则不会再去处理 A,因为 A

已经被从信号队列中取出了。同样,必须先取下 B,然后再做处理,所以在此期间,如果又被 C 打断,则不会再处理到 B 。当 C

处理完毕后,又返回到 B 中,处理完 B,又返回到 A。

对信号队列的处理

假设有多个信号在队列上等待。

在一次调度时机中,进程检查它的信号等待队列,对于处理方式为 SIG_IGN 和 SIG_DFL

的信号,不用返回到用户空间。对于需要返回到用户空间去执行信号处理函数的情况,在一次调度时机中只处理一个。

http://blog.csdn.net/rstevens/archive/2007/09/27/1803801.aspx

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值