1. 程式人生 > >信號對ERESTARTSYS的處理

信號對ERESTARTSYS的處理

it is lee can deb gre spa 發送 進入 ant

一、問題

在看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
; 只有這種情況下一定會處理信號,其它的都沒有保證。也就是說,只要安裝了信號處理函數,那麽很可能會都不會重新執行系統調用
}
}

信號對ERESTARTSYS的處理