1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2015, Joyent Inc. All rights reserved. 29 */ 30 31 #include <sys/timer.h> 32 #include <sys/systm.h> 33 #include <sys/param.h> 34 #include <sys/kmem.h> 35 #include <sys/debug.h> 36 37 static clock_backend_t clock_realtime; 38 39 static int 40 clock_realtime_settime(timespec_t *ts) 41 { 42 mutex_enter(&tod_lock); 43 tod_set(*ts); 44 set_hrestime(ts); 45 mutex_exit(&tod_lock); 46 47 return (0); 48 } 49 50 /* 51 * We normally won't execute this path; libc will see CLOCK_REALTIME and 52 * fast trap directly into gethrestime(). 53 */ 54 static int 55 clock_realtime_gettime(timespec_t *ts) 56 { 57 gethrestime(ts); 58 59 return (0); 60 } 61 62 static int 63 clock_realtime_getres(timespec_t *ts) 64 { 65 ts->tv_sec = 0; 66 ts->tv_nsec = nsec_per_tick; 67 68 return (0); 69 } 70 71 static void 72 clock_realtime_fire(void *arg) 73 { 74 int cnt2nth; 75 itimer_t *it = (itimer_t *)arg; 76 timeout_id_t *tidp = it->it_arg; 77 timespec_t now, interval2nth; 78 timespec_t *val, *interval; 79 proc_t *p = it->it_proc; 80 clock_t ticks; 81 82 /* 83 * First call into the timer subsystem to get the signal going. 84 */ 85 it->it_fire(it); 86 val = &it->it_itime.it_value; 87 interval = &it->it_itime.it_interval; 88 89 mutex_enter(&p->p_lock); 90 91 if (!timerspecisset(interval)) { 92 timerspecclear(val); 93 *tidp = 0; 94 } else { 95 /* 96 * If this is an interval timer, we need to determine a time 97 * at which to go off in the future. In the event that the 98 * clock has been adjusted, we want to find our new interval 99 * relatively quickly (and we don't want to simply take the 100 * current time and add the interval; it would lead to 101 * unnecessary jitter in the timer). We therefore take steps 102 * from the time we expected to go off into the future; 103 * if the resulting time is still in the past, then we double 104 * our step size and continue. Once the resulting time is 105 * in the future, we subtract our last step, change our step 106 * size back to the original interval, and repeat until we 107 * can get to a valid, future timeout in one step. This 108 * assures that we will get the minimum, valid timeout 109 * value in a reasonable amount of wall time. 110 */ 111 for (;;) { 112 interval2nth = *interval; 113 114 /* 115 * We put a floor on interval2nth at nsec_per_tick. 116 * If we don't do this, and the interval is shorter 117 * than the time required to run through this logic, 118 * we'll never catch up to the current time (which 119 * is a moving target). 120 */ 121 if (interval2nth.tv_sec == 0 && 122 interval2nth.tv_nsec < nsec_per_tick) 123 interval2nth.tv_nsec = nsec_per_tick; 124 125 for (cnt2nth = 0; ; cnt2nth++) { 126 timespecadd(val, &interval2nth); 127 gethrestime(&now); 128 if (timerspeccmp(val, &now) > 0) 129 break; 130 timespecadd(&interval2nth, &interval2nth); 131 } 132 if (cnt2nth == 0) 133 break; 134 timespecsub(val, &interval2nth); 135 } 136 137 ticks = timespectohz(val, now); 138 *tidp = realtime_timeout(clock_realtime_fire, it, ticks); 139 } 140 mutex_exit(&p->p_lock); 141 } 142 143 /* 144 * See the block comment in clock_realtime_timer_settime(), below. 145 */ 146 static void 147 clock_realtime_fire_first(void *arg) 148 { 149 itimer_t *it = (itimer_t *)arg; 150 timespec_t now; 151 timespec_t *val = &it->it_itime.it_value; 152 timeout_id_t *tidp = it->it_arg; 153 proc_t *p = it->it_proc; 154 155 gethrestime(&now); 156 157 if ((val->tv_sec > now.tv_sec) || 158 (val->tv_sec == now.tv_sec && val->tv_nsec > now.tv_nsec)) { 159 /* 160 * We went off too early. We'll go to bed for one more tick, 161 * regardless of the actual difference; if the difference 162 * is greater than one tick, then we must have seen an adjtime. 163 */ 164 mutex_enter(&p->p_lock); 165 *tidp = realtime_timeout(clock_realtime_fire, it, 1); 166 mutex_exit(&p->p_lock); 167 return; 168 } 169 170 clock_realtime_fire(arg); 171 } 172 173 /*ARGSUSED*/ 174 static int 175 clock_realtime_timer_create(itimer_t *it, void (*fire)(itimer_t *)) 176 { 177 it->it_arg = kmem_zalloc(sizeof (timeout_id_t), KM_SLEEP); 178 it->it_fire = fire; 179 180 return (0); 181 } 182 183 static int 184 clock_realtime_timer_settime(itimer_t *it, int flags, 185 const struct itimerspec *when) 186 { 187 timeout_id_t tid, *tidp = it->it_arg; 188 timespec_t now; 189 proc_t *p = it->it_proc; 190 clock_t ticks; 191 192 gethrestime(&now); 193 194 mutex_enter(&p->p_lock); 195 196 while ((tid = *tidp) != 0) { 197 *tidp = 0; 198 mutex_exit(&p->p_lock); 199 (void) untimeout(tid); 200 mutex_enter(&p->p_lock); 201 } 202 203 /* 204 * The timeout has been removed; it is safe to update it_itime. 205 */ 206 it->it_itime = *when; 207 208 if (timerspecisset(&it->it_itime.it_value)) { 209 if (!(flags & TIMER_ABSTIME)) 210 timespecadd(&it->it_itime.it_value, &now); 211 212 ticks = timespectohz(&it->it_itime.it_value, now); 213 214 /* 215 * gethrestime() works by reading hres_last_tick, and 216 * adding in the current time delta (that is, the amount of 217 * time which has passed since the last tick of the clock). 218 * As a result, the time returned in "now", above, represents 219 * an hrestime sometime after lbolt was last bumped. 220 * The "ticks" we've been returned from timespectohz(), then, 221 * reflects the number of times the clock will tick between 222 * "now" and our desired execution time. 223 * 224 * However, when we call into realtime_timeout(), below, 225 * "ticks" will be interpreted against lbolt. That is, 226 * if we specify 1 tick, we will be registering a callout 227 * for the next tick of the clock -- which may occur in 228 * less than (1 / hz) seconds. More generally, we are 229 * registering a callout for "ticks" of the clock, which 230 * may be less than ("ticks" / hz) seconds (but not more than 231 * (1 / hz) seconds less). In other words, we may go off 232 * early. 233 * 234 * This is only a problem for the initial firing of the 235 * timer, so we have the initial firing go through a 236 * different handler which implements a nanosleep-esque 237 * algorithm. 238 */ 239 *tidp = realtime_timeout(clock_realtime_fire_first, it, ticks); 240 } 241 242 mutex_exit(&p->p_lock); 243 244 return (0); 245 } 246 247 static int 248 clock_realtime_timer_gettime(itimer_t *it, struct itimerspec *when) 249 { 250 timespec_t now; 251 proc_t *p = it->it_proc; 252 253 /* 254 * We always keep it_itime up to date, so we just need to snapshot 255 * the time under p_lock, and clean it up. 256 */ 257 mutex_enter(&p->p_lock); 258 gethrestime(&now); 259 *when = it->it_itime; 260 mutex_exit(&p->p_lock); 261 262 if (!timerspecisset(&when->it_value)) 263 return (0); 264 265 if (timerspeccmp(&when->it_value, &now) < 0) { 266 /* 267 * If this timer should have already gone off, set it_value 268 * to 0. 269 */ 270 timerspecclear(&when->it_value); 271 } else { 272 timespecsub(&when->it_value, &now); 273 } 274 275 return (0); 276 } 277 278 static int 279 clock_realtime_timer_delete(itimer_t *it) 280 { 281 proc_t *p = it->it_proc; 282 timeout_id_t tid, *tidp = it->it_arg; 283 284 mutex_enter(&p->p_lock); 285 286 while ((tid = *tidp) != 0) { 287 *tidp = 0; 288 mutex_exit(&p->p_lock); 289 (void) untimeout(tid); 290 mutex_enter(&p->p_lock); 291 } 292 293 mutex_exit(&p->p_lock); 294 295 kmem_free(tidp, sizeof (timeout_id_t)); 296 297 return (0); 298 } 299 300 /*ARGSUSED*/ 301 void 302 clock_realtime_timer_lwpbind(itimer_t *it) 303 { 304 } 305 306 void 307 clock_realtime_init() 308 { 309 clock_backend_t *be = &clock_realtime; 310 struct sigevent *ev = &be->clk_default; 311 312 ev->sigev_signo = SIGALRM; 313 ev->sigev_notify = SIGEV_SIGNAL; 314 ev->sigev_value.sival_ptr = NULL; 315 316 be->clk_clock_settime = clock_realtime_settime; 317 be->clk_clock_gettime = clock_realtime_gettime; 318 be->clk_clock_getres = clock_realtime_getres; 319 be->clk_timer_gettime = clock_realtime_timer_gettime; 320 be->clk_timer_settime = clock_realtime_timer_settime; 321 be->clk_timer_delete = clock_realtime_timer_delete; 322 be->clk_timer_lwpbind = clock_realtime_timer_lwpbind; 323 be->clk_timer_create = clock_realtime_timer_create; 324 clock_add_backend(CLOCK_REALTIME, &clock_realtime); 325 /* 326 * For binary compatibility with old statically linked 327 * applications, we make the behavior of __CLOCK_REALTIME0 328 * the same as CLOCK_REALTIME. 329 */ 330 clock_add_backend(__CLOCK_REALTIME0, &clock_realtime); 331 } 332