Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1097 | dev | 1 | /*- |
2 | * Copyright (c) 1982, 1986, 1989, 1993 |
||
3 | * The Regents of the University of California. All rights reserved. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions |
||
7 | * are met: |
||
8 | * 1. Redistributions of source code must retain the above copyright |
||
9 | * notice, this list of conditions and the following disclaimer. |
||
10 | * 2. Redistributions in binary form must reproduce the above copyright |
||
11 | * notice, this list of conditions and the following disclaimer in the |
||
12 | * documentation and/or other materials provided with the distribution. |
||
13 | * 4. Neither the name of the University nor the names of its contributors |
||
14 | * may be used to endorse or promote products derived from this software |
||
15 | * without specific prior written permission. |
||
16 | * |
||
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
||
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
27 | * SUCH DAMAGE. |
||
28 | * |
||
29 | * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 |
||
30 | */ |
||
31 | |||
32 | #include <sys/cdefs.h> |
||
33 | __FBSDID("$FreeBSD: src/sys/kern/kern_time.c,v 1.116 2005/03/31 22:51:18 jhb Exp $"); |
||
34 | |||
35 | #include "opt_mac.h" |
||
36 | |||
37 | #include <sys/param.h> |
||
38 | #include <sys/systm.h> |
||
39 | #include <sys/lock.h> |
||
40 | #include <sys/mutex.h> |
||
41 | #include <sys/sysproto.h> |
||
42 | #include <sys/resourcevar.h> |
||
43 | #include <sys/signalvar.h> |
||
44 | #include <sys/jail.h> |
||
45 | #include <sys/kernel.h> |
||
46 | #include <sys/mac.h> |
||
47 | #include <sys/syscallsubr.h> |
||
48 | #include <sys/sysctl.h> |
||
49 | #include <sys/sysent.h> |
||
50 | #include <sys/proc.h> |
||
51 | #include <sys/time.h> |
||
52 | #include <sys/timetc.h> |
||
53 | #include <sys/vnode.h> |
||
54 | |||
55 | #include <vm/vm.h> |
||
56 | #include <vm/vm_extern.h> |
||
57 | |||
58 | int tz_minuteswest; |
||
59 | int tz_dsttime; |
||
60 | |||
61 | /* |
||
62 | * Time of day and interval timer support. |
||
63 | * |
||
64 | * These routines provide the kernel entry points to get and set |
||
65 | * the time-of-day and per-process interval timers. Subroutines |
||
66 | * here provide support for adding and subtracting timeval structures |
||
67 | * and decrementing interval timers, optionally reloading the interval |
||
68 | * timers when they expire. |
||
69 | */ |
||
70 | |||
71 | static int settime(struct thread *, struct timeval *); |
||
72 | static void timevalfix(struct timeval *); |
||
73 | static void no_lease_updatetime(int); |
||
74 | |||
75 | static int cf_usersettime; |
||
76 | static int cf_jailsettime; |
||
77 | SYSCTL_INT(_kern, OID_AUTO, usersettime, CTLFLAG_RW, &cf_usersettime, 0, |
||
78 | "Non-root is allowed to change system time"); |
||
79 | SYSCTL_INT(_kern, OID_AUTO, jailsettime, CTLFLAG_RW, &cf_jailsettime, 0, |
||
80 | "System time is allowed to be changed from jail"); |
||
81 | |||
82 | static void |
||
83 | no_lease_updatetime(deltat) |
||
84 | int deltat; |
||
85 | { |
||
86 | } |
||
87 | |||
88 | void (*lease_updatetime)(int) = no_lease_updatetime; |
||
89 | |||
90 | static int |
||
91 | settime(struct thread *td, struct timeval *tv) |
||
92 | { |
||
93 | struct timeval delta, tv1, tv2; |
||
94 | static struct timeval maxtime, laststep; |
||
95 | struct timespec ts; |
||
96 | int s; |
||
97 | |||
98 | s = splclock(); |
||
99 | microtime(&tv1); |
||
100 | delta = *tv; |
||
101 | timevalsub(&delta, &tv1); |
||
102 | |||
103 | /* |
||
104 | * If the system is secure, we do not allow the time to be |
||
105 | * set to a value earlier than 1 second less than the highest |
||
106 | * time we have yet seen. The worst a miscreant can do in |
||
107 | * this circumstance is "freeze" time. He couldn't go |
||
108 | * back to the past. |
||
109 | * |
||
110 | * We similarly do not allow the clock to be stepped more |
||
111 | * than one second, nor more than once per second. This allows |
||
112 | * a miscreant to make the clock march double-time, but no worse. |
||
113 | */ |
||
114 | if (securelevel_gt(td->td_ucred, 1) != 0) { |
||
115 | if (delta.tv_sec < 0 || delta.tv_usec < 0) { |
||
116 | /* |
||
117 | * Update maxtime to latest time we've seen. |
||
118 | */ |
||
119 | if (tv1.tv_sec > maxtime.tv_sec) |
||
120 | maxtime = tv1; |
||
121 | tv2 = *tv; |
||
122 | timevalsub(&tv2, &maxtime); |
||
123 | if (tv2.tv_sec < -1) { |
||
124 | tv->tv_sec = maxtime.tv_sec - 1; |
||
125 | printf("Time adjustment clamped to -1 second\n"); |
||
126 | } |
||
127 | } else { |
||
128 | if (tv1.tv_sec == laststep.tv_sec) { |
||
129 | splx(s); |
||
130 | return (EPERM); |
||
131 | } |
||
132 | if (delta.tv_sec > 1) { |
||
133 | tv->tv_sec = tv1.tv_sec + 1; |
||
134 | printf("Time adjustment clamped to +1 second\n"); |
||
135 | } |
||
136 | laststep = *tv; |
||
137 | } |
||
138 | } |
||
139 | |||
140 | ts.tv_sec = tv->tv_sec; |
||
141 | ts.tv_nsec = tv->tv_usec * 1000; |
||
142 | mtx_lock(&Giant); |
||
143 | tc_setclock(&ts); |
||
144 | (void) splsoftclock(); |
||
145 | lease_updatetime(delta.tv_sec); |
||
146 | splx(s); |
||
147 | resettodr(); |
||
148 | mtx_unlock(&Giant); |
||
149 | return (0); |
||
150 | } |
||
151 | |||
152 | #ifndef _SYS_SYSPROTO_H_ |
||
153 | struct clock_gettime_args { |
||
154 | clockid_t clock_id; |
||
155 | struct timespec *tp; |
||
156 | }; |
||
157 | #endif |
||
158 | |||
159 | /* |
||
160 | * MPSAFE |
||
161 | */ |
||
162 | /* ARGSUSED */ |
||
163 | int |
||
164 | clock_gettime(struct thread *td, struct clock_gettime_args *uap) |
||
165 | { |
||
166 | struct timespec ats; |
||
167 | struct timeval sys, user; |
||
168 | struct proc *p; |
||
169 | |||
170 | p = td->td_proc; |
||
171 | switch (uap->clock_id) { |
||
172 | case CLOCK_REALTIME: |
||
173 | nanotime(&ats); |
||
174 | break; |
||
175 | case CLOCK_VIRTUAL: |
||
176 | PROC_LOCK(p); |
||
177 | calcru(p, &user, &sys); |
||
178 | PROC_UNLOCK(p); |
||
179 | TIMEVAL_TO_TIMESPEC(&user, &ats); |
||
180 | break; |
||
181 | case CLOCK_PROF: |
||
182 | PROC_LOCK(p); |
||
183 | calcru(p, &user, &sys); |
||
184 | PROC_UNLOCK(p); |
||
185 | timevaladd(&user, &sys); |
||
186 | TIMEVAL_TO_TIMESPEC(&user, &ats); |
||
187 | break; |
||
188 | case CLOCK_MONOTONIC: |
||
189 | nanouptime(&ats); |
||
190 | break; |
||
191 | default: |
||
192 | return (EINVAL); |
||
193 | } |
||
194 | return (copyout(&ats, uap->tp, sizeof(ats))); |
||
195 | } |
||
196 | |||
197 | #ifndef _SYS_SYSPROTO_H_ |
||
198 | struct clock_settime_args { |
||
199 | clockid_t clock_id; |
||
200 | const struct timespec *tp; |
||
201 | }; |
||
202 | #endif |
||
203 | |||
204 | /* |
||
205 | * MPSAFE |
||
206 | */ |
||
207 | /* ARGSUSED */ |
||
208 | int |
||
209 | clock_settime(struct thread *td, struct clock_settime_args *uap) |
||
210 | { |
||
211 | struct timeval atv; |
||
212 | struct timespec ats; |
||
213 | int error; |
||
214 | |||
215 | #ifdef MAC |
||
216 | error = mac_check_system_settime(td->td_ucred); |
||
217 | if (error) |
||
218 | return (error); |
||
219 | #endif |
||
220 | if (!cf_jailsettime && jailed(td->td_ucred)) |
||
221 | return (EPERM); |
||
222 | if (!cf_usersettime && (error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0) |
||
223 | return (error); /* jail is already checked */ |
||
224 | |||
225 | if (uap->clock_id != CLOCK_REALTIME) |
||
226 | return (EINVAL); |
||
227 | if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0) |
||
228 | return (error); |
||
229 | if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000) |
||
230 | return (EINVAL); |
||
231 | /* XXX Don't convert nsec->usec and back */ |
||
232 | TIMESPEC_TO_TIMEVAL(&atv, &ats); |
||
233 | error = settime(td, &atv); |
||
234 | return (error); |
||
235 | } |
||
236 | |||
237 | #ifndef _SYS_SYSPROTO_H_ |
||
238 | struct clock_getres_args { |
||
239 | clockid_t clock_id; |
||
240 | struct timespec *tp; |
||
241 | }; |
||
242 | #endif |
||
243 | |||
244 | int |
||
245 | clock_getres(struct thread *td, struct clock_getres_args *uap) |
||
246 | { |
||
247 | struct timespec ts; |
||
248 | |||
249 | ts.tv_sec = 0; |
||
250 | switch (uap->clock_id) { |
||
251 | case CLOCK_REALTIME: |
||
252 | case CLOCK_MONOTONIC: |
||
253 | /* |
||
254 | * Round up the result of the division cheaply by adding 1. |
||
255 | * Rounding up is especially important if rounding down |
||
256 | * would give 0. Perfect rounding is unimportant. |
||
257 | */ |
||
258 | ts.tv_nsec = 1000000000 / tc_getfrequency() + 1; |
||
259 | break; |
||
260 | case CLOCK_VIRTUAL: |
||
261 | case CLOCK_PROF: |
||
262 | /* Accurately round up here because we can do so cheaply. */ |
||
263 | ts.tv_nsec = (1000000000 + hz - 1) / hz; |
||
264 | break; |
||
265 | default: |
||
266 | return (EINVAL); |
||
267 | } |
||
268 | if (uap->tp == NULL) |
||
269 | return (0); |
||
270 | return (copyout(&ts, uap->tp, sizeof(ts))); |
||
271 | } |
||
272 | |||
273 | static int nanowait; |
||
274 | |||
275 | int |
||
276 | kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) |
||
277 | { |
||
278 | struct timespec ts, ts2, ts3; |
||
279 | struct timeval tv; |
||
280 | int error; |
||
281 | |||
282 | if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) |
||
283 | return (EINVAL); |
||
284 | if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) |
||
285 | return (0); |
||
286 | getnanouptime(&ts); |
||
287 | timespecadd(&ts, rqt); |
||
288 | TIMESPEC_TO_TIMEVAL(&tv, rqt); |
||
289 | for (;;) { |
||
290 | error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", |
||
291 | tvtohz(&tv)); |
||
292 | getnanouptime(&ts2); |
||
293 | if (error != EWOULDBLOCK) { |
||
294 | if (error == ERESTART) |
||
295 | error = EINTR; |
||
296 | if (rmt != NULL) { |
||
297 | timespecsub(&ts, &ts2); |
||
298 | if (ts.tv_sec < 0) |
||
299 | timespecclear(&ts); |
||
300 | *rmt = ts; |
||
301 | } |
||
302 | return (error); |
||
303 | } |
||
304 | if (timespeccmp(&ts2, &ts, >=)) |
||
305 | return (0); |
||
306 | ts3 = ts; |
||
307 | timespecsub(&ts3, &ts2); |
||
308 | TIMESPEC_TO_TIMEVAL(&tv, &ts3); |
||
309 | } |
||
310 | } |
||
311 | |||
312 | #ifndef _SYS_SYSPROTO_H_ |
||
313 | struct nanosleep_args { |
||
314 | struct timespec *rqtp; |
||
315 | struct timespec *rmtp; |
||
316 | }; |
||
317 | #endif |
||
318 | |||
319 | /* |
||
320 | * MPSAFE |
||
321 | */ |
||
322 | /* ARGSUSED */ |
||
323 | int |
||
324 | nanosleep(struct thread *td, struct nanosleep_args *uap) |
||
325 | { |
||
326 | struct timespec rmt, rqt; |
||
327 | int error; |
||
328 | |||
329 | error = copyin(uap->rqtp, &rqt, sizeof(rqt)); |
||
330 | if (error) |
||
331 | return (error); |
||
332 | |||
333 | if (uap->rmtp && |
||
334 | !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) |
||
335 | return (EFAULT); |
||
336 | error = kern_nanosleep(td, &rqt, &rmt); |
||
337 | if (error && uap->rmtp) { |
||
338 | int error2; |
||
339 | |||
340 | error2 = copyout(&rmt, uap->rmtp, sizeof(rmt)); |
||
341 | if (error2) |
||
342 | error = error2; |
||
343 | } |
||
344 | return (error); |
||
345 | } |
||
346 | |||
347 | #ifndef _SYS_SYSPROTO_H_ |
||
348 | struct gettimeofday_args { |
||
349 | struct timeval *tp; |
||
350 | struct timezone *tzp; |
||
351 | }; |
||
352 | #endif |
||
353 | /* |
||
354 | * MPSAFE |
||
355 | */ |
||
356 | /* ARGSUSED */ |
||
357 | int |
||
358 | gettimeofday(struct thread *td, struct gettimeofday_args *uap) |
||
359 | { |
||
360 | struct timeval atv; |
||
361 | struct timezone rtz; |
||
362 | int error = 0; |
||
363 | |||
364 | if (uap->tp) { |
||
365 | microtime(&atv); |
||
366 | error = copyout(&atv, uap->tp, sizeof (atv)); |
||
367 | } |
||
368 | if (error == 0 && uap->tzp != NULL) { |
||
369 | rtz.tz_minuteswest = tz_minuteswest; |
||
370 | rtz.tz_dsttime = tz_dsttime; |
||
371 | error = copyout(&rtz, uap->tzp, sizeof (rtz)); |
||
372 | } |
||
373 | return (error); |
||
374 | } |
||
375 | |||
376 | #ifndef _SYS_SYSPROTO_H_ |
||
377 | struct settimeofday_args { |
||
378 | struct timeval *tv; |
||
379 | struct timezone *tzp; |
||
380 | }; |
||
381 | #endif |
||
382 | /* |
||
383 | * MPSAFE |
||
384 | */ |
||
385 | /* ARGSUSED */ |
||
386 | int |
||
387 | settimeofday(struct thread *td, struct settimeofday_args *uap) |
||
388 | { |
||
389 | struct timeval atv, *tvp; |
||
390 | struct timezone atz, *tzp; |
||
391 | int error; |
||
392 | |||
393 | if (uap->tv) { |
||
394 | error = copyin(uap->tv, &atv, sizeof(atv)); |
||
395 | if (error) |
||
396 | return (error); |
||
397 | tvp = &atv; |
||
398 | } else |
||
399 | tvp = NULL; |
||
400 | if (uap->tzp) { |
||
401 | error = copyin(uap->tzp, &atz, sizeof(atz)); |
||
402 | if (error) |
||
403 | return (error); |
||
404 | tzp = &atz; |
||
405 | } else |
||
406 | tzp = NULL; |
||
407 | return (kern_settimeofday(td, tvp, tzp)); |
||
408 | } |
||
409 | |||
410 | int |
||
411 | kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp) |
||
412 | { |
||
413 | int error = 0; |
||
414 | |||
415 | #ifdef MAC |
||
416 | error = mac_check_system_settime(td->td_ucred); |
||
417 | if (error) |
||
418 | return (error); |
||
419 | #endif |
||
420 | if (!cf_jailsettime && jailed(td->td_ucred)) |
||
421 | return (EPERM); |
||
422 | if (!cf_usersettime && (error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0) |
||
423 | return (error); /* jail is already checked */ |
||
424 | |||
425 | /* Verify all parameters before changing time. */ |
||
426 | if (tv) { |
||
427 | if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) |
||
428 | return (EINVAL); |
||
429 | error = settime(td, tv); |
||
430 | } |
||
431 | if (tzp && error == 0) { |
||
432 | tz_minuteswest = tzp->tz_minuteswest; |
||
433 | tz_dsttime = tzp->tz_dsttime; |
||
434 | } |
||
435 | return (error); |
||
436 | } |
||
437 | |||
438 | /* |
||
439 | * Get value of an interval timer. The process virtual and |
||
440 | * profiling virtual time timers are kept in the p_stats area, since |
||
441 | * they can be swapped out. These are kept internally in the |
||
442 | * way they are specified externally: in time until they expire. |
||
443 | * |
||
444 | * The real time interval timer is kept in the process table slot |
||
445 | * for the process, and its value (it_value) is kept as an |
||
446 | * absolute time rather than as a delta, so that it is easy to keep |
||
447 | * periodic real-time signals from drifting. |
||
448 | * |
||
449 | * Virtual time timers are processed in the hardclock() routine of |
||
450 | * kern_clock.c. The real time timer is processed by a timeout |
||
451 | * routine, called from the softclock() routine. Since a callout |
||
452 | * may be delayed in real time due to interrupt processing in the system, |
||
453 | * it is possible for the real time timeout routine (realitexpire, given below), |
||
454 | * to be delayed in real time past when it is supposed to occur. It |
||
455 | * does not suffice, therefore, to reload the real timer .it_value from the |
||
456 | * real time timers .it_interval. Rather, we compute the next time in |
||
457 | * absolute time the timer should go off. |
||
458 | */ |
||
459 | #ifndef _SYS_SYSPROTO_H_ |
||
460 | struct getitimer_args { |
||
461 | u_int which; |
||
462 | struct itimerval *itv; |
||
463 | }; |
||
464 | #endif |
||
465 | /* |
||
466 | * MPSAFE |
||
467 | */ |
||
468 | int |
||
469 | getitimer(struct thread *td, struct getitimer_args *uap) |
||
470 | { |
||
471 | struct itimerval aitv; |
||
472 | int error; |
||
473 | |||
474 | error = kern_getitimer(td, uap->which, &aitv); |
||
475 | if (error != 0) |
||
476 | return (error); |
||
477 | return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); |
||
478 | } |
||
479 | |||
480 | int |
||
481 | kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) |
||
482 | { |
||
483 | struct proc *p = td->td_proc; |
||
484 | struct timeval ctv; |
||
485 | |||
486 | if (which > ITIMER_PROF) |
||
487 | return (EINVAL); |
||
488 | |||
489 | if (which == ITIMER_REAL) { |
||
490 | /* |
||
491 | * Convert from absolute to relative time in .it_value |
||
492 | * part of real time timer. If time for real time timer |
||
493 | * has passed return 0, else return difference between |
||
494 | * current time and time for the timer to go off. |
||
495 | */ |
||
496 | PROC_LOCK(p); |
||
497 | *aitv = p->p_realtimer; |
||
498 | PROC_UNLOCK(p); |
||
499 | if (timevalisset(&aitv->it_value)) { |
||
500 | getmicrouptime(&ctv); |
||
501 | if (timevalcmp(&aitv->it_value, &ctv, <)) |
||
502 | timevalclear(&aitv->it_value); |
||
503 | else |
||
504 | timevalsub(&aitv->it_value, &ctv); |
||
505 | } |
||
506 | } else { |
||
507 | mtx_lock_spin(&sched_lock); |
||
508 | *aitv = p->p_stats->p_timer[which]; |
||
509 | mtx_unlock_spin(&sched_lock); |
||
510 | } |
||
511 | return (0); |
||
512 | } |
||
513 | |||
514 | #ifndef _SYS_SYSPROTO_H_ |
||
515 | struct setitimer_args { |
||
516 | u_int which; |
||
517 | struct itimerval *itv, *oitv; |
||
518 | }; |
||
519 | #endif |
||
520 | |||
521 | /* |
||
522 | * MPSAFE |
||
523 | */ |
||
524 | int |
||
525 | setitimer(struct thread *td, struct setitimer_args *uap) |
||
526 | { |
||
527 | struct itimerval aitv, oitv; |
||
528 | int error; |
||
529 | |||
530 | if (uap->itv == NULL) { |
||
531 | uap->itv = uap->oitv; |
||
532 | return (getitimer(td, (struct getitimer_args *)uap)); |
||
533 | } |
||
534 | |||
535 | if ((error = copyin(uap->itv, &aitv, sizeof(struct itimerval)))) |
||
536 | return (error); |
||
537 | error = kern_setitimer(td, uap->which, &aitv, &oitv); |
||
538 | if (error != 0 || uap->oitv == NULL) |
||
539 | return (error); |
||
540 | return (copyout(&oitv, uap->oitv, sizeof(struct itimerval))); |
||
541 | } |
||
542 | |||
543 | int |
||
544 | kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, |
||
545 | struct itimerval *oitv) |
||
546 | { |
||
547 | struct proc *p = td->td_proc; |
||
548 | struct timeval ctv; |
||
549 | |||
550 | if (aitv == NULL) |
||
551 | return (kern_getitimer(td, which, oitv)); |
||
552 | |||
553 | if (which > ITIMER_PROF) |
||
554 | return (EINVAL); |
||
555 | if (itimerfix(&aitv->it_value)) |
||
556 | return (EINVAL); |
||
557 | if (!timevalisset(&aitv->it_value)) |
||
558 | timevalclear(&aitv->it_interval); |
||
559 | else if (itimerfix(&aitv->it_interval)) |
||
560 | return (EINVAL); |
||
561 | |||
562 | if (which == ITIMER_REAL) { |
||
563 | PROC_LOCK(p); |
||
564 | if (timevalisset(&p->p_realtimer.it_value)) |
||
565 | callout_stop(&p->p_itcallout); |
||
566 | getmicrouptime(&ctv); |
||
567 | if (timevalisset(&aitv->it_value)) { |
||
568 | callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value), |
||
569 | realitexpire, p); |
||
570 | timevaladd(&aitv->it_value, &ctv); |
||
571 | } |
||
572 | *oitv = p->p_realtimer; |
||
573 | p->p_realtimer = *aitv; |
||
574 | PROC_UNLOCK(p); |
||
575 | if (timevalisset(&oitv->it_value)) { |
||
576 | if (timevalcmp(&oitv->it_value, &ctv, <)) |
||
577 | timevalclear(&oitv->it_value); |
||
578 | else |
||
579 | timevalsub(&oitv->it_value, &ctv); |
||
580 | } |
||
581 | } else { |
||
582 | mtx_lock_spin(&sched_lock); |
||
583 | *oitv = p->p_stats->p_timer[which]; |
||
584 | p->p_stats->p_timer[which] = *aitv; |
||
585 | mtx_unlock_spin(&sched_lock); |
||
586 | } |
||
587 | return (0); |
||
588 | } |
||
589 | |||
590 | /* |
||
591 | * Real interval timer expired: |
||
592 | * send process whose timer expired an alarm signal. |
||
593 | * If time is not set up to reload, then just return. |
||
594 | * Else compute next time timer should go off which is > current time. |
||
595 | * This is where delay in processing this timeout causes multiple |
||
596 | * SIGALRM calls to be compressed into one. |
||
597 | * tvtohz() always adds 1 to allow for the time until the next clock |
||
598 | * interrupt being strictly less than 1 clock tick, but we don't want |
||
599 | * that here since we want to appear to be in sync with the clock |
||
600 | * interrupt even when we're delayed. |
||
601 | */ |
||
602 | void |
||
603 | realitexpire(void *arg) |
||
604 | { |
||
605 | struct proc *p; |
||
606 | struct timeval ctv, ntv; |
||
607 | |||
608 | p = (struct proc *)arg; |
||
609 | PROC_LOCK(p); |
||
610 | psignal(p, SIGALRM); |
||
611 | if (!timevalisset(&p->p_realtimer.it_interval)) { |
||
612 | timevalclear(&p->p_realtimer.it_value); |
||
613 | if (p->p_flag & P_WEXIT) |
||
614 | wakeup(&p->p_itcallout); |
||
615 | PROC_UNLOCK(p); |
||
616 | return; |
||
617 | } |
||
618 | for (;;) { |
||
619 | timevaladd(&p->p_realtimer.it_value, |
||
620 | &p->p_realtimer.it_interval); |
||
621 | getmicrouptime(&ctv); |
||
622 | if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { |
||
623 | ntv = p->p_realtimer.it_value; |
||
624 | timevalsub(&ntv, &ctv); |
||
625 | callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1, |
||
626 | realitexpire, p); |
||
627 | PROC_UNLOCK(p); |
||
628 | return; |
||
629 | } |
||
630 | } |
||
631 | /*NOTREACHED*/ |
||
632 | } |
||
633 | |||
634 | /* |
||
635 | * Check that a proposed value to load into the .it_value or |
||
636 | * .it_interval part of an interval timer is acceptable, and |
||
637 | * fix it to have at least minimal value (i.e. if it is less |
||
638 | * than the resolution of the clock, round it up.) |
||
639 | */ |
||
640 | int |
||
641 | itimerfix(struct timeval *tv) |
||
642 | { |
||
643 | |||
644 | if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || |
||
645 | tv->tv_usec < 0 || tv->tv_usec >= 1000000) |
||
646 | return (EINVAL); |
||
647 | if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) |
||
648 | tv->tv_usec = tick; |
||
649 | return (0); |
||
650 | } |
||
651 | |||
652 | /* |
||
653 | * Decrement an interval timer by a specified number |
||
654 | * of microseconds, which must be less than a second, |
||
655 | * i.e. < 1000000. If the timer expires, then reload |
||
656 | * it. In this case, carry over (usec - old value) to |
||
657 | * reduce the value reloaded into the timer so that |
||
658 | * the timer does not drift. This routine assumes |
||
659 | * that it is called in a context where the timers |
||
660 | * on which it is operating cannot change in value. |
||
661 | */ |
||
662 | int |
||
663 | itimerdecr(struct itimerval *itp, int usec) |
||
664 | { |
||
665 | |||
666 | if (itp->it_value.tv_usec < usec) { |
||
667 | if (itp->it_value.tv_sec == 0) { |
||
668 | /* expired, and already in next interval */ |
||
669 | usec -= itp->it_value.tv_usec; |
||
670 | goto expire; |
||
671 | } |
||
672 | itp->it_value.tv_usec += 1000000; |
||
673 | itp->it_value.tv_sec--; |
||
674 | } |
||
675 | itp->it_value.tv_usec -= usec; |
||
676 | usec = 0; |
||
677 | if (timevalisset(&itp->it_value)) |
||
678 | return (1); |
||
679 | /* expired, exactly at end of interval */ |
||
680 | expire: |
||
681 | if (timevalisset(&itp->it_interval)) { |
||
682 | itp->it_value = itp->it_interval; |
||
683 | itp->it_value.tv_usec -= usec; |
||
684 | if (itp->it_value.tv_usec < 0) { |
||
685 | itp->it_value.tv_usec += 1000000; |
||
686 | itp->it_value.tv_sec--; |
||
687 | } |
||
688 | } else |
||
689 | itp->it_value.tv_usec = 0; /* sec is already 0 */ |
||
690 | return (0); |
||
691 | } |
||
692 | |||
693 | /* |
||
694 | * Add and subtract routines for timevals. |
||
695 | * N.B.: subtract routine doesn't deal with |
||
696 | * results which are before the beginning, |
||
697 | * it just gets very confused in this case. |
||
698 | * Caveat emptor. |
||
699 | */ |
||
700 | void |
||
701 | timevaladd(struct timeval *t1, const struct timeval *t2) |
||
702 | { |
||
703 | |||
704 | t1->tv_sec += t2->tv_sec; |
||
705 | t1->tv_usec += t2->tv_usec; |
||
706 | timevalfix(t1); |
||
707 | } |
||
708 | |||
709 | void |
||
710 | timevalsub(struct timeval *t1, const struct timeval *t2) |
||
711 | { |
||
712 | |||
713 | t1->tv_sec -= t2->tv_sec; |
||
714 | t1->tv_usec -= t2->tv_usec; |
||
715 | timevalfix(t1); |
||
716 | } |
||
717 | |||
718 | static void |
||
719 | timevalfix(struct timeval *t1) |
||
720 | { |
||
721 | |||
722 | if (t1->tv_usec < 0) { |
||
723 | t1->tv_sec--; |
||
724 | t1->tv_usec += 1000000; |
||
725 | } |
||
726 | if (t1->tv_usec >= 1000000) { |
||
727 | t1->tv_sec++; |
||
728 | t1->tv_usec -= 1000000; |
||
729 | } |
||
730 | } |
||
731 | |||
732 | /* |
||
733 | * ratecheck(): simple time-based rate-limit checking. |
||
734 | */ |
||
735 | int |
||
736 | ratecheck(struct timeval *lasttime, const struct timeval *mininterval) |
||
737 | { |
||
738 | struct timeval tv, delta; |
||
739 | int rv = 0; |
||
740 | |||
741 | getmicrouptime(&tv); /* NB: 10ms precision */ |
||
742 | delta = tv; |
||
743 | timevalsub(&delta, lasttime); |
||
744 | |||
745 | /* |
||
746 | * check for 0,0 is so that the message will be seen at least once, |
||
747 | * even if interval is huge. |
||
748 | */ |
||
749 | if (timevalcmp(&delta, mininterval, >=) || |
||
750 | (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { |
||
751 | *lasttime = tv; |
||
752 | rv = 1; |
||
753 | } |
||
754 | |||
755 | return (rv); |
||
756 | } |
||
757 | |||
758 | /* |
||
759 | * ppsratecheck(): packets (or events) per second limitation. |
||
760 | * |
||
761 | * Return 0 if the limit is to be enforced (e.g. the caller |
||
762 | * should drop a packet because of the rate limitation). |
||
763 | * |
||
764 | * maxpps of 0 always causes zero to be returned. maxpps of -1 |
||
765 | * always causes 1 to be returned; this effectively defeats rate |
||
766 | * limiting. |
||
767 | * |
||
768 | * Note that we maintain the struct timeval for compatibility |
||
769 | * with other bsd systems. We reuse the storage and just monitor |
||
770 | * clock ticks for minimal overhead. |
||
771 | */ |
||
772 | int |
||
773 | ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) |
||
774 | { |
||
775 | int now; |
||
776 | |||
777 | /* |
||
778 | * Reset the last time and counter if this is the first call |
||
779 | * or more than a second has passed since the last update of |
||
780 | * lasttime. |
||
781 | */ |
||
782 | now = ticks; |
||
783 | if (lasttime->tv_sec == 0 || (u_int)(now - lasttime->tv_sec) >= hz) { |
||
784 | lasttime->tv_sec = now; |
||
785 | *curpps = 1; |
||
786 | return (maxpps != 0); |
||
787 | } else { |
||
788 | (*curpps)++; /* NB: ignore potential overflow */ |
||
789 | return (maxpps < 0 || *curpps < maxpps); |
||
790 | } |
||
791 | } |