1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2019 Linaro Limited. All rights reserved.
4  * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
5  */
6 /*
7  * Basic test for clock_gettime(2) on multiple clocks:
8  *
9  *  1) CLOCK_REALTIME
10  *  2) CLOCK_MONOTONIC
11  *  3) CLOCK_PROCESS_CPUTIME_ID
12  *  4) CLOCK_THREAD_CPUTIME_ID
13  *  5) CLOCK_REALTIME_COARSE
14  *  6) CLOCK_MONOTONIC_COARSE
15  *  7) CLOCK_MONOTONIC_RAW
16  *  8) CLOCK_BOOTTIME
17  */
18 
19 #include "config.h"
20 #include "tst_timer.h"
21 #include "tst_safe_clocks.h"
22 #include "tst_test.h"
23 #include "lapi/syscalls.h"
24 
25 struct test_case {
26 	clockid_t clktype;
27 	int allow_inval;
28 };
29 
30 struct tmpfunc {
31 	int (*func)(clockid_t clk_id, struct timespec *tp);
32 	char *desc;
33 };
34 
35 struct test_case tc[] = {
36 	{
37 	 .clktype = CLOCK_REALTIME,
38 	 },
39 	{
40 	 .clktype = CLOCK_MONOTONIC,
41 	 },
42 	{
43 	 .clktype = CLOCK_PROCESS_CPUTIME_ID,
44 	 },
45 	{
46 	 .clktype = CLOCK_THREAD_CPUTIME_ID,
47 	 },
48 	{
49 	 .clktype = CLOCK_REALTIME_COARSE,
50 	 .allow_inval = 1,
51 	 },
52 	{
53 	 .clktype = CLOCK_MONOTONIC_COARSE,
54 	 .allow_inval = 1,
55 	 },
56 	{
57 	 .clktype = CLOCK_MONOTONIC_RAW,
58 	 .allow_inval = 1,
59 	 },
60 	{
61 	 .clktype = CLOCK_BOOTTIME,
62 	 .allow_inval = 1,
63 	 },
64 };
65 
sys_clock_gettime(clockid_t clk_id,struct timespec * tp)66 static int sys_clock_gettime(clockid_t clk_id, struct timespec *tp)
67 {
68 	return tst_syscall(__NR_clock_gettime, clk_id, tp);
69 }
70 
check_spec(struct timespec * spec)71 static int check_spec(struct timespec *spec)
72 {
73 	return (spec->tv_nsec != 0 || spec->tv_sec != 0) ? 1 : 0;
74 }
75 
verify_clock_gettime(unsigned int i)76 static void verify_clock_gettime(unsigned int i)
77 {
78 	size_t sz;
79 	struct timespec spec;
80 
81 	/*
82 	 * check clock_gettime() syscall AND libc (or vDSO) functions
83 	 */
84 	struct tmpfunc tf[] = {
85 		{ .func = sys_clock_gettime, .desc = "syscall"      },
86 		{ .func = clock_gettime, .desc = "vDSO or syscall"  },
87 	};
88 
89 	for (sz = 0; sz < ARRAY_SIZE(tf); sz++) {
90 
91 		memset(&spec, 0, sizeof(struct timespec));
92 
93 		TEST(tf[sz].func(tc[i].clktype, &spec));
94 
95 		if (TST_RET == -1) {
96 
97 			/* errors: allow unsupported clock types */
98 
99 			if (tc[i].allow_inval && TST_ERR == EINVAL) {
100 
101 				tst_res(TPASS, "clock_gettime(2): unsupported "
102 						"clock %s (%s) failed as "
103 						"expected",
104 						tst_clock_name(tc[i].clktype),
105 						tf[sz].desc);
106 
107 			} else {
108 
109 				tst_res(TFAIL | TTERRNO, "clock_gettime(2): "
110 						"clock %s (%s) failed "
111 						"unexpectedly",
112 						tst_clock_name(tc[i].clktype),
113 						tf[sz].desc);
114 			}
115 
116 		} else {
117 
118 			/* success: also check if timespec was changed */
119 
120 			if (check_spec(&spec)) {
121 				tst_res(TPASS, "clock_gettime(2): clock %s "
122 						"(%s) passed",
123 						tst_clock_name(tc[i].clktype),
124 						tf[sz].desc);
125 			} else {
126 
127 				tst_res(TFAIL, "clock_gettime(2): clock %s "
128 						"(%s) passed, unchanged "
129 						"timespec",
130 						tst_clock_name(tc[i].clktype),
131 						tf[sz].desc);
132 			}
133 		}
134 	}
135 }
136 
137 static struct tst_test test = {
138 	.test = verify_clock_gettime,
139 	.tcnt = ARRAY_SIZE(tc),
140 	.needs_root = 1,
141 };
142