1689f32fbSJohn Stultz /* Make sure timers don't return early
2689f32fbSJohn Stultz * by: john stultz (johnstul@us.ibm.com)
3689f32fbSJohn Stultz * John Stultz (john.stultz@linaro.org)
4689f32fbSJohn Stultz * (C) Copyright IBM 2012
5689f32fbSJohn Stultz * (C) Copyright Linaro 2013 2015
6689f32fbSJohn Stultz * Licensed under the GPLv2
7689f32fbSJohn Stultz *
8689f32fbSJohn Stultz * To build:
9689f32fbSJohn Stultz * $ gcc nanosleep.c -o nanosleep -lrt
10689f32fbSJohn Stultz *
11689f32fbSJohn Stultz * This program is free software: you can redistribute it and/or modify
12689f32fbSJohn Stultz * it under the terms of the GNU General Public License as published by
13689f32fbSJohn Stultz * the Free Software Foundation, either version 2 of the License, or
14689f32fbSJohn Stultz * (at your option) any later version.
15689f32fbSJohn Stultz *
16689f32fbSJohn Stultz * This program is distributed in the hope that it will be useful,
17689f32fbSJohn Stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of
18689f32fbSJohn Stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19689f32fbSJohn Stultz * GNU General Public License for more details.
20689f32fbSJohn Stultz */
21689f32fbSJohn Stultz
22c1ee4831SBen Hutchings #include <errno.h>
23689f32fbSJohn Stultz #include <stdio.h>
24689f32fbSJohn Stultz #include <stdlib.h>
25689f32fbSJohn Stultz #include <time.h>
26689f32fbSJohn Stultz #include <sys/time.h>
27689f32fbSJohn Stultz #include <sys/timex.h>
28689f32fbSJohn Stultz #include <string.h>
29689f32fbSJohn Stultz #include <signal.h>
30689f32fbSJohn Stultz #include "../kselftest.h"
31689f32fbSJohn Stultz
32689f32fbSJohn Stultz #define NSEC_PER_SEC 1000000000ULL
33689f32fbSJohn Stultz
34689f32fbSJohn Stultz #define CLOCK_REALTIME 0
35689f32fbSJohn Stultz #define CLOCK_MONOTONIC 1
36689f32fbSJohn Stultz #define CLOCK_PROCESS_CPUTIME_ID 2
37689f32fbSJohn Stultz #define CLOCK_THREAD_CPUTIME_ID 3
38689f32fbSJohn Stultz #define CLOCK_MONOTONIC_RAW 4
39689f32fbSJohn Stultz #define CLOCK_REALTIME_COARSE 5
40689f32fbSJohn Stultz #define CLOCK_MONOTONIC_COARSE 6
41689f32fbSJohn Stultz #define CLOCK_BOOTTIME 7
42689f32fbSJohn Stultz #define CLOCK_REALTIME_ALARM 8
43689f32fbSJohn Stultz #define CLOCK_BOOTTIME_ALARM 9
44689f32fbSJohn Stultz #define CLOCK_HWSPECIFIC 10
45689f32fbSJohn Stultz #define CLOCK_TAI 11
46689f32fbSJohn Stultz #define NR_CLOCKIDS 12
47689f32fbSJohn Stultz
48689f32fbSJohn Stultz #define UNSUPPORTED 0xf00f
49689f32fbSJohn Stultz
clockstring(int clockid)50689f32fbSJohn Stultz char *clockstring(int clockid)
51689f32fbSJohn Stultz {
52689f32fbSJohn Stultz switch (clockid) {
53689f32fbSJohn Stultz case CLOCK_REALTIME:
54689f32fbSJohn Stultz return "CLOCK_REALTIME";
55689f32fbSJohn Stultz case CLOCK_MONOTONIC:
56689f32fbSJohn Stultz return "CLOCK_MONOTONIC";
57689f32fbSJohn Stultz case CLOCK_PROCESS_CPUTIME_ID:
58689f32fbSJohn Stultz return "CLOCK_PROCESS_CPUTIME_ID";
59689f32fbSJohn Stultz case CLOCK_THREAD_CPUTIME_ID:
60689f32fbSJohn Stultz return "CLOCK_THREAD_CPUTIME_ID";
61689f32fbSJohn Stultz case CLOCK_MONOTONIC_RAW:
62689f32fbSJohn Stultz return "CLOCK_MONOTONIC_RAW";
63689f32fbSJohn Stultz case CLOCK_REALTIME_COARSE:
64689f32fbSJohn Stultz return "CLOCK_REALTIME_COARSE";
65689f32fbSJohn Stultz case CLOCK_MONOTONIC_COARSE:
66689f32fbSJohn Stultz return "CLOCK_MONOTONIC_COARSE";
67689f32fbSJohn Stultz case CLOCK_BOOTTIME:
68689f32fbSJohn Stultz return "CLOCK_BOOTTIME";
69689f32fbSJohn Stultz case CLOCK_REALTIME_ALARM:
70689f32fbSJohn Stultz return "CLOCK_REALTIME_ALARM";
71689f32fbSJohn Stultz case CLOCK_BOOTTIME_ALARM:
72689f32fbSJohn Stultz return "CLOCK_BOOTTIME_ALARM";
73689f32fbSJohn Stultz case CLOCK_TAI:
74689f32fbSJohn Stultz return "CLOCK_TAI";
75689f32fbSJohn Stultz };
76689f32fbSJohn Stultz return "UNKNOWN_CLOCKID";
77689f32fbSJohn Stultz }
78689f32fbSJohn Stultz
79689f32fbSJohn Stultz /* returns 1 if a <= b, 0 otherwise */
in_order(struct timespec a,struct timespec b)80689f32fbSJohn Stultz static inline int in_order(struct timespec a, struct timespec b)
81689f32fbSJohn Stultz {
82689f32fbSJohn Stultz if (a.tv_sec < b.tv_sec)
83689f32fbSJohn Stultz return 1;
84689f32fbSJohn Stultz if (a.tv_sec > b.tv_sec)
85689f32fbSJohn Stultz return 0;
86689f32fbSJohn Stultz if (a.tv_nsec > b.tv_nsec)
87689f32fbSJohn Stultz return 0;
88689f32fbSJohn Stultz return 1;
89689f32fbSJohn Stultz }
90689f32fbSJohn Stultz
timespec_add(struct timespec ts,unsigned long long ns)91689f32fbSJohn Stultz struct timespec timespec_add(struct timespec ts, unsigned long long ns)
92689f32fbSJohn Stultz {
93689f32fbSJohn Stultz ts.tv_nsec += ns;
94689f32fbSJohn Stultz while (ts.tv_nsec >= NSEC_PER_SEC) {
95689f32fbSJohn Stultz ts.tv_nsec -= NSEC_PER_SEC;
96689f32fbSJohn Stultz ts.tv_sec++;
97689f32fbSJohn Stultz }
98689f32fbSJohn Stultz return ts;
99689f32fbSJohn Stultz }
100689f32fbSJohn Stultz
nanosleep_test(int clockid,long long ns)101689f32fbSJohn Stultz int nanosleep_test(int clockid, long long ns)
102689f32fbSJohn Stultz {
103689f32fbSJohn Stultz struct timespec now, target, rel;
104689f32fbSJohn Stultz
105689f32fbSJohn Stultz /* First check abs time */
106689f32fbSJohn Stultz if (clock_gettime(clockid, &now))
107689f32fbSJohn Stultz return UNSUPPORTED;
108689f32fbSJohn Stultz target = timespec_add(now, ns);
109689f32fbSJohn Stultz
110689f32fbSJohn Stultz if (clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL))
111689f32fbSJohn Stultz return UNSUPPORTED;
112689f32fbSJohn Stultz clock_gettime(clockid, &now);
113689f32fbSJohn Stultz
114689f32fbSJohn Stultz if (!in_order(target, now))
115689f32fbSJohn Stultz return -1;
116689f32fbSJohn Stultz
117689f32fbSJohn Stultz /* Second check reltime */
118689f32fbSJohn Stultz clock_gettime(clockid, &now);
119689f32fbSJohn Stultz rel.tv_sec = 0;
120689f32fbSJohn Stultz rel.tv_nsec = 0;
121689f32fbSJohn Stultz rel = timespec_add(rel, ns);
122689f32fbSJohn Stultz target = timespec_add(now, ns);
123689f32fbSJohn Stultz clock_nanosleep(clockid, 0, &rel, NULL);
124689f32fbSJohn Stultz clock_gettime(clockid, &now);
125689f32fbSJohn Stultz
126689f32fbSJohn Stultz if (!in_order(target, now))
127689f32fbSJohn Stultz return -1;
128689f32fbSJohn Stultz return 0;
129689f32fbSJohn Stultz }
130689f32fbSJohn Stultz
main(int argc,char ** argv)131689f32fbSJohn Stultz int main(int argc, char **argv)
132689f32fbSJohn Stultz {
133689f32fbSJohn Stultz long long length;
134689f32fbSJohn Stultz int clockid, ret;
135689f32fbSJohn Stultz
136*2d87048aSWolfram Sang ksft_print_header();
137*2d87048aSWolfram Sang ksft_set_plan(NR_CLOCKIDS);
138*2d87048aSWolfram Sang
139689f32fbSJohn Stultz for (clockid = CLOCK_REALTIME; clockid < NR_CLOCKIDS; clockid++) {
140689f32fbSJohn Stultz
141689f32fbSJohn Stultz /* Skip cputime clockids since nanosleep won't increment cputime */
142689f32fbSJohn Stultz if (clockid == CLOCK_PROCESS_CPUTIME_ID ||
143689f32fbSJohn Stultz clockid == CLOCK_THREAD_CPUTIME_ID ||
144*2d87048aSWolfram Sang clockid == CLOCK_HWSPECIFIC) {
145*2d87048aSWolfram Sang ksft_test_result_skip("%-31s\n", clockstring(clockid));
146689f32fbSJohn Stultz continue;
147*2d87048aSWolfram Sang }
148689f32fbSJohn Stultz
149fe483192SKees Cook fflush(stdout);
150689f32fbSJohn Stultz
151689f32fbSJohn Stultz length = 10;
152689f32fbSJohn Stultz while (length <= (NSEC_PER_SEC * 10)) {
153689f32fbSJohn Stultz ret = nanosleep_test(clockid, length);
154689f32fbSJohn Stultz if (ret == UNSUPPORTED) {
155*2d87048aSWolfram Sang ksft_test_result_skip("%-31s\n", clockstring(clockid));
156689f32fbSJohn Stultz goto next;
157689f32fbSJohn Stultz }
158689f32fbSJohn Stultz if (ret < 0) {
159*2d87048aSWolfram Sang ksft_test_result_fail("%-31s\n", clockstring(clockid));
160*2d87048aSWolfram Sang ksft_exit_fail();
161689f32fbSJohn Stultz }
162689f32fbSJohn Stultz length *= 100;
163689f32fbSJohn Stultz }
164*2d87048aSWolfram Sang ksft_test_result_pass("%-31s\n", clockstring(clockid));
165689f32fbSJohn Stultz next:
166689f32fbSJohn Stultz ret = 0;
167689f32fbSJohn Stultz }
168*2d87048aSWolfram Sang ksft_exit_pass();
169689f32fbSJohn Stultz }
170