- 论坛徽章:
- 0
|
Unix提供了等待信号的系统调用,sigsuspend就是其中一个,在CU(
[color="#4a664d"]www.chinaunix.net
)上曾经讨论过一个关于该系统调用的问题,这里也做一下解疑。
CU网友讨论的问题的核心就是到底sigsuspend先返回还是signal handler先返回。这个问题Stevens在《Unix环境高级编程》一书中是如是回答的“If a signal is caught and if the signal handler returns, then sigsuspend returns and the signal mask of the process is set to its value before the call to sigsuspend.”,由于sigsuspend是原子操作,所以这句给人的感觉就是先调用signal handler先返回,然后sigsuspend再返回。但其第一个例子这么讲又说不通,看下面的代码:
CU上讨论该问题起于中的该例子:
int main(void) {
sigset_t newmask, oldmask, zeromask;
if (signal(SIGINT, sig_int) == SIG_ERR)
err_sys("signal(SIGINT) error");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
/* block SIGINT and save current signal mask */
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) (1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
大致就是上面这个过程,噢,原来signal handler是原子操作的一部分,而且是在恢复屏蔽字后执行的,所以上面的例子是没有问题的,Stevens说的也没错。由于Linux和Unix的千丝万缕的联系,所以在两个平台上绝大部分的系统调用的语义是一致的。上面的sigsuspend的原子操作也是从《深入理解Linux内核》一书中揣度出来的。书中的描述如下:
The sigsuspend( ) system call puts the process in the TASK_INTERRUPTIBLE state, after having blocked the standard signals specified by a bit mask array to which the mask parameter points. The process will wake up only when a nonignored, nonblocked signal is sent to it. The corresponding sys_sigsuspend( ) service routine executes these statements:
mask &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
spin_lock_irq(¤t->sigmask_lock);
saveset = current->blocked;
siginitset(¤t->blocked, mask);
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
regs->eax = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule( );
if (do_signal(regs, &saveset))
return -EINTR;
}
而最后的do_signal函数调用则是负责调用User Signal Handler的家伙。我想到这CU上的那个问题该被解疑清楚了吧。
added by j4ckl1u::::::::::::::::::::::::::::2.6内核的sigsuspend的实现
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int
sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
mask &= _BLOCKABLE;
spin_lock_irq(¤t->sighand->siglock); //加锁,
current->saved_sigmask = current->blocked; //保存以前的mask
siginitset(¤t->blocked, mask); //将blocked设置为mask
recalc_sigpending(); //监查是否有未决信号
spin_unlock_irq(¤t->sighand->siglock); //解锁
current->state = TASK_INTERRUPTIBLE; //将线程的状态设置为可被信号唤醒的挂起
schedule(); //让出cpu 等待信号的到来
set_thread_flag(TIF_RESTORE_SIGMASK); //设置需要恢复mask标志,什么时候恢复????
return -ERESTARTNOHAND;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/5958/showart_141570.html |
|