Linux:信号处理器可以被抢占吗?

我遇到以下信号处理程序代码存储errnovariables,以便它不会影响主线程的errno处理。

void myhandler(int signo) { int esaved; esaved = errno; write(STDOUT_FILENO, "Got a signal\n", 13); errno = esaved; } 

但是这真的有用吗? 如果另一个线程在write()之后和恢复errno之前检查共享的errnovariables,会发生什么情况? 那个线程由于竞争状态会得到错误的errno值吗?

或者一个信号处理程序相对于一个线程/进程primefaces地执行,所以一旦信号处理程序执行,内核不会安排回线程直到信号处理程序结束?

换句话说 – 一开始,一个信号处理程序执行时不会被下面的中断:

  - 1) Scheduler (process/threads), or - 2) Other signals, or - 3) Hardware interrupt handlers ? 

变量errno是线程特定的,或者更准确地说,在一个线程环境中,是一个线程本地值或每个线程值 – 所以在这个线程中errno做法不会影响其他线程中的errno

保存和恢复errno的代码的目的是为了隐藏myhandler()write()系统调用所设置的任何错误。 但是,如果write()失败,它可能会将errno为一个新的值 – 它不会是零,但是这只是你可以说的 – 但是你要求的代码在write()调用之前恢复了值write()在调用write() ,所以写入发生的事实是“不可见的”,因为它不会影响此线程的errno

信号处理函数本身可能会被信号掩码中的信号所中断,而这些信号正在响应信号。 它也可以被重新安排。 硬件中断也可能发生,但代码将很难注意到这些影响。


在Linux上,你可能会发现/usr/include/bits/errno.h定义了宏errno (用比这里显示的更多的#ifdef代码包装):

 extern int *__errno_location (void) __THROW __attribute__ ((__const__)); # if !defined _LIBC || defined _LIBC_REENTRANT /* When using threads, errno is a per-thread value. */ # define errno (*__errno_location ()) # endif 

信号处理程序确实可以被另一个信号中断(假设它不是首先调用处理程序的信号)。

您的处理程序仍然可以通过传递另一种信号来中断。 为了避免这种情况,可以使用传递给sigaction的action结构的sa_mask成员来显式指定在信号处理程序运行时哪些信号应该被阻塞。 除了处理程序被调用的信号以外,这些信号以及通常由进程阻塞的任何其他信号。 请参阅阻止处理程序。

当处理程序返回时,被阻塞的信号集恢复到处理程序运行之前的值。 因此,在处理程序中使用sigprocmask只影响处理程序本身执行期间可能到达的信号,而不是处理程序返回时可以到达的信号。

http://www.gnu.org/software/libc/manual/html_node/Signals-in-Handler.html#Signals-in-Handler

在Linux上, errno是一个宏,它扩展成一个函数调用,返回每个线程都不同的可修改的左值。

查看手册页 :

errno由ISO C标准定义为int类型的可修改左值,且不能被明确声明; errno可能是一个宏。 errno是线程本地的; 在一个线程中设置它不会影响其在任何其他线程中的值。

但是,实际上信号可以在信号处理程序的中间执行(如果您使用signal()而不是sigaction() ,这取决于您的环境;这些不一致是推荐使用sigaction() ),或者另一个信号可以中断处理程序的执行。 这就是为什么当您设置信号处置时,通常在执行信号处理程序期间,通过将其添加到信号掩码中来阻止信号(对于该处理程序,在多个信号的情况下) 。 这可以防止信号处理程序自行中断(在某些情况下防止无限循环)。

参考文献:

  • 可以传递给sigaction() sa_mask组件:

    sa_mask指定在执行信号处理程序期间应该被阻塞的信号的掩码(即,被添加到调用信号处理程序的线程的信号掩码)。 另外, 触发处理程序的信号将被阻塞 ,除非使用了SA_NODEFER标志。

  • signal()

    signal()的唯一可移植使用是将信号的处置设置为SIG_DFL或SIG_IGN。 使用signal()建立信号处理程序的语义在不同的系统中是不同的(POSIX.1明确地允许这种变化); 不要为此使用它。

    POSIX.1通过指定sigaction(2)解决了可移植性问题 ,它在调用信号处理程序时提供了对语义的显式控制。 使用该接口而不是signal()。

    此外,快速交付相同的信号可能会导致处理程序的递归调用。