现在我们转入代码看是如何处理的:
static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs)
{
int ret;
//在执行系统调用的时候,可能被信号给中断了.
//要根据返回值判断是否可以重启系统调用
/* Are we from a system call? */
if (regs->orig_eax >= 0) {
/* If so, check system call restarting.. */
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;
}
/* fallthrough */
case -ERESTARTNOINTR:
regs->eax = regs->orig_eax;
regs->eip -= 2;
}
}
/*
* If TF is set due to a debugger (PT_DTRACE), clear the TF flag so
* that register information in the sigcontext is correct.
*/
//如果处于跟踪状态
//就像进行中断处理程序,关闭中断一样
if (unlikely(regs->eflags & TF_MASK)
&& likely(current->ptrace & PT_DTRACE)) {
current->ptrace &= ~PT_DTRACE;
regs->eflags &= ~TF_MASK;
}
/* Set up the stack frame */
//SA_SIGINFO:为信号处理提供额外的信息
//建立帧结构
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);
//SA_NODEFER:在执行信号处理函数的时候,不屏弊信号
if (!(ka->sa.sa_flags & SA_NODEFER))
//如果没有定义SA_NODEFER.那屏弊掉当前信号
sigaddset(¤t->blocked,sig);
//更新TIF_SIGPENDING 标志位
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
}
return ret;
}
首先,也要恢复被中断的系统调用.然后,再调用setup_frame()或者是setup_rt_frame().setup_rt_frame()是有跟实时信号有关的.在这里以setup_frame()为例进行分析.代码如下:
static int setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs)
{
void __user *restorer;
struct sigframe __user *frame;
int err = 0;
int usig;
//取得在用户空间栈中存放frame的位置
frame = get_sigframe(ka, regs, sizeof(*frame));
//检查是否是可写的
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
//在有的执行域里.信号的数值可能不一样,因此,需要转换一下
//signal_invmap:信号转换表
usig = current_thread_info()->exec_domain
&& current_thread_info()->exec_domain->signal_invmap
&& sig < 32
? current_thread_info()->exec_domain->signal_invmap[sig]
: sig;
err = __put_user(usig, &frame->sig);
if (err)
goto give_sigsegv;
//保存当前内核栈里保存的用户空间的硬件环境
err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
if (err)
goto give_sigsegv;
//set:这里是表示进程以前的信号掩码
//在extramask里保存以前的信号掩码
if (_NSIG_WORDS > 1) {
//将set->sig的高32位存于extramask中
err = __copy_to_user(&frame->extramask, &set->sig[1],
sizeof(frame->extramask));
if (err)
goto give_sigsegv;
}
if (current->binfmt->hasvdso)
restorer = (void *)VDSO_SYM(&__kernel_sigreturn);
else
restorer = (void *)&frame->retcode;
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
/* Set up to return from userspace. */
//使frame->pretcode指向 frame->retcode
err |= __put_user(restorer, &frame->pretcode);
/*
* This is popl %eax ; movl $,%eax ; int $0x80
*
* WE DO NOT USE IT ANY MORE! It's only left here for historical
* reasons and because gdb uses it as a signature to notice
* signal handler stack frames.
*/
//frame->retcode:执行完信号处理函数后的下一条指令
//这里构建了一次系统调用.调用号是__NR_sigreturn
err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
if (err)
goto give_sigsegv;
/* Set up registers for signal handler */
//因为regs结构已经保存在frame之中了.这里可以随意的修改
//修改用户空间的栈指针位置,指向frame
regs->esp = (unsigned long) frame;
//返回到用户空间的下一条指令
//即返回到用户空间后,执行信号处理程序
regs->eip = (unsigned long) ka->sa.sa_handler;
regs->eax = (unsigned long) sig;
regs->edx = (unsigned long) 0;
regs->ecx = (unsigned long) 0;
//用户空间的段寄存器都是__USER_DS
//这里是为了防止有意外的修改
regs->xds = __USER_DS;
regs->xes = __USER_DS;
regs->xss = __USER_DS;
regs->xcs = __USER_CS;
/*
* Clear TF when entering the signal handler, but
* notify any tracer that was single-stepping it.
* The tracer may want to single-step inside the
* handler too.
*/
//清除跟踪标志
//就像是处理中断处理程序,清除中断标志位一样
regs->eflags &= ~TF_MASK;
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->eip, frame->pretcode);
#endif
return 0;
give_sigsegv:
force_sigsegv(sig, current);
return -EFAULT;
}
get_sigframe()代码如下:
static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
{
unsigned long esp;
/* Default to using normal stack */
esp = regs->esp;
/* This is the X/Open sanctioned signal stack switching. */
//用户指定了栈位置
//sas__ss_flags:判断指定的栈位置是否为于当前栈的下部有效空间
//进程的地址空间中,栈空间占据着最上部
if (ka->sa.sa_flags & SA_ONSTACK) {
if (sas_ss_flags(esp) == 0)
//获得栈顶位置
esp = current->sas_ss_sp + current->sas_ss_size;
}
/* This is the legacy signal stack switching. */
//从Unix中遗留的调用.为了保持兼容性而设置
//不提 倡使用
else if ((regs->xss & 0xffff) != __USER_DS &&
!(ka->sa.sa_flags & SA_RESTORER) &&
ka->sa.sa_restorer) {
esp = (unsigned long) ka->sa.sa_restorer;
}
//为frame结构空出位置
esp -= frame_size;
/* Align the stack pointer according to the i386 ABI,
* i.e. so that on function entry ((sp + 4) & 15) == 0. */
//按照i386 ABI规范.对齐栈指针
esp = ((esp + 4) & -16ul) - 4;
return (void __user *) esp;
} |