在Linux上如何执行asynchronous信号处理程序?
我想知道如何在Linux上执行asynchronous信号处理程序。 首先,我不清楚哪个线程执行信号处理程序。 其次,我想知道使线程执行信号处理程序的步骤。
首先,我读了两个不同的,看似矛盾的解释:
-
由Andries Brouwer 撰写的Linux Kernel第5.2节“接收信号”指出 :
当信号到达时,进程被中断,当前的寄存器被保存,信号处理程序被调用。 当信号处理程序返回时,中断的活动继续。
-
StackOverflow问题“处理multithreading程序中的asynchronous信号”使我认为Linux的行为就像SCO Unix一样 :
当一个信号被传送到一个进程时,如果它被捕获,它将被满足以下任一条件的线程中的一个,并且只处理一个:
-
在sigwait (2)系统调用中阻塞的线程,其参数确实包含捕获信号的types。
-
信号掩码不包含捕获信号的types的线程。
其他注意事项
- 被阻塞在sigwait (2)中的线程优先于不阻塞信号types的线程。
- 如果多个线程满足这些要求(也许两个线程调用sigwait (2) ),则会select其中一个线程。 这个select是不可预测的应用程序。
- 如果没有线程符合条件,则信号将在进程级别保持“挂起”状态,直到某个线程符合条件。
此外, Moshe Bar的“Linux信号处理模型”指出: “asynchronous信号被传递到第一个线程,而不是阻塞信号”,我解释为这个信号被传递给某个线程,其信号的sigmask 不包括信号。
-
哪一个是正确的?
关于第二个问题,堆栈和选定线程的内容会发生什么变化? 假设线程运行信号处理程序T正在执行一个do_stuff()
函数。 线程T的堆栈是否直接用来执行信号处理程序(即信号蹦床的地址被推送到T的堆栈上,控制stream程到达信号处理程序)? 另外,是一个单独的堆栈使用? 它是如何工作的?
如果考虑到Linux黑客往往对线程和进程之间的差异感到困惑,这两个解释并不矛盾,主要是因为尝试假冒线程可能被实现为共享进程的历史错误记忆。 🙂
说了这么多,解释#2更加详细,完整和正确。
至于堆栈和寄存器内容,每个线程可以注册自己的备用信号处理堆栈,并且该进程可以基于每个信号select哪些信号将在交替的信号处理堆栈上被递送。 中断的上下文(寄存器,信号掩码等)将被保存在线程堆栈上的ucontext_t
结构中,以及蹦床返回地址。 使用SA_SIGINFO
标志安装的信号处理程序能够检查这个ucontext_t
结构,但是他们唯一可以做的便携事件是检查(并可能修改)保存的信号掩码。 (我不确定是否修改它是由标准认可的,但它是非常有用的,因为它允许信号处理程序在返回时自动replace被中断的代码的信号掩码,例如让信号被阻塞,所以不会再发生。)
- 赶上Ctrl + C / SIGINT并在python中优雅退出多进程
- 我怎样才能捕获一个CTRL-C事件? (C ++)
- 提供/传递参数给信号处理程序
- 什么是正确的方式来使我的PyQt应用程序退出从控制台死亡(Ctrl-C)?
- 在什么情况下C ++析构函数不会被调用?
- 我怎样才能捕获SIGSEGV(分段错误),并得到在Android上的JNI下的堆栈跟踪?
- Android致命信号11
- 通过使用BookSleeve的ConnectionUtils.Connect(),使用SignalR和Redis messagebus进行故障转移
- Pusher vs Pubnub vs开源Socket.io / SignalR.net / Faye / jWebSocket