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
clock_realtime_settime(timespec_t * ts)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
clock_realtime_gettime(timespec_t * ts)55 clock_realtime_gettime(timespec_t *ts)
56 {
57 gethrestime(ts);
58
59 return (0);
60 }
61
62 static int
clock_realtime_getres(timespec_t * ts)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
clock_realtime_fire(void * arg)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
clock_realtime_fire_first(void * arg)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
clock_realtime_timer_create(itimer_t * it,void (* fire)(itimer_t *))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
clock_realtime_timer_settime(itimer_t * it,int flags,const struct itimerspec * when)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
clock_realtime_timer_gettime(itimer_t * it,struct itimerspec * when)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
clock_realtime_timer_delete(itimer_t * it)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
clock_realtime_timer_lwpbind(itimer_t * it)302 clock_realtime_timer_lwpbind(itimer_t *it)
303 {
304 }
305
306 void
clock_realtime_init()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