[BACK]Return to kern_time.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/kern_time.c between version 1.54 and 1.54.2.11

version 1.54, 2000/09/19 23:26:25 version 1.54.2.11, 2002/02/28 04:14:45
Line 71 
Line 71 
  *      @(#)kern_time.c 8.4 (Berkeley) 5/26/95   *      @(#)kern_time.c 8.4 (Berkeley) 5/26/95
  */   */
   
   #include <sys/cdefs.h>
   __KERNEL_RCSID(0, "$NetBSD$");
   
 #include "fs_nfs.h"  #include "fs_nfs.h"
 #include "opt_nfs.h"  #include "opt_nfs.h"
 #include "opt_nfsserver.h"  #include "opt_nfsserver.h"
Line 79 
Line 82 
 #include <sys/resourcevar.h>  #include <sys/resourcevar.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
 #include <sys/systm.h>  #include <sys/systm.h>
   #include <sys/lwp.h>
   #include <sys/malloc.h>
 #include <sys/proc.h>  #include <sys/proc.h>
   #include <sys/sa.h>
   #include <sys/savar.h>
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/signalvar.h>  #include <sys/signalvar.h>
 #include <sys/syslog.h>  #include <sys/syslog.h>
Line 97 
Line 104 
   
 #include <machine/cpu.h>  #include <machine/cpu.h>
   
 /*  static void realtimerupcall(struct lwp *, void *);
  * Time of day and interval timer support.  
   
   /* Time of day and interval timer support.
  *   *
  * These routines provide the kernel entry points to get and set   * These routines provide the kernel entry points to get and set
  * the time-of-day and per-process interval timers.  Subroutines   * the time-of-day and per-process interval timers.  Subroutines
Line 109 
Line 118 
   
 /* This function is used by clock_settime and settimeofday */  /* This function is used by clock_settime and settimeofday */
 int  int
 settime(tv)  settime(struct timeval *tv)
         struct timeval *tv;  
 {  {
         struct timeval delta;          struct timeval delta;
         struct cpu_info *ci;          struct cpu_info *ci;
Line 119  settime(tv)
Line 127  settime(tv)
         /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */          /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
         s = splclock();          s = splclock();
         timersub(tv, &time, &delta);          timersub(tv, &time, &delta);
         if ((delta.tv_sec < 0 || delta.tv_usec < 0) && securelevel > 1)          if ((delta.tv_sec < 0 || delta.tv_usec < 0) && securelevel > 1) {
                   splx(s);
                 return (EPERM);                  return (EPERM);
           }
 #ifdef notyet  #ifdef notyet
         if ((delta.tv_sec < 86400) && securelevel > 0)          if ((delta.tv_sec < 86400) && securelevel > 0) {
                   splx(s);
                 return (EPERM);                  return (EPERM);
           }
 #endif  #endif
         time = *tv;          time = *tv;
         (void) spllowersoftclock();          (void) spllowersoftclock();
Line 147  settime(tv)
Line 159  settime(tv)
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_clock_gettime(p, v, retval)  sys_clock_gettime(struct lwp *l, void *v, register_t *retval)
         struct proc *p;  
         void *v;  
         register_t *retval;  
 {  {
         struct sys_clock_gettime_args /* {          struct sys_clock_gettime_args /* {
                 syscallarg(clockid_t) clock_id;                  syscallarg(clockid_t) clock_id;
Line 159  sys_clock_gettime(p, v, retval)
Line 168  sys_clock_gettime(p, v, retval)
         clockid_t clock_id;          clockid_t clock_id;
         struct timeval atv;          struct timeval atv;
         struct timespec ats;          struct timespec ats;
           int s;
   
         clock_id = SCARG(uap, clock_id);          clock_id = SCARG(uap, clock_id);
         if (clock_id != CLOCK_REALTIME)          switch (clock_id) {
           case CLOCK_REALTIME:
                   microtime(&atv);
                   TIMEVAL_TO_TIMESPEC(&atv,&ats);
                   break;
           case CLOCK_MONOTONIC:
                   /* XXX "hz" granularity */
                   s = splclock();
                   atv = mono_time;
                   splx(s);
                   TIMEVAL_TO_TIMESPEC(&atv,&ats);
                   break;
           default:
                 return (EINVAL);                  return (EINVAL);
           }
         microtime(&atv);  
         TIMEVAL_TO_TIMESPEC(&atv,&ats);  
   
         return copyout(&ats, SCARG(uap, tp), sizeof(ats));          return copyout(&ats, SCARG(uap, tp), sizeof(ats));
 }  }
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_clock_settime(p, v, retval)  sys_clock_settime(l, v, retval)
         struct proc *p;          struct lwp *l;
         void *v;          void *v;
         register_t *retval;          register_t *retval;
 {  {
Line 181  sys_clock_settime(p, v, retval)
Line 201  sys_clock_settime(p, v, retval)
                 syscallarg(clockid_t) clock_id;                  syscallarg(clockid_t) clock_id;
                 syscallarg(const struct timespec *) tp;                  syscallarg(const struct timespec *) tp;
         } */ *uap = v;          } */ *uap = v;
         clockid_t clock_id;          struct proc *p = l->l_proc;
         struct timeval atv;  
         struct timespec ats;  
         int error;          int error;
   
         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)          if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
                 return (error);                  return (error);
   
         clock_id = SCARG(uap, clock_id);          return (clock_settime1(SCARG(uap, clock_id), SCARG(uap, tp)));
         if (clock_id != CLOCK_REALTIME)  }
                 return (EINVAL);  
   
         if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)  
                 return (error);  
   
         TIMESPEC_TO_TIMEVAL(&atv,&ats);  int
         if ((error = settime(&atv)))  clock_settime1(clock_id, tp)
           clockid_t clock_id;
           const struct timespec *tp;
   {
           struct timespec ats;
           struct timeval atv;
           int error;
   
           if ((error = copyin(tp, &ats, sizeof(ats))) != 0)
                 return (error);                  return (error);
   
           switch (clock_id) {
           case CLOCK_REALTIME:
                   TIMESPEC_TO_TIMEVAL(&atv, &ats);
                   if ((error = settime(&atv)) != 0)
                           return (error);
                   break;
           case CLOCK_MONOTONIC:
                   return (EINVAL);        /* read-only clock */
           default:
                   return (EINVAL);
           }
   
         return 0;          return 0;
 }  }
   
 int  int
 sys_clock_getres(p, v, retval)  sys_clock_getres(struct lwp *l, void *v, register_t *retval)
         struct proc *p;  
         void *v;  
         register_t *retval;  
 {  {
         struct sys_clock_getres_args /* {          struct sys_clock_getres_args /* {
                 syscallarg(clockid_t) clock_id;                  syscallarg(clockid_t) clock_id;
Line 218  sys_clock_getres(p, v, retval)
Line 250  sys_clock_getres(p, v, retval)
         int error = 0;          int error = 0;
   
         clock_id = SCARG(uap, clock_id);          clock_id = SCARG(uap, clock_id);
         if (clock_id != CLOCK_REALTIME)          switch (clock_id) {
                 return (EINVAL);          case CLOCK_REALTIME:
           case CLOCK_MONOTONIC:
         if (SCARG(uap, tp)) {  
                 ts.tv_sec = 0;                  ts.tv_sec = 0;
                 ts.tv_nsec = 1000000000 / hz;                  ts.tv_nsec = 1000000000 / hz;
                   break;
           default:
                   return (EINVAL);
           }
   
           if (SCARG(uap, tp))
                 error = copyout(&ts, SCARG(uap, tp), sizeof(ts));                  error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
         }  
   
         return error;          return error;
 }  }
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_nanosleep(p, v, retval)  sys_nanosleep(struct lwp *l, void *v, register_t *retval)
         struct proc *p;  
         void *v;  
         register_t *retval;  
 {  {
         static int nanowait;          static int nanowait;
         struct sys_nanosleep_args/* {          struct sys_nanosleep_args/* {
Line 254  sys_nanosleep(p, v, retval)
Line 286  sys_nanosleep(p, v, retval)
                 return (error);                  return (error);
   
         TIMESPEC_TO_TIMEVAL(&atv,&rqt)          TIMESPEC_TO_TIMEVAL(&atv,&rqt)
         if (itimerfix(&atv))          if (itimerfix(&atv) || atv.tv_sec > 1000000000)
                 return (EINVAL);                  return (EINVAL);
   
         s = splclock();          s = splclock();
Line 296  sys_nanosleep(p, v, retval)
Line 328  sys_nanosleep(p, v, retval)
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_gettimeofday(p, v, retval)  sys_gettimeofday(struct lwp *l, void *v, register_t *retval)
         struct proc *p;  
         void *v;  
         register_t *retval;  
 {  {
         struct sys_gettimeofday_args /* {          struct sys_gettimeofday_args /* {
                 syscallarg(struct timeval *) tp;                  syscallarg(struct timeval *) tp;
Line 329  sys_gettimeofday(p, v, retval)
Line 358  sys_gettimeofday(p, v, retval)
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_settimeofday(p, v, retval)  sys_settimeofday(struct lwp *l, void *v, register_t *retval)
         struct proc *p;  
         void *v;  
         register_t *retval;  
 {  {
         struct sys_settimeofday_args /* {          struct sys_settimeofday_args /* {
                 syscallarg(const struct timeval *) tv;                  syscallarg(const struct timeval *) tv;
                 syscallarg(const struct timezone *) tzp;                  syscallarg(const struct timezone *) tzp;
         } */ *uap = v;          } */ *uap = v;
         struct timeval atv;          struct proc *p = l->l_proc;
         struct timezone atz;  
         int error;          int error;
   
         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)          if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
                 return (error);                  return (error);
   
           return settimeofday1(SCARG(uap, tv), SCARG(uap, tzp), p);
   }
   
   int
   settimeofday1(utv, utzp, p)
           const struct timeval *utv;
           const struct timezone *utzp;
           struct proc *p;
   {
           struct timeval atv;
           struct timezone atz;
           struct timeval *tv = NULL;
           struct timezone *tzp = NULL;
           int error;
   
         /* Verify all parameters before changing time. */          /* Verify all parameters before changing time. */
         if (SCARG(uap, tv) && (error = copyin(SCARG(uap, tv),          if (utv) {
             &atv, sizeof(atv))))                  if ((error = copyin(utv, &atv, sizeof(atv))) != 0)
                 return (error);                          return (error);
                   tv = &atv;
           }
         /* XXX since we don't use tz, probably no point in doing copyin. */          /* XXX since we don't use tz, probably no point in doing copyin. */
         if (SCARG(uap, tzp) && (error = copyin(SCARG(uap, tzp),          if (utzp) {
             &atz, sizeof(atz))))                  if ((error = copyin(utzp, &atz, sizeof(atz))) != 0)
                 return (error);                          return (error);
         if (SCARG(uap, tv))                  tzp = &atz;
                 if ((error = settime(&atv)))          }
   
           if (tv)
                   if ((error = settime(tv)) != 0)
                         return (error);                          return (error);
         /*          /*
          * NetBSD has no kernel notion of time zone, and only an           * NetBSD has no kernel notion of time zone, and only an
          * obsolete program would try to set it, so we log a warning.           * obsolete program would try to set it, so we log a warning.
          */           */
         if (SCARG(uap, tzp))          if (tzp)
                 log(LOG_WARNING, "pid %d attempted to set the "                  log(LOG_WARNING, "pid %d attempted to set the "
                     "(obsolete) kernel time zone\n", p->p_pid);                      "(obsolete) kernel time zone\n", p->p_pid);
         return (0);          return (0);
Line 371  long bigadj = 1000000;  /* use 10x skew 
Line 417  long bigadj = 1000000;  /* use 10x skew 
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_adjtime(p, v, retval)  sys_adjtime(struct lwp *l, void *v, register_t *retval)
         struct proc *p;  
         void *v;  
         register_t *retval;  
 {  {
         struct sys_adjtime_args /* {          struct sys_adjtime_args /* {
                 syscallarg(const struct timeval *) delta;                  syscallarg(const struct timeval *) delta;
                 syscallarg(struct timeval *) olddelta;                  syscallarg(struct timeval *) olddelta;
         } */ *uap = v;          } */ *uap = v;
         struct timeval atv;          struct proc *p = l->l_proc;
         long ndelta, ntickdelta, odelta;          int error;
         int s, error;  
   
         if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)          if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
                 return (error);                  return (error);
   
         error = copyin(SCARG(uap, delta), &atv, sizeof(struct timeval));          return adjtime1(SCARG(uap, delta), SCARG(uap, olddelta), p);
   }
   
   int
   adjtime1(delta, olddelta, p)
           const struct timeval *delta;
           struct timeval *olddelta;
           struct proc *p;
   {
           struct timeval atv;
           struct timeval *oatv = NULL;
           long ndelta, ntickdelta, odelta;
           int error;
           int s;
   
           error = copyin(delta, &atv, sizeof(struct timeval));
         if (error)          if (error)
                 return (error);                  return (error);
         if (SCARG(uap, olddelta) != NULL &&  
             uvm_useracc((caddr_t)SCARG(uap, olddelta), sizeof(struct timeval),          if (olddelta != NULL) {
              B_WRITE) == FALSE)                  if (uvm_useracc((caddr_t)olddelta,
                 return (EFAULT);                      sizeof(struct timeval), B_WRITE) == FALSE)
                           return (EFAULT);
                   oatv = olddelta;
           }
   
         /*          /*
          * Compute the total correction and the rate at which to apply it.           * Compute the total correction and the rate at which to apply it.
Line 423  sys_adjtime(p, v, retval)
Line 483  sys_adjtime(p, v, retval)
         tickdelta = ntickdelta;          tickdelta = ntickdelta;
         splx(s);          splx(s);
   
         if (SCARG(uap, olddelta)) {          if (olddelta) {
                 atv.tv_sec = odelta / 1000000;                  atv.tv_sec = odelta / 1000000;
                 atv.tv_usec = odelta % 1000000;                  atv.tv_usec = odelta % 1000000;
                 (void) copyout(&atv, SCARG(uap, olddelta),                  (void) copyout(&atv, olddelta, sizeof(struct timeval));
                     sizeof(struct timeval));  
         }          }
         return (0);          return (0);
 }  }
   
 /*  /*
  * Get value of an interval timer.  The process virtual and   * Interval timer support. Both the BSD getitimer() family and the POSIX
  * profiling virtual time timers are kept in the p_stats area, since   * timer_*() family of routines are supported.
  * they can be swapped out.  These are kept internally in the   *
  * way they are specified externally: in time until they expire.   * All timers are kept in an array pointed to by p_timers, which is
    * allocated on demand - many processes don't use timers at all. The
    * first three elements in this array are reserved for the BSD timers:
    * element 0 is ITIMER_REAL, element 1 is ITIMER_VIRTUAL, and element
    * 2 is ITIMER_PROF. The rest may be allocated by the timer_create()
    * syscall.
  *   *
  * The real time interval timer is kept in the process table slot   * Realtime timers are kept in the ptimer structure as an absolute
  * for the process, and its value (it_value) is kept as an   * time; virtual time timers are kept as deltas.  Virtual time timers
  * absolute time rather than as a delta, so that it is easy to keep   * are processed in the hardclock() routine of kern_clock.c.  The real
  * periodic real-time signals from drifting.   * time timer is processed by a callout routine, called from the
  *   * softclock() routine.  Since a callout may be delayed in real time
  * Virtual time timers are processed in the hardclock() routine of   * due to interrupt processing in the system, it is possible for the
  * kern_clock.c.  The real time timer is processed by a timeout   * real time timeout routine (realtimeexpire, given below), to be
  * routine, called from the softclock() routine.  Since a callout   * delayed in real time past when it is supposed to occur.  It does
  * may be delayed in real time due to interrupt processing in the system,   * not suffice, therefore, to reload the real timer .it_value from the
  * it is possible for the real time timeout routine (realitexpire, given below),  
  * to be delayed in real time past when it is supposed to occur.  It  
  * does not suffice, therefore, to reload the real timer .it_value from the  
  * real time timers .it_interval.  Rather, we compute the next time in   * real time timers .it_interval.  Rather, we compute the next time in
  * absolute time the timer should go off.   * absolute time the timer should go off.
  */   */
 /* ARGSUSED */  
   /* Allocate a POSIX realtime timer. */
   int
   sys_timer_create(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_timer_create_args /* {
                   syscallarg(clockid_t) clock_id;
                   syscallarg(struct sigevent *) evp;
                   syscallarg(timer_t *) timerid;
           } */ *uap = v;
           struct proc *p = l->l_proc;
           clockid_t id;
           struct sigevent *evp;
           struct ptimer *pt;
           int timerid, error;
   
           id = SCARG(uap, clock_id);
           if (id != CLOCK_REALTIME)
                   return (EINVAL);
   
           if (p->p_timers == NULL)
                   timers_alloc(p);
   
           for (timerid = 3; timerid < TIMER_MAX; timerid++)
                   if (p->p_timers[timerid] == NULL)
                           break;
   
           if (timerid == TIMER_MAX)
                   return EAGAIN;
   
           pt = pool_get(&ptimer_pool, PR_WAITOK);
           evp = SCARG(uap, evp);
           if (evp) {
                   if (((error =
                       copyin(evp, &pt->pt_ev, sizeof (pt->pt_ev))) != 0) ||
                       ((pt->pt_ev.sigev_notify < SIGEV_NONE) ||
                           (pt->pt_ev.sigev_notify > SIGEV_SA))) {
                           pool_put(&ptimer_pool, pt);
                           return (error ? error : EINVAL);
                   }
           } else {
                   pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
                   pt->pt_ev.sigev_signo = SIGALRM;
                   pt->pt_ev.sigev_value.sival_int = timerid;
           }
           pt->pt_info.si_signo = pt->pt_ev.sigev_signo;
           pt->pt_info.si_errno = 0;
           pt->pt_info.si_code = 0;
           pt->pt_info.si_pid = p->p_pid;
           pt->pt_info.si_uid = p->p_cred->p_ruid;
           pt->pt_info.si_addr = NULL;
           pt->pt_info.si_status = 0;
           pt->pt_info.si_value = pt->pt_ev.sigev_value;
   
           callout_init(&pt->pt_ch);
           pt->pt_type = CLOCK_REALTIME;
           pt->pt_proc = p;
           pt->pt_overruns = 0;
   
           p->p_timers[timerid] = pt;
   
           return copyout(&timerid, SCARG(uap, timerid), sizeof(timerid));
   }
   
   
   /* Delete a POSIX realtime timer */
   int
   sys_timer_delete(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_timer_delete_args /*  {
                   syscallarg(timer_t) timerid;
           } */ *uap = v;
           struct proc *p = l->l_proc;
           int timerid;
           struct ptimer *pt;
   
           timerid = SCARG(uap, timerid);
   
           if ((p->p_timers == NULL) ||
               (timerid < 2) || (timerid >= TIMER_MAX) ||
               ((pt = p->p_timers[timerid]) == NULL))
                   return (EINVAL);
   
           callout_stop(&pt->pt_ch);
           p->p_timers[timerid] = NULL;
           pool_put(&ptimer_pool, pt);
   
           return (0);
   }
   
   /* Set and arm a POSIX realtime timer */
   int
   sys_timer_settime(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_timer_settime_args /* {
                   syscallarg(timer_t) timerid;
                   syscallarg(int) flags;
                   syscallarg(const struct itimerspec *) value;
                   syscallarg(struct itimerspec *) ovalue;
           } */ *uap = v;
           struct proc *p = l->l_proc;
           int error, s, timerid;
           struct itimerval val, oval;
           struct itimerspec value, ovalue;
           struct ptimer *pt;
   
           timerid = SCARG(uap, timerid);
   
           if ((p->p_timers == NULL) ||
               (timerid < 2) || (timerid >= TIMER_MAX) ||
               ((pt = p->p_timers[timerid]) == NULL))
                   return (EINVAL);
   
           if ((error = copyin(SCARG(uap, value), &value,
               sizeof(struct itimerspec))) != 0)
                   return (error);
   
           TIMESPEC_TO_TIMEVAL(&val.it_value, &value.it_value);
           TIMESPEC_TO_TIMEVAL(&val.it_interval, &value.it_interval);
           if (itimerfix(&val.it_value) || itimerfix(&val.it_interval))
                   return (EINVAL);
   
           oval = pt->pt_time;
           pt->pt_time = val;
   
           s = splclock();
           callout_stop(&pt->pt_ch);
           if (timerisset(&pt->pt_time.it_value)) {
                   if ((SCARG(uap, flags) & TIMER_ABSTIME) == 0)
                           timeradd(&pt->pt_time.it_value, &time,
                               &pt->pt_time.it_value);
                   /*
                    * Don't need to check hzto() return value, here.
                    * callout_reset() does it for us.
                    */
                   callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
                       realtimerexpire, pt);
           }
           splx(s);
   
           if (SCARG(uap, ovalue)) {
                   TIMEVAL_TO_TIMESPEC(&oval.it_value, &ovalue.it_value);
                   TIMEVAL_TO_TIMESPEC(&oval.it_interval, &ovalue.it_interval);
                   return copyout(&ovalue, SCARG(uap, ovalue),
                       sizeof(struct itimerspec));
           }
   
           return (0);
   }
   
   /* Return the time remaining until a POSIX timer fires. */
 int  int
 sys_getitimer(p, v, retval)  sys_timer_gettime(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_timer_gettime_args /* {
                   syscallarg(timer_t) timerid;
                   syscallarg(struct itimerspec *) value;
           } */ *uap = v;
           struct itimerval aitv;
           struct itimerspec its;
           struct proc *p = l->l_proc;
           int timerid;
           struct ptimer *pt;
   
           timerid = SCARG(uap, timerid);
   
           if ((p->p_timers == NULL) ||
               (timerid < 2) || (timerid >= TIMER_MAX) ||
               ((pt = p->p_timers[timerid]) == NULL))
                   return (EINVAL);
   
           aitv = pt->pt_time;
   
           /*
            * Real-time timers are kept in absolute time, but this interface
            * is supposed to return a relative time.
            */
           if (timerisset(&aitv.it_value)) {
                   if (timercmp(&aitv.it_value, &time, <))
                           timerclear(&aitv.it_value);
                   else
                           timersub(&aitv.it_value, &time, &aitv.it_value);
           }
   
           TIMEVAL_TO_TIMESPEC(&aitv.it_interval, &its.it_interval);
           TIMEVAL_TO_TIMESPEC(&aitv.it_value, &its.it_value);
   
           return copyout(&its, SCARG(uap, value), sizeof(its));
   }
   
   /*
    * Return the count of the number of times a periodic timer expired
    * while a notification was already pending. The counter is reset when
    * a timer expires and a notification can be posted.
    */
   int
   sys_timer_getoverrun(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_timer_getoverrun_args /* {
                   syscallarg(timer_t) timerid;
           } */ *uap = v;
           struct proc *p = l->l_proc;
           int timerid;
           struct ptimer *pt;
   
           timerid = SCARG(uap, timerid);
   
           if ((p->p_timers == NULL) ||
               (timerid < 2) || (timerid >= TIMER_MAX) ||
               ((pt = p->p_timers[timerid]) == NULL))
                   return (EINVAL);
   
           *retval = pt->pt_overruns;
   
           return (0);
   }
   
   /* Glue function that triggers an upcall; called from userret(). */
   static void
   realtimerupcall(struct lwp *l, void *arg)
   {
           struct ptimer *pt;
   
           pt = (struct ptimer *)arg;
           sa_upcall(l, SA_UPCALL_SIGEV, NULL, l, sizeof(siginfo_t),
               &pt->pt_info);
   
           /* The upcall should only be generated once. */
           l->l_proc->p_userret = NULL;
   }
   
   
   /*
    * Real interval timer expired:
    * send process whose timer expired an alarm signal.
    * If time is not set up to reload, then just return.
    * Else compute next time timer should go off which is > current time.
    * This is where delay in processing this timeout causes multiple
    * SIGALRM calls to be compressed into one.
    */
   void
   realtimerexpire(void *arg)
   {
           struct ptimer *pt;
         struct proc *p;          struct proc *p;
         void *v;          int s;
         register_t *retval;  
           pt = (struct ptimer *)arg;
           p = pt->pt_proc;
           if (pt->pt_ev.sigev_notify == SIGEV_SIGNAL) {
                   /*
                    * No RT signal infrastructure exists at this time;
                    * just post the signal number and throw away the
                    * value.
                    */
                   if (sigismember(&p->p_sigctx.ps_siglist, pt->pt_ev.sigev_signo))
                           pt->pt_overruns++;
                   else {
                           pt->pt_overruns = 0;
                           psignal(p, pt->pt_ev.sigev_signo);
                   }
           } else if (pt->pt_ev.sigev_notify == SIGEV_SA && (p->p_flag & P_SA)) {
                   int notified = 0;
                   /* Cause the process to generate an upcall when it returns. */
   
                   if (p->p_nrlwps == 0) {
                           struct sadata_upcall *sd;
                           struct lwp *l2;
                           int s, ret;
   
                           SCHED_LOCK(s);
                           l2 = sa_getcachelwp(p);
                           if (l2 != NULL) {
                                   sd = sadata_upcall_alloc(0);
                                   cpu_setfunc(l2, sa_switchcall, NULL);
                                   ret = sa_upcall0(l2, SA_UPCALL_SIGEV,
                                       NULL, NULL, sizeof(siginfo_t),
                                       &pt->pt_info, sd);
                                   if (ret == 0) {
                                           p->p_nrlwps++;
                                           l2->l_priority = l2->l_usrpri;
                                           PRELE(l2);
                                           setrunnable(l2);
                                           notified = 1;
                                   } else
                                           sa_putcachelwp(p, l2);
                           }
                           SCHED_UNLOCK(s);
                   } else if (p->p_userret == NULL) {
                           pt->pt_overruns = 0;
                           p->p_userret = realtimerupcall;
                           p->p_userret_arg = pt;
                           notified = 1;
                   }
                   if (notified == 0)
                           pt->pt_overruns++;
           }
           if (!timerisset(&pt->pt_time.it_interval)) {
                   timerclear(&pt->pt_time.it_value);
                   return;
           }
           for (;;) {
                   s = splclock();
                   timeradd(&pt->pt_time.it_value,
                       &pt->pt_time.it_interval, &pt->pt_time.it_value);
                   if (timercmp(&pt->pt_time.it_value, &time, >)) {
                           /*
                            * Don't need to check hzto() return value, here.
                            * callout_reset() does it for us.
                            */
                           callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
                               realtimerexpire, pt);
                           splx(s);
                           return;
                   }
                   splx(s);
                   pt->pt_overruns++;
           }
   }
   
   /* BSD routine to get the value of an interval timer. */
   /* ARGSUSED */
   int
   sys_getitimer(struct lwp *l, void *v, register_t *retval)
 {  {
         struct sys_getitimer_args /* {          struct sys_getitimer_args /* {
                 syscallarg(int) which;                  syscallarg(int) which;
                 syscallarg(struct itimerval *) itv;                  syscallarg(struct itimerval *) itv;
         } */ *uap = v;          } */ *uap = v;
         int which = SCARG(uap, which);          struct proc *p = l->l_proc;
         struct itimerval aitv;          struct itimerval aitv;
         int s;          int s, which;
   
           which = SCARG(uap, which);
   
         if ((u_int)which > ITIMER_PROF)          if ((u_int)which > ITIMER_PROF)
                 return (EINVAL);                  return (EINVAL);
         s = splclock();  
         if (which == ITIMER_REAL) {          if ((p->p_timers == NULL) || (p->p_timers[which] == NULL)) {
                 /*                  timerclear(&aitv.it_value);
                  * Convert from absolute to relative time in .it_value                  timerclear(&aitv.it_interval);
                  * part of real time timer.  If time for real time timer          } else {
                  * has passed return 0, else return difference between                  s = splclock();
                  * current time and time for the timer to go off.                  if (which == ITIMER_REAL) {
                  */                          /*
                 aitv = p->p_realtimer;                           * Convert from absolute to relative time in
                 if (timerisset(&aitv.it_value)) {                           * .it_value part of real time timer.  If time
                         if (timercmp(&aitv.it_value, &time, <))                           * for real time timer has passed return 0,
                                 timerclear(&aitv.it_value);                           * else return difference between current time
                         else                           * and time for the timer to go off.
                                 timersub(&aitv.it_value, &time, &aitv.it_value);                           */
                 }                          aitv = p->p_timers[ITIMER_REAL]->pt_time;
         } else                          if (timerisset(&aitv.it_value)) {
                 aitv = p->p_stats->p_timer[which];                                  if (timercmp(&aitv.it_value, &time, <))
         splx(s);                                          timerclear(&aitv.it_value);
                                   else
                                           timersub(&aitv.it_value, &time, &aitv.it_value);
                           }
                   } else
                           aitv = p->p_timers[which]->pt_time;
                   splx(s);
           }
   
         return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval)));          return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval)));
   
 }  }
   
   /* BSD routine to set/arm an interval timer. */
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_setitimer(p, v, retval)  sys_setitimer(struct lwp *l, void *v, register_t *retval)
         struct proc *p;  
         void *v;  
         register_t *retval;  
 {  {
         struct sys_setitimer_args /* {          struct sys_setitimer_args /* {
                 syscallarg(int) which;                  syscallarg(int) which;
                 syscallarg(const struct itimerval *) itv;                  syscallarg(const struct itimerval *) itv;
                 syscallarg(struct itimerval *) oitv;                  syscallarg(struct itimerval *) oitv;
         } */ *uap = v;          } */ *uap = v;
           struct proc *p = l->l_proc;
         int which = SCARG(uap, which);          int which = SCARG(uap, which);
         struct sys_getitimer_args getargs;          struct sys_getitimer_args getargs;
         struct itimerval aitv;          struct itimerval aitv;
         const struct itimerval *itvp;          const struct itimerval *itvp;
           struct ptimer *pt;
         int s, error;          int s, error;
   
         if ((u_int)which > ITIMER_PROF)          if ((u_int)which > ITIMER_PROF)
                 return (EINVAL);                  return (EINVAL);
         itvp = SCARG(uap, itv);          itvp = SCARG(uap, itv);
         if (itvp && (error = copyin(itvp, &aitv, sizeof(struct itimerval))))          if (itvp &&
               (error = copyin(itvp, &aitv, sizeof(struct itimerval)) != 0))
                 return (error);                  return (error);
         if (SCARG(uap, oitv) != NULL) {          if (SCARG(uap, oitv) != NULL) {
                 SCARG(&getargs, which) = which;                  SCARG(&getargs, which) = which;
                 SCARG(&getargs, itv) = SCARG(uap, oitv);                  SCARG(&getargs, itv) = SCARG(uap, oitv);
                 if ((error = sys_getitimer(p, &getargs, retval)) != 0)                  if ((error = sys_getitimer(l, &getargs, retval)) != 0)
                         return (error);                          return (error);
         }          }
         if (itvp == 0)          if (itvp == 0)
                 return (0);                  return (0);
         if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))          if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
                 return (EINVAL);                  return (EINVAL);
         s = splclock();  
           /*
            * Don't bother allocating data structures if the process just
            * wants to clear the timer.
            */
           if (!timerisset(&aitv.it_value) &&
               ((p->p_timers == NULL) || (p->p_timers[which] == NULL)))
                   return (0);
   
           if (p->p_timers == NULL)
                   timers_alloc(p);
           if (p->p_timers[which] == NULL) {
                   pt = pool_get(&ptimer_pool, PR_WAITOK);
                   callout_init(&pt->pt_ch);
                   pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
                   pt->pt_overruns = 0;
                   pt->pt_proc = p;
                   pt->pt_type = which;
                   switch (which) {
                   case ITIMER_REAL:
                           pt->pt_ev.sigev_signo = SIGALRM;
                           break;
                   case ITIMER_VIRTUAL:
                           pt->pt_ev.sigev_signo = SIGVTALRM;
                           break;
                   case ITIMER_PROF:
                           pt->pt_ev.sigev_signo = SIGPROF;
                           break;
                   }
           } else
                   pt = p->p_timers[which];
   
           pt->pt_time = aitv;
           p->p_timers[which] = pt;
         if (which == ITIMER_REAL) {          if (which == ITIMER_REAL) {
                 callout_stop(&p->p_realit_ch);                  s = splclock();
                 if (timerisset(&aitv.it_value)) {                  callout_stop(&pt->pt_ch);
                   if (timerisset(&pt->pt_time.it_value)) {
                           timeradd(&pt->pt_time.it_value, &time,
                               &pt->pt_time.it_value);
                         /*                          /*
                          * Don't need to check hzto() return value, here.                           * Don't need to check hzto() return value, here.
                          * callout_reset() does it for us.                           * callout_reset() does it for us.
                          */                           */
                         timeradd(&aitv.it_value, &time, &aitv.it_value);                          callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
                         callout_reset(&p->p_realit_ch, hzto(&aitv.it_value),                              realtimerexpire, pt);
                             realitexpire, p);  
                 }                  }
                 p->p_realtimer = aitv;                  splx(s);
         } else          }
                 p->p_stats->p_timer[which] = aitv;  
         splx(s);  
         return (0);          return (0);
 }  }
   
 /*  /* Utility routines to manage the array of pointers to timers. */
  * Real interval timer expired:  
  * send process whose timer expired an alarm signal.  
  * If time is not set up to reload, then just return.  
  * Else compute next time timer should go off which is > current time.  
  * This is where delay in processing this timeout causes multiple  
  * SIGALRM calls to be compressed into one.  
  */  
 void  void
 realitexpire(arg)  timers_alloc(struct proc *p)
         void *arg;  
 {  {
         struct proc *p;          int i;
         int s;          struct ptimer **pts;
   
         p = (struct proc *)arg;          pts = malloc(TIMER_MAX * sizeof(struct timer *), M_SUBPROC, 0);
         psignal(p, SIGALRM);          for (i = 0; i < TIMER_MAX; i++)
         if (!timerisset(&p->p_realtimer.it_interval)) {                  pts[i] = NULL;
                 timerclear(&p->p_realtimer.it_value);          p->p_timers = pts;
                 return;  }
         }  
         for (;;) {  void
                 s = splclock();  timers_free(struct proc *p)
                 timeradd(&p->p_realtimer.it_value,  {
                     &p->p_realtimer.it_interval, &p->p_realtimer.it_value);          int i;
                 if (timercmp(&p->p_realtimer.it_value, &time, >)) {          struct ptimer *pt, **pts;
                         /*  
                          * Don't need to check hzto() return value, here.          if (p->p_timers) {
                          * callout_reset() does it for us.                  pts = p->p_timers;
                          */                  p->p_timers = NULL;
                         callout_reset(&p->p_realit_ch,                  for (i = 0; i < TIMER_MAX; i++)
                             hzto(&p->p_realtimer.it_value), realitexpire, p);                          if ((pt = pts[i]) != NULL) {
                         splx(s);                                  if (pt->pt_type == CLOCK_REALTIME)
                         return;                                          callout_stop(&pt->pt_ch);
                 }                                  pool_put(&ptimer_pool, pt);
                 splx(s);                          }
                   free(pts, M_SUBPROC);
         }          }
 }  }
   
