分类: LINUX
2011-11-10 14:51:53
Signal 是linux/unix 系统的一种重要的消息机制,与kernel的中断机制类似,对进程进行控制。在kernel中与signal 相关的代码存在于:kernel/signal、arch/**/kernel/signal中,用于管理内核态signal的控制
1. Signal Deliver
Get_signal_to_deliver
if (unlikely(signal->group_stop_count > 0) &&
do_signal_stop(0))
goto relock;
signr = dequeue_signal(current, ¤t->blocked, info); //从当前进程的signal队列中取一个signal,
if (!signr) //在系统中是可能会出现signr为0的情况,(如果不存在SIGIOT,就会定义SIGIOT为0,但什么时候会发送SIGIOT也不去深究了)
break; /* will return 0 */
if (signr != SIGKILL) {
signr = ptrace_signal(signr, info,
regs, cookie);
if (!signr)
continue;
}
在拿出这个信号时,对AlARM信号做了一点特殊处理(略)。接下来就是对取出来的这个信号进行处理:
if (ka->sa.sa_handler == SIG_IGN) /* IGN:直接跳出,原来IGN在kernel里面就pass掉了*/
continue;
if (ka->sa.sa_handler != SIG_DFL) { // 这里就是这次查找的重点了,如果是用户定义的处理信号,则后面的处理也就没有。后面的处理包括:sig_kernel_stop / sig_kernel_coredump,从字面意思上讲即是:停掉进程(包括线程组线程)、转储进程内存镜像。
/* Run the handler. */
*return_ka = *ka;
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
break; /* will return non-zero "signr" value */
}
接下来看看coredump文件的生成:
if (sig_kernel_coredump(signr)) {
if (print_fatal_signals)
print_fatal_signal(regs, info->si_signo);
/*
* If it was able to dump core, this kills all
* other threads in the group and synchronizes with
* their demise. If we lost the race with another
* thread getting here, it set group_exit_code
* first and our do_group_exit call below will use
* that value and ignore the one we pass it.
*/
do_coredump(info->si_signo, info->si_signo, regs);
}
2. 中断处理发生在中断上下文,具有随机性,依赖于底层硬件动作。我们说signal与中断类似,那么这个与中断类似运行在进程上下文的signal是怎么完成其操作的呢?
以mips为例,signal deliver的工作路径为:
do_notify_resume <-- do_signal <--- get_signal_to_deliver
do_notify_resume最终在一组汇编中(entry.S中)
work_notifysig: # deal with pending signals and
# notify-resume requests
move a0, sp
li a1, 0
jal do_notify_resume # a2 already loaded
j resume_userspace
最终被__ret_from_irq、restore_all、syscall_exit_work_partial调用,也就是说信号的发送时机在函数调用、进程切换、中断处理结束的过程中