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