1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
// Copyright 2022 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
#define _GNU_SOURCE
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <emscripten/emscripten.h>
_Atomic int got_alarm[3];
void alarm_handler(int dummy) {
printf("Received SIGALRM!\n");
got_alarm[ITIMER_REAL]++;
}
void vtalarm_handler(int dummy) {
printf("Received SIGVTALRM!\n");
got_alarm[ITIMER_VIRTUAL]++;
}
void prof_handler(int dummy) {
printf("Received SIGPROF!\n");
got_alarm[ITIMER_PROF]++;
}
void test_oneoff(int which) {
memset(got_alarm, 0, sizeof(got_alarm));
int rtn;
struct itimerval val;
memset(&val, 0, sizeof(val));
// Set a timer for 1 second
val.it_value.tv_sec = 1;
rtn = setitimer(which, &val, NULL);
assert(rtn == 0);
rtn = getitimer(which, &val);
assert(rtn == 0);
printf("ms remaining: %d\n", val.it_value.tv_usec / 1000);
assert(val.it_value.tv_usec || val.it_value.tv_sec);
// Wait 100ms
usleep(100 * 1000);
// Verify less time remains
rtn = getitimer(which, &val);
assert(rtn == 0);
printf("ms remaining: %d\n", val.it_value.tv_usec / 1000);
assert(val.it_value.tv_sec == 0);
assert(val.it_value.tv_usec > 0);
// Wait 1.5s
assert(!got_alarm[which]);
usleep(1500 * 1000);
// Verify that the time fired and is no longer active
assert(got_alarm[which]);
rtn = getitimer(which, &val);
assert(val.it_value.tv_sec == 0);
assert(val.it_value.tv_usec == 0);
}
#define NUM_TIMERS 10
#define ERROR_MARGIN 3
void test_sequence(int which) {
memset(got_alarm, 0, sizeof(got_alarm));
// Set a timer to fire every 100ms
struct itimerval val;
val.it_value.tv_sec = 0;
val.it_value.tv_usec = 100 * 1000;
val.it_interval.tv_sec = 0;
val.it_interval.tv_usec = 100 * 1000;
int rtn = setitimer(which, &val, NULL);
// Sleep for a little over NUM_TIMERS * 100ms
usleep((NUM_TIMERS * 100 + 50) * 1000);
printf("got %d alarms\n", got_alarm[which]);
// Normally we would expect NUM_TIMERS to fire in this time
// but leave some wiggle room for scheduling anomalies.
assert(got_alarm[which] > NUM_TIMERS - ERROR_MARGIN);
assert(got_alarm[which] < NUM_TIMERS + ERROR_MARGIN);
struct itimerval old;
val.it_value.tv_sec = 0;
val.it_value.tv_usec = 0;
rtn = setitimer(ITIMER_REAL, &val, &old);
}
void set_handlers() {
sighandler_t rtn;
rtn = signal(SIGALRM, alarm_handler);
assert(rtn != SIG_ERR);
rtn = signal(SIGVTALRM, vtalarm_handler);
assert(rtn != SIG_ERR);
rtn = signal(SIGPROF, prof_handler);
assert(rtn != SIG_ERR);
}
int main() {
set_handlers();
test_oneoff(ITIMER_REAL);
test_oneoff(ITIMER_VIRTUAL);
test_oneoff(ITIMER_PROF);
test_sequence(ITIMER_REAL);
printf("done\n");
return 0;
}
|