uts: make emu10k non-verbose
[unleashed.git] / kernel / os / clock_realtime.c
blob4a75984b239b670676e4372fde8b81ac6cef2f4f
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2015, Joyent Inc. All rights reserved.
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>
37 static clock_backend_t clock_realtime;
39 static int
40 clock_realtime_settime(timespec_t *ts)
42 mutex_enter(&tod_lock);
43 tod_set(*ts);
44 set_hrestime(ts);
45 mutex_exit(&tod_lock);
47 return (0);
51 * We normally won't execute this path; libc will see CLOCK_REALTIME and
52 * fast trap directly into gethrestime().
54 static int
55 clock_realtime_gettime(timespec_t *ts)
57 gethrestime(ts);
59 return (0);
62 static int
63 clock_realtime_getres(timespec_t *ts)
65 ts->tv_sec = 0;
66 ts->tv_nsec = nsec_per_tick;
68 return (0);
71 static void
72 clock_realtime_fire(void *arg)
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;
83 * First call into the timer subsystem to get the signal going.
85 it->it_fire(it);
86 val = &it->it_itime.it_value;
87 interval = &it->it_itime.it_interval;
89 mutex_enter(&p->p_lock);
91 if (!timerspecisset(interval)) {
92 timerspecclear(val);
93 *tidp = 0;
94 } else {
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.
111 for (;;) {
112 interval2nth = *interval;
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).
121 if (interval2nth.tv_sec == 0 &&
122 interval2nth.tv_nsec < nsec_per_tick)
123 interval2nth.tv_nsec = nsec_per_tick;
125 for (cnt2nth = 0; ; cnt2nth++) {
126 timespecadd(val, &interval2nth);
127 gethrestime(&now);
128 if (timerspeccmp(val, &now) > 0)
129 break;
130 timespecadd(&interval2nth, &interval2nth);
132 if (cnt2nth == 0)
133 break;
134 timespecsub(val, &interval2nth);
137 ticks = timespectohz(val, now);
138 *tidp = realtime_timeout(clock_realtime_fire, it, ticks);
140 mutex_exit(&p->p_lock);
144 * See the block comment in clock_realtime_timer_settime(), below.
146 static void
147 clock_realtime_fire_first(void *arg)
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;
155 gethrestime(&now);
157 if ((val->tv_sec > now.tv_sec) ||
158 (val->tv_sec == now.tv_sec && val->tv_nsec > now.tv_nsec)) {
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.
164 mutex_enter(&p->p_lock);
165 *tidp = realtime_timeout(clock_realtime_fire, it, 1);
166 mutex_exit(&p->p_lock);
167 return;
170 clock_realtime_fire(arg);
173 /*ARGSUSED*/
174 static int
175 clock_realtime_timer_create(itimer_t *it, void (*fire)(itimer_t *))
177 it->it_arg = kmem_zalloc(sizeof (timeout_id_t), KM_SLEEP);
178 it->it_fire = fire;
180 return (0);
183 static int
184 clock_realtime_timer_settime(itimer_t *it, int flags,
185 const struct itimerspec *when)
187 timeout_id_t tid, *tidp = it->it_arg;
188 timespec_t now;
189 proc_t *p = it->it_proc;
190 clock_t ticks;
192 gethrestime(&now);
194 mutex_enter(&p->p_lock);
196 while ((tid = *tidp) != 0) {
197 *tidp = 0;
198 mutex_exit(&p->p_lock);
199 (void) untimeout(tid);
200 mutex_enter(&p->p_lock);
204 * The timeout has been removed; it is safe to update it_itime.
206 it->it_itime = *when;
208 if (timerspecisset(&it->it_itime.it_value)) {
209 if (!(flags & TIMER_ABSTIME))
210 timespecadd(&it->it_itime.it_value, &now);
212 ticks = timespectohz(&it->it_itime.it_value, now);
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.
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.
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.
239 *tidp = realtime_timeout(clock_realtime_fire_first, it, ticks);
242 mutex_exit(&p->p_lock);
244 return (0);
247 static int
248 clock_realtime_timer_gettime(itimer_t *it, struct itimerspec *when)
250 timespec_t now;
251 proc_t *p = it->it_proc;
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.
257 mutex_enter(&p->p_lock);
258 gethrestime(&now);
259 *when = it->it_itime;
260 mutex_exit(&p->p_lock);
262 if (!timerspecisset(&when->it_value))
263 return (0);
265 if (timerspeccmp(&when->it_value, &now) < 0) {
267 * If this timer should have already gone off, set it_value
268 * to 0.
270 timerspecclear(&when->it_value);
271 } else {
272 timespecsub(&when->it_value, &now);
275 return (0);
278 static int
279 clock_realtime_timer_delete(itimer_t *it)
281 proc_t *p = it->it_proc;
282 timeout_id_t tid, *tidp = it->it_arg;
284 mutex_enter(&p->p_lock);
286 while ((tid = *tidp) != 0) {
287 *tidp = 0;
288 mutex_exit(&p->p_lock);
289 (void) untimeout(tid);
290 mutex_enter(&p->p_lock);
293 mutex_exit(&p->p_lock);
295 kmem_free(tidp, sizeof (timeout_id_t));
297 return (0);
300 /*ARGSUSED*/
301 void
302 clock_realtime_timer_lwpbind(itimer_t *it)
306 void
307 clock_realtime_init()
309 clock_backend_t *be = &clock_realtime;
310 struct sigevent *ev = &be->clk_default;
312 ev->sigev_signo = SIGALRM;
313 ev->sigev_notify = SIGEV_SIGNAL;
314 ev->sigev_value.sival_ptr = NULL;
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);
326 * For binary compatibility with old statically linked
327 * applications, we make the behavior of __CLOCK_REALTIME0
328 * the same as CLOCK_REALTIME.
330 clock_add_backend(__CLOCK_REALTIME0, &clock_realtime);