]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_time.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1982, 1986, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * @(#)kern_time.c 8.4 (Berkeley) 5/26/95
58 #include <sys/param.h>
59 #include <sys/resourcevar.h>
60 #include <sys/kernel.h>
61 #include <sys/systm.h>
63 #include <sys/vnode.h>
65 #include <sys/mount.h>
67 #include <kern/cpu_number.h>
69 #include <kern/clock.h>
71 #define HZ 100 /* XXX */
76 * Time of day and interval timer support.
78 * These routines provide the kernel entry points to get and set
79 * the time-of-day and per-process interval timers. Subroutines
80 * here provide support for adding and subtracting timeval structures
81 * and decrementing interval timers, optionally reloading the interval
82 * timers when they expire.
84 struct gettimeofday_args
{
90 gettimeofday(p
, uap
, retval
)
92 register struct gettimeofday_args
*uap
;
100 if (error
= copyout((caddr_t
)&atv
, (caddr_t
)uap
->tp
,
106 error
= copyout((caddr_t
)&tz
, (caddr_t
)uap
->tzp
,
112 struct settimeofday_args
{
114 struct timezone
*tzp
;
118 settimeofday(p
, uap
, retval
)
120 struct settimeofday_args
*uap
;
127 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
129 /* Verify all parameters before changing time. */
130 if (uap
->tv
&& (error
= copyin((caddr_t
)uap
->tv
,
131 (caddr_t
)&atv
, sizeof(atv
))))
133 if (uap
->tzp
&& (error
= copyin((caddr_t
)uap
->tzp
,
134 (caddr_t
)&atz
, sizeof(atz
))))
150 now
.tv_sec
= tv
->tv_sec
;
151 now
.tv_nsec
= tv
->tv_usec
* NSEC_PER_USEC
;
153 clock_set_calendar_value(now
);
154 delta
= tv
->tv_sec
- time
.tv_sec
;
155 boottime
.tv_sec
+= delta
;
156 #if NFSCLIENT || NFSSERVER
157 lease_updatetime(delta
);
164 int tickadj
= 240000 / (60 * HZ
); /* "standard" clock skew, us./tick */
165 int tickdelta
; /* current clock skew, us. per tick */
166 long timedelta
; /* unapplied time correction, us. */
167 long bigadj
= 1000000; /* use 10x skew above bigadj us. */
169 struct adjtime_args
{
170 struct timeval
*delta
;
171 struct timeval
*olddelta
;
175 adjtime(p
, uap
, retval
)
177 register struct adjtime_args
*uap
;
180 struct timeval atv
, oatv
;
181 register long ndelta
;
184 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
186 if(error
= copyin((caddr_t
)uap
->delta
, (caddr_t
)&atv
,
187 sizeof (struct timeval
)))
190 ndelta
= atv
.tv_sec
* 1000000 + atv
.tv_usec
;
193 tickdelta
= 10 * tickadj
;
196 if (ndelta
% tickdelta
)
197 ndelta
= ndelta
/ tickdelta
* tickdelta
;
201 oatv
.tv_sec
= timedelta
/ 1000000;
202 oatv
.tv_usec
= timedelta
% 1000000;
208 (void) copyout((caddr_t
)&oatv
, (caddr_t
)uap
->olddelta
,
209 sizeof (struct timeval
));
213 #define SECDAY ((unsigned)(24*60*60)) /* seconds per day */
214 #define SECYR ((unsigned)(365*SECDAY)) /* per common year */
215 #define YRREF 70 /* UNIX time referenced to 1970 */
218 * Initialze the time of day register.
219 * Trust the RTC except for the case where it is set before
220 * the UNIX epoch. In that case use the the UNIX epoch.
221 * The argument passed in is ignored.
229 * The calendar has already been
230 * set up from the battery clock.
232 * The value returned by microtime()
233 * is gotten from the calendar.
238 * This variable still exists to keep
239 * 'w' happy. It should only be considered
242 boottime
.tv_sec
= time
.tv_sec
;
243 boottime
.tv_usec
= 0;
246 * If the RTC does not have acceptable value, i.e. time before
247 * the UNIX epoch, set it to the UNIX epoch
249 if (time
.tv_sec
< 0) {
250 printf ("WARNING: preposterous time in Real Time Clock");
251 time
.tv_sec
= 0; /* the UNIX epoch */
255 printf(" -- CHECK AND RESET THE DATE!\n");
262 * Get value of an interval timer. The process virtual and
263 * profiling virtual time timers are kept in the u. area, since
264 * they can be swapped out. These are kept internally in the
265 * way they are specified externally: in time until they expire.
267 * The real time interval timer is kept in the process table slot
268 * for the process, and its value (it_value) is kept as an
269 * absolute time rather than as a delta, so that it is easy to keep
270 * periodic real-time signals from drifting.
272 * Virtual time timers are processed in the hardclock() routine of
273 * kern_clock.c. The real time timer is processed by a timeout
274 * routine, called from the softclock() routine. Since a callout
275 * may be delayed in real time due to interrupt processing in the system,
276 * it is possible for the real time timeout routine (realitexpire, given below),
277 * to be delayed in real time past when it is supposed to occur. It
278 * does not suffice, therefore, to reload the real timer .it_value from the
279 * real time timers .it_interval. Rather, we compute the next time in
280 * absolute time the timer should go off.
283 struct getitimer_args
{
285 struct itimerval
*itv
;
289 getitimer(p
, uap
, retval
)
291 register struct getitimer_args
*uap
;
294 struct itimerval aitv
;
297 if (uap
->which
> ITIMER_PROF
)
301 if (uap
->which
== ITIMER_REAL
) {
303 * Convert from absoulte to relative time in .it_value
304 * part of real time timer. If time for real time timer
305 * has passed return 0, else return difference between
306 * current time and time for the timer to go off.
308 aitv
= p
->p_realtimer
;
309 if (timerisset(&aitv
.it_value
))
310 if (timercmp(&aitv
.it_value
, &time
, <))
311 timerclear(&aitv
.it_value
);
313 timevalsub(&aitv
.it_value
, &time
);
315 aitv
=p
->p_stats
->p_timer
[uap
->which
];
317 return(copyout((caddr_t
)&aitv
, (caddr_t
)uap
->itv
,
318 sizeof (struct itimerval
)));
321 struct setitimer_args
{
323 struct itimerval
*itv
;
324 struct itimerval
*oitv
;
328 setitimer(p
, uap
, retval
)
330 register struct setitimer_args
*uap
;
333 struct itimerval aitv
;
334 register struct itimerval
*itvp
;
337 if (uap
->which
> ITIMER_PROF
)
340 if (itvp
&& (error
= copyin((caddr_t
)itvp
, (caddr_t
)&aitv
,
341 sizeof(struct itimerval
))))
343 if ((uap
->itv
= uap
->oitv
) &&
344 (error
= getitimer(p
, uap
, retval
)))
348 if (itimerfix(&aitv
.it_value
) || itimerfix(&aitv
.it_interval
))
351 if (uap
->which
== ITIMER_REAL
) {
352 untimeout(realitexpire
, (caddr_t
)p
);
353 if (timerisset(&aitv
.it_value
)) {
354 timevaladd(&aitv
.it_value
, &time
);
355 timeout(realitexpire
, (caddr_t
)p
, hzto(&aitv
.it_value
));
357 p
->p_realtimer
= aitv
;
359 p
->p_stats
->p_timer
[uap
->which
] = aitv
;
361 return(0); /* To insure good return value on success */
365 * Real interval timer expired:
366 * send process whose timer expired an alarm signal.
367 * If time is not set up to reload, then just return.
368 * Else compute next time timer should go off which is > current time.
369 * This is where delay in processing this timeout causes multiple
370 * SIGALRM calls to be compressed into one.
376 register struct proc
*p
;
378 boolean_t funnel_state
;
380 funnel_state
= thread_funnel_set(kernel_flock
,TRUE
);
382 p
= (struct proc
*)arg
;
384 if (!timerisset(&p
->p_realtimer
.it_interval
)) {
385 timerclear(&p
->p_realtimer
.it_value
);
386 (void) thread_funnel_set(kernel_flock
, FALSE
);
391 * If the time's way off, don't try to compensate by getting
392 * there incrementally.
395 if (p
->p_realtimer
.it_value
.tv_sec
< time
.tv_sec
- 10) {
396 p
->p_realtimer
.it_value
= time
;
397 timeout(realitexpire
, (caddr_t
)p
,
398 hzto(&p
->p_realtimer
.it_value
));
400 (void) thread_funnel_set(kernel_flock
, FALSE
);
408 timevaladd(&p
->p_realtimer
.it_value
,
409 &p
->p_realtimer
.it_interval
);
410 if (timercmp(&p
->p_realtimer
.it_value
, &time
, >)) {
411 timeout(realitexpire
, (caddr_t
)p
,
412 hzto(&p
->p_realtimer
.it_value
));
414 (void) thread_funnel_set(kernel_flock
, FALSE
);
420 (void) thread_funnel_set(kernel_flock
, FALSE
);
424 * Check that a proposed value to load into the .it_value or
425 * .it_interval part of an interval timer is acceptable, and
426 * fix it to have at least minimal value (i.e. if it is less
427 * than the resolution of the clock, round it up.)
434 if (tv
->tv_sec
< 0 || tv
->tv_sec
> 100000000 ||
435 tv
->tv_usec
< 0 || tv
->tv_usec
>= 1000000)
437 if (tv
->tv_sec
== 0 && tv
->tv_usec
!= 0 && tv
->tv_usec
< tick
)
443 * Decrement an interval timer by a specified number
444 * of microseconds, which must be less than a second,
445 * i.e. < 1000000. If the timer expires, then reload
446 * it. In this case, carry over (usec - old value) to
447 * reducint the value reloaded into the timer so that
448 * the timer does not drift. This routine assumes
449 * that it is called in a context where the timers
450 * on which it is operating cannot change in value.
453 itimerdecr(itp
, usec
)
454 register struct itimerval
*itp
;
458 if (itp
->it_value
.tv_usec
< usec
) {
459 if (itp
->it_value
.tv_sec
== 0) {
460 /* expired, and already in next interval */
461 usec
-= itp
->it_value
.tv_usec
;
464 itp
->it_value
.tv_usec
+= 1000000;
465 itp
->it_value
.tv_sec
--;
467 itp
->it_value
.tv_usec
-= usec
;
469 if (timerisset(&itp
->it_value
))
471 /* expired, exactly at end of interval */
473 if (timerisset(&itp
->it_interval
)) {
474 itp
->it_value
= itp
->it_interval
;
475 itp
->it_value
.tv_usec
-= usec
;
476 if (itp
->it_value
.tv_usec
< 0) {
477 itp
->it_value
.tv_usec
+= 1000000;
478 itp
->it_value
.tv_sec
--;
481 itp
->it_value
.tv_usec
= 0; /* sec is already 0 */
486 * Add and subtract routines for timevals.
487 * N.B.: subtract routine doesn't deal with
488 * results which are before the beginning,
489 * it just gets very confused in this case.
494 struct timeval
*t1
, *t2
;
497 t1
->tv_sec
+= t2
->tv_sec
;
498 t1
->tv_usec
+= t2
->tv_usec
;
503 struct timeval
*t1
, *t2
;
506 t1
->tv_sec
-= t2
->tv_sec
;
507 t1
->tv_usec
-= t2
->tv_usec
;
515 if (t1
->tv_usec
< 0) {
517 t1
->tv_usec
+= 1000000;
519 if (t1
->tv_usec
>= 1000000) {
521 t1
->tv_usec
-= 1000000;
526 * Return the best possible estimate of the time in the timeval
527 * to which tvp points.
530 microtime(struct timeval
* tvp
)
532 mach_timespec_t now
= clock_get_calendar_value();
534 tvp
->tv_sec
= now
.tv_sec
;
535 tvp
->tv_usec
= now
.tv_nsec
/ NSEC_PER_USEC
;