我正在阅读linux 2.6.11
sys_sigsuspend的实现如下

 34 /*
 35  * Atomically swap in the new signal mask, and wait for a signal.
 36  */
 37 asmlinkage int
 38 sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 39 {
 40         struct pt_regs * regs = (struct pt_regs *) &history0;
 41         sigset_t saveset;
 42
 43         mask &= _BLOCKABLE;
 44         spin_lock_irq(&current->sighand->siglock);
 45         saveset = current->blocked;
 46         siginitset(&current->blocked, mask);
 47         recalc_sigpending();
 48         spin_unlock_irq(&current->sighand->siglock);
 49
 50         regs->eax = -EINTR;
 51         while (1) {
 52                 current->state = TASK_INTERRUPTIBLE;
 53                 schedule();
 54                 if (do_signal(regs, &saveset))
 55                         return -EINTR;
 56         }
 57 }


在ULK3中,作者说


  sigsuspend()系统调用不允许在取消阻塞之后和调用schedule()之前发送信号,因为在该时间间隔内其他进程无法抢占CPU。


在spin_unlock_irq和schedule之间,系统调用可以被中断和抢占,因此其他进程可以有足够的时间发送不受阻塞的信号

但是在这种情况下,信号将丢失,因为在信号交付后将进行处理。

这就是为什么sigsuspend应该是原子的,而不是根据其实现方式。

最佳答案

sigsuspend实现是正确的,但是ULK中的解释似乎具有误导性。

当进程执行内核代码时,该执行永远不会被用户的信号中断。相反,此类信号会累积在当前任务结构内部。在该过程离开内核代码并返回给用户一个的那一刻,所有累积(但未阻塞)的信号都被触发。

schedule()内核的功能检查是否积累了一些信号。如果它们是current->state并且是TASK_INTERRUPTIBLE,则schedule()返回。因此,在schedule()调用之前收集的所有信号都不会丢失。

sigsuspend()系统调用的原子性意味着,如果发出临时不受该调用阻塞的信号,则该调用将确保看到并返回。只需将取消阻塞和检查信号放在同一内核函数中即可轻松实现这种原子性。

关于linux - sys_sigsuspend如何在Linux内核2.6.11中具有原子性?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29838398/

10-16 19:02