我有一些这样的代码,在 CI 上失败了一次,在本地失败了一次,但我无法可靠地重现它。代码如下:
#include <stddef.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
int main(void) {
// Ignore SIGALRM
signal(SIGALRM, SIG_IGN);
// Set a timer for every 100us
struct itimerval ival = {0};
ival.it_value.tv_usec = 100;
ival.it_interval.tv_usec = 100;
setitimer(ITIMER_REAL, &ival, NULL);
// Busy-wait 1s
time_t start = time(NULL);
while (time(NULL) <= start);
// Disable the timer
ival.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &ival, NULL);
// Restore the default SIGALRM disposition
signal(SIGALRM, SIG_DFL);
// Busy-wait 1s
start = time(NULL);
while (time(NULL) <= start);
return 0;
}
我观察到的故障是由于SIGALRM
(shell 显示“闹钟”)导致进程终止。SIGALRM
最终返回后,是否有可能从计时器传递一个setitimer()
?
POSIX 措辞setitimer()
对于信号之间的顺序以及setitimer()
禁用计时器不是很清楚。
我曾在 Linux 上观察到一次此崩溃,在 macOS 上观察到一次。
事实证明,这根本不是问题
setitimer()
,而是我的信号处理程序注册代码的 ABA 问题。我基本上有一个信号处理程序数组,这样我就可以在测试期间动态添加/删除它们。但是如果你有一个循环执行而信号处理程序
然后交错
A1, A2, B1, A3, A4, B2
将导致它认为两个处理程序都是NULL
并重新引发致命信号。