1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2016 Joyent, Inc.
14 * Copyright 2025 Oxide Computer Company
15 */
16
17 /*
18 * Basic tests for timespec_get(3C).
19 */
20
21 #include <time.h>
22 #include <limits.h>
23 #include <err.h>
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <sys/sysmacros.h>
27
28 typedef struct {
29 int gc_base;
30 clockid_t gc_clock;
31 const char *gc_desc;
32 } get_cmp_t;
33
34 static const get_cmp_t ts_gets[] = {
35 { TIME_UTC, CLOCK_REALTIME, "real time clock" },
36 { TIME_MONOTONIC, CLOCK_HIGHRES, "highres clock" },
37 { TIME_ACTIVE, CLOCK_PROCESS_CPUTIME_ID, "process clock" },
38 { TIME_THREAD_ACTIVE, CLOCK_THREAD_CPUTIME_ID, "thread clock" },
39 { TIME_THREAD_ACTIVE_USR, CLOCK_VIRTUAL, "thread (usr) clock" },
40 };
41
42 static const int bad_clocks[] = { 7777, -7777, INT16_MIN, CHAR_MAX };
43
44 static int
timespec_cmp(const struct timespec * ls,const struct timespec * rs)45 timespec_cmp(const struct timespec *ls, const struct timespec *rs)
46 {
47 if (ls->tv_sec > rs->tv_sec)
48 return (-1);
49 if (ls->tv_sec < rs->tv_sec)
50 return (1);
51 if (ls->tv_nsec > rs->tv_nsec)
52 return (-1);
53 if (ls->tv_nsec > rs->tv_nsec)
54 return (-1);
55 if (ls->tv_nsec < rs->tv_nsec)
56 return (1);
57
58 return (0);
59 }
60
61 static bool
timespec_test_one(const char * desc,int base,clockid_t clock)62 timespec_test_one(const char *desc, int base, clockid_t clock)
63 {
64 int ret;
65 struct timespec ts, pre, post;
66
67 if (clock_gettime(clock, &pre) != 0) {
68 warn("TEST FAILED: %s: pre clock_gettime(%d) failed", desc,
69 clock);
70 return (false);
71 }
72
73 if ((ret = timespec_get(&ts, base)) != base) {
74 warnx("TEST FAILED: %s timespec_get did not return %d: got %d",
75 desc, base, ret);
76 return (false);
77 }
78
79 if (clock_gettime(clock, &post) != 0) {
80 warn("TEST FAILED: %s: post clock_gettime(%d) failed", desc,
81 clock);
82 return (false);
83 }
84
85 if (timespec_cmp(&pre, &ts) != 1) {
86 warnx("TEST FAILED: %s: timespec_get did not come after "
87 "pre-clock_gettime: found clock 0x%lx/0x%lx vs. timespec "
88 "0x%lx/0x%lx", desc, pre.tv_sec, pre.tv_nsec, ts.tv_sec,
89 ts.tv_nsec);
90 return (false);
91 }
92
93 if (timespec_cmp(&ts, &post) != 1) {
94 warnx("TEST FAILED: %s: timespec_get did not come before "
95 "post-clock_gettime: found timespec 0x%lx/0x%lx vs. clock "
96 "0x%lx/0x%lx", desc, ts.tv_sec, ts.tv_nsec, post.tv_sec,
97 post.tv_nsec);
98 return (false);
99 }
100
101 (void) printf("TEST PASSED: %s: basic timespec_get works\n", desc);
102 return (true);
103 }
104
105 int
main(void)106 main(void)
107 {
108 int ret = EXIT_SUCCESS;
109
110 for (size_t i = 0; i < ARRAY_SIZE(ts_gets); i++) {
111 if (!timespec_test_one(ts_gets[i].gc_desc, ts_gets[i].gc_base,
112 ts_gets[i].gc_clock)) {
113 ret = EXIT_FAILURE;
114 }
115 }
116
117 for (size_t i = 0; i < ARRAY_SIZE(bad_clocks); i++) {
118 struct timespec ts;
119
120 if (timespec_getres(&ts, bad_clocks[i]) != 0) {
121 warnx("TEST FAILED: timespec_get didn't fail "
122 "with bad clock (%d)", bad_clocks[i]);
123 ret = EXIT_FAILURE;
124 } else {
125 (void) printf("TEST PASSED: timespec_get failed "
126 "with bad clock (%d)\n", bad_clocks[i]);
127 }
128 }
129
130 if (ret == EXIT_SUCCESS) {
131 (void) printf("All tests passed successfully\n");
132 }
133
134 return (ret);
135 }
136