more lint
[unix-history] / usr / src / sys / kern / kern_time.c
CommitLineData
b32450f4 1/* kern_time.c 5.10 82/10/17 */
aac7ea5b
BJ
2
3#include "../h/param.h"
b6f30e0a 4#include "../h/dir.h" /* XXX */
aac7ea5b 5#include "../h/user.h"
b6f30e0a 6#include "../h/kernel.h"
aac7ea5b
BJ
7#include "../h/reg.h"
8#include "../h/inode.h"
9#include "../h/proc.h"
b6f30e0a 10
1edb1cf8
BJ
11/*
12 * Time of day and interval timer support.
aa261505
BJ
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.
1edb1cf8
BJ
19 */
20
b6f30e0a 21gettimeofday()
4147b3f6 22{
b6f30e0a
BJ
23 register struct a {
24 struct timeval *tp;
25 struct timezone *tzp;
26 } *uap = (struct a *)u.u_ap;
27 struct timeval atv;
1edb1cf8 28 int s;
4147b3f6 29
1edb1cf8 30 s = spl7(); atv = time; splx(s);
b6f30e0a
BJ
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;
1edb1cf8 37 /* SHOULD HAVE PER-PROCESS TIMEZONE */
b32450f4 38 if (copyout((caddr_t)&tz, (caddr_t)uap->tzp, sizeof (tz))) {
b6f30e0a
BJ
39 u.u_error = EFAULT;
40 return;
41 }
4147b3f6
BJ
42}
43
b6f30e0a 44settimeofday()
aac7ea5b 45{
b6f30e0a 46 register struct a {
1edb1cf8
BJ
47 struct timeval *tv;
48 struct timezone *tzp;
b6f30e0a
BJ
49 } *uap = (struct a *)u.u_ap;
50 struct timeval atv;
51 struct timezone atz;
4147b3f6 52
b6f30e0a
BJ
53 if (copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (struct timeval))) {
54 u.u_error = EFAULT;
55 return;
56 }
1edb1cf8
BJ
57 setthetime(&atv);
58 if (uap->tzp && suser()) {
b6f30e0a
BJ
59 if (copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof (atz))) {
60 u.u_error = EFAULT;
61 return;
62 }
b6f30e0a 63 }
4147b3f6
BJ
64}
65
1edb1cf8
BJ
66setthetime(tv)
67 struct timeval *tv;
68{
1edb1cf8
BJ
69 int s;
70
71 if (!suser())
72 return;
aa261505 73/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
1edb1cf8
BJ
74 boottime.tv_sec += tv->tv_sec - time.tv_sec;
75 s = spl7(); time = *tv; splx(s);
76 clockset();
77}
78
aa261505
BJ
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 */
b6f30e0a 100getitimer()
aac7ea5b
BJ
101{
102 register struct a {
b6f30e0a
BJ
103 u_int which;
104 struct itimerval *itv;
105 } *uap = (struct a *)u.u_ap;
d01b68d6 106 struct itimerval aitv;
b6f30e0a 107 int s;
aac7ea5b 108
b6f30e0a
BJ
109 if (uap->which > 2) {
110 u.u_error = EINVAL;
111 return;
aac7ea5b 112 }
b6f30e0a 113 s = spl7();
d01b68d6 114 if (uap->which == ITIMER_REAL) {
aa261505
BJ
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 */
d01b68d6
BJ
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);
b32450f4
BJ
130 if (copyout((caddr_t)&aitv, (caddr_t)uap->itv,
131 sizeof (struct itimerval)))
aac7ea5b 132 u.u_error = EFAULT;
b6f30e0a 133 splx(s);
aac7ea5b
BJ
134}
135
b6f30e0a 136setitimer()
aac7ea5b
BJ
137{
138 register struct a {
b6f30e0a 139 u_int which;
1edb1cf8 140 struct itimerval *itv, *oitv;
b6f30e0a
BJ
141 } *uap = (struct a *)u.u_ap;
142 struct itimerval aitv;
143 int s;
d01b68d6 144 register struct proc *p = u.u_procp;
aac7ea5b 145
b6f30e0a
BJ
146 if (uap->which > 2) {
147 u.u_error = EINVAL;
1edb1cf8 148 return;
b6f30e0a
BJ
149 }
150 if (copyin((caddr_t)uap->itv, (caddr_t)&aitv,
151 sizeof (struct itimerval))) {
152 u.u_error = EFAULT;
1edb1cf8
BJ
153 return;
154 }
155 if (uap->oitv) {
156 uap->itv = uap->oitv;
157 getitimer();
b6f30e0a 158 }
1edb1cf8
BJ
159 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) {
160 u.u_error = EINVAL;
161 return;
162 }
163 s = spl7();
d01b68d6 164 if (uap->which == ITIMER_REAL) {
b32450f4 165 untimeout(realitexpire, (caddr_t)p);
d01b68d6
BJ
166 if (timerisset(&aitv.it_value)) {
167 timevaladd(&aitv.it_value, &time);
b32450f4 168 timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
d01b68d6
BJ
169 }
170 p->p_realtimer = aitv;
171 } else
1edb1cf8 172 u.u_timer[uap->which] = aitv;
b6f30e0a 173 splx(s);
b6f30e0a
BJ
174}
175
aa261505
BJ
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 */
184realitexpire(p)
d01b68d6
BJ
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, >)) {
b32450f4
BJ
199 timeout(realitexpire, (caddr_t)p,
200 hzto(&p->p_realtimer.it_value));
d01b68d6
BJ
201 splx(s);
202 return;
203 }
204 splx(s);
205 }
206}
207
aa261505
BJ
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 */
1edb1cf8
BJ
214itimerfix(tv)
215 struct timeval *tv;
b6f30e0a 216{
b6f30e0a 217
d01b68d6
BJ
218 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
219 tv->tv_usec < 0 || tv->tv_usec >= 1000000)
1edb1cf8
BJ
220 return (EINVAL);
221 if (tv->tv_sec == 0 && tv->tv_usec < tick)
222 tv->tv_usec = tick;
223 return (0);
b6f30e0a
BJ
224}
225
aa261505
BJ
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 */
b6f30e0a
BJ
236itimerdecr(itp, usec)
237 register struct itimerval *itp;
238 int usec;
239{
240
1edb1cf8
BJ
241 if (itp->it_value.tv_usec < usec) {
242 if (itp->it_value.tv_sec == 0) {
aa261505 243 /* expired, and already in next interval */
1edb1cf8 244 usec -= itp->it_value.tv_usec;
b6f30e0a 245 goto expire;
1edb1cf8
BJ
246 }
247 itp->it_value.tv_usec += 1000000;
248 itp->it_value.tv_sec--;
aac7ea5b 249 }
1edb1cf8
BJ
250 itp->it_value.tv_usec -= usec;
251 usec = 0;
252 if (timerisset(&itp->it_value))
b6f30e0a 253 return (1);
aa261505 254 /* expired, exactly at end of interval */
b6f30e0a 255expire:
1edb1cf8
BJ
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
aa261505 264 itp->it_value.tv_usec = 0; /* sec is already 0 */
b6f30e0a 265 return (0);
aac7ea5b
BJ
266}
267
aa261505
BJ
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 */
275timevaladd(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
284timevalsub(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
293timevalfix(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
b6f30e0a
BJ
307#ifndef NOCOMPAT
308otime()
309{
310
311 u.u_r.r_time = time.tv_sec;
312}
313
1edb1cf8
BJ
314ostime()
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
aa261505
BJ
326/* from old timeb.h */
327struct timeb {
328 time_t time;
329 u_short millitm;
330 short timezone;
331 short dstflag;
332};
b6f30e0a
BJ
333
334oftime()
aac7ea5b
BJ
335{
336 register struct a {
b6f30e0a 337 struct timeb *tp;
aac7ea5b 338 } *uap;
aa261505 339 struct timeb tb;
aac7ea5b 340
aac7ea5b 341 uap = (struct a *)u.u_ap;
b6f30e0a 342 (void) spl7();
aa261505
BJ
343 tb.time = time.tv_sec;
344 tb.millitm = time.tv_usec / 1000;
b6f30e0a 345 (void) spl0();
aa261505
BJ
346 tb.timezone = tz.tz_minuteswest;
347 tb.dstflag = tz.tz_dsttime;
206ecc72 348 if (copyout((caddr_t)&tb, (caddr_t)uap->tp, sizeof (tb)) < 0)
aac7ea5b
BJ
349 u.u_error = EFAULT;
350}
aa261505 351
c052185f
BJ
352oalarm()
353{
354 register struct a {
355 int deltat;
356 } *uap = (struct a *)u.u_ap;
357 register struct proc *p = u.u_procp;
c052185f
BJ
358 int s = spl7();
359
b32450f4 360 untimeout(realitexpire, (caddr_t)p);
c052185f
BJ
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;
b32450f4 372 timeout(realitexpire, (caddr_t)p, hzto(&p->p_realtimer.it_value));
c052185f
BJ
373 splx(s);
374}
aa261505 375#endif