8#include <sys/syscall.h>
9#include <sys/timerfd.h>
12void vdso_init_from_sysinfo_ehdr(uintptr_t base);
13void* vdso_sym(
const char* version,
const char* name);
15static int64_t nanoseconds(
struct timespec value) {
16 if (value.tv_sec < 0 || value.tv_nsec < 0 || value.tv_nsec >= 1000000000)
18 return (int64_t)value.tv_sec * 1000000000 + value.tv_nsec;
21static int64_t direct_clock(clockid_t clock) {
22 struct timespec value;
23 return syscall(SYS_clock_gettime, clock, &value) ? -1 : nanoseconds(value);
26int signal_timer_test_raw_clock(
void) {
27 int failed = 0, changed = 0, fd = -1, have_timer = 0;
29 const int64_t saved_real = direct_clock(CLOCK_REALTIME);
30 const int64_t saved_mono = direct_clock(CLOCK_MONOTONIC);
31 const uintptr_t vdso_base = getauxval(AT_SYSINFO_EHDR);
32 CHECK(vdso_base != 0 && saved_real >= 0 && saved_mono >= 0);
33 vdso_init_from_sysinfo_ehdr(vdso_base);
34 int (*vdso_clock)(clockid_t,
struct timespec*) =
35 (
int (*)(clockid_t,
struct timespec*))vdso_sym(
"LINUX_2.6",
"__vdso_clock_gettime");
36 CHECK(vdso_clock != NULL);
38 int64_t previous_libc = -1, previous_vdso = -1, previous_direct = -1;
39 for (
unsigned n = 0; n < 16; ++n) {
40 struct timespec libc_value, vdso_value;
41 const int64_t before = direct_clock(CLOCK_MONOTONIC);
42 CHECK(clock_gettime(CLOCK_MONOTONIC_RAW, &libc_value) == 0);
43 CHECK(vdso_clock(CLOCK_MONOTONIC_RAW, &vdso_value) == 0);
44 const int64_t raw = direct_clock(CLOCK_MONOTONIC_RAW);
45 const int64_t after = direct_clock(CLOCK_MONOTONIC);
46 const int64_t libc_raw = nanoseconds(libc_value), vdso_raw = nanoseconds(vdso_value);
47 CHECK(before >= 0 && raw >= before && raw <= after && raw >= previous_direct);
49 CHECK(libc_raw >= 0 && libc_raw >= before - 1000000000 && libc_raw <= after);
50 CHECK(vdso_raw >= 0 && vdso_raw >= before - 1000000000 && vdso_raw <= after);
51 CHECK(libc_raw >= previous_libc && vdso_raw >= previous_vdso);
52 previous_libc = libc_raw;
53 previous_vdso = vdso_raw;
54 previous_direct = raw;
57 puts(
"SIGNAL-TIMER-CONTRACT: PASS raw-clock-vdso-libc-syscall");
59 struct timespec resolution = {-1, -1};
60 CHECK(clock_getres(CLOCK_MONOTONIC_RAW, &resolution) == 0);
61 CHECK(resolution.tv_sec == 0 && resolution.tv_nsec == 1);
62 resolution = (
struct timespec){-1, -1};
63 CHECK(syscall(SYS_clock_getres, CLOCK_MONOTONIC_RAW, &resolution) == 0);
64 CHECK(resolution.tv_sec == 0 && resolution.tv_nsec == 1);
65 CHECK(clock_getres(CLOCK_MONOTONIC_RAW, NULL) == 0);
66 CHECK(syscall(SYS_clock_getres, CLOCK_MONOTONIC_RAW, NULL) == 0);
67 CHECK(vdso_clock(CLOCK_MONOTONIC_RAW, NULL) == -EFAULT);
68 CHECK(syscall(SYS_clock_gettime, CLOCK_MONOTONIC_RAW, NULL) == -1 && errno == EFAULT);
69 CHECK(syscall(SYS_clock_getres, CLOCK_MONOTONIC_RAW, (
void*)1) == -1 && errno == EFAULT);
70 CHECK(clock_gettime(-1, &resolution) == -1 && errno == EINVAL);
71 CHECK(vdso_clock(-1, &resolution) == -EINVAL);
72 CHECK(syscall(SYS_clock_gettime, -1, &resolution) == -1 && errno == EINVAL);
74 const struct timespec zero = {0, 0};
75 struct timespec remainder = {123, 456};
76 CHECK(clock_nanosleep(CLOCK_MONOTONIC_RAW, 0, &zero, &remainder) == EINVAL);
77 CHECK(remainder.tv_sec == 123 && remainder.tv_nsec == 456);
78 CHECK(syscall(SYS_clock_nanosleep, CLOCK_MONOTONIC_RAW, TIMER_ABSTIME, &zero, NULL) == -1 &&
80 CHECK(clock_settime(CLOCK_MONOTONIC_RAW, &zero) == -1 && errno == EINVAL);
81 CHECK(syscall(SYS_clock_settime, CLOCK_MONOTONIC_RAW, &zero) == -1 && errno == EINVAL);
82 have_timer = timer_create(CLOCK_MONOTONIC_RAW, NULL, &timer) == 0;
83 CHECK(!have_timer && errno == EINVAL);
84 fd = timerfd_create(CLOCK_MONOTONIC_RAW, TFD_NONBLOCK);
85 CHECK(fd == -1 && errno == EINVAL);
86 puts(
"SIGNAL-TIMER-CONTRACT: PASS raw-clock-read-only");
89 for (
unsigned route = 0; route < 2; ++route) {
90 const int64_t real_before = direct_clock(CLOCK_REALTIME);
91 const int64_t raw_before = direct_clock(CLOCK_MONOTONIC_RAW);
92 const int64_t mono_before = direct_clock(CLOCK_MONOTONIC);
94 struct timespec target = st_timespec(real_before + 10000000000);
95 CHECK(clock_settime(CLOCK_REALTIME, &target) == 0);
97 struct timex adjustment = {.modes = ADJ_SETOFFSET, .time = {.tv_sec = -20}};
98 CHECK(adjtimex(&adjustment) >= 0);
101 const int64_t raw_after = direct_clock(CLOCK_MONOTONIC_RAW);
102 const int64_t mono_after = direct_clock(CLOCK_MONOTONIC);
103 const int64_t real_after = direct_clock(CLOCK_REALTIME);
104 CHECK(raw_before >= 0 && raw_after >= raw_before && mono_after >= mono_before);
105 const int64_t drift = (raw_after - raw_before) - (mono_after - mono_before);
106 CHECK(drift > -1000000000 && drift < 1000000000);
107 CHECK(route ? real_after < real_before - 18000000000
108 : real_after >= real_before + 10000000000);
109 struct timespec vdso_value, libc_value;
110 CHECK(vdso_clock(CLOCK_MONOTONIC_RAW, &vdso_value) == 0);
111 CHECK(clock_gettime(CLOCK_MONOTONIC_RAW, &libc_value) == 0);
112 CHECK(nanoseconds(vdso_value) >= raw_before - 1000000000 &&
113 nanoseconds(vdso_value) <= direct_clock(CLOCK_MONOTONIC));
114 CHECK(nanoseconds(libc_value) >= raw_before - 1000000000 &&
115 nanoseconds(libc_value) <= direct_clock(CLOCK_MONOTONIC));
117 puts(
"SIGNAL-TIMER-CONTRACT: PASS raw-clock-realtime-independent");
119 puts(
"SIGNAL-TIMER-CONTRACT: SKIP raw-clock-realtime-independent requires root");
127 struct timespec restored = st_timespec(saved_real + direct_clock(CLOCK_MONOTONIC) - saved_mono);
128 if (clock_settime(CLOCK_REALTIME, &restored))