问题描述
我有一个 C 程序。我希望它在收到 SIGTERM 时总是干净地退出,退出代码为 0。我可以注册信号处理程序的最早位置是什么?我将它添加到 main()
的顶部,但我担心它可能会在信号注册之前获得一个 sigterm。
是否可以更早地注册信号处理程序?
解决方法
是的,你可以。使用平台特定的初始值设定项,例如 gcc 的 __attribute((constructor))
。但这并不是一个可靠的解决方案。
如果您希望“在收到 SIGTERM 时始终以退出代码 0 干净地退出”,则指示进程生成代码以 SIGTERM
blocked 开头。 >
然后您的 main
可以注册一个信号处理程序并解除对 SIGTERM
的阻塞(使用 sigprocmask
或 pthread_sigmask
,此时如果收到信号处理程序将立即运行在进程创建到解除信号阻塞调用之间的任何时间点。
本质上,它会将信号的传递推迟到您准备好处理它的程度。
(请注意,如果您在忽略而不是阻止信号的情况下启动进程,则接收到的信号的任何实例直到忽略该信号都将丢失,就好像它们从未发生过一样。这似乎与您所说的背道而驰要求。)
,如果可以切换到 C++:在程序开始和 main
之间初始化全局变量。因此,理论上您可以使用如下代码在调用 main
之前运行。
int f() {
signal(...);
return 0;
}
int x = f();
但是您无法保证全局对象的初始化顺序,因此 x
可能不会首先初始化,而是最后初始化。
但是回到您最初的要求:启动程序和 main
之间的时间如此之短,您为什么要在这么短的时间内为有人发送 SIGTERM
做好准备?这不是不太可能发生吗?
如果可能,您可以将父级更改为忽略 SIGTERM
,然后是 fork
和 execve
。 signal man page 说
通过 fork(2) 创建的子级继承了其父级的副本 信号处置。在 execve(2) 期间, 处理的信号被重置为默认值;的处置 忽略的信号保持不变。
因此您可以忽略 SIGTERM
开始您的进程,直到它为 SIGTERM
设置处理程序。