1*dea9f5e6SRobert Mustacchi /*
2*dea9f5e6SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*dea9f5e6SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*dea9f5e6SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*dea9f5e6SRobert Mustacchi  * 1.0 of the CDDL.
6*dea9f5e6SRobert Mustacchi  *
7*dea9f5e6SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*dea9f5e6SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*dea9f5e6SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*dea9f5e6SRobert Mustacchi  */
11*dea9f5e6SRobert Mustacchi 
12*dea9f5e6SRobert Mustacchi /*
13*dea9f5e6SRobert Mustacchi  * Copyright 2021 Oxide Comptuer Company
14*dea9f5e6SRobert Mustacchi  */
15*dea9f5e6SRobert Mustacchi 
16*dea9f5e6SRobert Mustacchi /*
17*dea9f5e6SRobert Mustacchi  * Test a bunch of basics around clocks.
18*dea9f5e6SRobert Mustacchi  */
19*dea9f5e6SRobert Mustacchi 
20*dea9f5e6SRobert Mustacchi #include <time.h>
21*dea9f5e6SRobert Mustacchi #include <err.h>
22*dea9f5e6SRobert Mustacchi #include <stdlib.h>
23*dea9f5e6SRobert Mustacchi #include <libproc.h>
24*dea9f5e6SRobert Mustacchi #include <thread.h>
25*dea9f5e6SRobert Mustacchi #include <sys/sysmacros.h>
26*dea9f5e6SRobert Mustacchi 
27*dea9f5e6SRobert Mustacchi typedef hrtime_t (*clock_alttime_f)(void);
28*dea9f5e6SRobert Mustacchi 
29*dea9f5e6SRobert Mustacchi typedef struct clock_gettime_test {
30*dea9f5e6SRobert Mustacchi 	clockid_t	cgt_clock;
31*dea9f5e6SRobert Mustacchi 	clock_alttime_f	cgt_alt;
32*dea9f5e6SRobert Mustacchi 	const char	*cgt_name;
33*dea9f5e6SRobert Mustacchi } clock_gettime_test_t;
34*dea9f5e6SRobert Mustacchi 
35*dea9f5e6SRobert Mustacchi typedef struct clock_gettime_thr_arg {
36*dea9f5e6SRobert Mustacchi 	hrtime_t	cgta_usr;
37*dea9f5e6SRobert Mustacchi 	hrtime_t	cgta_usrsys;
38*dea9f5e6SRobert Mustacchi } clock_gettime_thr_arg_t;
39*dea9f5e6SRobert Mustacchi 
40*dea9f5e6SRobert Mustacchi static hrtime_t
clock_ts2hrt(const timespec_t * tsp)41*dea9f5e6SRobert Mustacchi clock_ts2hrt(const timespec_t *tsp)
42*dea9f5e6SRobert Mustacchi {
43*dea9f5e6SRobert Mustacchi 	return ((tsp->tv_sec * NANOSEC) + tsp->tv_nsec);
44*dea9f5e6SRobert Mustacchi }
45*dea9f5e6SRobert Mustacchi 
46*dea9f5e6SRobert Mustacchi static hrtime_t
clock_gettime_proc(void)47*dea9f5e6SRobert Mustacchi clock_gettime_proc(void)
48*dea9f5e6SRobert Mustacchi {
49*dea9f5e6SRobert Mustacchi 	psinfo_t ps;
50*dea9f5e6SRobert Mustacchi 
51*dea9f5e6SRobert Mustacchi 	if (proc_get_psinfo(getpid(), &ps) != 0) {
52*dea9f5e6SRobert Mustacchi 		warn("failed to get psinfo for process");
53*dea9f5e6SRobert Mustacchi 		return (0);
54*dea9f5e6SRobert Mustacchi 	}
55*dea9f5e6SRobert Mustacchi 
56*dea9f5e6SRobert Mustacchi 	return (clock_ts2hrt(&ps.pr_time));
57*dea9f5e6SRobert Mustacchi }
58*dea9f5e6SRobert Mustacchi 
59*dea9f5e6SRobert Mustacchi static hrtime_t
clock_gettime_thread(void)60*dea9f5e6SRobert Mustacchi clock_gettime_thread(void)
61*dea9f5e6SRobert Mustacchi {
62*dea9f5e6SRobert Mustacchi 	lwpsinfo_t lwpsinfo;
63*dea9f5e6SRobert Mustacchi 
64*dea9f5e6SRobert Mustacchi 	if (proc_get_lwpsinfo(getpid(), thr_self(), &lwpsinfo) != 0) {
65*dea9f5e6SRobert Mustacchi 		warn("failed to get lwpsinfo for thread %u", thr_self());
66*dea9f5e6SRobert Mustacchi 		return (0);
67*dea9f5e6SRobert Mustacchi 	}
68*dea9f5e6SRobert Mustacchi 
69*dea9f5e6SRobert Mustacchi 	return (clock_ts2hrt(&lwpsinfo.pr_time));
70*dea9f5e6SRobert Mustacchi }
71*dea9f5e6SRobert Mustacchi 
72*dea9f5e6SRobert Mustacchi clock_gettime_test_t clock_tests[] = {
73*dea9f5e6SRobert Mustacchi 	{ CLOCK_HIGHRES, gethrtime, "highres" },
74*dea9f5e6SRobert Mustacchi 	{ CLOCK_VIRTUAL, gethrvtime, "virtual" },
75*dea9f5e6SRobert Mustacchi 	{ CLOCK_THREAD_CPUTIME_ID, clock_gettime_thread, "thread_cputime" },
76*dea9f5e6SRobert Mustacchi 	{ CLOCK_PROCESS_CPUTIME_ID, clock_gettime_proc, "proc_cputime" }
77*dea9f5e6SRobert Mustacchi };
78*dea9f5e6SRobert Mustacchi 
79*dea9f5e6SRobert Mustacchi /*
80*dea9f5e6SRobert Mustacchi  * Do a series of reads of the clock from clock_gettime and its secondary
81*dea9f5e6SRobert Mustacchi  * source. Make sure that we always see increasing values.
82*dea9f5e6SRobert Mustacchi  */
83*dea9f5e6SRobert Mustacchi static boolean_t
clock_test(clock_gettime_test_t * test)84*dea9f5e6SRobert Mustacchi clock_test(clock_gettime_test_t *test)
85*dea9f5e6SRobert Mustacchi {
86*dea9f5e6SRobert Mustacchi 	hrtime_t hrt0, hrt1, hrt2, convts0, convts1;
87*dea9f5e6SRobert Mustacchi 	struct timespec ts0, ts1;
88*dea9f5e6SRobert Mustacchi 	boolean_t ret = B_TRUE;
89*dea9f5e6SRobert Mustacchi 
90*dea9f5e6SRobert Mustacchi 	if (clock_gettime(test->cgt_clock, &ts0) != 0) {
91*dea9f5e6SRobert Mustacchi 		warn("failed to get clock %u", test->cgt_clock);
92*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
93*dea9f5e6SRobert Mustacchi 	}
94*dea9f5e6SRobert Mustacchi 
95*dea9f5e6SRobert Mustacchi 	hrt0 = test->cgt_alt();
96*dea9f5e6SRobert Mustacchi 	hrt1 = test->cgt_alt();
97*dea9f5e6SRobert Mustacchi 
98*dea9f5e6SRobert Mustacchi 	if (clock_gettime(test->cgt_clock, &ts1) != 0) {
99*dea9f5e6SRobert Mustacchi 		warn("failed to get clock %u", test->cgt_clock);
100*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
101*dea9f5e6SRobert Mustacchi 	}
102*dea9f5e6SRobert Mustacchi 
103*dea9f5e6SRobert Mustacchi 	hrt2 = test->cgt_alt();
104*dea9f5e6SRobert Mustacchi 
105*dea9f5e6SRobert Mustacchi 	convts0 = clock_ts2hrt(&ts0);
106*dea9f5e6SRobert Mustacchi 	convts1 = clock_ts2hrt(&ts1);
107*dea9f5e6SRobert Mustacchi 
108*dea9f5e6SRobert Mustacchi 	if (convts0 > hrt0) {
109*dea9f5e6SRobert Mustacchi 		warnx("clock %s traveled backwards, clock_gettime ahead of "
110*dea9f5e6SRobert Mustacchi 		    "later alternate: clock_gettime %lld, alternate: %lld",
111*dea9f5e6SRobert Mustacchi 		    test->cgt_name, convts0, hrt0);
112*dea9f5e6SRobert Mustacchi 		ret = B_FALSE;
113*dea9f5e6SRobert Mustacchi 	}
114*dea9f5e6SRobert Mustacchi 
115*dea9f5e6SRobert Mustacchi 	if (hrt0 > hrt1) {
116*dea9f5e6SRobert Mustacchi 		warnx("clock %s traveled backwards, alternate ahead of "
117*dea9f5e6SRobert Mustacchi 		    "later alternate: first alternate %lld, later "
118*dea9f5e6SRobert Mustacchi 		    "alternate: %lld", test->cgt_name, hrt0, hrt1);
119*dea9f5e6SRobert Mustacchi 		ret = B_FALSE;
120*dea9f5e6SRobert Mustacchi 	}
121*dea9f5e6SRobert Mustacchi 
122*dea9f5e6SRobert Mustacchi 	if (convts1 > hrt2) {
123*dea9f5e6SRobert Mustacchi 		warnx("clock %s traveled backwards, clock_gettime ahead of "
124*dea9f5e6SRobert Mustacchi 		    "later alternate: clock_gettime %lld, alternate: %lld",
125*dea9f5e6SRobert Mustacchi 		    test->cgt_name, convts1, hrt2);
126*dea9f5e6SRobert Mustacchi 		ret = B_FALSE;
127*dea9f5e6SRobert Mustacchi 	}
128*dea9f5e6SRobert Mustacchi 
129*dea9f5e6SRobert Mustacchi 	if (hrt1 > hrt2) {
130*dea9f5e6SRobert Mustacchi 		warnx("clock %s traveled backwards, alternate ahead of "
131*dea9f5e6SRobert Mustacchi 		    "later alternate: first alternate %lld, later "
132*dea9f5e6SRobert Mustacchi 		    "alternate: %lld", test->cgt_name, hrt1, hrt2);
133*dea9f5e6SRobert Mustacchi 		ret = B_FALSE;
134*dea9f5e6SRobert Mustacchi 	}
135*dea9f5e6SRobert Mustacchi 
136*dea9f5e6SRobert Mustacchi 	if (convts0 > convts1) {
137*dea9f5e6SRobert Mustacchi 		warnx("clock %s traveled backwards, clock_gettime ahead of "
138*dea9f5e6SRobert Mustacchi 		    "later clock_gettime: first clock_gettime %lld, later "
139*dea9f5e6SRobert Mustacchi 		    "clock_gettime: %lld", test->cgt_name, convts0, convts1);
140*dea9f5e6SRobert Mustacchi 		ret = B_FALSE;
141*dea9f5e6SRobert Mustacchi 	}
142*dea9f5e6SRobert Mustacchi 
143*dea9f5e6SRobert Mustacchi 	return (ret);
144*dea9f5e6SRobert Mustacchi }
145*dea9f5e6SRobert Mustacchi 
146*dea9f5e6SRobert Mustacchi static void *
clock_test_thr(void * arg)147*dea9f5e6SRobert Mustacchi clock_test_thr(void *arg)
148*dea9f5e6SRobert Mustacchi {
149*dea9f5e6SRobert Mustacchi 	boolean_t ret = B_TRUE;
150*dea9f5e6SRobert Mustacchi 
151*dea9f5e6SRobert Mustacchi 	for (uint_t i = 0; i < ARRAY_SIZE(clock_tests); i++) {
152*dea9f5e6SRobert Mustacchi 		boolean_t rval = clock_test(&clock_tests[i]);
153*dea9f5e6SRobert Mustacchi 		if (!rval) {
154*dea9f5e6SRobert Mustacchi 			ret = B_FALSE;
155*dea9f5e6SRobert Mustacchi 		}
156*dea9f5e6SRobert Mustacchi 
157*dea9f5e6SRobert Mustacchi 		(void) printf("TEST %s: basic %s usage and interleaving%s\n",
158*dea9f5e6SRobert Mustacchi 		    rval ? "PASSED" : "FAILED", clock_tests[i].cgt_name,
159*dea9f5e6SRobert Mustacchi 		    thr_self() == 1 ? "" : " (in thread)");
160*dea9f5e6SRobert Mustacchi 	}
161*dea9f5e6SRobert Mustacchi 
162*dea9f5e6SRobert Mustacchi 	return ((void *)(uintptr_t)ret);
163*dea9f5e6SRobert Mustacchi }
164*dea9f5e6SRobert Mustacchi 
165*dea9f5e6SRobert Mustacchi static void *
clock_test_cputime_thr(void * arg)166*dea9f5e6SRobert Mustacchi clock_test_cputime_thr(void *arg)
167*dea9f5e6SRobert Mustacchi {
168*dea9f5e6SRobert Mustacchi 	struct timespec ts;
169*dea9f5e6SRobert Mustacchi 	clock_gettime_thr_arg_t *cp = arg;
170*dea9f5e6SRobert Mustacchi 
171*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_VIRTUAL, &ts) != 0) {
172*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_VIRTUAL");
173*dea9f5e6SRobert Mustacchi 		cp->cgta_usr = 0;
174*dea9f5e6SRobert Mustacchi 	} else {
175*dea9f5e6SRobert Mustacchi 		cp->cgta_usr = clock_ts2hrt(&ts);
176*dea9f5e6SRobert Mustacchi 	}
177*dea9f5e6SRobert Mustacchi 
178*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_VIRTUAL, &ts) != 0) {
179*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_VIRTUAL");
180*dea9f5e6SRobert Mustacchi 		cp->cgta_usrsys = 0;
181*dea9f5e6SRobert Mustacchi 	} else {
182*dea9f5e6SRobert Mustacchi 		cp->cgta_usrsys = clock_ts2hrt(&ts);
183*dea9f5e6SRobert Mustacchi 	}
184*dea9f5e6SRobert Mustacchi 
185*dea9f5e6SRobert Mustacchi 	return (NULL);
186*dea9f5e6SRobert Mustacchi }
187*dea9f5e6SRobert Mustacchi 
188*dea9f5e6SRobert Mustacchi /*
189*dea9f5e6SRobert Mustacchi  * Compare the value of CLOCK_THREAD_CPUTIME_ID between a new thread and the
190*dea9f5e6SRobert Mustacchi  * main thread.
191*dea9f5e6SRobert Mustacchi  */
192*dea9f5e6SRobert Mustacchi static boolean_t
clock_test_thread_clock(void)193*dea9f5e6SRobert Mustacchi clock_test_thread_clock(void)
194*dea9f5e6SRobert Mustacchi {
195*dea9f5e6SRobert Mustacchi 	thread_t thr;
196*dea9f5e6SRobert Mustacchi 	clock_gettime_thr_arg_t arg;
197*dea9f5e6SRobert Mustacchi 	hrtime_t hrt;
198*dea9f5e6SRobert Mustacchi 	struct timespec ts;
199*dea9f5e6SRobert Mustacchi 	boolean_t ret = B_TRUE;
200*dea9f5e6SRobert Mustacchi 
201*dea9f5e6SRobert Mustacchi 	if (thr_create(NULL, 0, clock_test_cputime_thr, &arg, 0, &thr) != 0) {
202*dea9f5e6SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to create thread to run basic "
203*dea9f5e6SRobert Mustacchi 		    "tests!");
204*dea9f5e6SRobert Mustacchi 	}
205*dea9f5e6SRobert Mustacchi 
206*dea9f5e6SRobert Mustacchi 	if (thr_join(thr, NULL, NULL) != 0) {
207*dea9f5e6SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to join to thread that ran basic "
208*dea9f5e6SRobert Mustacchi 		    "tests");
209*dea9f5e6SRobert Mustacchi 	}
210*dea9f5e6SRobert Mustacchi 
211*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_VIRTUAL, &ts) != 0) {
212*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_VIRTUAL");
213*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
214*dea9f5e6SRobert Mustacchi 	}
215*dea9f5e6SRobert Mustacchi 
216*dea9f5e6SRobert Mustacchi 	hrt = clock_ts2hrt(&ts);
217*dea9f5e6SRobert Mustacchi 	if (arg.cgta_usr > hrt) {
218*dea9f5e6SRobert Mustacchi 		warnx("new thread %u somehow had higher CLOCK_VIRTUAL time "
219*dea9f5e6SRobert Mustacchi 		    "than main thread: new thread: %lld, main thread: %lld",
220*dea9f5e6SRobert Mustacchi 		    thr, hrt, arg.cgta_usr);
221*dea9f5e6SRobert Mustacchi 		ret = B_FALSE;
222*dea9f5e6SRobert Mustacchi 	}
223*dea9f5e6SRobert Mustacchi 
224*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) {
225*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_THREAD_CPUTIME_ID");
226*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
227*dea9f5e6SRobert Mustacchi 	}
228*dea9f5e6SRobert Mustacchi 
229*dea9f5e6SRobert Mustacchi 	hrt = clock_ts2hrt(&ts);
230*dea9f5e6SRobert Mustacchi 	if (arg.cgta_usr > hrt) {
231*dea9f5e6SRobert Mustacchi 		warnx("new thread %u somehow had higher "
232*dea9f5e6SRobert Mustacchi 		    "CLOCK_THREAD_CPUTIME_ID time than main thread: new "
233*dea9f5e6SRobert Mustacchi 		    "thread: %lld, main thread: %lld", thr, hrt, arg.cgta_usr);
234*dea9f5e6SRobert Mustacchi 		ret = B_FALSE;
235*dea9f5e6SRobert Mustacchi 	}
236*dea9f5e6SRobert Mustacchi 
237*dea9f5e6SRobert Mustacchi 	return (ret);
238*dea9f5e6SRobert Mustacchi }
239*dea9f5e6SRobert Mustacchi 
240*dea9f5e6SRobert Mustacchi /*
241*dea9f5e6SRobert Mustacchi  * This test is a little circumspect. It's basically going to argue that all the
242*dea9f5e6SRobert Mustacchi  * time we spent doing kernel actions should be larger than the additional bit
243*dea9f5e6SRobert Mustacchi  * of user time to make a subsequent system call. That seems probably
244*dea9f5e6SRobert Mustacchi  * reasonable given everything we've done; however, there's no way to feel like
245*dea9f5e6SRobert Mustacchi  * it's not possibly going to lead to false positives. If so, then just delete
246*dea9f5e6SRobert Mustacchi  * this.
247*dea9f5e6SRobert Mustacchi  */
248*dea9f5e6SRobert Mustacchi static boolean_t
clock_test_thread_sys(void)249*dea9f5e6SRobert Mustacchi clock_test_thread_sys(void)
250*dea9f5e6SRobert Mustacchi {
251*dea9f5e6SRobert Mustacchi 	struct timespec usr, sys;
252*dea9f5e6SRobert Mustacchi 	hrtime_t hrtusr, hrtsys;
253*dea9f5e6SRobert Mustacchi 
254*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &sys) != 0) {
255*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_THREAD_CPUTIME_ID");
256*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
257*dea9f5e6SRobert Mustacchi 	}
258*dea9f5e6SRobert Mustacchi 
259*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_VIRTUAL, &usr) != 0) {
260*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_VIRTUAL");
261*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
262*dea9f5e6SRobert Mustacchi 	}
263*dea9f5e6SRobert Mustacchi 
264*dea9f5e6SRobert Mustacchi 	hrtusr = clock_ts2hrt(&usr);
265*dea9f5e6SRobert Mustacchi 	hrtsys = clock_ts2hrt(&sys);
266*dea9f5e6SRobert Mustacchi 
267*dea9f5e6SRobert Mustacchi 	if (hrtusr > hrtsys) {
268*dea9f5e6SRobert Mustacchi 		warnx("CLOCK_VIRTUAL was greater than CLOCK_THREAD_CPUTIME_ID: "
269*dea9f5e6SRobert Mustacchi 		    "usr time: %lld, usr/sys time: %lld (this may be a race)",
270*dea9f5e6SRobert Mustacchi 		    hrtusr, hrtsys);
271*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
272*dea9f5e6SRobert Mustacchi 	}
273*dea9f5e6SRobert Mustacchi 
274*dea9f5e6SRobert Mustacchi 	return (B_TRUE);
275*dea9f5e6SRobert Mustacchi }
276*dea9f5e6SRobert Mustacchi 
277*dea9f5e6SRobert Mustacchi /*
278*dea9f5e6SRobert Mustacchi  * This is similar to clock_test_thread_sys(), but using the process clock and
279*dea9f5e6SRobert Mustacchi  * the thread clock. This is circumspect for similar reasons.
280*dea9f5e6SRobert Mustacchi  */
281*dea9f5e6SRobert Mustacchi static boolean_t
clock_test_thread_proc(void)282*dea9f5e6SRobert Mustacchi clock_test_thread_proc(void)
283*dea9f5e6SRobert Mustacchi {
284*dea9f5e6SRobert Mustacchi 	struct timespec thr, proc;
285*dea9f5e6SRobert Mustacchi 	hrtime_t hrtthr, hrtproc;
286*dea9f5e6SRobert Mustacchi 
287*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &proc) != 0) {
288*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_VIRTUAL");
289*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
290*dea9f5e6SRobert Mustacchi 	}
291*dea9f5e6SRobert Mustacchi 
292*dea9f5e6SRobert Mustacchi 	if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &thr) != 0) {
293*dea9f5e6SRobert Mustacchi 		warn("failed to get clock CLOCK_THREAD_CPUTIME_ID");
294*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
295*dea9f5e6SRobert Mustacchi 	}
296*dea9f5e6SRobert Mustacchi 
297*dea9f5e6SRobert Mustacchi 	hrtthr = clock_ts2hrt(&thr);
298*dea9f5e6SRobert Mustacchi 	hrtproc = clock_ts2hrt(&proc);
299*dea9f5e6SRobert Mustacchi 
300*dea9f5e6SRobert Mustacchi 	if (hrtthr > hrtproc) {
301*dea9f5e6SRobert Mustacchi 		warnx("CLOCK_THRAD_CPUTIME_ID was greater than "
302*dea9f5e6SRobert Mustacchi 		    "CLOCK_PROCESS_CPUTIME_ID: thr time: %lld, proc time: %lld "
303*dea9f5e6SRobert Mustacchi 		    "(this may be a race)", hrtthr, hrtproc);
304*dea9f5e6SRobert Mustacchi 		return (B_FALSE);
305*dea9f5e6SRobert Mustacchi 	}
306*dea9f5e6SRobert Mustacchi 
307*dea9f5e6SRobert Mustacchi 	return (B_TRUE);
308*dea9f5e6SRobert Mustacchi }
309*dea9f5e6SRobert Mustacchi 
310*dea9f5e6SRobert Mustacchi int
main(void)311*dea9f5e6SRobert Mustacchi main(void)
312*dea9f5e6SRobert Mustacchi {
313*dea9f5e6SRobert Mustacchi 	int ret = EXIT_SUCCESS;
314*dea9f5e6SRobert Mustacchi 	void *thr_ret;
315*dea9f5e6SRobert Mustacchi 	thread_t thr;
316*dea9f5e6SRobert Mustacchi 	boolean_t bval;
317*dea9f5e6SRobert Mustacchi 
318*dea9f5e6SRobert Mustacchi 	thr_ret = clock_test_thr(NULL);
319*dea9f5e6SRobert Mustacchi 	if (!(boolean_t)(uintptr_t)thr_ret) {
320*dea9f5e6SRobert Mustacchi 		ret = EXIT_FAILURE;
321*dea9f5e6SRobert Mustacchi 	}
322*dea9f5e6SRobert Mustacchi 
323*dea9f5e6SRobert Mustacchi 	if (thr_create(NULL, 0, clock_test_thr, NULL, 0, &thr) != 0) {
324*dea9f5e6SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to create thread to run basic "
325*dea9f5e6SRobert Mustacchi 		    "tests!");
326*dea9f5e6SRobert Mustacchi 	}
327*dea9f5e6SRobert Mustacchi 
328*dea9f5e6SRobert Mustacchi 	if (thr_join(thr, NULL, &thr_ret) != 0) {
329*dea9f5e6SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to join to thread that ran basic "
330*dea9f5e6SRobert Mustacchi 		    "tests");
331*dea9f5e6SRobert Mustacchi 	}
332*dea9f5e6SRobert Mustacchi 
333*dea9f5e6SRobert Mustacchi 	if (!(boolean_t)(uintptr_t)thr_ret) {
334*dea9f5e6SRobert Mustacchi 		ret = EXIT_FAILURE;
335*dea9f5e6SRobert Mustacchi 	}
336*dea9f5e6SRobert Mustacchi 
337*dea9f5e6SRobert Mustacchi 	bval = clock_test_thread_clock();
338*dea9f5e6SRobert Mustacchi 	(void) printf("TEST %s: comparing CLOCK_THREAD_CPUTIME_ID and "
339*dea9f5e6SRobert Mustacchi 	    "CLOCK_VIRTUAL between threads\n", bval ? "PASSED" : "FAILED");
340*dea9f5e6SRobert Mustacchi 
341*dea9f5e6SRobert Mustacchi 	bval = clock_test_thread_sys();
342*dea9f5e6SRobert Mustacchi 	(void) printf("TEST %s: comparing CLOCK_THREAD_CPUTIME_ID and "
343*dea9f5e6SRobert Mustacchi 	    "CLOCK_VIRTUAL\n", bval ? "PASSED" : "FAILED");
344*dea9f5e6SRobert Mustacchi 
345*dea9f5e6SRobert Mustacchi 
346*dea9f5e6SRobert Mustacchi 	bval = clock_test_thread_proc();
347*dea9f5e6SRobert Mustacchi 	(void) printf("TEST %s: comparing CLOCK_THREAD_CPUTIME_ID and "
348*dea9f5e6SRobert Mustacchi 	    "CLOCK_PROCESS_CPUTIME_ID\n", bval ? "PASSED" : "FAILED");
349*dea9f5e6SRobert Mustacchi 	/*
350*dea9f5e6SRobert Mustacchi 	 * XXX CLOCK_THREAD_CPUTIME_ID > CLOCK_VIRTUAL for same thread?
351*dea9f5e6SRobert Mustacchi 	 * XXX CLOCK_PROCESS_CPUTIME_ID > CLOCK_THREAD_CPUTIME_ID
352*dea9f5e6SRobert Mustacchi 	 */
353*dea9f5e6SRobert Mustacchi 
354*dea9f5e6SRobert Mustacchi 	return (ret);
355*dea9f5e6SRobert Mustacchi }
356