FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_time.c
1 /* $NetBSD: kern_time.c,v 1.82.2.2 2005/12/07 10:06:26 tron 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. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 *
67 * @(#)kern_time.c 8.4 (Berkeley) 5/26/95
68 */
69
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.82.2.2 2005/12/07 10:06:26 tron Exp $");
72
73 #include "fs_nfs.h"
74 #include "opt_nfs.h"
75 #include "opt_nfsserver.h"
76
77 #include <sys/param.h>
78 #include <sys/resourcevar.h>
79 #include <sys/kernel.h>
80 #include <sys/systm.h>
81 #include <sys/malloc.h>
82 #include <sys/proc.h>
83 #include <sys/sa.h>
84 #include <sys/savar.h>
85 #include <sys/vnode.h>
86 #include <sys/signalvar.h>
87 #include <sys/syslog.h>
88
89 #include <sys/mount.h>
90 #include <sys/syscallargs.h>
91
92 #include <uvm/uvm_extern.h>
93
94 #if defined(NFS) || defined(NFSSERVER)
95 #include <nfs/rpcv2.h>
96 #include <nfs/nfsproto.h>
97 #include <nfs/nfs_var.h>
98 #endif
99
100 #include <machine/cpu.h>
101
102 static void timerupcall(struct lwp *, void *);
103
104
105 /* Time of day and interval timer support.
106 *
107 * These routines provide the kernel entry points to get and set
108 * the time-of-day and per-process interval timers. Subroutines
109 * here provide support for adding and subtracting timeval structures
110 * and decrementing interval timers, optionally reloading the interval
111 * timers when they expire.
112 */
113
114 /* This function is used by clock_settime and settimeofday */
115 int
116 settime(struct timeval *tv)
117 {
118 struct timeval delta;
119 struct cpu_info *ci;
120 int s;
121
122 /*
123 * Don't allow the time to be set forward so far it will wrap
124 * and become negative, thus allowing an attacker to bypass
125 * the next check below. The cutoff is 1 year before rollover
126 * occurs, so even if the attacker uses adjtime(2) to move
127 * the time past the cutoff, it will take a very long time
128 * to get to the wrap point.
129 *
130 * XXX: we check against INT_MAX since on 64-bit
131 * platforms, sizeof(int) != sizeof(long) and
132 * time_t is 32 bits even when atv.tv_sec is 64 bits.
133 */
134 if (tv->tv_sec > INT_MAX - 365*24*60*60) {
135 struct proc *p = curproc;
136 struct proc *pp = p->p_pptr;
137 log(LOG_WARNING, "pid %d (%s) "
138 "invoked by uid %d ppid %d (%s) "
139 "tried to set clock forward to %ld\n",
140 p->p_pid, p->p_comm, pp->p_ucred->cr_uid,
141 pp->p_pid, pp->p_comm, (long)tv->tv_sec);
142 return (EPERM);
143 }
144 /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
145 s = splclock();
146 timersub(tv, &time, &delta);
147 if ((delta.tv_sec < 0 || delta.tv_usec < 0) && securelevel > 1) {
148 splx(s);
149 return (EPERM);
150 }
151 #ifdef notyet
152 if ((delta.tv_sec < 86400) && securelevel > 0) {
153 splx(s);
154 return (EPERM);
155 }
156 #endif
157 time = *tv;
158 (void) spllowersoftclock();
159 timeradd(&boottime, &delta, &boottime);
160 /*
161 * XXXSMP
162 * This is wrong. We should traverse a list of all
163 * CPUs and add the delta to the runtime of those
164 * CPUs which have a process on them.
165 */
166 ci = curcpu();
167 timeradd(&ci->ci_schedstate.spc_runtime, &delta,
168 &ci->ci_schedstate.spc_runtime);
169 # if (defined(NFS) && !defined (NFS_V2_ONLY)) || defined(NFSSERVER)
170 nqnfs_lease_updatetime(delta.tv_sec);
171 # endif
172 splx(s);
173 resettodr();
174 return (0);
175 }
176
177 /* ARGSUSED */
178 int
179 sys_clock_gettime(struct lwp *l, void *v, register_t *retval)
180 {
181 struct sys_clock_gettime_args /* {
182 syscallarg(clockid_t) clock_id;
183 syscallarg(struct timespec *) tp;
184 } */ *uap = v;
185 clockid_t clock_id;
186 struct timeval atv;
187 struct timespec ats;
188 int s;
189
190 clock_id = SCARG(uap, clock_id);
191 switch (clock_id) {
192 case CLOCK_REALTIME:
193 microtime(&atv);
194 TIMEVAL_TO_TIMESPEC(&atv,&ats);
195 break;
196 case CLOCK_MONOTONIC:
197 /* XXX "hz" granularity */
198 s = splclock();
199 atv = mono_time;
200 splx(s);
201 TIMEVAL_TO_TIMESPEC(&atv,&ats);
202 break;
203 default:
204 return (EINVAL);
205 }
206
207 return copyout(&ats, SCARG(uap, tp), sizeof(ats));
208 }
209
210 /* ARGSUSED */
211 int
212 sys_clock_settime(l, v, retval)
213 struct lwp *l;
214 void *v;
215 register_t *retval;
216 {
217 struct sys_clock_settime_args /* {
218 syscallarg(clockid_t) clock_id;
219 syscallarg(const struct timespec *) tp;
220 } */ *uap = v;
221 struct proc *p = l->l_proc;
222 int error;
223
224 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
225 return (error);
226
227 return (clock_settime1(SCARG(uap, clock_id), SCARG(uap, tp)));
228 }
229
230
231 int
232 clock_settime1(clock_id, tp)
233 clockid_t clock_id;
234 const struct timespec *tp;
235 {
236 struct timespec ats;
237 struct timeval atv;
238 int error;
239
240 if ((error = copyin(tp, &ats, sizeof(ats))) != 0)
241 return (error);
242
243 switch (clock_id) {
244 case CLOCK_REALTIME:
245 TIMESPEC_TO_TIMEVAL(&atv, &ats);
246 if ((error = settime(&atv)) != 0)
247 return (error);
248 break;
249 case CLOCK_MONOTONIC:
250 return (EINVAL); /* read-only clock */
251 default:
252 return (EINVAL);
253 }
254
255 return 0;
256 }
257
258 int
259 sys_clock_getres(struct lwp *l, void *v, register_t *retval)
260 {
261 struct sys_clock_getres_args /* {
262 syscallarg(clockid_t) clock_id;
263 syscallarg(struct timespec *) tp;
264 } */ *uap = v;
265 clockid_t clock_id;
266 struct timespec ts;
267 int error = 0;
268
269 clock_id = SCARG(uap, clock_id);
270 switch (clock_id) {
271 case CLOCK_REALTIME:
272 case CLOCK_MONOTONIC:
273 ts.tv_sec = 0;
274 ts.tv_nsec = 1000000000 / hz;
275 break;
276 default:
277 return (EINVAL);
278 }
279
280 if (SCARG(uap, tp))
281 error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
282
283 return error;
284 }
285
286 /* ARGSUSED */
287 int
288 sys_nanosleep(struct lwp *l, void *v, register_t *retval)
289 {
290 static int nanowait;
291 struct sys_nanosleep_args/* {
292 syscallarg(struct timespec *) rqtp;
293 syscallarg(struct timespec *) rmtp;
294 } */ *uap = v;
295 struct timespec rqt;
296 struct timespec rmt;
297 struct timeval atv, utv;
298 int error, s, timo;
299
300 error = copyin((caddr_t)SCARG(uap, rqtp), (caddr_t)&rqt,
301 sizeof(struct timespec));
302 if (error)
303 return (error);
304
305 TIMESPEC_TO_TIMEVAL(&atv,&rqt)
306 if (itimerfix(&atv))
307 return (EINVAL);
308
309 s = splclock();
310 timeradd(&atv,&time,&atv);
311 timo = hzto(&atv);
312 /*
313 * Avoid inadvertantly sleeping forever
314 */
315 if (timo == 0)
316 timo = 1;
317 splx(s);
318
319 error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
320 if (error == ERESTART)
321 error = EINTR;
322 if (error == EWOULDBLOCK)
323 error = 0;
324
325 if (SCARG(uap, rmtp)) {
326 int error;
327
328 s = splclock();
329 utv = time;
330 splx(s);
331
332 timersub(&atv, &utv, &utv);
333 if (utv.tv_sec < 0)
334 timerclear(&utv);
335
336 TIMEVAL_TO_TIMESPEC(&utv,&rmt);
337 error = copyout((caddr_t)&rmt, (caddr_t)SCARG(uap,rmtp),
338 sizeof(rmt));
339 if (error)
340 return (error);
341 }
342
343 return error;
344 }
345
346 /* ARGSUSED */
347 int
348 sys_gettimeofday(struct lwp *l, void *v, register_t *retval)
349 {
350 struct sys_gettimeofday_args /* {
351 syscallarg(struct timeval *) tp;
352 syscallarg(struct timezone *) tzp;
353 } */ *uap = v;
354 struct timeval atv;
355 int error = 0;
356 struct timezone tzfake;
357
358 if (SCARG(uap, tp)) {
359 microtime(&atv);
360 error = copyout(&atv, SCARG(uap, tp), sizeof(atv));
361 if (error)
362 return (error);
363 }
364 if (SCARG(uap, tzp)) {
365 /*
366 * NetBSD has no kernel notion of time zone, so we just
367 * fake up a timezone struct and return it if demanded.
368 */
369 tzfake.tz_minuteswest = 0;
370 tzfake.tz_dsttime = 0;
371 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake));
372 }
373 return (error);
374 }
375
376 /* ARGSUSED */
377 int
378 sys_settimeofday(struct lwp *l, void *v, register_t *retval)
379 {
380 struct sys_settimeofday_args /* {
381 syscallarg(const struct timeval *) tv;
382 syscallarg(const struct timezone *) tzp;
383 } */ *uap = v;
384 struct proc *p = l->l_proc;
385 int error;
386
387 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
388 return (error);
389
390 return settimeofday1(SCARG(uap, tv), SCARG(uap, tzp), p);
391 }
392
393 int
394 settimeofday1(utv, utzp, p)
395 const struct timeval *utv;
396 const struct timezone *utzp;
397 struct proc *p;
398 {
399 struct timeval atv;
400 struct timezone atz;
401 struct timeval *tv = NULL;
402 struct timezone *tzp = NULL;
403 int error;
404
405 /* Verify all parameters before changing time. */
406 if (utv) {
407 if ((error = copyin(utv, &atv, sizeof(atv))) != 0)
408 return (error);
409 tv = &atv;
410 }
411 /* XXX since we don't use tz, probably no point in doing copyin. */
412 if (utzp) {
413 if ((error = copyin(utzp, &atz, sizeof(atz))) != 0)
414 return (error);
415 tzp = &atz;
416 }
417
418 if (tv)
419 if ((error = settime(tv)) != 0)
420 return (error);
421 /*
422 * NetBSD has no kernel notion of time zone, and only an
423 * obsolete program would try to set it, so we log a warning.
424 */
425 if (tzp)
426 log(LOG_WARNING, "pid %d attempted to set the "
427 "(obsolete) kernel time zone\n", p->p_pid);
428 return (0);
429 }
430
431 int tickdelta; /* current clock skew, us. per tick */
432 long timedelta; /* unapplied time correction, us. */
433 long bigadj = 1000000; /* use 10x skew above bigadj us. */
434 int time_adjusted; /* set if an adjustment is made */
435
436 /* ARGSUSED */
437 int
438 sys_adjtime(struct lwp *l, void *v, register_t *retval)
439 {
440 struct sys_adjtime_args /* {
441 syscallarg(const struct timeval *) delta;
442 syscallarg(struct timeval *) olddelta;
443 } */ *uap = v;
444 struct proc *p = l->l_proc;
445 int error;
446
447 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
448 return (error);
449
450 return adjtime1(SCARG(uap, delta), SCARG(uap, olddelta), p);
451 }
452
453 int
454 adjtime1(delta, olddelta, p)
455 const struct timeval *delta;
456 struct timeval *olddelta;
457 struct proc *p;
458 {
459 struct timeval atv;
460 long ndelta, ntickdelta, odelta;
461 int error;
462 int s;
463
464 error = copyin(delta, &atv, sizeof(struct timeval));
465 if (error)
466 return (error);
467
468 /*
469 * Compute the total correction and the rate at which to apply it.
470 * Round the adjustment down to a whole multiple of the per-tick
471 * delta, so that after some number of incremental changes in
472 * hardclock(), tickdelta will become zero, lest the correction
473 * overshoot and start taking us away from the desired final time.
474 */
475 ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
476 if (ndelta > bigadj || ndelta < -bigadj)
477 ntickdelta = 10 * tickadj;
478 else
479 ntickdelta = tickadj;
480 if (ndelta % ntickdelta)
481 ndelta = ndelta / ntickdelta * ntickdelta;
482
483 /*
484 * To make hardclock()'s job easier, make the per-tick delta negative
485 * if we want time to run slower; then hardclock can simply compute
486 * tick + tickdelta, and subtract tickdelta from timedelta.
487 */
488 if (ndelta < 0)
489 ntickdelta = -ntickdelta;
490 if (ndelta != 0)
491 /* We need to save the system clock time during shutdown */
492 time_adjusted |= 1;
493 s = splclock();
494 odelta = timedelta;
495 timedelta = ndelta;
496 tickdelta = ntickdelta;
497 splx(s);
498
499 if (olddelta) {
500 atv.tv_sec = odelta / 1000000;
501 atv.tv_usec = odelta % 1000000;
502 error = copyout(&atv, olddelta, sizeof(struct timeval));
503 }
504 return error;
505 }
506
507 /*
508 * Interval timer support. Both the BSD getitimer() family and the POSIX
509 * timer_*() family of routines are supported.
510 *
511 * All timers are kept in an array pointed to by p_timers, which is
512 * allocated on demand - many processes don't use timers at all. The
513 * first three elements in this array are reserved for the BSD timers:
514 * element 0 is ITIMER_REAL, element 1 is ITIMER_VIRTUAL, and element
515 * 2 is ITIMER_PROF. The rest may be allocated by the timer_create()
516 * syscall.
517 *
518 * Realtime timers are kept in the ptimer structure as an absolute
519 * time; virtual time timers are kept as a linked list of deltas.
520 * Virtual time timers are processed in the hardclock() routine of
521 * kern_clock.c. The real time timer is processed by a callout
522 * routine, called from the softclock() routine. Since a callout may
523 * be delayed in real time due to interrupt processing in the system,
524 * it is possible for the real time timeout routine (realtimeexpire,
525 * given below), to be delayed in real time past when it is supposed
526 * to occur. It does not suffice, therefore, to reload the real timer
527 * .it_value from the real time timers .it_interval. Rather, we
528 * compute the next time in absolute time the timer should go off. */
529
530 /* Allocate a POSIX realtime timer. */
531 int
532 sys_timer_create(struct lwp *l, void *v, register_t *retval)
533 {
534 struct sys_timer_create_args /* {
535 syscallarg(clockid_t) clock_id;
536 syscallarg(struct sigevent *) evp;
537 syscallarg(timer_t *) timerid;
538 } */ *uap = v;
539 struct proc *p = l->l_proc;
540 clockid_t id;
541 struct sigevent *evp;
542 struct ptimer *pt;
543 timer_t timerid;
544 int error;
545
546 id = SCARG(uap, clock_id);
547 if (id < CLOCK_REALTIME ||
548 id > CLOCK_PROF)
549 return (EINVAL);
550
551 if (p->p_timers == NULL)
552 timers_alloc(p);
553
554 /* Find a free timer slot, skipping those reserved for setitimer(). */
555 for (timerid = 3; timerid < TIMER_MAX; timerid++)
556 if (p->p_timers->pts_timers[timerid] == NULL)
557 break;
558
559 if (timerid == TIMER_MAX)
560 return EAGAIN;
561
562 pt = pool_get(&ptimer_pool, PR_WAITOK);
563 evp = SCARG(uap, evp);
564 if (evp) {
565 if (((error =
566 copyin(evp, &pt->pt_ev, sizeof (pt->pt_ev))) != 0) ||
567 ((pt->pt_ev.sigev_notify < SIGEV_NONE) ||
568 (pt->pt_ev.sigev_notify > SIGEV_SA))) {
569 pool_put(&ptimer_pool, pt);
570 return (error ? error : EINVAL);
571 }
572 } else {
573 pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
574 switch (id) {
575 case CLOCK_REALTIME:
576 pt->pt_ev.sigev_signo = SIGALRM;
577 break;
578 case CLOCK_VIRTUAL:
579 pt->pt_ev.sigev_signo = SIGVTALRM;
580 break;
581 case CLOCK_PROF:
582 pt->pt_ev.sigev_signo = SIGPROF;
583 break;
584 }
585 pt->pt_ev.sigev_value.sival_int = timerid;
586 }
587 pt->pt_info.ksi_signo = pt->pt_ev.sigev_signo;
588 pt->pt_info.ksi_errno = 0;
589 pt->pt_info.ksi_code = 0;
590 pt->pt_info.ksi_pid = p->p_pid;
591 pt->pt_info.ksi_uid = p->p_cred->p_ruid;
592 pt->pt_info.ksi_sigval = pt->pt_ev.sigev_value;
593
594 pt->pt_type = id;
595 pt->pt_proc = p;
596 pt->pt_overruns = 0;
597 pt->pt_poverruns = 0;
598 pt->pt_entry = timerid;
599 timerclear(&pt->pt_time.it_value);
600 if (id == CLOCK_REALTIME)
601 callout_init(&pt->pt_ch);
602 else
603 pt->pt_active = 0;
604
605 p->p_timers->pts_timers[timerid] = pt;
606
607 return copyout(&timerid, SCARG(uap, timerid), sizeof(timerid));
608 }
609
610
611 /* Delete a POSIX realtime timer */
612 int
613 sys_timer_delete(struct lwp *l, void *v, register_t *retval)
614 {
615 struct sys_timer_delete_args /* {
616 syscallarg(timer_t) timerid;
617 } */ *uap = v;
618 struct proc *p = l->l_proc;
619 timer_t timerid;
620 struct ptimer *pt, *ptn;
621 int s;
622
623 timerid = SCARG(uap, timerid);
624
625 if ((p->p_timers == NULL) ||
626 (timerid < 2) || (timerid >= TIMER_MAX) ||
627 ((pt = p->p_timers->pts_timers[timerid]) == NULL))
628 return (EINVAL);
629
630 if (pt->pt_type == CLOCK_REALTIME)
631 callout_stop(&pt->pt_ch);
632 else if (pt->pt_active) {
633 s = splclock();
634 ptn = LIST_NEXT(pt, pt_list);
635 LIST_REMOVE(pt, pt_list);
636 for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list))
637 timeradd(&pt->pt_time.it_value, &ptn->pt_time.it_value,
638 &ptn->pt_time.it_value);
639 splx(s);
640 }
641
642 p->p_timers->pts_timers[timerid] = NULL;
643 pool_put(&ptimer_pool, pt);
644
645 return (0);
646 }
647
648 /*
649 * Set up the given timer. The value in pt->pt_time.it_value is taken
650 * to be an absolute time for CLOCK_REALTIME timers and a relative
651 * time for virtual timers.
652 * Must be called at splclock().
653 */
654 void
655 timer_settime(struct ptimer *pt)
656 {
657 struct ptimer *ptn, *pptn;
658 struct ptlist *ptl;
659
660 if (pt->pt_type == CLOCK_REALTIME) {
661 callout_stop(&pt->pt_ch);
662 if (timerisset(&pt->pt_time.it_value)) {
663 /*
664 * Don't need to check hzto() return value, here.
665 * callout_reset() does it for us.
666 */
667 callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
668 realtimerexpire, pt);
669 }
670 } else {
671 if (pt->pt_active) {
672 ptn = LIST_NEXT(pt, pt_list);
673 LIST_REMOVE(pt, pt_list);
674 for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list))
675 timeradd(&pt->pt_time.it_value,
676 &ptn->pt_time.it_value,
677 &ptn->pt_time.it_value);
678 }
679 if (timerisset(&pt->pt_time.it_value)) {
680 if (pt->pt_type == CLOCK_VIRTUAL)
681 ptl = &pt->pt_proc->p_timers->pts_virtual;
682 else
683 ptl = &pt->pt_proc->p_timers->pts_prof;
684
685 for (ptn = LIST_FIRST(ptl), pptn = NULL;
686 ptn && timercmp(&pt->pt_time.it_value,
687 &ptn->pt_time.it_value, >);
688 pptn = ptn, ptn = LIST_NEXT(ptn, pt_list))
689 timersub(&pt->pt_time.it_value,
690 &ptn->pt_time.it_value,
691 &pt->pt_time.it_value);
692
693 if (pptn)
694 LIST_INSERT_AFTER(pptn, pt, pt_list);
695 else
696 LIST_INSERT_HEAD(ptl, pt, pt_list);
697
698 for ( ; ptn ; ptn = LIST_NEXT(ptn, pt_list))
699 timersub(&ptn->pt_time.it_value,
700 &pt->pt_time.it_value,
701 &ptn->pt_time.it_value);
702
703 pt->pt_active = 1;
704 } else
705 pt->pt_active = 0;
706 }
707 }
708
709 void
710 timer_gettime(struct ptimer *pt, struct itimerval *aitv)
711 {
712 struct ptimer *ptn;
713
714 *aitv = pt->pt_time;
715 if (pt->pt_type == CLOCK_REALTIME) {
716 /*
717 * Convert from absolute to relative time in .it_value
718 * part of real time timer. If time for real time
719 * timer has passed return 0, else return difference
720 * between current time and time for the timer to go
721 * off.
722 */
723 if (timerisset(&aitv->it_value)) {
724 if (timercmp(&aitv->it_value, &time, <))
725 timerclear(&aitv->it_value);
726 else
727 timersub(&aitv->it_value, &time,
728 &aitv->it_value);
729 }
730 } else if (pt->pt_active) {
731 if (pt->pt_type == CLOCK_VIRTUAL)
732 ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_virtual);
733 else
734 ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_prof);
735 for ( ; ptn && ptn != pt; ptn = LIST_NEXT(ptn, pt_list))
736 timeradd(&aitv->it_value,
737 &ptn->pt_time.it_value, &aitv->it_value);
738 KASSERT(ptn != NULL); /* pt should be findable on the list */
739 } else
740 timerclear(&aitv->it_value);
741 }
742
743
744
745 /* Set and arm a POSIX realtime timer */
746 int
747 sys_timer_settime(struct lwp *l, void *v, register_t *retval)
748 {
749 struct sys_timer_settime_args /* {
750 syscallarg(timer_t) timerid;
751 syscallarg(int) flags;
752 syscallarg(const struct itimerspec *) value;
753 syscallarg(struct itimerspec *) ovalue;
754 } */ *uap = v;
755 struct proc *p = l->l_proc;
756 int error, s, timerid;
757 struct itimerval val, oval;
758 struct itimerspec value, ovalue;
759 struct ptimer *pt;
760
761 timerid = SCARG(uap, timerid);
762
763 if ((p->p_timers == NULL) ||
764 (timerid < 2) || (timerid >= TIMER_MAX) ||
765 ((pt = p->p_timers->pts_timers[timerid]) == NULL))
766 return (EINVAL);
767
768 if ((error = copyin(SCARG(uap, value), &value,
769 sizeof(struct itimerspec))) != 0)
770 return (error);
771
772 TIMESPEC_TO_TIMEVAL(&val.it_value, &value.it_value);
773 TIMESPEC_TO_TIMEVAL(&val.it_interval, &value.it_interval);
774 if (itimerfix(&val.it_value) || itimerfix(&val.it_interval))
775 return (EINVAL);
776
777 oval = pt->pt_time;
778 pt->pt_time = val;
779
780 s = splclock();
781 /*
782 * If we've been passed a relative time for a realtime timer,
783 * convert it to absolute; if an absolute time for a virtual
784 * timer, convert it to relative and make sure we don't set it
785 * to zero, which would cancel the timer, or let it go
786 * negative, which would confuse the comparison tests.
787 */
788 if (timerisset(&pt->pt_time.it_value)) {
789 if (pt->pt_type == CLOCK_REALTIME) {
790 if ((SCARG(uap, flags) & TIMER_ABSTIME) == 0)
791 timeradd(&pt->pt_time.it_value, &time,
792 &pt->pt_time.it_value);
793 } else {
794 if ((SCARG(uap, flags) & TIMER_ABSTIME) != 0) {
795 timersub(&pt->pt_time.it_value, &time,
796 &pt->pt_time.it_value);
797 if (!timerisset(&pt->pt_time.it_value) ||
798 pt->pt_time.it_value.tv_sec < 0) {
799 pt->pt_time.it_value.tv_sec = 0;
800 pt->pt_time.it_value.tv_usec = 1;
801 }
802 }
803 }
804 }
805
806 timer_settime(pt);
807 splx(s);
808
809 if (SCARG(uap, ovalue)) {
810 TIMEVAL_TO_TIMESPEC(&oval.it_value, &ovalue.it_value);
811 TIMEVAL_TO_TIMESPEC(&oval.it_interval, &ovalue.it_interval);
812 return copyout(&ovalue, SCARG(uap, ovalue),
813 sizeof(struct itimerspec));
814 }
815
816 return (0);
817 }
818
819 /* Return the time remaining until a POSIX timer fires. */
820 int
821 sys_timer_gettime(struct lwp *l, void *v, register_t *retval)
822 {
823 struct sys_timer_gettime_args /* {
824 syscallarg(timer_t) timerid;
825 syscallarg(struct itimerspec *) value;
826 } */ *uap = v;
827 struct itimerval aitv;
828 struct itimerspec its;
829 struct proc *p = l->l_proc;
830 int s, timerid;
831 struct ptimer *pt;
832
833 timerid = SCARG(uap, timerid);
834
835 if ((p->p_timers == NULL) ||
836 (timerid < 2) || (timerid >= TIMER_MAX) ||
837 ((pt = p->p_timers->pts_timers[timerid]) == NULL))
838 return (EINVAL);
839
840 s = splclock();
841 timer_gettime(pt, &aitv);
842 splx(s);
843
844 TIMEVAL_TO_TIMESPEC(&aitv.it_interval, &its.it_interval);
845 TIMEVAL_TO_TIMESPEC(&aitv.it_value, &its.it_value);
846
847 return copyout(&its, SCARG(uap, value), sizeof(its));
848 }
849
850 /*
851 * Return the count of the number of times a periodic timer expired
852 * while a notification was already pending. The counter is reset when
853 * a timer expires and a notification can be posted.
854 */
855 int
856 sys_timer_getoverrun(struct lwp *l, void *v, register_t *retval)
857 {
858 struct sys_timer_getoverrun_args /* {
859 syscallarg(timer_t) timerid;
860 } */ *uap = v;
861 struct proc *p = l->l_proc;
862 int timerid;
863 struct ptimer *pt;
864
865 timerid = SCARG(uap, timerid);
866
867 if ((p->p_timers == NULL) ||
868 (timerid < 2) || (timerid >= TIMER_MAX) ||
869 ((pt = p->p_timers->pts_timers[timerid]) == NULL))
870 return (EINVAL);
871
872 *retval = pt->pt_poverruns;
873
874 return (0);
875 }
876
877 /* Glue function that triggers an upcall; called from userret(). */
878 static void
879 timerupcall(struct lwp *l, void *arg)
880 {
881 struct ptimers *pt = (struct ptimers *)arg;
882 unsigned int i, fired, done;
883 extern struct pool siginfo_pool; /* XXX Ew. */
884
885 KDASSERT(l->l_proc->p_sa);
886 /* Bail out if we do not own the virtual processor */
887 if (l->l_savp->savp_lwp != l)
888 return ;
889
890 KERNEL_PROC_LOCK(l);
891
892 fired = pt->pts_fired;
893 done = 0;
894 while ((i = ffs(fired)) != 0) {
895 siginfo_t *si;
896 int mask = 1 << --i;
897 int f;
898
899 f = l->l_flag & L_SA;
900 l->l_flag &= ~L_SA;
901 si = pool_get(&siginfo_pool, PR_WAITOK);
902 si->_info = pt->pts_timers[i]->pt_info.ksi_info;
903 if (sa_upcall(l, SA_UPCALL_SIGEV | SA_UPCALL_DEFER, NULL, l,
904 sizeof(*si), si) == 0)
905 done |= mask;
906 fired &= ~mask;
907 l->l_flag |= f;
908 }
909 pt->pts_fired &= ~done;
910 if (pt->pts_fired == 0)
911 l->l_proc->p_userret = NULL;
912
913 KERNEL_PROC_UNLOCK(l);
914 }
915
916
917 /*
918 * Real interval timer expired:
919 * send process whose timer expired an alarm signal.
920 * If time is not set up to reload, then just return.
921 * Else compute next time timer should go off which is > current time.
922 * This is where delay in processing this timeout causes multiple
923 * SIGALRM calls to be compressed into one.
924 */
925 void
926 realtimerexpire(void *arg)
927 {
928 struct ptimer *pt;
929 int s;
930
931 pt = (struct ptimer *)arg;
932
933 itimerfire(pt);
934
935 if (!timerisset(&pt->pt_time.it_interval)) {
936 timerclear(&pt->pt_time.it_value);
937 return;
938 }
939 for (;;) {
940 s = splclock();
941 timeradd(&pt->pt_time.it_value,
942 &pt->pt_time.it_interval, &pt->pt_time.it_value);
943 if (timercmp(&pt->pt_time.it_value, &time, >)) {
944 /*
945 * Don't need to check hzto() return value, here.
946 * callout_reset() does it for us.
947 */
948 callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
949 realtimerexpire, pt);
950 splx(s);
951 return;
952 }
953 splx(s);
954 pt->pt_overruns++;
955 }
956 }
957
958 /* BSD routine to get the value of an interval timer. */
959 /* ARGSUSED */
960 int
961 sys_getitimer(struct lwp *l, void *v, register_t *retval)
962 {
963 struct sys_getitimer_args /* {
964 syscallarg(int) which;
965 syscallarg(struct itimerval *) itv;
966 } */ *uap = v;
967 struct proc *p = l->l_proc;
968 struct itimerval aitv;
969 int s, which;
970
971 which = SCARG(uap, which);
972
973 if ((u_int)which > ITIMER_PROF)
974 return (EINVAL);
975
976 if ((p->p_timers == NULL) || (p->p_timers->pts_timers[which] == NULL)){
977 timerclear(&aitv.it_value);
978 timerclear(&aitv.it_interval);
979 } else {
980 s = splclock();
981 timer_gettime(p->p_timers->pts_timers[which], &aitv);
982 splx(s);
983 }
984
985 return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval)));
986
987 }
988
989 /* BSD routine to set/arm an interval timer. */
990 /* ARGSUSED */
991 int
992 sys_setitimer(struct lwp *l, void *v, register_t *retval)
993 {
994 struct sys_setitimer_args /* {
995 syscallarg(int) which;
996 syscallarg(const struct itimerval *) itv;
997 syscallarg(struct itimerval *) oitv;
998 } */ *uap = v;
999 struct proc *p = l->l_proc;
1000 int which = SCARG(uap, which);
1001 struct sys_getitimer_args getargs;
1002 struct itimerval aitv;
1003 const struct itimerval *itvp;
1004 struct ptimer *pt;
1005 int s, error;
1006
1007 if ((u_int)which > ITIMER_PROF)
1008 return (EINVAL);
1009 itvp = SCARG(uap, itv);
1010 if (itvp &&
1011 (error = copyin(itvp, &aitv, sizeof(struct itimerval)) != 0))
1012 return (error);
1013 if (SCARG(uap, oitv) != NULL) {
1014 SCARG(&getargs, which) = which;
1015 SCARG(&getargs, itv) = SCARG(uap, oitv);
1016 if ((error = sys_getitimer(l, &getargs, retval)) != 0)
1017 return (error);
1018 }
1019 if (itvp == 0)
1020 return (0);
1021 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
1022 return (EINVAL);
1023
1024 /*
1025 * Don't bother allocating data structures if the process just
1026 * wants to clear the timer.
1027 */
1028 if (!timerisset(&aitv.it_value) &&
1029 ((p->p_timers == NULL) ||(p->p_timers->pts_timers[which] == NULL)))
1030 return (0);
1031
1032 if (p->p_timers == NULL)
1033 timers_alloc(p);
1034 if (p->p_timers->pts_timers[which] == NULL) {
1035 pt = pool_get(&ptimer_pool, PR_WAITOK);
1036 pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
1037 pt->pt_ev.sigev_value.sival_int = which;
1038 pt->pt_overruns = 0;
1039 pt->pt_proc = p;
1040 pt->pt_type = which;
1041 pt->pt_entry = which;
1042 switch (which) {
1043 case ITIMER_REAL:
1044 callout_init(&pt->pt_ch);
1045 pt->pt_ev.sigev_signo = SIGALRM;
1046 break;
1047 case ITIMER_VIRTUAL:
1048 pt->pt_active = 0;
1049 pt->pt_ev.sigev_signo = SIGVTALRM;
1050 break;
1051 case ITIMER_PROF:
1052 pt->pt_active = 0;
1053 pt->pt_ev.sigev_signo = SIGPROF;
1054 break;
1055 }
1056 } else
1057 pt = p->p_timers->pts_timers[which];
1058
1059 pt->pt_time = aitv;
1060 p->p_timers->pts_timers[which] = pt;
1061
1062 s = splclock();
1063 if ((which == ITIMER_REAL) && timerisset(&pt->pt_time.it_value)) {
1064 /* Convert to absolute time */
1065 timeradd(&pt->pt_time.it_value, &time, &pt->pt_time.it_value);
1066 }
1067 timer_settime(pt);
1068 splx(s);
1069
1070 return (0);
1071 }
1072
1073 /* Utility routines to manage the array of pointers to timers. */
1074 void
1075 timers_alloc(struct proc *p)
1076 {
1077 int i;
1078 struct ptimers *pts;
1079
1080 pts = malloc(sizeof (struct ptimers), M_SUBPROC, 0);
1081 LIST_INIT(&pts->pts_virtual);
1082 LIST_INIT(&pts->pts_prof);
1083 for (i = 0; i < TIMER_MAX; i++)
1084 pts->pts_timers[i] = NULL;
1085 pts->pts_fired = 0;
1086 p->p_timers = pts;
1087 }
1088
1089 /*
1090 * Clean up the per-process timers. If "which" is set to TIMERS_ALL,
1091 * then clean up all timers and free all the data structures. If
1092 * "which" is set to TIMERS_POSIX, only clean up the timers allocated
1093 * by timer_create(), not the BSD setitimer() timers, and only free the
1094 * structure if none of those remain.
1095 */
1096 void
1097 timers_free(struct proc *p, int which)
1098 {
1099 int i, s;
1100 struct ptimers *pts;
1101 struct ptimer *pt, *ptn;
1102 struct timeval tv;
1103
1104 if (p->p_timers) {
1105 pts = p->p_timers;
1106 if (which == TIMERS_ALL)
1107 i = 0;
1108 else {
1109 s = splclock();
1110 timerclear(&tv);
1111 for (ptn = LIST_FIRST(&p->p_timers->pts_virtual);
1112 ptn && ptn != pts->pts_timers[ITIMER_VIRTUAL];
1113 ptn = LIST_NEXT(ptn, pt_list))
1114 timeradd(&tv, &ptn->pt_time.it_value, &tv);
1115 LIST_FIRST(&p->p_timers->pts_virtual) = NULL;
1116 if (ptn) {
1117 timeradd(&tv, &ptn->pt_time.it_value,
1118 &ptn->pt_time.it_value);
1119 LIST_INSERT_HEAD(&p->p_timers->pts_virtual,
1120 ptn, pt_list);
1121 }
1122
1123 timerclear(&tv);
1124 for (ptn = LIST_FIRST(&p->p_timers->pts_prof);
1125 ptn && ptn != pts->pts_timers[ITIMER_PROF];
1126 ptn = LIST_NEXT(ptn, pt_list))
1127 timeradd(&tv, &ptn->pt_time.it_value, &tv);
1128 LIST_FIRST(&p->p_timers->pts_prof) = NULL;
1129 if (ptn) {
1130 timeradd(&tv, &ptn->pt_time.it_value,
1131 &ptn->pt_time.it_value);
1132 LIST_INSERT_HEAD(&p->p_timers->pts_prof, ptn,
1133 pt_list);
1134 }
1135 splx(s);
1136 i = 3;
1137 }
1138 for ( ; i < TIMER_MAX; i++)
1139 if ((pt = pts->pts_timers[i]) != NULL) {
1140 if (pt->pt_type == CLOCK_REALTIME)
1141 callout_stop(&pt->pt_ch);
1142 pts->pts_timers[i] = NULL;
1143 pool_put(&ptimer_pool, pt);
1144 }
1145 if ((pts->pts_timers[0] == NULL) &&
1146 (pts->pts_timers[1] == NULL) &&
1147 (pts->pts_timers[2] == NULL)) {
1148 p->p_timers = NULL;
1149 free(pts, M_SUBPROC);
1150 }
1151 }
1152 }
1153
1154 /*
1155 * Check that a proposed value to load into the .it_value or
1156 * .it_interval part of an interval timer is acceptable, and
1157 * fix it to have at least minimal value (i.e. if it is less
1158 * than the resolution of the clock, round it up.)
1159 */
1160 int
1161 itimerfix(struct timeval *tv)
1162 {
1163
1164 if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000)
1165 return (EINVAL);
1166 if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
1167 tv->tv_usec = tick;
1168 return (0);
1169 }
1170
1171 /*
1172 * Decrement an interval timer by a specified number
1173 * of microseconds, which must be less than a second,
1174 * i.e. < 1000000. If the timer expires, then reload
1175 * it. In this case, carry over (usec - old value) to
1176 * reduce the value reloaded into the timer so that
1177 * the timer does not drift. This routine assumes
1178 * that it is called in a context where the timers
1179 * on which it is operating cannot change in value.
1180 */
1181 int
1182 itimerdecr(struct ptimer *pt, int usec)
1183 {
1184 struct itimerval *itp;
1185
1186 itp = &pt->pt_time;
1187 if (itp->it_value.tv_usec < usec) {
1188 if (itp->it_value.tv_sec == 0) {
1189 /* expired, and already in next interval */
1190 usec -= itp->it_value.tv_usec;
1191 goto expire;
1192 }
1193 itp->it_value.tv_usec += 1000000;
1194 itp->it_value.tv_sec--;
1195 }
1196 itp->it_value.tv_usec -= usec;
1197 usec = 0;
1198 if (timerisset(&itp->it_value))
1199 return (1);
1200 /* expired, exactly at end of interval */
1201 expire:
1202 if (timerisset(&itp->it_interval)) {
1203 itp->it_value = itp->it_interval;
1204 itp->it_value.tv_usec -= usec;
1205 if (itp->it_value.tv_usec < 0) {
1206 itp->it_value.tv_usec += 1000000;
1207 itp->it_value.tv_sec--;
1208 }
1209 timer_settime(pt);
1210 } else
1211 itp->it_value.tv_usec = 0; /* sec is already 0 */
1212 return (0);
1213 }
1214
1215 void
1216 itimerfire(struct ptimer *pt)
1217 {
1218 struct proc *p = pt->pt_proc;
1219 struct sadata_vp *vp;
1220 int s;
1221 unsigned int i;
1222
1223 if (pt->pt_ev.sigev_notify == SIGEV_SIGNAL) {
1224 /*
1225 * No RT signal infrastructure exists at this time;
1226 * just post the signal number and throw away the
1227 * value.
1228 */
1229 if (sigismember(&p->p_sigctx.ps_siglist, pt->pt_ev.sigev_signo))
1230 pt->pt_overruns++;
1231 else {
1232 ksiginfo_t ksi;
1233 (void)memset(&ksi, 0, sizeof(ksi));
1234 ksi.ksi_signo = pt->pt_ev.sigev_signo;
1235 ksi.ksi_code = SI_TIMER;
1236 ksi.ksi_sigval = pt->pt_ev.sigev_value;
1237 pt->pt_poverruns = pt->pt_overruns;
1238 pt->pt_overruns = 0;
1239 kpsignal(p, &ksi, NULL);
1240 }
1241 } else if (pt->pt_ev.sigev_notify == SIGEV_SA && (p->p_flag & P_SA)) {
1242 /* Cause the process to generate an upcall when it returns. */
1243
1244 if (p->p_userret == NULL) {
1245 /*
1246 * XXX stop signals can be processed inside tsleep,
1247 * which can be inside sa_yield's inner loop, which
1248 * makes testing for sa_idle alone insuffucent to
1249 * determine if we really should call setrunnable.
1250 */
1251 pt->pt_poverruns = pt->pt_overruns;
1252 pt->pt_overruns = 0;
1253 i = 1 << pt->pt_entry;
1254 p->p_timers->pts_fired = i;
1255 p->p_userret = timerupcall;
1256 p->p_userret_arg = p->p_timers;
1257
1258 SCHED_LOCK(s);
1259 SLIST_FOREACH(vp, &p->p_sa->sa_vps, savp_next) {
1260 if (vp->savp_lwp->l_flag & L_SA_IDLE) {
1261 vp->savp_lwp->l_flag &= ~L_SA_IDLE;
1262 sched_wakeup(vp->savp_lwp);
1263 break;
1264 }
1265 }
1266 SCHED_UNLOCK(s);
1267 } else if (p->p_userret == timerupcall) {
1268 i = 1 << pt->pt_entry;
1269 if ((p->p_timers->pts_fired & i) == 0) {
1270 pt->pt_poverruns = pt->pt_overruns;
1271 pt->pt_overruns = 0;
1272 p->p_timers->pts_fired |= i;
1273 } else
1274 pt->pt_overruns++;
1275 } else {
1276 pt->pt_overruns++;
1277 if ((p->p_flag & P_WEXIT) == 0)
1278 printf("itimerfire(%d): overrun %d on timer %x (userret is %p)\n",
1279 p->p_pid, pt->pt_overruns,
1280 pt->pt_ev.sigev_value.sival_int,
1281 p->p_userret);
1282 }
1283 }
1284
1285 }
1286
1287 /*
1288 * ratecheck(): simple time-based rate-limit checking. see ratecheck(9)
1289 * for usage and rationale.
1290 */
1291 int
1292 ratecheck(struct timeval *lasttime, const struct timeval *mininterval)
1293 {
1294 struct timeval tv, delta;
1295 int s, rv = 0;
1296
1297 s = splclock();
1298 tv = mono_time;
1299 splx(s);
1300
1301 timersub(&tv, lasttime, &delta);
1302
1303 /*
1304 * check for 0,0 is so that the message will be seen at least once,
1305 * even if interval is huge.
1306 */
1307 if (timercmp(&delta, mininterval, >=) ||
1308 (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
1309 *lasttime = tv;
1310 rv = 1;
1311 }
1312
1313 return (rv);
1314 }
1315
1316 /*
1317 * ppsratecheck(): packets (or events) per second limitation.
1318 */
1319 int
1320 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
1321 {
1322 struct timeval tv, delta;
1323 int s, rv;
1324
1325 s = splclock();
1326 tv = mono_time;
1327 splx(s);
1328
1329 timersub(&tv, lasttime, &delta);
1330
1331 /*
1332 * check for 0,0 is so that the message will be seen at least once.
1333 * if more than one second have passed since the last update of
1334 * lasttime, reset the counter.
1335 *
1336 * we do increment *curpps even in *curpps < maxpps case, as some may
1337 * try to use *curpps for stat purposes as well.
1338 */
1339 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
1340 delta.tv_sec >= 1) {
1341 *lasttime = tv;
1342 *curpps = 0;
1343 }
1344 if (maxpps < 0)
1345 rv = 1;
1346 else if (*curpps < maxpps)
1347 rv = 1;
1348 else
1349 rv = 0;
1350
1351 #if 1 /*DIAGNOSTIC?*/
1352 /* be careful about wrap-around */
1353 if (*curpps + 1 > *curpps)
1354 *curpps = *curpps + 1;
1355 #else
1356 /*
1357 * assume that there's not too many calls to this function.
1358 * not sure if the assumption holds, as it depends on *caller's*
1359 * behavior, not the behavior of this function.
1360 * IMHO it is wrong to make assumption on the caller's behavior,
1361 * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
1362 */
1363 *curpps = *curpps + 1;
1364 #endif
1365
1366 return (rv);
1367 }
Cache object: 6e865498a56d2d62e154ed36254c1a36
|