信号对ERESTARTSYS的处理

一、问题

在看nanosleep的时候,看到这个函数返回的错误码是-ERESTART_RESTARTBLOCK,所以就比较好奇的看了这个地方的代码,然后看到是在do_signal和handle_signal函数中判断了这些错误码的意义。然后就看一下它们具体的意义。

二、信号的发送

sys_kill(int pid, int sig)---》》》kill_something_info---》》》kill_pid_info---》》》group_send_sig_info----》》》__group_send_sig_info

 /* Short-circuit ignored signals.  */
 if (sig_ignored(p, sig))
  return ret;

 if (LEGACY_QUEUE(&p->signal->shared_pending, sig))
  /* This is a non-RT signal and we already have one queued.  */
  return ret;
这里的内核可忽略信号有

static int sig_ignored(struct task_struct *t, int sig)
{
 void __user * handler;

 /*
  * Tracers always want to know about signals..
  */
 if (t->ptrace & PT_PTRACED)
  return 0;

 /*
  * Blocked signals are never ignored, since the
  * signal handler may change by the time it is
  * unblocked.
  */
 if (sigismember(&t->blocked, sig))
  return 0;

 /* Is it explicitly or implicitly ignored? */
 handler = t->sighand->action[sig-1].sa.sa_handler;
 return   handler == SIG_IGN ||
  (handler == SIG_DFL && sig_kernel_ignore(sig));
}

也就是

#define sig_kernel_ignore(sig)
  (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_IGNORE_MASK))

这些信号如果没有安装信号处理函数,那么这个地方发送信号也不会将线程唤醒。

但是我们现在假设是其它的信号。

三、信号的执行

static void fastcall do_signal(struct pt_regs *regs)---》》》get_signal_to_deliver

  signr = dequeue_signal(current, mask, info);
……

 ka = &current->sighand->action[signr-1];
  if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
   continue;
  if (ka->sa.sa_handler != SIG_DFL) {
   /* 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 */
  }

  /*
   * Now we are doing the default action for this signal.
   */
  if (sig_kernel_ignore(signr)) /* Default is nothing. */ 走到这里,说明这个信号是SIG_DFL,否则将会在上面直接退出
   continue;

假设对于其它的不能忽略信号,例如SIGPIPE信号,此时就会执行到上面的SIG_IGN的时候进入continue,从而这个信号被消耗掉,从而执行到下面的返回,最终这个函数返回的信号值可能为零。

signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 if (signr > 0
) {
  /* Reenable any watchpoints before delivering the
   * signal to user space. The processor register will
   * have been cleared if the watchpoint triggered
   * inside the kernel.
   */
  if (unlikely(current->thread.debugreg[7]))
   set_debugreg(current->thread.debugreg[7], 7);

  /* Whee!  Actually deliver the signal.  */
  if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
   /* a signal was successfully delivered; the saved
    * sigmask will have been stored in the signal frame,
    * and will be restored by sigreturn, so we can simply
    * clear the TIF_RESTORE_SIGMASK flag */
   if (test_thread_flag(TIF_RESTORE_SIGMASK))
    clear_thread_flag(TIF_RESTORE_SIGMASK);
  }

  return;
 }

 /* Did we come from a system call? */
 if (regs->orig_eax >= 0) { 只有返回值为零,才会执行下面的函数,说明信号被忽略了或者说是缺省处理
  /* Restart the system call - no handlers present */
  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;
  }
 }
对于未忽略的信号,处理流程为


 /* 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
只有这种情况下一定会处理信号,其它的都没有保证。也就是说,只要安装了信号处理函数,那么很可能会都不会重新执行系统调用
  }
 }

原文地址:https://www.cnblogs.com/tsecer/p/10485729.html