The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_time.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.