xref: /csrg-svn/sys/kern/kern_time.c (revision 37591)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)kern_time.c	7.9 (Berkeley) 05/01/89
18  */
19 
20 #include "param.h"
21 #include "dir.h"		/* XXX */
22 #include "user.h"
23 #include "kernel.h"
24 #include "proc.h"
25 
26 #include "machine/reg.h"
27 #include "machine/cpu.h"
28 
29 /*
30  * Time of day and interval timer support.
31  *
32  * These routines provide the kernel entry points to get and set
33  * the time-of-day and per-process interval timers.  Subroutines
34  * here provide support for adding and subtracting timeval structures
35  * and decrementing interval timers, optionally reloading the interval
36  * timers when they expire.
37  */
38 
39 gettimeofday()
40 {
41 	register struct a {
42 		struct	timeval *tp;
43 		struct	timezone *tzp;
44 	} *uap = (struct a *)u.u_ap;
45 	struct timeval atv;
46 
47 	if (uap->tp) {
48 		microtime(&atv);
49 		u.u_error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
50 			sizeof (atv));
51 		if (u.u_error)
52 			return;
53 	}
54 	if (uap->tzp)
55 		u.u_error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
56 			sizeof (tz));
57 }
58 
59 settimeofday()
60 {
61 	register struct a {
62 		struct	timeval *tv;
63 		struct	timezone *tzp;
64 	} *uap = (struct a *)u.u_ap;
65 	struct timeval atv;
66 	struct timezone atz;
67 	int s;
68 
69 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
70 		return;
71 	if (uap->tv) {
72 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
73 			sizeof (struct timeval));
74 		if (u.u_error)
75 			return;
76 		/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
77 		boottime.tv_sec += atv.tv_sec - time.tv_sec;
78 		s = splhigh(); time = atv; splx(s);
79 		resettodr();
80 	}
81 	if (uap->tzp == 0)
82 		return;
83 	u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof (atz));
84 	if (u.u_error == 0)
85 		tz = atz;
86 }
87 
88 extern	int tickadj;			/* "standard" clock skew, us./tick */
89 int	tickdelta;			/* current clock skew, us. per tick */
90 long	timedelta;			/* unapplied time correction, us. */
91 long	bigadj = 1000000;		/* use 10x skew above bigadj us. */
92 
93 adjtime()
94 {
95 	register struct a {
96 		struct timeval *delta;
97 		struct timeval *olddelta;
98 	} *uap = (struct a *)u.u_ap;
99 	struct timeval atv, oatv;
100 	register long ndelta;
101 	int s;
102 
103 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
104 		return;
105 	u.u_error = copyin((caddr_t)uap->delta, (caddr_t)&atv,
106 		sizeof (struct timeval));
107 	if (u.u_error)
108 		return;
109 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
110 	if (timedelta == 0)
111 		if (ndelta > bigadj)
112 			tickdelta = 10 * tickadj;
113 		else
114 			tickdelta = tickadj;
115 	if (ndelta % tickdelta)
116 		ndelta = ndelta / tickadj * tickadj;
117 
118 	s = splclock();
119 	if (uap->olddelta) {
120 		oatv.tv_sec = timedelta / 1000000;
121 		oatv.tv_usec = timedelta % 1000000;
122 	}
123 	timedelta = ndelta;
124 	splx(s);
125 
126 	if (uap->olddelta)
127 		(void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta,
128 			sizeof (struct timeval));
129 }
130 
131 /*
132  * Get value of an interval timer.  The process virtual and
133  * profiling virtual time timers are kept in the u. area, since
134  * they can be swapped out.  These are kept internally in the
135  * way they are specified externally: in time until they expire.
136  *
137  * The real time interval timer is kept in the process table slot
138  * for the process, and its value (it_value) is kept as an
139  * absolute time rather than as a delta, so that it is easy to keep
140  * periodic real-time signals from drifting.
141  *
142  * Virtual time timers are processed in the hardclock() routine of
143  * kern_clock.c.  The real time timer is processed by a timeout
144  * routine, called from the softclock() routine.  Since a callout
145  * may be delayed in real time due to interrupt processing in the system,
146  * it is possible for the real time timeout routine (realitexpire, given below),
147  * to be delayed in real time past when it is supposed to occur.  It
148  * does not suffice, therefore, to reload the real timer .it_value from the
149  * real time timers .it_interval.  Rather, we compute the next time in
150  * absolute time the timer should go off.
151  */
152 getitimer()
153 {
154 	register struct a {
155 		u_int	which;
156 		struct	itimerval *itv;
157 	} *uap = (struct a *)u.u_ap;
158 	struct itimerval aitv;
159 	int s;
160 
161 	if (uap->which > ITIMER_PROF) {
162 		u.u_error = EINVAL;
163 		return;
164 	}
165 	s = splclock();
166 	if (uap->which == ITIMER_REAL) {
167 		/*
168 		 * Convert from absoulte to relative time in .it_value
169 		 * part of real time timer.  If time for real time timer
170 		 * has passed return 0, else return difference between
171 		 * current time and time for the timer to go off.
172 		 */
173 		aitv = u.u_procp->p_realtimer;
174 		if (timerisset(&aitv.it_value))
175 			if (timercmp(&aitv.it_value, &time, <))
176 				timerclear(&aitv.it_value);
177 			else
178 				timevalsub(&aitv.it_value, &time);
179 	} else
180 		aitv = u.u_timer[uap->which];
181 	splx(s);
182 	u.u_error = copyout((caddr_t)&aitv, (caddr_t)uap->itv,
183 	    sizeof (struct itimerval));
184 }
185 
186 setitimer()
187 {
188 	register struct a {
189 		u_int	which;
190 		struct	itimerval *itv, *oitv;
191 	} *uap = (struct a *)u.u_ap;
192 	struct itimerval aitv;
193 	register struct itimerval *itvp;
194 	int s;
195 	register struct proc *p = u.u_procp;
196 
197 	if (uap->which > ITIMER_PROF) {
198 		u.u_error = EINVAL;
199 		return;
200 	}
201 	itvp = uap->itv;
202 	if (itvp && (u.u_error = copyin((caddr_t)itvp, (caddr_t)&aitv,
203 	    sizeof(struct itimerval))))
204 		return;
205 	if (uap->itv = uap->oitv) {
206 		getitimer();
207 		if (u.u_error)
208 			return;
209 	}
210 	if (itvp == 0)
211 		return;
212 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) {
213 		u.u_error = EINVAL;
214 		return;
215 	}
216 	s = splclock();
217 	if (uap->which == ITIMER_REAL) {
218 		untimeout(realitexpire, (caddr_t)p);
219 		if (timerisset(&aitv.it_value)) {
220 			timevaladd(&aitv.it_value, &time);
221 			timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
222 		}
223 		p->p_realtimer = aitv;
224 	} else
225 		u.u_timer[uap->which] = aitv;
226 	splx(s);
227 }
228 
229 /*
230  * Real interval timer expired:
231  * send process whose timer expired an alarm signal.
232  * If time is not set up to reload, then just return.
233  * Else compute next time timer should go off which is > current time.
234  * This is where delay in processing this timeout causes multiple
235  * SIGALRM calls to be compressed into one.
236  */
237 realitexpire(p)
238 	register struct proc *p;
239 {
240 	int s;
241 
242 	psignal(p, SIGALRM);
243 	if (!timerisset(&p->p_realtimer.it_interval)) {
244 		timerclear(&p->p_realtimer.it_value);
245 		return;
246 	}
247 	for (;;) {
248 		s = splclock();
249 		timevaladd(&p->p_realtimer.it_value,
250 		    &p->p_realtimer.it_interval);
251 		if (timercmp(&p->p_realtimer.it_value, &time, >)) {
252 			timeout(realitexpire, (caddr_t)p,
253 			    hzto(&p->p_realtimer.it_value));
254 			splx(s);
255 			return;
256 		}
257 		splx(s);
258 	}
259 }
260 
261 /*
262  * Check that a proposed value to load into the .it_value or
263  * .it_interval part of an interval timer is acceptable, and
264  * fix it to have at least minimal value (i.e. if it is less
265  * than the resolution of the clock, round it up.)
266  */
267 itimerfix(tv)
268 	struct timeval *tv;
269 {
270 
271 	if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
272 	    tv->tv_usec < 0 || tv->tv_usec >= 1000000)
273 		return (EINVAL);
274 	if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
275 		tv->tv_usec = tick;
276 	return (0);
277 }
278 
279 /*
280  * Decrement an interval timer by a specified number
281  * of microseconds, which must be less than a second,
282  * i.e. < 1000000.  If the timer expires, then reload
283  * it.  In this case, carry over (usec - old value) to
284  * reducint the value reloaded into the timer so that
285  * the timer does not drift.  This routine assumes
286  * that it is called in a context where the timers
287  * on which it is operating cannot change in value.
288  */
289 itimerdecr(itp, usec)
290 	register struct itimerval *itp;
291 	int usec;
292 {
293 
294 	if (itp->it_value.tv_usec < usec) {
295 		if (itp->it_value.tv_sec == 0) {
296 			/* expired, and already in next interval */
297 			usec -= itp->it_value.tv_usec;
298 			goto expire;
299 		}
300 		itp->it_value.tv_usec += 1000000;
301 		itp->it_value.tv_sec--;
302 	}
303 	itp->it_value.tv_usec -= usec;
304 	usec = 0;
305 	if (timerisset(&itp->it_value))
306 		return (1);
307 	/* expired, exactly at end of interval */
308 expire:
309 	if (timerisset(&itp->it_interval)) {
310 		itp->it_value = itp->it_interval;
311 		itp->it_value.tv_usec -= usec;
312 		if (itp->it_value.tv_usec < 0) {
313 			itp->it_value.tv_usec += 1000000;
314 			itp->it_value.tv_sec--;
315 		}
316 	} else
317 		itp->it_value.tv_usec = 0;		/* sec is already 0 */
318 	return (0);
319 }
320 
321 /*
322  * Add and subtract routines for timevals.
323  * N.B.: subtract routine doesn't deal with
324  * results which are before the beginning,
325  * it just gets very confused in this case.
326  * Caveat emptor.
327  */
328 timevaladd(t1, t2)
329 	struct timeval *t1, *t2;
330 {
331 
332 	t1->tv_sec += t2->tv_sec;
333 	t1->tv_usec += t2->tv_usec;
334 	timevalfix(t1);
335 }
336 
337 timevalsub(t1, t2)
338 	struct timeval *t1, *t2;
339 {
340 
341 	t1->tv_sec -= t2->tv_sec;
342 	t1->tv_usec -= t2->tv_usec;
343 	timevalfix(t1);
344 }
345 
346 timevalfix(t1)
347 	struct timeval *t1;
348 {
349 
350 	if (t1->tv_usec < 0) {
351 		t1->tv_sec--;
352 		t1->tv_usec += 1000000;
353 	}
354 	if (t1->tv_usec >= 1000000) {
355 		t1->tv_sec++;
356 		t1->tv_usec -= 1000000;
357 	}
358 }
359