8#include <sys/resource.h>
11static volatile sig_atomic_t virtual_expiries, profile_expiries;
12static volatile uint64_t checksum = 0x12345678;
14static void expired(
int signal) {
15 if (signal == SIGVTALRM)
17 else if (signal == SIGPROF)
21static int arm_cpu(
int timer,
int value_ms,
int interval_ms) {
22 struct itimerval setting = {.it_value = {value_ms / 1000, (value_ms % 1000) * 1000},
23 .it_interval = {interval_ms / 1000, (interval_ms % 1000) * 1000}};
24 return setitimer(timer, &setting, NULL);
27static int64_t timeval_us(
struct timeval value) {
28 return (int64_t)value.tv_sec * 1000000 + value.tv_usec;
31static void user_chunk(
void) {
32 uint64_t value = checksum;
33 for (
unsigned i = 0; i < 65536; ++i) {
41static int burn_user(
int milliseconds) {
42 struct rusage before, after;
43 if (getrusage(RUSAGE_SELF, &before))
45 int64_t deadline = st_now(CLOCK_MONOTONIC) + 5000000000;
48 if (getrusage(RUSAGE_SELF, &after) || st_now(CLOCK_MONOTONIC) >= deadline)
50 }
while (timeval_us(after.ru_utime) - timeval_us(before.ru_utime) < milliseconds * 1000);
54static int await_expiries(
volatile sig_atomic_t* count, sig_atomic_t target) {
55 int64_t deadline = st_now(CLOCK_MONOTONIC) + 5000000000;
56 while (*count < target) {
58 if (st_now(CLOCK_MONOTONIC) >= deadline)
64int signal_timer_test_cpu_itimers(
void) {
66 struct sigaction action = {.sa_handler = expired};
67 struct itimerval observed;
68 struct rusage before, after;
69 sigemptyset(&action.sa_mask);
70 CHECK(sigaction(SIGVTALRM, &action, NULL) == 0);
71 CHECK(sigaction(SIGPROF, &action, NULL) == 0);
72 CHECK(arm_cpu(ITIMER_VIRTUAL, 0, 0) == 0 && arm_cpu(ITIMER_PROF, 0, 0) == 0);
73 CHECK(getrusage(RUSAGE_SELF, &before) == 0 && burn_user(40) == 0 &&
74 getrusage(RUSAGE_SELF, &after) == 0);
76 CHECK(timeval_us(after.ru_utime) > timeval_us(before.ru_utime) &&
77 timeval_us(after.ru_stime) >= timeval_us(before.ru_stime) && !virtual_expiries &&
79 puts(
"CPU-ITIMER-CONTRACT: PASS disarmed-rusage");
81 CHECK(arm_cpu(ITIMER_VIRTUAL, 20, 0) == 0 && arm_cpu(ITIMER_PROF, 50, 0) == 0);
82 CHECK(await_expiries(&virtual_expiries, 1) == 0 && await_expiries(&profile_expiries, 1) == 0);
83 CHECK(getitimer(ITIMER_VIRTUAL, &observed) == 0 && !timeval_us(observed.it_value));
84 CHECK(getitimer(ITIMER_PROF, &observed) == 0 && !timeval_us(observed.it_value));
85 CHECK(virtual_expiries == 1 && profile_expiries == 1);
86 puts(
"CPU-ITIMER-CONTRACT: PASS one-shot-signals");
88 CHECK(arm_cpu(ITIMER_VIRTUAL, 20, 20) == 0 && arm_cpu(ITIMER_PROF, 20, 20) == 0);
89 CHECK(await_expiries(&virtual_expiries, 3) == 0 && await_expiries(&profile_expiries, 3) == 0);
90 CHECK(arm_cpu(ITIMER_VIRTUAL, 0, 0) == 0);
91 sig_atomic_t virtual_before = virtual_expiries;
92 CHECK(await_expiries(&profile_expiries, profile_expiries + 2) == 0);
94 CHECK(virtual_expiries <= virtual_before + 1);
95 CHECK(getitimer(ITIMER_VIRTUAL, &observed) == 0 && !timeval_us(observed.it_value));
96 virtual_before = virtual_expiries;
97 CHECK(arm_cpu(ITIMER_VIRTUAL, 20, 0) == 0);
98 CHECK(await_expiries(&virtual_expiries, virtual_before + 1) == 0);
99 CHECK(await_expiries(&profile_expiries, profile_expiries + 2) == 0);
100 CHECK(getitimer(ITIMER_PROF, &observed) == 0 && timeval_us(observed.it_interval) == 20000 &&
101 timeval_us(observed.it_value) > 0);
102 CHECK(arm_cpu(ITIMER_VIRTUAL, 20, 20) == 0 && arm_cpu(ITIMER_PROF, 0, 0) == 0);
103 CHECK(await_expiries(&virtual_expiries, virtual_expiries + 2) == 0);
104 CHECK(getitimer(ITIMER_PROF, &observed) == 0 && !timeval_us(observed.it_value));
105 puts(
"CPU-ITIMER-CONTRACT: PASS independent-periodic-interest");
107 CHECK(arm_cpu(ITIMER_VIRTUAL, 0, 0) == 0 && burn_user(80) == 0);
108 virtual_before = virtual_expiries;
109 CHECK(arm_cpu(ITIMER_VIRTUAL, 50, 0) == 0);
110 CHECK(getitimer(ITIMER_VIRTUAL, &observed) == 0 && timeval_us(observed.it_value) >= 35000);
111 CHECK(burn_user(10) == 0 && getitimer(ITIMER_VIRTUAL, &observed) == 0 &&
112 timeval_us(observed.it_value) > 0);
113 CHECK(await_expiries(&virtual_expiries, virtual_before + 1) == 0);
114 CHECK(getitimer(ITIMER_VIRTUAL, &observed) == 0 && !timeval_us(observed.it_value));
115 printf(
"CPU-ITIMER-CONTRACT: PASS rearm-baseline virtual=%d profile=%d checksum=%llu\n",
116 (
int)virtual_expiries, (
int)profile_expiries, (
unsigned long long)checksum);
118 arm_cpu(ITIMER_VIRTUAL, 0, 0);
119 arm_cpu(ITIMER_PROF, 0, 0);