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