timer_getoverrun()在使用sleep()时的行为不像预期的那样

这里是一个程序,它和sleep()子程序一起使用POSIX per-process定时器。 定时器到期时发送的信号已被设置为SIGUSR1而不是SIGALRM ,因为SIGALRM可能在sleep()内部使用,但似乎仍然不起作用。

我使用命令行timer-overruns -d 1 -n 10000000 (1 cs间隔)来运行程序,理论上,我们应该在对sigwaitinfo()调用之间预计有100次sigwaitinfo() 。 但是, timer_getoverrun()返回0。

我也尝试过使用一个耗时for循环来引入延迟的版本。 在这种情况下,超限logging下来。

有谁知道为什么发生这种情况? 我正在运行一个3.4 Linux内核。

节目源

 /* * timer-overruns.c */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <time.h> // Signal to be used for timer expirations #define TIMER_SIGNAL SIGUSR1 int main(int argc, char **argv) { int opt; int d = 0; int r = 0; // Repeat indefinitely struct itimerspec its; its.it_interval.tv_sec = 0; its.it_interval.tv_nsec = 0; // Parse arguments while ((opt = getopt(argc, argv, "d:r:s:n:")) != -1) { switch (opt) { case 'd': // Delay before calling sigwaitinfo() d = atoi(optarg); break; case 'r': // Number of times to call sigwaitinfo() r = atoi(optarg); break; case 's': // Timer interval (seconds) its.it_interval.tv_sec = its.it_value.tv_sec = atoi(optarg); break; case 'n': // Timer interval (nanoseconds) its.it_interval.tv_nsec = its.it_value.tv_nsec = atoi(optarg); break; default: /* '?' */ fprintf(stderr, "Usage: %s [-d signal_accept_delay] [-r repetitions] [-s interval_seconds] [-n interval_nanoseconds]\n", argv[0]); exit(EXIT_FAILURE); } } // Check sanity of command line arguments short e = 0; if (d < 0) { fprintf(stderr, "Delay (-d) cannot be negative!\n"); e++; } if (r < 0) { fprintf(stderr, "Number of repetitions (-r) cannot be negative!\n"); e++; } if (its.it_interval.tv_sec < 0) { fprintf(stderr, "Interval seconds value (-s) cannot be negative!\n"); e++; } if (its.it_interval.tv_nsec < 0) { fprintf(stderr, "Interval nanoseconds value (-n) cannot be negative!\n"); e++; } if (its.it_interval.tv_nsec > 999999999) { fprintf(stderr, "Interval nanoseconds value (-n) must be < 1 second.\n"); e++; } if (e > 0) exit(EXIT_FAILURE); // Set default values if not specified if (its.it_interval.tv_sec == 0 && its.it_interval.tv_nsec == 0) { its.it_interval.tv_sec = its.it_value.tv_sec = 1; its.it_value.tv_nsec = 0; } printf("Running with timer delay %d.%09d seconds\n", (int) its.it_interval.tv_sec, (int) its.it_interval.tv_nsec); // Will be waiting for signals synchronously, so block the one in use. sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, TIMER_SIGNAL); sigprocmask(SIG_BLOCK, &sigset, NULL ); // Create and arm the timer struct sigevent sev; timer_t timer; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = TIMER_SIGNAL; sev.sigev_value.sival_ptr = timer; timer_create(CLOCK_REALTIME, &sev, &timer); timer_settime(timer, TIMER_ABSTIME, &its, NULL ); // Signal handling loop int overruns; siginfo_t si; // Make the loop infinite if r = 0 if (r == 0) r = -1; while (r != 0) { // Sleeping should cause overruns if (d > 0) sleep(d); sigwaitinfo(&sigset, &si); // Check that the signal is from the timer if (si.si_code != SI_TIMER) continue; overruns = timer_getoverrun(timer); if (overruns > 0) { printf("Timer overrun occurred for %d expirations.\n", overruns); } // Decrement r if not repeating indefinitely if (r > 0) r--; } return EXIT_SUCCESS; } 

只有设置了纳秒时,您无法设置其its.it_value.tv_sec ,即-n 10000000而不是-s 0 。 正确地初始化它的its.it_value ,或使用-s 0参数,你的代码应该工作 – 在时尚之后。

由于sigemptyset(&sigset); sigaddset(&sigset, TIMER_SIGNAL); sigprocmask(SIG_BLOCK, &sigset, NULL); sigemptyset(&sigset); sigaddset(&sigset, TIMER_SIGNAL); sigprocmask(SIG_BLOCK, &sigset, NULL); 我不认为有竞争条件, sigwaitinfo()应该可靠地获取待处理的信号。 有关详细信息,请参阅sigwaitinfo()手册页。 它在Notes部分描述了这个非常相同的用例。

看起来定时器触发后timer_getoverrun()返回的值是假的,至少在x86-64的3.5.0内核上是这样。 换句话说,在循环之前加上这个,

  printf("Overruns: %d\n", timer_getoverrun(timer)); sigwaitinfo(&sigset, &si); printf("Overruns: %d (%d)\n", timer_getoverrun(timer), si.si_overrun); sigwaitinfo(&sigset, &si); printf("Overruns: %d (%d)\n", timer_getoverrun(timer), si.si_overrun); 

会输出零,一个看似随机的超限计数,然后是预期的超限计数。 (定时器和siginfo溢出计数都匹配。)我怀疑是在kernel / posix-timers.c有问题,但我可能是错误的..问题似乎是第一个计时器事件将使用随机值先前的超限计数。 我想我会进一步调查。

如果你能告诉我你在内核上看到的是否相同,我将非常感激。 (也请说明确切的版本和体系结构,我在amd64(x86-64)上运行Ubuntu linux-image-3.5.0-3-generic,版本3.5.0-3.3。