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