xref: /csrg-svn/sys/kern/kern_time.c (revision 8625)
1 /*	kern_time.c	5.10	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, (caddr_t)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, (caddr_t)uap->itv,
131 	    sizeof (struct itimerval)))
132 		u.u_error = EFAULT;
133 	splx(s);
134 }
135 
136 setitimer()
137 {
138 	register struct a {
139 		u_int	which;
140 		struct	itimerval *itv, *oitv;
141 	} *uap = (struct a *)u.u_ap;
142 	struct itimerval aitv;
143 	int s;
144 	register struct proc *p = u.u_procp;
145 
146 	if (uap->which > 2) {
147 		u.u_error = EINVAL;
148 		return;
149 	}
150 	if (copyin((caddr_t)uap->itv, (caddr_t)&aitv,
151 	    sizeof (struct itimerval))) {
152 		u.u_error = EFAULT;
153 		return;
154 	}
155 	if (uap->oitv) {
156 		uap->itv = uap->oitv;
157 		getitimer();
158 	}
159 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) {
160 		u.u_error = EINVAL;
161 		return;
162 	}
163 	s = spl7();
164 	if (uap->which == ITIMER_REAL) {
165 		untimeout(realitexpire, (caddr_t)p);
166 		if (timerisset(&aitv.it_value)) {
167 			timevaladd(&aitv.it_value, &time);
168 			timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
169 		}
170 		p->p_realtimer = aitv;
171 	} else
172 		u.u_timer[uap->which] = aitv;
173 	splx(s);
174 }
175 
176 /*
177  * Real interval timer expired:
178  * send process whose timer expired an alarm signal.
179  * If time is not set up to reload, then just return.
180  * Else compute next time timer should go off which is > current time.
181  * This is where delay in processing this timeout causes multiple
182  * SIGALRM calls to be compressed into one.
183  */
184 realitexpire(p)
185 	register struct proc *p;
186 {
187 	int s;
188 
189 	psignal(p, SIGALRM);
190 	if (!timerisset(&p->p_realtimer.it_interval)) {
191 		timerclear(&p->p_realtimer.it_value);
192 		return;
193 	}
194 	for (;;) {
195 		s = spl7();
196 		timevaladd(&p->p_realtimer.it_value,
197 		    &p->p_realtimer.it_interval);
198 		if (timercmp(&p->p_realtimer.it_value, &time, >)) {
199 			timeout(realitexpire, (caddr_t)p,
200 			    hzto(&p->p_realtimer.it_value));
201 			splx(s);
202 			return;
203 		}
204 		splx(s);
205 	}
206 }
207 
208 /*
209  * Check that a proposed value to load into the .it_value or
210  * .it_interval part of an interval timer is acceptable, and
211  * fix it to have at least minimal value (i.e. if it is less
212  * than the resolution of the clock, round it up.)
213  */
214 itimerfix(tv)
215 	struct timeval *tv;
216 {
217 
218 	if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
219 	    tv->tv_usec < 0 || tv->tv_usec >= 1000000)
220 		return (EINVAL);
221 	if (tv->tv_sec == 0 && tv->tv_usec < tick)
222 		tv->tv_usec = tick;
223 	return (0);
224 }
225 
226 /*
227  * Decrement an interval timer by a specified number
228  * of microseconds, which must be less than a second,
229  * i.e. < 1000000.  If the timer expires, then reload
230  * it.  In this case, carry over (usec - old value) to
231  * reducint the value reloaded into the timer so that
232  * the timer does not drift.  This routine assumes
233  * that it is called in a context where the timers
234  * on which it is operating cannot change in value.
235  */
236 itimerdecr(itp, usec)
237 	register struct itimerval *itp;
238 	int usec;
239 {
240 
241 	if (itp->it_value.tv_usec < usec) {
242 		if (itp->it_value.tv_sec == 0) {
243 			/* expired, and already in next interval */
244 			usec -= itp->it_value.tv_usec;
245 			goto expire;
246 		}
247 		itp->it_value.tv_usec += 1000000;
248 		itp->it_value.tv_sec--;
249 	}
250 	itp->it_value.tv_usec -= usec;
251 	usec = 0;
252 	if (timerisset(&itp->it_value))
253 		return (1);
254 	/* expired, exactly at end of interval */
255 expire:
256 	if (timerisset(&itp->it_interval)) {
257 		itp->it_value = itp->it_interval;
258 		itp->it_value.tv_usec -= usec;
259 		if (itp->it_value.tv_usec < 0) {
260 			itp->it_value.tv_usec += 1000000;
261 			itp->it_value.tv_sec--;
262 		}
263 	} else
264 		itp->it_value.tv_usec = 0;		/* sec is already 0 */
265 	return (0);
266 }
267 
268 /*
269  * Add and subtract routines for timevals.
270  * N.B.: subtract routine doesn't deal with
271  * results which are before the beginning,
272  * it just gets very confused in this case.
273  * Caveat emptor.
274  */
275 timevaladd(t1, t2)
276 	struct timeval *t1, *t2;
277 {
278 
279 	t1->tv_sec += t2->tv_sec;
280 	t1->tv_usec += t2->tv_usec;
281 	timevalfix(t1);
282 }
283 
284 timevalsub(t1, t2)
285 	struct timeval *t1, *t2;
286 {
287 
288 	t1->tv_sec -= t2->tv_sec;
289 	t1->tv_usec -= t2->tv_usec;
290 	timevalfix(t1);
291 }
292 
293 timevalfix(t1)
294 	struct timeval *t1;
295 {
296 
297 	if (t1->tv_usec < 0) {
298 		t1->tv_sec--;
299 		t1->tv_usec += 1000000;
300 	}
301 	if (t1->tv_usec >= 1000000) {
302 		t1->tv_sec++;
303 		t1->tv_usec -= 1000000;
304 	}
305 }
306 
307 #ifndef NOCOMPAT
308 otime()
309 {
310 
311 	u.u_r.r_time = time.tv_sec;
312 }
313 
314 ostime()
315 {
316 	register struct a {
317 		int	time;
318 	} *uap = (struct a *)u.u_ap;
319 	struct timeval tv;
320 
321 	tv.tv_sec = uap->time;
322 	tv.tv_usec = 0;
323 	setthetime(&tv);
324 }
325 
326 /* from old timeb.h */
327 struct timeb {
328 	time_t	time;
329 	u_short	millitm;
330 	short	timezone;
331 	short	dstflag;
332 };
333 
334 oftime()
335 {
336 	register struct a {
337 		struct	timeb	*tp;
338 	} *uap;
339 	struct timeb tb;
340 
341 	uap = (struct a *)u.u_ap;
342 	(void) spl7();
343 	tb.time = time.tv_sec;
344 	tb.millitm = time.tv_usec / 1000;
345 	(void) spl0();
346 	tb.timezone = tz.tz_minuteswest;
347 	tb.dstflag = tz.tz_dsttime;
348 	if (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb)) < 0)
349 		u.u_error = EFAULT;
350 }
351 
352 oalarm()
353 {
354 	register struct a {
355 		int	deltat;
356 	} *uap = (struct a *)u.u_ap;
357 	register struct proc *p = u.u_procp;
358 	int s = spl7();
359 
360 	untimeout(realitexpire, (caddr_t)p);
361 	timerclear(&p->p_realtimer.it_interval);
362 	u.u_r.r_val1 = 0;
363 	if (timerisset(&p->p_realtimer.it_value) &&
364 	    timercmp(&p->p_realtimer.it_value, &time, >))
365 		u.u_r.r_val1 = p->p_realtimer.it_value.tv_sec - time.tv_sec;
366 	if (uap->deltat == 0) {
367 		splx(s);
368 		return;
369 	}
370 	p->p_realtimer.it_value = time;
371 	p->p_realtimer.it_value.tv_sec += uap->deltat;
372 	timeout(realitexpire, (caddr_t)p, hzto(&p->p_realtimer.it_value));
373 	splx(s);
374 }
375 #endif
376