xref: /illumos-gate/usr/src/test/libc-tests/tests/timespec_get.c (revision d3aba68370c737a5035fef1f4c6a95a1ba0d815f)
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