传递及捕获信号
该函数在返回用户态时才会被调用
- static void fastcall do_signal(struct pt_regs *reg)
-
{
-
siginfo_t info;
-
int signr;
-
struct k_sigaction ka;
-
sigset_t *oldset;
-
if(!user_mode(regs))
-
return;
-
//修复信号栈,保存阻塞信号的位掩码
-
if(test_thread_flags(TIF_RESTORE_SIGMASK))
-
oldset = ¤t->saved_sigmask;
-
else
-
oldset = ¤t->blocked;
-
//获取信号的处理函数
-
signr = get_signal_to_deliver(&info,&ka,regs,NULL);
-
if(signr > 0) {
-
if(unlikely(current->thread.debugreg[7]))
-
set_debugreg(current->thread.debugreg[7],7);
-
//具体调用信号处理函数执行
-
if(handle_signal(signr,&info,&ka,oldset,regs) == 0)
-
{
-
if(test_thread_flag(TIF_RESOTRE_SIGMASK))
-
clear_thread_flag(TIF_RESTORE_SIGMASK);
-
}
-
return;
-
}
-
if(regs->orig_eax >= 0) {
-
switch(regs->eax) {
-
case -ERESTARTNOHAND:
-
case -ERESTARTSYS:
-
case -ERESTARTNOINTR:
-
regs->eax = regs->orig_eax;
-
regs->eip -= 2;
-
break;
-
case -ERESTART_RESTARTBLOCK:
-
regs->eax = __NR_restart_syscall;//对该系统调用进行重启
-
regs->eip -= 2;
-
break;
-
}
-
}
-
if(test_thread_flag(TIF_RESTORE_SIGMASK)) {
-
clear_thread_flag(TIF_RESTORE_SIGMASK);
-
sigprocmask(SIG_SETMASK,¤t->saved_sigmask,NULL);
-
}
-
}
而get_signal_to_deliver源代码如下:
- int get_signal_to_deliver(siginfo_t *info,struct k_sigaction *return_ka,struct pt_regs *regs,void *cookie)
-
{
-
…..
-
relock:
-
spin_lock_irq(¤t->sighand->siglock);
-
for(;;)
-
{
-
struct k_sigaction *ka;
-
if(unlikely(current->signal->group_stop_count > 0)
-
&& handle_group_stop())
-
goto relock;
-
//从私有悬挂队列或共享队列中摘下一个信号
-
signr = dequeue_signal(current,mask,info);
-
if(signr) break;
-
…....
-
ka = ¤t->sighand->action[signr-1];
-
if(ka->sa.sa_handler == SIG_IGN)//如果信号被忽略,直接丢弃
-
continue;
-
if(ka->sa.sa_handler != SIG_DFL)//返回该信号的处理函数
-
{
-
*return_ka = *ka;
-
if(ka->sa.sa_flags & SA_ONESHOT)
-
ka->sa.sa_handler = SIG_DFL;
-
break;
-
}
-
//接受进程为其他进程,但为内核缺省进程,主要
-
//为:SIGCONT,SIGCHILD,SIGWINCH,SIGURG
-
if(sig_kernel_ignore(signr))
-
continue;
-
//如果接受进程为init时
-
if(is_global_init(current))
-
continue;
-
//信号为:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
-
//SIGSTOP:发送进程停止信号(不能捕获或忽略)
-
//SIGTSTP:交互式停止信号
-
//SIGTTIN/SIGTTOU:后台进程组的进程从终端读/写内容
-
if(sig_kernel_stop(signr)) {
-
if(signr != SIGSTOP) {
-
spin_unlock_irq(¤t->sighand->siglock);
-
//只要和父进程处于同一回话中就不为孤儿进程
-
if(is_current_pgrp_orphaned())
-
goto relock;
-
spin_lock_irq(¤t->sighand->siglock);
-
}
-
//停止整个线程组
-
if(likely(do_signal_stop(signr))) {
-
goto relock;
-
}
-
continue;
-
}
-
.....
-
}}
系统调用的重新执行
如果进程处于TASK_INTERRUPTIBLE状态,并且某个进程向它发送了一个信号,那么内核不完成系统调用就把进程设置为TASK_RUNNING状态,当切换回用户态时信号被传递给进程.当出现这种情况,系统没有完成它的工作,但返回EINTR,ERESTARTNOHAND,
ERESTART_RESTARTBLOCK,ERESTARTSYS或ERESTARTNOINTR错误码
- static int handle_signal(unsigned long sig,siginfo_t *info,
-
struct k_sigaction *ka,sigset_t *oldset,struct pt_regs *regs)
-
{
-
int ret;
-
//在最初系统调用时,eax保存系统调用号,执行完成返回系统调用结果
-
if(regs->orig_eax >=0) {
-
switch(regs->eax) {//根据系统调用返回结果,进行重启调用前的恢复
-
case -ERESTART_RESTARTBLOCK:
-
case -ERESTARTNOHAND:
-
regs->eax = -EINTR;
-
break;
-
case -ERESTARTSYS:
-
if(!(ka->sa.sa_flags & SA_RESTART)) {
-
regs->eax = -EINTR;
-
break;
-
}
-
case -ERESTARTNOINTR:
-
regs->eax = regs->orig_eax;
-
regs->eip -= 2;
-
}
-
}
-
…...
-
//创建用户态调用栈
-
if(ka->sa.sa_flags & SA_SIGINFO)
-
ret = setup_rt_frame(sig,ka,info,oldset,regs);
-
else ret = setup_frame(sig,ka,oldset,,regs);
-
if(ret == 0) {
-
spin_lock_irq(¤t->sighand->siglock);
-
sigorsets(¤t->blocked,¤t->blocked,
-
&ka->sa.sa_mask);
-
if(!(ka->sa.sa_flags & SA_NODEFER))
-
sigaddset(¤t->blocked,sig);
-
recalc_sigpending();
-
spin_unlock_irq(¤t->sighand->siglock);
-
}
-
return ret;
-
}
参考资料
1.linux-2.24.3内核源码
2.深入理解Linux内核(第三版)
3.APUE
阅读(1976) | 评论(0) | 转发(0) |