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