kern_time.c revision 1.54.2.3 1 /* $NetBSD: kern_time.c,v 1.54.2.3 2001/09/21 22:36:26 nathanw Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christopher G. Demetriou.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1982, 1986, 1989, 1993
41 * The Regents of the University of California. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 *
71 * @(#)kern_time.c 8.4 (Berkeley) 5/26/95
72 */
73
74 #include "fs_nfs.h"
75 #include "opt_nfs.h"
76 #include "opt_nfsserver.h"
77
78 #include <sys/param.h>
79 #include <sys/resourcevar.h>
80 #include <sys/kernel.h>
81 #include <sys/systm.h>
82 #include <sys/lwp.h>
83 #include <sys/proc.h>
84 #include <sys/vnode.h>
85 #include <sys/signalvar.h>
86 #include <sys/syslog.h>
87
88 #include <sys/mount.h>
89 #include <sys/syscallargs.h>
90
91 #include <uvm/uvm_extern.h>
92
93 #if defined(NFS) || defined(NFSSERVER)
94 #include <nfs/rpcv2.h>
95 #include <nfs/nfsproto.h>
96 #include <nfs/nfs_var.h>
97 #endif
98
99 #include <machine/cpu.h>
100
101 /*
102 * Time of day and interval timer support.
103 *
104 * These routines provide the kernel entry points to get and set
105 * the time-of-day and per-process interval timers. Subroutines
106 * here provide support for adding and subtracting timeval structures
107 * and decrementing interval timers, optionally reloading the interval
108 * timers when they expire.
109 */
110
111 /* This function is used by clock_settime and settimeofday */
112 int
113 settime(tv)
114 struct timeval *tv;
115 {
116 struct timeval delta;
117 struct cpu_info *ci;
118 int s;
119
120 /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
121 s = splclock();
122 timersub(tv, &time, &delta);
123 if ((delta.tv_sec < 0 || delta.tv_usec < 0) && securelevel > 1) {
124 splx(s);
125 return (EPERM);
126 }
127 #ifdef notyet
128 if ((delta.tv_sec < 86400) && securelevel > 0) {
129 splx(s);
130 return (EPERM);
131 }
132 #endif
133 time = *tv;
134 (void) spllowersoftclock();
135 timeradd(&boottime, &delta, &boottime);
136 /*
137 * XXXSMP
138 * This is wrong. We should traverse a list of all
139 * CPUs and add the delta to the runtime of those
140 * CPUs which have a process on them.
141 */
142 ci = curcpu();
143 timeradd(&ci->ci_schedstate.spc_runtime, &delta,
144 &ci->ci_schedstate.spc_runtime);
145 # if (defined(NFS) && !defined (NFS_V2_ONLY)) || defined(NFSSERVER)
146 nqnfs_lease_updatetime(delta.tv_sec);
147 # endif
148 splx(s);
149 resettodr();
150 return (0);
151 }
152
153 /* ARGSUSED */
154 int
155 sys_clock_gettime(l, v, retval)
156 struct lwp *l;
157 void *v;
158 register_t *retval;
159 {
160 struct sys_clock_gettime_args /* {
161 syscallarg(clockid_t) clock_id;
162 syscallarg(struct timespec *) tp;
163 } */ *uap = v;
164 clockid_t clock_id;
165 struct timeval atv;
166 struct timespec ats;
167
168 clock_id = SCARG(uap, clock_id);
169 if (clock_id != CLOCK_REALTIME)
170 return (EINVAL);
171
172 microtime(&atv);
173 TIMEVAL_TO_TIMESPEC(&atv,&ats);
174
175 return copyout(&ats, SCARG(uap, tp), sizeof(ats));
176 }
177
178 /* ARGSUSED */
179 int
180 sys_clock_settime(l, v, retval)
181 struct lwp *l;
182 void *v;
183 register_t *retval;
184 {
185 struct sys_clock_settime_args /* {
186 syscallarg(clockid_t) clock_id;
187 syscallarg(const struct timespec *) tp;
188 } */ *uap = v;
189 struct proc *p = l->l_proc;
190 clockid_t clock_id;
191 struct timespec ats;
192 int error;
193
194 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
195 return (error);
196
197 clock_id = SCARG(uap, clock_id);
198
199 if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
200 return (error);
201
202 return (clock_settime1(clock_id, &ats));
203 }
204
205
206 int
207 clock_settime1(clock_id, ats)
208 clockid_t clock_id;
209 struct timespec *ats;
210 {
211 struct timeval atv;
212 int error;
213
214 if (clock_id != CLOCK_REALTIME)
215 return (EINVAL);
216
217 TIMESPEC_TO_TIMEVAL(&atv, ats);
218 if ((error = settime(&atv)) != 0)
219 return (error);
220
221 return 0;
222 }
223
224 int
225 sys_clock_getres(l, v, retval)
226 struct lwp *l;
227 void *v;
228 register_t *retval;
229 {
230 struct sys_clock_getres_args /* {
231 syscallarg(clockid_t) clock_id;
232 syscallarg(struct timespec *) tp;
233 } */ *uap = v;
234 clockid_t clock_id;
235 struct timespec ts;
236 int error = 0;
237
238 clock_id = SCARG(uap, clock_id);
239 if (clock_id != CLOCK_REALTIME)
240 return (EINVAL);
241
242 if (SCARG(uap, tp)) {
243 ts.tv_sec = 0;
244 ts.tv_nsec = 1000000000 / hz;
245
246 error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
247 }
248
249 return error;
250 }
251
252 /* ARGSUSED */
253 int
254 sys_nanosleep(l, v, retval)
255 struct lwp *l;
256 void *v;
257 register_t *retval;
258 {
259 static int nanowait;
260 struct sys_nanosleep_args/* {
261 syscallarg(struct timespec *) rqtp;
262 syscallarg(struct timespec *) rmtp;
263 } */ *uap = v;
264 struct timespec rqt;
265 struct timespec rmt;
266 struct timeval atv, utv;
267 int error, s, timo;
268
269 error = copyin((caddr_t)SCARG(uap, rqtp), (caddr_t)&rqt,
270 sizeof(struct timespec));
271 if (error)
272 return (error);
273
274 TIMESPEC_TO_TIMEVAL(&atv,&rqt)
275 if (itimerfix(&atv))
276 return (EINVAL);
277
278 s = splclock();
279 timeradd(&atv,&time,&atv);
280 timo = hzto(&atv);
281 /*
282 * Avoid inadvertantly sleeping forever
283 */
284 if (timo == 0)
285 timo = 1;
286 splx(s);
287
288 error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
289 if (error == ERESTART)
290 error = EINTR;
291 if (error == EWOULDBLOCK)
292 error = 0;
293
294 if (SCARG(uap, rmtp)) {
295 int error;
296
297 s = splclock();
298 utv = time;
299 splx(s);
300
301 timersub(&atv, &utv, &utv);
302 if (utv.tv_sec < 0)
303 timerclear(&utv);
304
305 TIMEVAL_TO_TIMESPEC(&utv,&rmt);
306 error = copyout((caddr_t)&rmt, (caddr_t)SCARG(uap,rmtp),
307 sizeof(rmt));
308 if (error)
309 return (error);
310 }
311
312 return error;
313 }
314
315 /* ARGSUSED */
316 int
317 sys_gettimeofday(l, v, retval)
318 struct lwp *l;
319 void *v;
320 register_t *retval;
321 {
322 struct sys_gettimeofday_args /* {
323 syscallarg(struct timeval *) tp;
324 syscallarg(struct timezone *) tzp;
325 } */ *uap = v;
326 struct timeval atv;
327 int error = 0;
328 struct timezone tzfake;
329
330 if (SCARG(uap, tp)) {
331 microtime(&atv);
332 error = copyout(&atv, SCARG(uap, tp), sizeof(atv));
333 if (error)
334 return (error);
335 }
336 if (SCARG(uap, tzp)) {
337 /*
338 * NetBSD has no kernel notion of time zone, so we just
339 * fake up a timezone struct and return it if demanded.
340 */
341 tzfake.tz_minuteswest = 0;
342 tzfake.tz_dsttime = 0;
343 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake));
344 }
345 return (error);
346 }
347
348 /* ARGSUSED */
349 int
350 sys_settimeofday(l, v, retval)
351 struct lwp *l;
352 void *v;
353 register_t *retval;
354 {
355 struct sys_settimeofday_args /* {
356 syscallarg(const struct timeval *) tv;
357 syscallarg(const struct timezone *) tzp;
358 } */ *uap = v;
359 struct proc *p = l->l_proc;
360 struct timeval atv;
361 struct timezone atz;
362 struct timeval *tv = NULL;
363 struct timezone *tzp = NULL;
364 int error;
365
366 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
367 return (error);
368
369 /* Verify all parameters before changing time. */
370 if (SCARG(uap, tv)) {
371 if ((error = copyin(SCARG(uap, tv), &atv, sizeof(atv))) != 0)
372 return (error);
373 tv = &atv;
374 }
375 /* XXX since we don't use tz, probably no point in doing copyin. */
376 if (SCARG(uap, tzp)) {
377 if ((error = copyin(SCARG(uap, tzp), &atz, sizeof(atz))) != 0)
378 return (error);
379 tzp = &atz;
380 }
381
382 return settimeofday1(tv, tzp, p);
383 }
384
385 int
386 settimeofday1(tv, tzp, p)
387 struct timeval *tv;
388 struct timezone *tzp;
389 struct proc *p;
390 {
391 int error;
392
393 if (tv)
394 if ((error = settime(tv)) != 0)
395 return (error);
396 /*
397 * NetBSD has no kernel notion of time zone, and only an
398 * obsolete program would try to set it, so we log a warning.
399 */
400 if (tzp)
401 log(LOG_WARNING, "pid %d attempted to set the "
402 "(obsolete) kernel time zone\n", p->p_pid);
403 return (0);
404 }
405
406 int tickdelta; /* current clock skew, us. per tick */
407 long timedelta; /* unapplied time correction, us. */
408 long bigadj = 1000000; /* use 10x skew above bigadj us. */
409
410 /* ARGSUSED */
411 int
412 sys_adjtime(l, v, retval)
413 struct lwp *l;
414 void *v;
415 register_t *retval;
416 {
417 struct sys_adjtime_args /* {
418 syscallarg(const struct timeval *) delta;
419 syscallarg(struct timeval *) olddelta;
420 } */ *uap = v;
421 struct proc *p = l->l_proc;
422 struct timeval atv;
423 struct timeval *oatv = NULL;
424 int error;
425
426 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
427 return (error);
428
429 error = copyin(SCARG(uap, delta), &atv, sizeof(struct timeval));
430 if (error)
431 return (error);
432
433 if (SCARG(uap, olddelta) != NULL) {
434 if (uvm_useracc((caddr_t)SCARG(uap, olddelta),
435 sizeof(struct timeval), B_WRITE) == FALSE)
436 return (EFAULT);
437 oatv = SCARG(uap, olddelta);
438 }
439
440 return adjtime1(&atv, oatv, p);
441 }
442
443 int
444 adjtime1(delta, olddelta, p)
445 struct timeval *delta;
446 struct timeval *olddelta;
447 struct proc *p;
448 {
449 long ndelta, ntickdelta, odelta;
450 int s;
451
452 /*
453 * Compute the total correction and the rate at which to apply it.
454 * Round the adjustment down to a whole multiple of the per-tick
455 * delta, so that after some number of incremental changes in
456 * hardclock(), tickdelta will become zero, lest the correction
457 * overshoot and start taking us away from the desired final time.
458 */
459 ndelta = delta->tv_sec * 1000000 + delta->tv_usec;
460 if (ndelta > bigadj || ndelta < -bigadj)
461 ntickdelta = 10 * tickadj;
462 else
463 ntickdelta = tickadj;
464 if (ndelta % ntickdelta)
465 ndelta = ndelta / ntickdelta * ntickdelta;
466
467 /*
468 * To make hardclock()'s job easier, make the per-tick delta negative
469 * if we want time to run slower; then hardclock can simply compute
470 * tick + tickdelta, and subtract tickdelta from timedelta.
471 */
472 if (ndelta < 0)
473 ntickdelta = -ntickdelta;
474 s = splclock();
475 odelta = timedelta;
476 timedelta = ndelta;
477 tickdelta = ntickdelta;
478 splx(s);
479
480 if (olddelta) {
481 delta->tv_sec = odelta / 1000000;
482 delta->tv_usec = odelta % 1000000;
483 (void) copyout(delta, olddelta, sizeof(struct timeval));
484 }
485 return (0);
486 }
487
488 /*
489 * Get value of an interval timer. The process virtual and
490 * profiling virtual time timers are kept in the p_stats area, since
491 * they can be swapped out. These are kept internally in the
492 * way they are specified externally: in time until they expire.
493 *
494 * The real time interval timer is kept in the process table slot
495 * for the process, and its value (it_value) is kept as an
496 * absolute time rather than as a delta, so that it is easy to keep
497 * periodic real-time signals from drifting.
498 *
499 * Virtual time timers are processed in the hardclock() routine of
500 * kern_clock.c. The real time timer is processed by a timeout
501 * routine, called from the softclock() routine. Since a callout
502 * may be delayed in real time due to interrupt processing in the system,
503 * it is possible for the real time timeout routine (realitexpire, given below),
504 * to be delayed in real time past when it is supposed to occur. It
505 * does not suffice, therefore, to reload the real timer .it_value from the
506 * real time timers .it_interval. Rather, we compute the next time in
507 * absolute time the timer should go off.
508 */
509 /* ARGSUSED */
510 int
511 sys_getitimer(l, v, retval)
512 struct lwp *l;
513 void *v;
514 register_t *retval;
515 {
516 struct sys_getitimer_args /* {
517 syscallarg(int) which;
518 syscallarg(struct itimerval *) itv;
519 } */ *uap = v;
520 struct proc *p = l->l_proc;
521 int which = SCARG(uap, which);
522 struct itimerval aitv;
523 int s;
524
525 if ((u_int)which > ITIMER_PROF)
526 return (EINVAL);
527 s = splclock();
528 if (which == ITIMER_REAL) {
529 /*
530 * Convert from absolute to relative time in .it_value
531 * part of real time timer. If time for real time timer
532 * has passed return 0, else return difference between
533 * current time and time for the timer to go off.
534 */
535 aitv = p->p_realtimer;
536 if (timerisset(&aitv.it_value)) {
537 if (timercmp(&aitv.it_value, &time, <))
538 timerclear(&aitv.it_value);
539 else
540 timersub(&aitv.it_value, &time, &aitv.it_value);
541 }
542 } else
543 aitv = p->p_stats->p_timer[which];
544 splx(s);
545 return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval)));
546 }
547
548 /* ARGSUSED */
549 int
550 sys_setitimer(l, v, retval)
551 struct lwp *l;
552 void *v;
553 register_t *retval;
554 {
555 struct sys_setitimer_args /* {
556 syscallarg(int) which;
557 syscallarg(const struct itimerval *) itv;
558 syscallarg(struct itimerval *) oitv;
559 } */ *uap = v;
560 struct proc *p = l->l_proc;
561 int which = SCARG(uap, which);
562 struct sys_getitimer_args getargs;
563 struct itimerval aitv;
564 const struct itimerval *itvp;
565 int s, error;
566
567 if ((u_int)which > ITIMER_PROF)
568 return (EINVAL);
569 itvp = SCARG(uap, itv);
570 if (itvp &&
571 (error = copyin(itvp, &aitv, sizeof(struct itimerval)) != 0))
572 return (error);
573 if (SCARG(uap, oitv) != NULL) {
574 SCARG(&getargs, which) = which;
575 SCARG(&getargs, itv) = SCARG(uap, oitv);
576 if ((error = sys_getitimer(l, &getargs, retval)) != 0)
577 return (error);
578 }
579 if (itvp == 0)
580 return (0);
581 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
582 return (EINVAL);
583 s = splclock();
584 if (which == ITIMER_REAL) {
585 callout_stop(&p->p_realit_ch);
586 if (timerisset(&aitv.it_value)) {
587 /*
588 * Don't need to check hzto() return value, here.
589 * callout_reset() does it for us.
590 */
591 timeradd(&aitv.it_value, &time, &aitv.it_value);
592 callout_reset(&p->p_realit_ch, hzto(&aitv.it_value),
593 realitexpire, p);
594 }
595 p->p_realtimer = aitv;
596 } else
597 p->p_stats->p_timer[which] = aitv;
598 splx(s);
599 return (0);
600 }
601
602 /*
603 * Real interval timer expired:
604 * send process whose timer expired an alarm signal.
605 * If time is not set up to reload, then just return.
606 * Else compute next time timer should go off which is > current time.
607 * This is where delay in processing this timeout causes multiple
608 * SIGALRM calls to be compressed into one.
609 */
610 void
611 realitexpire(arg)
612 void *arg;
613 {
614 struct proc *p;
615 int s;
616
617 p = (struct proc *)arg;
618 psignal(p, SIGALRM);
619 if (!timerisset(&p->p_realtimer.it_interval)) {
620 timerclear(&p->p_realtimer.it_value);
621 return;
622 }
623 for (;;) {
624 s = splclock();
625 timeradd(&p->p_realtimer.it_value,
626 &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
627 if (timercmp(&p->p_realtimer.it_value, &time, >)) {
628 /*
629 * Don't need to check hzto() return value, here.
630 * callout_reset() does it for us.
631 */
632 callout_reset(&p->p_realit_ch,
633 hzto(&p->p_realtimer.it_value), realitexpire, p);
634 splx(s);
635 return;
636 }
637 splx(s);
638 }
639 }
640
641 /*
642 * Check that a proposed value to load into the .it_value or
643 * .it_interval part of an interval timer is acceptable, and
644 * fix it to have at least minimal value (i.e. if it is less
645 * than the resolution of the clock, round it up.)
646 */
647 int
648 itimerfix(tv)
649 struct timeval *tv;
650 {
651
652 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
653 tv->tv_usec < 0 || tv->tv_usec >= 1000000)
654 return (EINVAL);
655 if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
656 tv->tv_usec = tick;
657 return (0);
658 }
659
660 /*
661 * Decrement an interval timer by a specified number
662 * of microseconds, which must be less than a second,
663 * i.e. < 1000000. If the timer expires, then reload
664 * it. In this case, carry over (usec - old value) to
665 * reduce the value reloaded into the timer so that
666 * the timer does not drift. This routine assumes
667 * that it is called in a context where the timers
668 * on which it is operating cannot change in value.
669 */
670 int
671 itimerdecr(itp, usec)
672 struct itimerval *itp;
673 int usec;
674 {
675
676 if (itp->it_value.tv_usec < usec) {
677 if (itp->it_value.tv_sec == 0) {
678 /* expired, and already in next interval */
679 usec -= itp->it_value.tv_usec;
680 goto expire;
681 }
682 itp->it_value.tv_usec += 1000000;
683 itp->it_value.tv_sec--;
684 }
685 itp->it_value.tv_usec -= usec;
686 usec = 0;
687 if (timerisset(&itp->it_value))
688 return (1);
689 /* expired, exactly at end of interval */
690 expire:
691 if (timerisset(&itp->it_interval)) {
692 itp->it_value = itp->it_interval;
693 itp->it_value.tv_usec -= usec;
694 if (itp->it_value.tv_usec < 0) {
695 itp->it_value.tv_usec += 1000000;
696 itp->it_value.tv_sec--;
697 }
698 } else
699 itp->it_value.tv_usec = 0; /* sec is already 0 */
700 return (0);
701 }
702
703 /*
704 * ratecheck(): simple time-based rate-limit checking. see ratecheck(9)
705 * for usage and rationale.
706 */
707 int
708 ratecheck(lasttime, mininterval)
709 struct timeval *lasttime;
710 const struct timeval *mininterval;
711 {
712 struct timeval tv, delta;
713 int s, rv = 0;
714
715 s = splclock();
716 tv = mono_time;
717 splx(s);
718
719 timersub(&tv, lasttime, &delta);
720
721 /*
722 * check for 0,0 is so that the message will be seen at least once,
723 * even if interval is huge.
724 */
725 if (timercmp(&delta, mininterval, >=) ||
726 (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
727 *lasttime = tv;
728 rv = 1;
729 }
730
731 return (rv);
732 }
733
734 /*
735 * ppsratecheck(): packets (or events) per second limitation.
736 */
737 int
738 ppsratecheck(lasttime, curpps, maxpps)
739 struct timeval *lasttime;
740 int *curpps;
741 int maxpps; /* maximum pps allowed */
742 {
743 struct timeval tv, delta;
744 int s, rv;
745
746 s = splclock();
747 tv = mono_time;
748 splx(s);
749
750 timersub(&tv, lasttime, &delta);
751
752 /*
753 * check for 0,0 is so that the message will be seen at least once.
754 * if more than one second have passed since the last update of
755 * lasttime, reset the counter.
756 *
757 * we do increment *curpps even in *curpps < maxpps case, as some may
758 * try to use *curpps for stat purposes as well.
759 */
760 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
761 delta.tv_sec >= 1) {
762 *lasttime = tv;
763 *curpps = 0;
764 rv = 1;
765 } else if (maxpps < 0)
766 rv = 1;
767 else if (*curpps < maxpps)
768 rv = 1;
769 else
770 rv = 0;
771
772 #if 1 /*DIAGNOSTIC?*/
773 /* be careful about wrap-around */
774 if (*curpps + 1 > *curpps)
775 *curpps = *curpps + 1;
776 #else
777 /*
778 * assume that there's not too many calls to this function.
779 * not sure if the assumption holds, as it depends on *caller's*
780 * behavior, not the behavior of this function.
781 * IMHO it is wrong to make assumption on the caller's behavior,
782 * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
783 */
784 *curpps = *curpps + 1;
785 #endif
786
787 return (rv);
788 }
789