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 2021 Oxide Computer Company
14  */
15 
16 /*
17  * This clock backend implements basic support for the CLOCK_PROCESS_CPUTIME_ID
18  * clock. This clock is weakly defined by POSIX as "The identifier of the
19  * CPU-time clock associated with the process making a clock() or timer*()
20  * function call". We interpret that as including LMS_USER, LMS_SYSTEM, and
21  * LMS_TRAP microstates. This is similar to what we do in proc(5) for the
22  * lwpstatus_t and the prstatus_t.
23  *
24  * At this time, we only provide the ability to read the current time (e.g.
25  * through a call to clock_gettime(3C)). There is never a case where being able
26  * to set the time makes sense today and even if so, the privileges required for
27  * that are circumspect. Today, we do not support the ability to create interval
28  * timers based on this backend (e.g. timer_create(3C) and timer_settime(3C)).
29  * However, there is no reason that couldn't be added.
30  *
31  * To implement this, we leverage the existing microstate aggregation time that
32  * is done in /proc.
33  */
34 
35 #include <sys/timer.h>
36 #include <sys/cyclic.h>
37 #include <sys/msacct.h>
38 
39 static clock_backend_t clock_process;
40 
41 static int
clock_process_settime(timespec_t * ts)42 clock_process_settime(timespec_t *ts)
43 {
44 	return (EINVAL);
45 }
46 
47 static int
clock_process_gettime(timespec_t * ts)48 clock_process_gettime(timespec_t *ts)
49 {
50 	hrtime_t hrt;
51 	proc_t *p = curproc;
52 
53 	/*
54 	 * mstate_aggr_state() automatically includes LMS_TRAP when we ask for
55 	 * LMS_SYSTEM below.
56 	 */
57 	mutex_enter(&p->p_lock);
58 	hrt = mstate_aggr_state(p, LMS_USER);
59 	hrt += mstate_aggr_state(p, LMS_SYSTEM);
60 	mutex_exit(&p->p_lock);
61 
62 	hrt2ts(hrt, ts);
63 
64 	return (0);
65 }
66 
67 /*
68  * See the discussion in clock_thread_getres() for the why of using
69  * cyclic_getres() here.
70  */
71 static int
clock_process_getres(timespec_t * ts)72 clock_process_getres(timespec_t *ts)
73 {
74 	hrt2ts(cyclic_getres(), (timestruc_t *)ts);
75 
76 	return (0);
77 }
78 
79 static int
clock_process_timer_create(itimer_t * it,void (* fire)(itimer_t *))80 clock_process_timer_create(itimer_t *it, void (*fire)(itimer_t *))
81 {
82 	return (EINVAL);
83 }
84 
85 static int
clock_process_timer_settime(itimer_t * it,int flags,const struct itimerspec * when)86 clock_process_timer_settime(itimer_t *it, int flags,
87     const struct itimerspec *when)
88 {
89 	return (EINVAL);
90 }
91 
92 static int
clock_process_timer_gettime(itimer_t * it,struct itimerspec * when)93 clock_process_timer_gettime(itimer_t *it, struct itimerspec *when)
94 {
95 	return (EINVAL);
96 }
97 
98 static int
clock_process_timer_delete(itimer_t * it)99 clock_process_timer_delete(itimer_t *it)
100 {
101 	return (EINVAL);
102 }
103 
104 static void
clock_process_timer_lwpbind(itimer_t * it)105 clock_process_timer_lwpbind(itimer_t *it)
106 {
107 }
108 
109 void
clock_process_init(void)110 clock_process_init(void)
111 {
112 	/*
113 	 * While this clock backend doesn't support notifications right now, we
114 	 * still fill out the default for what it would be.
115 	 */
116 	clock_process.clk_default.sigev_signo = SIGALRM;
117 	clock_process.clk_default.sigev_notify = SIGEV_SIGNAL;
118 	clock_process.clk_default.sigev_value.sival_ptr = NULL;
119 
120 	clock_process.clk_clock_settime = clock_process_settime;
121 	clock_process.clk_clock_gettime = clock_process_gettime;
122 	clock_process.clk_clock_getres = clock_process_getres;
123 	clock_process.clk_timer_create = clock_process_timer_create;
124 	clock_process.clk_timer_settime = clock_process_timer_settime;
125 	clock_process.clk_timer_gettime = clock_process_timer_gettime;
126 	clock_process.clk_timer_delete = clock_process_timer_delete;
127 	clock_process.clk_timer_lwpbind = clock_process_timer_lwpbind;
128 
129 	clock_add_backend(CLOCK_PROCESS_CPUTIME_ID, &clock_process);
130 }
131