12#include <sys/syscall.h>
14static int arm(timer_t timer,
int milliseconds,
int interval) {
15 struct itimerspec setting = {.it_value = st_timespec((int64_t)milliseconds * 1000000),
16 .it_interval = st_timespec((int64_t)interval * 1000000)};
17 return timer_settime(timer, 0, &setting, NULL);
19static int64_t remaining(
const struct itimerspec* setting) {
20 return (int64_t)setting->it_value.tv_sec * 1000000000 + setting->it_value.tv_nsec;
23static int basic_timers(
void) {
24 int failed = 0, live = 0;
26 struct sigevent event = {.sigev_notify = SIGEV_NONE};
27 struct itimerspec setting, replacement = {.it_value = {0, 1000000}};
28 void* bad = mmap(NULL, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
29 CHECK(bad != MAP_FAILED);
30 CHECK(timer_create(CLOCK_MONOTONIC, &event, &timer) == 0);
32 CHECK(timer_gettime(timer, &setting) == 0 && remaining(&setting) == 0);
33 CHECK(arm(timer, 3000, 0) == 0);
34 CHECK(timer_gettime(timer, &setting) == 0 && remaining(&setting) > 1000000000);
35 CHECK(timer_settime(timer, 0, &replacement, bad) == -1 && errno == EFAULT);
36 CHECK(timer_gettime(timer, &setting) == 0 && remaining(&setting) > 1000000000);
37 CHECK(timer_gettime(timer, bad) == -1 && errno == EFAULT);
38 CHECK(syscall(SYS_timer_settime, timer, 0, NULL, NULL) == -1 && errno == EINVAL);
39 CHECK(syscall(SYS_timer_settime, timer, 0, bad, NULL) == -1 && errno == EFAULT);
40 replacement.it_value.tv_nsec = 1000000000;
41 CHECK(timer_settime(timer, 0, &replacement, NULL) == -1 && errno == EINVAL);
42 CHECK(arm(timer, 0, 10) == 0);
43 CHECK(timer_gettime(timer, &setting) == 0 && remaining(&setting) == 0 &&
44 setting.it_interval.tv_sec == 0 && setting.it_interval.tv_nsec == 0);
45 CHECK(timer_delete(timer) == 0);
47 CHECK(timer_gettime(timer, &setting) == -1 && errno == EINVAL);
48 CHECK(syscall(SYS_timer_create, CLOCK_MONOTONIC, NULL, bad) == -1 && errno == EFAULT);
49 CHECK(timer_create(CLOCK_PROCESS_CPUTIME_ID, &event, &timer) == -1 && errno == EINVAL);
53 if (bad != MAP_FAILED)
58static int delivered_timers(
void) {
59 int failed = 0, live = 0, masked = 0;
61 sigset_t set, original;
63 struct timespec zero = {0}, timeout = {2, 0};
64 struct itimerspec setting;
65 struct sigevent event = {
66 .sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGRTMIN, .sigev_value.sival_int = 0x4567};
68 sigaddset(&set, SIGRTMIN);
69 sigaddset(&set, SIGALRM);
70 CHECK(pthread_sigmask(SIG_BLOCK, &set, &original) == 0);
72 CHECK(timer_create(CLOCK_MONOTONIC, &event, &timer) == 0);
74 CHECK(arm(timer, 60, 0) == 0);
75 CHECK(sigtimedwait(&set, &info, &timeout) == SIGRTMIN && info.si_code == SI_TIMER &&
76 info.si_value.sival_int == 0x4567 && info.si_overrun == 0);
77 CHECK(timer_gettime(timer, &setting) == 0 && remaining(&setting) == 0);
78 CHECK(timer_getoverrun(timer) == 0);
79 CHECK(arm(timer, 30, 30) == 0);
81 CHECK(sigtimedwait(&set, &info, &timeout) == SIGRTMIN && info.si_code == SI_TIMER &&
82 info.si_overrun >= 1 && timer_getoverrun(timer) == info.si_overrun);
83 CHECK(arm(timer, 0, 0) == 0);
84 CHECK(sigtimedwait(&set, &info, &zero) == -1 && errno == EAGAIN);
86 CHECK(arm(timer, 20, 0) == 0);
88 CHECK(arm(timer, 500, 0) == 0);
89 CHECK(sigtimedwait(&set, &info, &zero) == -1 && errno == EAGAIN);
90 CHECK(arm(timer, 20, 0) == 0);
92 CHECK(timer_delete(timer) == 0);
94 CHECK(sigtimedwait(&set, &info, &zero) == -1 && errno == EAGAIN);
96 CHECK(timer_create(CLOCK_REALTIME, NULL, &timer) == 0);
98 CHECK(arm(timer, 40, 0) == 0);
99 CHECK(sigtimedwait(&set, &info, &timeout) == SIGALRM && info.si_code == SI_TIMER &&
100 info.si_value.sival_int == (
int)(intptr_t)timer);
105 while (sigtimedwait(&set, &info, &zero) >= 0) {
107 pthread_sigmask(SIG_SETMASK, &original, NULL);
115 volatile int tid, done;
118static void target_done(
void* argument) {
120 __atomic_store_n(&target->done, 1, __ATOMIC_RELEASE);
124 struct timespec timeout = {2, 0};
125 pthread_cleanup_push(target_done, target);
126 __atomic_store_n(&target->tid, (
int)syscall(SYS_gettid), __ATOMIC_RELEASE);
127 target->result = sigtimedwait(&target->set, &target->info, &timeout);
128 pthread_cleanup_pop(1);
133 volatile int count, tid;
135static void timer_callback(
union sigval value) {
137 __atomic_store_n(&state->tid, (
int)syscall(SYS_gettid), __ATOMIC_RELEASE);
138 __atomic_add_fetch(&state->count, 1, __ATOMIC_RELEASE);
139 sem_post(&state->completed);
141static int threaded_timers(
void) {
142 int failed = 0, live = 0, masked = 0, worker_active = 0, sem_live = 0;
149 struct timespec zero = {0};
150 struct itimerspec setting;
151 struct sigevent event = {
152 .sigev_notify = SIGEV_THREAD_ID, .sigev_signo = SIGRTMAX, .sigev_value.sival_int = 6401};
153 sigemptyset(&target.set);
154 sigaddset(&target.set, SIGRTMAX);
155 CHECK(pthread_sigmask(SIG_BLOCK, &target.set, &original) == 0);
159 CHECK(st_wait(&target.tid, 1000) == 0);
160 event.sigev_notify_thread_id = target.tid;
161 CHECK(timer_create(CLOCK_MONOTONIC, &event, &timer) == 0);
163 CHECK(arm(timer, 40, 0) == 0);
164 CHECK(st_wait(&target.done, 2000) == 0 && pthread_join(
worker, NULL) == 0);
166 CHECK(target.result == SIGRTMAX && target.info.si_code == SI_TIMER &&
167 target.info.si_value.sival_int == 6401);
168 CHECK(sigtimedwait(&target.set, &info, &zero) == -1 && errno == EAGAIN);
169 CHECK(timer_gettime(timer, &setting) == -1 && errno == EINVAL);
172 CHECK(sem_init(&callback.completed, 0, 0) == 0);
174 event = (
struct sigevent){.sigev_notify = SIGEV_THREAD,
175 .sigev_notify_function = timer_callback,
176 .sigev_value.sival_ptr = &callback};
177 CHECK(timer_create(CLOCK_MONOTONIC, &event, &timer) == 0);
179 CHECK(arm(timer, 40, 0) == 0);
180 struct timespec deadline = st_timespec(st_now(CLOCK_REALTIME) + 2000000000);
181 CHECK(sem_timedwait(&callback.completed, &deadline) == 0);
182 CHECK(__atomic_load_n(&callback.count, __ATOMIC_ACQUIRE) == 1 &&
183 __atomic_load_n(&callback.tid, __ATOMIC_ACQUIRE) != syscall(SYS_gettid));
184 CHECK(timer_gettime(timer, &setting) == 0 && remaining(&setting) == 0);
185 CHECK(timer_delete(timer) == 0);
187 int64_t deadline_exit = st_now(CLOCK_MONOTONIC) + 2000000000;
188 while (syscall(SYS_tkill, callback.tid, 0) == 0 && st_now(CLOCK_MONOTONIC) < deadline_exit)
190 CHECK(syscall(SYS_tkill, callback.tid, 0) == -1 && errno == ESRCH);
198 if (st_wait(&target.done, 1000) == 0)
199 pthread_join(
worker, NULL);
204 sem_destroy(&callback.completed);
206 while (sigtimedwait(&target.set, &info, &zero) >= 0) {
208 pthread_sigmask(SIG_SETMASK, &original, NULL);
213int signal_timer_exec(
int argc,
char** argv) {
217 timer_t old = (timer_t)(intptr_t)strtol(argv[2], NULL, 10), timer;
218 struct itimerspec setting;
219 if (timer_gettime(old, &setting) != -1 || errno != EINVAL)
221 struct sigevent event = {.sigev_notify = SIGEV_NONE};
222 if (timer_create(CLOCK_MONOTONIC, &event, &timer) || timer == old)
224 if (timer_gettime(timer, &setting) || remaining(&setting) || timer_delete(timer))
228 sigaddset(&set, SIGRTMIN);
229 struct timespec zero = {0};
231 if (sigtimedwait(&set, NULL, &zero) != -1 || errno != EAGAIN)
235static int timer_lifetime(
void) {
236 int failed = 0, live = 0;
238 struct sigevent event = {.sigev_notify = SIGEV_NONE};
239 struct itimerspec setting;
241 CHECK(timer_create(CLOCK_MONOTONIC, &event, &timer) == 0);
243 CHECK(arm(timer, 30000, 0) == 0);
244 CHECK((child = fork()) >= 0);
248 if (timer_gettime(timer, &setting) != -1 || errno != EINVAL)
250 if (timer_create(CLOCK_MONOTONIC, &event, &own) || own == timer)
252 if (timer_delete(own))
256 CHECK(st_reap(child, 6000) == 0);
257 CHECK(timer_gettime(timer, &setting) == 0 && remaining(&setting) > 0);
258 CHECK((child = fork()) >= 0);
263 sigaddset(&set, SIGRTMIN);
264 if (pthread_sigmask(SIG_BLOCK, &set, NULL))
266 event = (
struct sigevent){.sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGRTMIN};
268 if (timer_create(CLOCK_MONOTONIC, &event, &own) || arm(own, 30, 30))
272 snprintf(identifier,
sizeof(identifier),
"%ld", (
long)(intptr_t)own);
273 execl(
"/applications/signal-timer-contract-test",
"signal-timer-contract-test",
"timer-exec",
274 identifier, (
char*)NULL);
277 CHECK(st_reap(child, 6000) == 0);
284int signal_timer_test_timers(
void) {
285 if (basic_timers() || delivered_timers() || threaded_timers() || timer_lifetime())