Line 589  realitexpire(arg)
Line 1007  realitexpire(arg)
  * than the resolution of the clock, round it up.)   * than the resolution of the clock, round it up.)
  */   */
 int  int
 itimerfix(tv)  itimerfix(struct timeval *tv)
         struct timeval *tv;  
 {  {
   
         if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||          if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000)
             tv->tv_usec < 0 || tv->tv_usec >= 1000000)  
                 return (EINVAL);                  return (EINVAL);
         if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)          if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
                 tv->tv_usec = tick;                  tv->tv_usec = tick;
Line 612  itimerfix(tv)
Line 1028  itimerfix(tv)
  * on which it is operating cannot change in value.   * on which it is operating cannot change in value.
  */   */
 int  int
 itimerdecr(itp, usec)  itimerdecr(struct itimerval *itp, int usec)
         struct itimerval *itp;  
         int usec;  
 {  {
   
         if (itp->it_value.tv_usec < usec) {          if (itp->it_value.tv_usec < usec) {
Line 649  expire:
Line 1063  expire:
  * for usage and rationale.   * for usage and rationale.
  */   */
 int  int
 ratecheck(lasttime, mininterval)  ratecheck(struct timeval *lasttime, const struct timeval *mininterval)
         struct timeval *lasttime;  
         const struct timeval *mininterval;  
 {  {
         struct timeval tv, delta;          struct timeval tv, delta;
         int s, rv = 0;          int s, rv = 0;
Line 679  ratecheck(lasttime, mininterval)
Line 1091  ratecheck(lasttime, mininterval)
  * ppsratecheck(): packets (or events) per second limitation.   * ppsratecheck(): packets (or events) per second limitation.
  */   */
 int  int
 ppsratecheck(lasttime, curpps, maxpps)  ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
         struct timeval *lasttime;  
         int *curpps;  
         int maxpps;     /* maximum pps allowed */  
 {  {
         struct timeval tv, delta;          struct timeval tv, delta;
         int s, rv;          int s, rv;

Legend:
Removed from v.1.54  
changed lines
  Added in v.1.54.2.11

CVSweb <webmaster@jp.NetBSD.org>