xref: /illumos-gate/usr/src/uts/common/os/clock_thread.c (revision dea9f5e6a4938723acec9624b3aa3f680f2f5c9f)
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 Computer Company
14*dea9f5e6SRobert Mustacchi  */
15*dea9f5e6SRobert Mustacchi 
16*dea9f5e6SRobert Mustacchi /*
17*dea9f5e6SRobert Mustacchi  * This clock backend implements basic support for the following two clocks:
18*dea9f5e6SRobert Mustacchi  *
19*dea9f5e6SRobert Mustacchi  *   o CLOCK_VIRTUAL		This provides the ability to read the amount of
20*dea9f5e6SRobert Mustacchi  *				user CPU time that the calling thread has spent
21*dea9f5e6SRobert Mustacchi  *				on CPU. This is the LMS_USER cpu microstate.
22*dea9f5e6SRobert Mustacchi  *
23*dea9f5e6SRobert Mustacchi  *   o CLOCK_THREAD_CPUTIME_ID	This clock is similar to the above; however, it
24*dea9f5e6SRobert Mustacchi  *				also includes system time. This is the LMS_USER,
25*dea9f5e6SRobert Mustacchi  *				LMS_SYSTEM, and LMS_TRAP microstates combined
26*dea9f5e6SRobert Mustacchi  *				together. We include LMS_TRAP here because that
27*dea9f5e6SRobert Mustacchi  *				is what you see in a thread's lwpstatus file.
28*dea9f5e6SRobert Mustacchi  *
29*dea9f5e6SRobert Mustacchi  * At this time, we only provide the ability to read the current time (e.g.
30*dea9f5e6SRobert Mustacchi  * through a call to clock_gettime(3C)). There is never a case where being able
31*dea9f5e6SRobert Mustacchi  * to set the time makes sense today and truthfully, lying about a process's
32*dea9f5e6SRobert Mustacchi  * runtime should be left to mdb -kw. Today, we do not support the ability to
33*dea9f5e6SRobert Mustacchi  * create interval timers based on this backend (e.g. timer_create(3C) and
34*dea9f5e6SRobert Mustacchi  * timer_settime(3C)). However, there is no reason that couldn't be added.
35*dea9f5e6SRobert Mustacchi  *
36*dea9f5e6SRobert Mustacchi  * A nice simplification here is that this clock is always about reading from
37*dea9f5e6SRobert Mustacchi  * the current thread. This means that one can always access it. Because the
38*dea9f5e6SRobert Mustacchi  * calling thread exists and is in this code, it means that we know it is here.
39*dea9f5e6SRobert Mustacchi  * Any other privilege information is left to the broader kernel.
40*dea9f5e6SRobert Mustacchi  *
41*dea9f5e6SRobert Mustacchi  * Because the only difference between these is the question of whether or not
42*dea9f5e6SRobert Mustacchi  * we include LMS_SYSTEM time in the value, we generally use the same actual
43*dea9f5e6SRobert Mustacchi  * clock backend functions except for the one that implements
44*dea9f5e6SRobert Mustacchi  * clk_clock_gettime().
45*dea9f5e6SRobert Mustacchi  */
46*dea9f5e6SRobert Mustacchi 
47*dea9f5e6SRobert Mustacchi #include <sys/timer.h>
48*dea9f5e6SRobert Mustacchi #include <sys/cyclic.h>
49*dea9f5e6SRobert Mustacchi #include <sys/msacct.h>
50*dea9f5e6SRobert Mustacchi 
51*dea9f5e6SRobert Mustacchi static clock_backend_t clock_thread_usr;
52*dea9f5e6SRobert Mustacchi static clock_backend_t clock_thread_usrsys;
53*dea9f5e6SRobert Mustacchi 
54*dea9f5e6SRobert Mustacchi static int
clock_thread_settime(timespec_t * ts)55*dea9f5e6SRobert Mustacchi clock_thread_settime(timespec_t *ts)
56*dea9f5e6SRobert Mustacchi {
57*dea9f5e6SRobert Mustacchi 	return (EINVAL);
58*dea9f5e6SRobert Mustacchi }
59*dea9f5e6SRobert Mustacchi 
60*dea9f5e6SRobert Mustacchi static int
clock_thread_usr_gettime(timespec_t * ts)61*dea9f5e6SRobert Mustacchi clock_thread_usr_gettime(timespec_t *ts)
62*dea9f5e6SRobert Mustacchi {
63*dea9f5e6SRobert Mustacchi 	hrtime_t hrt;
64*dea9f5e6SRobert Mustacchi 	kthread_t *t = curthread;
65*dea9f5e6SRobert Mustacchi 	klwp_t *lwp = ttolwp(t);
66*dea9f5e6SRobert Mustacchi 
67*dea9f5e6SRobert Mustacchi 	hrt = lwp->lwp_mstate.ms_acct[LMS_USER];
68*dea9f5e6SRobert Mustacchi 	scalehrtime(&hrt);
69*dea9f5e6SRobert Mustacchi 	hrt2ts(hrt, ts);
70*dea9f5e6SRobert Mustacchi 
71*dea9f5e6SRobert Mustacchi 	return (0);
72*dea9f5e6SRobert Mustacchi }
73*dea9f5e6SRobert Mustacchi 
74*dea9f5e6SRobert Mustacchi static int
clock_thread_usrsys_gettime(timespec_t * ts)75*dea9f5e6SRobert Mustacchi clock_thread_usrsys_gettime(timespec_t *ts)
76*dea9f5e6SRobert Mustacchi {
77*dea9f5e6SRobert Mustacchi 	hrtime_t hrt;
78*dea9f5e6SRobert Mustacchi 	kthread_t *t = curthread;
79*dea9f5e6SRobert Mustacchi 
80*dea9f5e6SRobert Mustacchi 	/*
81*dea9f5e6SRobert Mustacchi 	 * mstate_thread_onproc_time() takes care of doing the following:
82*dea9f5e6SRobert Mustacchi 	 *
83*dea9f5e6SRobert Mustacchi 	 *  o Combining LMS_USER, LMS_SYSTEM, and LMS_TRAP.
84*dea9f5e6SRobert Mustacchi 	 *  o Ensuring that the result is scaled
85*dea9f5e6SRobert Mustacchi 	 *  o Ensuring that the time that's elapsed to the point of our asking
86*dea9f5e6SRobert Mustacchi 	 *    is included. By definition the kernel is executing in LMS_SYSTEM
87*dea9f5e6SRobert Mustacchi 	 *    so this ensures that we add that time which isn't currently in the
88*dea9f5e6SRobert Mustacchi 	 *    microstate to this.
89*dea9f5e6SRobert Mustacchi 	 */
90*dea9f5e6SRobert Mustacchi 	thread_lock(t);
91*dea9f5e6SRobert Mustacchi 	hrt = mstate_thread_onproc_time(t);
92*dea9f5e6SRobert Mustacchi 	thread_unlock(t);
93*dea9f5e6SRobert Mustacchi 
94*dea9f5e6SRobert Mustacchi 	hrt2ts(hrt, ts);
95*dea9f5e6SRobert Mustacchi 	return (0);
96*dea9f5e6SRobert Mustacchi }
97*dea9f5e6SRobert Mustacchi 
98*dea9f5e6SRobert Mustacchi /*
99*dea9f5e6SRobert Mustacchi  * The question of the resolution here is a thorny one. Technically this would
100*dea9f5e6SRobert Mustacchi  * really be based upon the resolution of gethrtime_unscaled(), as we can
101*dea9f5e6SRobert Mustacchi  * actually tell that much due to our use of CPU microstate accounting. However,
102*dea9f5e6SRobert Mustacchi  * from a timer resolution perspective it's actually quite different and would
103*dea9f5e6SRobert Mustacchi  * in theory be based on the system tick rate.
104*dea9f5e6SRobert Mustacchi  *
105*dea9f5e6SRobert Mustacchi  * This basically leaves us with two options:
106*dea9f5e6SRobert Mustacchi  *
107*dea9f5e6SRobert Mustacchi  *   1) Use 'nsec_per_tick' to go down the Hz path.
108*dea9f5e6SRobert Mustacchi  *   2) Use the cyclic resolution, which basically is kind of the resolution of
109*dea9f5e6SRobert Mustacchi  *      that timer.
110*dea9f5e6SRobert Mustacchi  *
111*dea9f5e6SRobert Mustacchi  * POSIX is unclear as to the effect of the resolution in the case of timer_*()
112*dea9f5e6SRobert Mustacchi  * functions and only really says it is used to impact the implementation of
113*dea9f5e6SRobert Mustacchi  * clock_settime() which of course isn't actually supported here. As a result,
114*dea9f5e6SRobert Mustacchi  * we opt to prefer the cyclic resolution, which is closer to the actual
115*dea9f5e6SRobert Mustacchi  * resolution of this subsystem. Strictly speaking, this might not be completely
116*dea9f5e6SRobert Mustacchi  * accurate, but should be on current platforms.
117*dea9f5e6SRobert Mustacchi  */
118*dea9f5e6SRobert Mustacchi static int
clock_thread_getres(timespec_t * ts)119*dea9f5e6SRobert Mustacchi clock_thread_getres(timespec_t *ts)
120*dea9f5e6SRobert Mustacchi {
121*dea9f5e6SRobert Mustacchi 	hrt2ts(cyclic_getres(), (timestruc_t *)ts);
122*dea9f5e6SRobert Mustacchi 
123*dea9f5e6SRobert Mustacchi 	return (0);
124*dea9f5e6SRobert Mustacchi }
125*dea9f5e6SRobert Mustacchi 
126*dea9f5e6SRobert Mustacchi static int
clock_thread_timer_create(itimer_t * it,void (* fire)(itimer_t *))127*dea9f5e6SRobert Mustacchi clock_thread_timer_create(itimer_t *it, void (*fire)(itimer_t *))
128*dea9f5e6SRobert Mustacchi {
129*dea9f5e6SRobert Mustacchi 	return (EINVAL);
130*dea9f5e6SRobert Mustacchi }
131*dea9f5e6SRobert Mustacchi 
132*dea9f5e6SRobert Mustacchi static int
clock_thread_timer_settime(itimer_t * it,int flags,const struct itimerspec * when)133*dea9f5e6SRobert Mustacchi clock_thread_timer_settime(itimer_t *it, int flags,
134*dea9f5e6SRobert Mustacchi     const struct itimerspec *when)
135*dea9f5e6SRobert Mustacchi {
136*dea9f5e6SRobert Mustacchi 	return (EINVAL);
137*dea9f5e6SRobert Mustacchi }
138*dea9f5e6SRobert Mustacchi 
139*dea9f5e6SRobert Mustacchi static int
clock_thread_timer_gettime(itimer_t * it,struct itimerspec * when)140*dea9f5e6SRobert Mustacchi clock_thread_timer_gettime(itimer_t *it, struct itimerspec *when)
141*dea9f5e6SRobert Mustacchi {
142*dea9f5e6SRobert Mustacchi 	return (EINVAL);
143*dea9f5e6SRobert Mustacchi }
144*dea9f5e6SRobert Mustacchi 
145*dea9f5e6SRobert Mustacchi static int
clock_thread_timer_delete(itimer_t * it)146*dea9f5e6SRobert Mustacchi clock_thread_timer_delete(itimer_t *it)
147*dea9f5e6SRobert Mustacchi {
148*dea9f5e6SRobert Mustacchi 	return (EINVAL);
149*dea9f5e6SRobert Mustacchi }
150*dea9f5e6SRobert Mustacchi 
151*dea9f5e6SRobert Mustacchi static void
clock_thread_timer_lwpbind(itimer_t * it)152*dea9f5e6SRobert Mustacchi clock_thread_timer_lwpbind(itimer_t *it)
153*dea9f5e6SRobert Mustacchi {
154*dea9f5e6SRobert Mustacchi }
155*dea9f5e6SRobert Mustacchi 
156*dea9f5e6SRobert Mustacchi void
clock_thread_init(void)157*dea9f5e6SRobert Mustacchi clock_thread_init(void)
158*dea9f5e6SRobert Mustacchi {
159*dea9f5e6SRobert Mustacchi 	/*
160*dea9f5e6SRobert Mustacchi 	 * While this clock backends don't support notifications right now, we
161*dea9f5e6SRobert Mustacchi 	 * still fill out the default for what it would be.
162*dea9f5e6SRobert Mustacchi 	 */
163*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_default.sigev_signo = SIGALRM;
164*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_default.sigev_notify = SIGEV_SIGNAL;
165*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_default.sigev_value.sival_ptr = NULL;
166*dea9f5e6SRobert Mustacchi 
167*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_clock_settime = clock_thread_settime;
168*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_clock_gettime = clock_thread_usr_gettime;
169*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_clock_getres = clock_thread_getres;
170*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_timer_create = clock_thread_timer_create;
171*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_timer_settime = clock_thread_timer_settime;
172*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_timer_gettime = clock_thread_timer_gettime;
173*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_timer_delete = clock_thread_timer_delete;
174*dea9f5e6SRobert Mustacchi 	clock_thread_usr.clk_timer_lwpbind = clock_thread_timer_lwpbind;
175*dea9f5e6SRobert Mustacchi 
176*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_default.sigev_signo = SIGALRM;
177*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_default.sigev_notify = SIGEV_SIGNAL;
178*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_default.sigev_value.sival_ptr = NULL;
179*dea9f5e6SRobert Mustacchi 
180*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_clock_settime = clock_thread_settime;
181*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_clock_gettime = clock_thread_usrsys_gettime;
182*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_clock_getres = clock_thread_getres;
183*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_timer_create = clock_thread_timer_create;
184*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_timer_settime = clock_thread_timer_settime;
185*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_timer_gettime = clock_thread_timer_gettime;
186*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_timer_delete = clock_thread_timer_delete;
187*dea9f5e6SRobert Mustacchi 	clock_thread_usrsys.clk_timer_lwpbind = clock_thread_timer_lwpbind;
188*dea9f5e6SRobert Mustacchi 
189*dea9f5e6SRobert Mustacchi 	clock_add_backend(CLOCK_VIRTUAL, &clock_thread_usr);
190*dea9f5e6SRobert Mustacchi 	clock_add_backend(CLOCK_THREAD_CPUTIME_ID, &clock_thread_usrsys);
191*dea9f5e6SRobert Mustacchi }
192