首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

linux进程管理之信号处理(转)(6)

linux进程管理之信号处理(转)(6)

现在我们转入代码看是如何处理的:
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;
}
继承事业,薪火相传
返回列表