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