|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1989, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)kern_time.c 8.4 (Berkeley) 5/26/95
59: */
60:
61: #include <sys/param.h>
62: #include <sys/resourcevar.h>
63: #include <sys/kernel.h>
64: #include <sys/systm.h>
65: #include <sys/proc.h>
66: #include <sys/vnode.h>
67:
68: #include <sys/mount.h>
69:
70: #include <machine/cpu.h>
71:
72: #include <kern/clock.h>
73:
74: /*
75: * Time of day and interval timer support.
76: *
77: * These routines provide the kernel entry points to get and set
78: * the time-of-day and per-process interval timers. Subroutines
79: * here provide support for adding and subtracting timeval structures
80: * and decrementing interval timers, optionally reloading the interval
81: * timers when they expire.
82: */
83: struct gettimeofday_args{
84: struct timeval *tp;
85: struct timezone *tzp;
86: };
87: /* ARGSUSED */
88: int
89: gettimeofday(p, uap, retval)
90: struct proc *p;
91: register struct gettimeofday_args *uap;
92: register_t *retval;
93: {
94: struct timeval atv;
95: int error = 0;
96:
97: if (uap->tp) {
98: microtime(&atv);
99: if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
100: sizeof (atv)))
101: return(error);
102: }
103:
104: if (uap->tzp)
105: error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
106: sizeof (tz));
107:
108: return(error);
109: }
110:
111: struct settimeofday_args {
112: struct timeval *tv;
113: struct timezone *tzp;
114: };
115: /* ARGSUSED */
116: int
117: settimeofday(p, uap, retval)
118: struct proc *p;
119: struct settimeofday_args *uap;
120: register_t *retval;
121: {
122: struct timeval atv;
123: struct timezone atz;
124: int error, s;
125:
126: if (error = suser(p->p_ucred, &p->p_acflag))
127: return (error);
128: /* Verify all parameters before changing time. */
129: if (uap->tv && (error = copyin((caddr_t)uap->tv,
130: (caddr_t)&atv, sizeof(atv))))
131: return (error);
132: if (uap->tzp && (error = copyin((caddr_t)uap->tzp,
133: (caddr_t)&atz, sizeof(atz))))
134: return (error);
135: if (uap->tv) {
136: error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
137: sizeof (struct timeval));
138: if (error)
139: return(error);
140: setthetime(&atv);
141: }
142: if (uap->tzp)
143: tz = atz;
144: return (0);
145: }
146:
147: setthetime(tv)
148: struct timeval *tv;
149: {
150: tvalspec_t now;
151: long delta;
152: int s;
153:
154: now.tv_sec = tv->tv_sec;
155: now.tv_nsec = tv->tv_usec * NSEC_PER_USEC;
156:
157: clock_set_counter(Calendar, now);
158: delta = tv->tv_sec - time.tv_sec;
159: boottime.tv_sec += delta;
160: #if NFSCLIENT || NFSSERVER
161: lease_updatetime(delta);
162: #endif
163: s = splhigh();
164: microtime(&time);
165: splx(s);
166: }
167:
168: int tickadj = 240000 / (60 * HZ); /* "standard" clock skew, us./tick */
169: int tickdelta; /* current clock skew, us. per tick */
170: long timedelta; /* unapplied time correction, us. */
171: long bigadj = 1000000; /* use 10x skew above bigadj us. */
172:
173:
174: struct adjtime_args {
175: struct timeval *delta;
176: struct timeval *olddelta;
177: };
178: /* ARGSUSED */
179: int
180: adjtime(p, uap, retval)
181: struct proc *p;
182: register struct adjtime_args *uap;
183: register_t *retval;
184: {
185: struct timeval atv, oatv;
186: register long ndelta;
187: int s, error;
188:
189: if (error = suser(p->p_ucred, &p->p_acflag))
190: return (error);
191: if(error = copyin((caddr_t)uap->delta, (caddr_t)&atv,
192: sizeof (struct timeval)))
193: return(error);
194:
195: ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
196: if (timedelta == 0)
197: if (ndelta > bigadj)
198: tickdelta = 10 * tickadj;
199: else
200: tickdelta = tickadj;
201: if (ndelta % tickdelta)
202: ndelta = ndelta / tickdelta * tickdelta;
203:
204: s = splclock();
205: if (uap->olddelta) {
206: oatv.tv_sec = timedelta / 1000000;
207: oatv.tv_usec = timedelta % 1000000;
208: }
209: timedelta = ndelta;
210: splx(s);
211:
212: if (uap->olddelta)
213: (void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta,
214: sizeof (struct timeval));
215: return(0);
216: }
217:
218: #define SECDAY ((unsigned)(24*60*60)) /* seconds per day */
219: #define SECYR ((unsigned)(365*SECDAY)) /* per common year */
220: #define YRREF 70 /* UNIX time referenced to 1970 */
221:
222: /*
223: * Initialze the time of day register, based on the time base which is, e.g.
224: * from a filesystem.
225: */
226: void
227: inittodr(base)
228: time_t base;
229: {
230: long deltat;
231:
232: if (base < (87-YRREF) * SECYR || base < 0) { /* fs < than 1987? */
233: printf("WARNING: preposterous time in file system");
234: goto check;
235: }
236:
237: /*
238: * The value returned by microtime()
239: * is gotten from the 'Calendar' clock.
240: * It is initialized from the RTC early
241: * on during system intialization, so
242: * that it contains a useful value at this
243: * point.
244: */
245: microtime(&time);
246:
247: /*
248: * This variable still exists to keep
249: * 'w' happy. It should only be considered
250: * an approximation.
251: */
252: boottime.tv_sec = time.tv_sec;
253: boottime.tv_usec = 0;
254:
255: /*
256: * See if we gained/lost two or more days;
257: * if so, assume something is amiss.
258: * Avoid changing RTC if RTC time > file system time and delta is
259: * less than two days.
260: */
261: deltat = time.tv_sec - base;
262: if (deltat < 0)
263: deltat = -deltat;
264: if ((deltat < 2*SECDAY) && (time.tv_sec > base))
265: return;
266: if (time.tv_sec < SECYR) {
267: printf ("WARNING: clock not set properly");
268: time.tv_sec = base;
269: time.tv_usec = 0;
270: setthetime(&time);
271: boottime = time;
272: goto check;
273: }
274:
275: if (deltat > 90*SECDAY) { /* assume rtc is way off */
276: printf ("WARNING: preposterous time in Real Time Clock");
277: time.tv_sec = base;
278: time.tv_usec = 0;
279: setthetime(&time);
280: boottime = time;
281: goto check;
282: }
283: printf("WARNING: clock lost %d days", deltat / SECDAY);
284: check:
285: printf(" -- CHECK AND RESET THE DATE!\n");
286: }
287:
288: /*
289: * Get value of an interval timer. The process virtual and
290: * profiling virtual time timers are kept in the u. area, since
291: * they can be swapped out. These are kept internally in the
292: * way they are specified externally: in time until they expire.
293: *
294: * The real time interval timer is kept in the process table slot
295: * for the process, and its value (it_value) is kept as an
296: * absolute time rather than as a delta, so that it is easy to keep
297: * periodic real-time signals from drifting.
298: *
299: * Virtual time timers are processed in the hardclock() routine of
300: * kern_clock.c. The real time timer is processed by a timeout
301: * routine, called from the softclock() routine. Since a callout
302: * may be delayed in real time due to interrupt processing in the system,
303: * it is possible for the real time timeout routine (realitexpire, given below),
304: * to be delayed in real time past when it is supposed to occur. It
305: * does not suffice, therefore, to reload the real timer .it_value from the
306: * real time timers .it_interval. Rather, we compute the next time in
307: * absolute time the timer should go off.
308: */
309:
310: struct getitimer_args {
311: u_int which;
312: struct itimerval *itv;
313: };
314: /* ARGSUSED */
315: int
316: getitimer(p, uap, retval)
317: struct proc *p;
318: register struct getitimer_args *uap;
319: register_t *retval;
320: {
321: struct itimerval aitv;
322: int s;
323:
324: if (uap->which > ITIMER_PROF)
325: return(EINVAL);
326:
327: s = splclock();
328: if (uap->which == ITIMER_REAL) {
329: /*
330: * Convert from absoulte to relative time in .it_value
331: * part of real time timer. If time for real time timer
332: * has passed return 0, else return difference between
333: * current time and time for the timer to go off.
334: */
335: aitv = p->p_realtimer;
336: if (timerisset(&aitv.it_value))
337: if (timercmp(&aitv.it_value, &time, <))
338: timerclear(&aitv.it_value);
339: else
340: timevalsub(&aitv.it_value, &time);
341: } else
342: aitv =p->p_stats->p_timer[uap->which];
343: splx(s);
344: return(copyout((caddr_t)&aitv, (caddr_t)uap->itv,
345: sizeof (struct itimerval)));
346: }
347:
348: struct setitimer_args {
349: u_int which;
350: struct itimerval *itv;
351: struct itimerval *oitv;
352: };
353: /* ARGSUSED */
354: int
355: setitimer(p, uap, retval)
356: struct proc *p;
357: register struct setitimer_args *uap;
358: register_t *retval;
359: {
360: struct itimerval aitv;
361: register struct itimerval *itvp;
362: int s, error;
363:
364: if (uap->which > ITIMER_PROF)
365: return(EINVAL);
366: itvp = uap->itv;
367: if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
368: sizeof(struct itimerval))))
369: return (error);
370: if ((uap->itv = uap->oitv) &&
371: (error = getitimer(p, uap, retval)))
372: return (error);
373: if (itvp == 0)
374: return (0);
375: if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
376: return (EINVAL);
377: s = splclock();
378: if (uap->which == ITIMER_REAL) {
379: untimeout(realitexpire, (caddr_t)p);
380: if (timerisset(&aitv.it_value)) {
381: timevaladd(&aitv.it_value, &time);
382: timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
383: }
384: p->p_realtimer = aitv;
385: } else
386: p->p_stats->p_timer[uap->which] = aitv;
387: splx(s);
388: return(0); /* To insure good return value on success */
389: }
390:
391: /*
392: * Real interval timer expired:
393: * send process whose timer expired an alarm signal.
394: * If time is not set up to reload, then just return.
395: * Else compute next time timer should go off which is > current time.
396: * This is where delay in processing this timeout causes multiple
397: * SIGALRM calls to be compressed into one.
398: */
399: void
400: realitexpire(arg)
401: void *arg;
402: {
403: register struct proc *p;
404: int s;
405:
406: p = (struct proc *)arg;
407: psignal(p, SIGALRM);
408: if (!timerisset(&p->p_realtimer.it_interval)) {
409: timerclear(&p->p_realtimer.it_value);
410: return;
411: }
412:
413: /*
414: * If the time's way off, don't try to compensate by getting
415: * there incrementally.
416: */
417: s = splclock();
418: if (p->p_realtimer.it_value.tv_sec < time.tv_sec - 10) {
419: p->p_realtimer.it_value = time;
420: timeout(realitexpire, (caddr_t)p,
421: hzto(&p->p_realtimer.it_value));
422: splx(s);
423: return;
424:
425: }
426: splx(s);
427:
428: for (;;) {
429: s = splclock();
430: timevaladd(&p->p_realtimer.it_value,
431: &p->p_realtimer.it_interval);
432: if (timercmp(&p->p_realtimer.it_value, &time, >)) {
433: timeout(realitexpire, (caddr_t)p,
434: hzto(&p->p_realtimer.it_value));
435: splx(s);
436: return;
437: }
438: splx(s);
439: }
440: }
441:
442: /*
443: * Check that a proposed value to load into the .it_value or
444: * .it_interval part of an interval timer is acceptable, and
445: * fix it to have at least minimal value (i.e. if it is less
446: * than the resolution of the clock, round it up.)
447: */
448: int
449: itimerfix(tv)
450: struct timeval *tv;
451: {
452:
453: if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
454: tv->tv_usec < 0 || tv->tv_usec >= 1000000)
455: return (EINVAL);
456: if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
457: tv->tv_usec = tick;
458: return (0);
459: }
460:
461: /*
462: * Decrement an interval timer by a specified number
463: * of microseconds, which must be less than a second,
464: * i.e. < 1000000. If the timer expires, then reload
465: * it. In this case, carry over (usec - old value) to
466: * reducint the value reloaded into the timer so that
467: * the timer does not drift. This routine assumes
468: * that it is called in a context where the timers
469: * on which it is operating cannot change in value.
470: */
471: int
472: itimerdecr(itp, usec)
473: register struct itimerval *itp;
474: int usec;
475: {
476:
477: if (itp->it_value.tv_usec < usec) {
478: if (itp->it_value.tv_sec == 0) {
479: /* expired, and already in next interval */
480: usec -= itp->it_value.tv_usec;
481: goto expire;
482: }
483: itp->it_value.tv_usec += 1000000;
484: itp->it_value.tv_sec--;
485: }
486: itp->it_value.tv_usec -= usec;
487: usec = 0;
488: if (timerisset(&itp->it_value))
489: return (1);
490: /* expired, exactly at end of interval */
491: expire:
492: if (timerisset(&itp->it_interval)) {
493: itp->it_value = itp->it_interval;
494: itp->it_value.tv_usec -= usec;
495: if (itp->it_value.tv_usec < 0) {
496: itp->it_value.tv_usec += 1000000;
497: itp->it_value.tv_sec--;
498: }
499: } else
500: itp->it_value.tv_usec = 0; /* sec is already 0 */
501: return (0);
502: }
503:
504: /*
505: * Add and subtract routines for timevals.
506: * N.B.: subtract routine doesn't deal with
507: * results which are before the beginning,
508: * it just gets very confused in this case.
509: * Caveat emptor.
510: */
511: timevaladd(t1, t2)
512: struct timeval *t1, *t2;
513: {
514:
515: t1->tv_sec += t2->tv_sec;
516: t1->tv_usec += t2->tv_usec;
517: timevalfix(t1);
518: }
519:
520: timevalsub(t1, t2)
521: struct timeval *t1, *t2;
522: {
523:
524: t1->tv_sec -= t2->tv_sec;
525: t1->tv_usec -= t2->tv_usec;
526: timevalfix(t1);
527: }
528:
529: timevalfix(t1)
530: struct timeval *t1;
531: {
532:
533: if (t1->tv_usec < 0) {
534: t1->tv_sec--;
535: t1->tv_usec += 1000000;
536: }
537: if (t1->tv_usec >= 1000000) {
538: t1->tv_sec++;
539: t1->tv_usec -= 1000000;
540: }
541: }
542:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.