[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.141 and 1.141.4.1

version 1.141, 2008/02/25 12:25:03 version 1.141.4.1, 2008/05/18 12:35:09
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
   
 /*-  /*-
  * Copyright (c) 2000, 2004, 2005, 2007 The NetBSD Foundation, Inc.   * Copyright (c) 2000, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
  *   *
  * This code is derived from software contributed to The NetBSD Foundation   * This code is derived from software contributed to The NetBSD Foundation
Line 15 
Line 15 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software  
  *    must display the following acknowledgement:  
  *      This product includes software developed by the NetBSD  
  *      Foundation, Inc. and its contributors.  
  * 4. Neither the name of The NetBSD Foundation nor the names of its  
  *    contributors may be used to endorse or promote products derived  
  *    from this software without specific prior written permission.  
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS   * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
Line 79  __KERNEL_RCSID(0, "$NetBSD$");
Line 72  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/signalvar.h>  #include <sys/signalvar.h>
 #include <sys/syslog.h>  #include <sys/syslog.h>
 #include <sys/timetc.h>  #include <sys/timetc.h>
   #include <sys/timex.h>
 #include <sys/kauth.h>  #include <sys/kauth.h>
   
 #include <sys/mount.h>  #include <sys/mount.h>
 #include <sys/syscallargs.h>  #include <sys/syscallargs.h>
   #include <sys/cpu.h>
   
 #include <uvm/uvm_extern.h>  #include <uvm/uvm_extern.h>
   
 #include <sys/cpu.h>  static void     timer_intr(void *);
   static void     itimerfire(struct ptimer *);
   static void     itimerfree(struct ptimers *, int);
   
 kmutex_t        time_lock;  kmutex_t        timer_lock;
   
   static void     *timer_sih;
   static TAILQ_HEAD(, ptimer) timer_queue;
   
 POOL_INIT(ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl",  POOL_INIT(ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl",
     &pool_allocator_nointr, IPL_NONE);      &pool_allocator_nointr, IPL_NONE);
Line 102  void
Line 101  void
 time_init(void)  time_init(void)
 {  {
   
         mutex_init(&time_lock, MUTEX_DEFAULT, IPL_NONE);          /* nothing yet */
   }
   
   void
   time_init2(void)
   {
   
           TAILQ_INIT(&timer_queue);
           mutex_init(&timer_lock, MUTEX_DEFAULT, IPL_SCHED);
           timer_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE,
               timer_intr, NULL);
 }  }
   
 /* Time of day and interval timer support.  /* Time of day and interval timer support.
Line 157  settime1(struct proc *p, struct timespec
Line 166  settime1(struct proc *p, struct timespec
          * pausing all CPUs while we adjust the clock.           * pausing all CPUs while we adjust the clock.
          */           */
         timeval2bintime(&delta, &btdelta);          timeval2bintime(&delta, &btdelta);
         mutex_enter(&proclist_lock);          mutex_enter(proc_lock);
         LIST_FOREACH(l, &alllwp, l_list) {          LIST_FOREACH(l, &alllwp, l_list) {
                 lwp_lock(l);                  lwp_lock(l);
                 bintime_add(&l->l_stime, &btdelta);                  bintime_add(&l->l_stime, &btdelta);
                 lwp_unlock(l);                  lwp_unlock(l);
         }          }
         mutex_exit(&proclist_lock);          mutex_exit(proc_lock);
         resettodr();          resettodr();
         splx(s);          splx(s);
   
Line 446  adjtime1(const struct timeval *delta, st
Line 455  adjtime1(const struct timeval *delta, st
         extern int64_t time_adjtime;  /* in kern_ntptime.c */          extern int64_t time_adjtime;  /* in kern_ntptime.c */
   
         if (olddelta) {          if (olddelta) {
                   mutex_spin_enter(&timecounter_lock);
                 atv.tv_sec = time_adjtime / 1000000;                  atv.tv_sec = time_adjtime / 1000000;
                 atv.tv_usec = time_adjtime % 1000000;                  atv.tv_usec = time_adjtime % 1000000;
                   mutex_spin_exit(&timecounter_lock);
                 if (atv.tv_usec < 0) {                  if (atv.tv_usec < 0) {
                         atv.tv_usec += 1000000;                          atv.tv_usec += 1000000;
                         atv.tv_sec--;                          atv.tv_sec--;
Line 462  adjtime1(const struct timeval *delta, st
Line 473  adjtime1(const struct timeval *delta, st
                 if (error)                  if (error)
                         return (error);                          return (error);
   
                   mutex_spin_enter(&timecounter_lock);
                 time_adjtime = (int64_t)atv.tv_sec * 1000000 +                  time_adjtime = (int64_t)atv.tv_sec * 1000000 +
                         atv.tv_usec;                          atv.tv_usec;
                   if (time_adjtime) {
                 if (time_adjtime)  
                         /* We need to save the system time during shutdown */                          /* We need to save the system time during shutdown */
                         time_adjusted |= 1;                          time_adjusted |= 1;
                   }
                   mutex_spin_exit(&timecounter_lock);
         }          }
   
         return error;          return error;
Line 517  timer_create1(timer_t *tid, clockid_t id
Line 530  timer_create1(timer_t *tid, clockid_t id
 {  {
         int error;          int error;
         timer_t timerid;          timer_t timerid;
           struct ptimers *pts;
         struct ptimer *pt;          struct ptimer *pt;
         struct proc *p;          struct proc *p;
   
         p = l->l_proc;          p = l->l_proc;
   
         if (id < CLOCK_REALTIME ||          if (id < CLOCK_REALTIME || id > CLOCK_PROF)
             id > CLOCK_PROF)  
                 return (EINVAL);                  return (EINVAL);
   
         if (p->p_timers == NULL)          if ((pts = p->p_timers) == NULL)
                 timers_alloc(p);                  pts = timers_alloc(p);
   
         /* Find a free timer slot, skipping those reserved for setitimer(). */  
         for (timerid = 3; timerid < TIMER_MAX; timerid++)  
                 if (p->p_timers->pts_timers[timerid] == NULL)  
                         break;  
   
         if (timerid == TIMER_MAX)  
                 return EAGAIN;  
   
         pt = pool_get(&ptimer_pool, PR_WAITOK);          pt = pool_get(&ptimer_pool, PR_WAITOK);
         if (evp) {          if (evp != NULL) {
                 if (((error =                  if (((error =
                     (*fetch_event)(evp, &pt->pt_ev, sizeof(pt->pt_ev))) != 0) ||                      (*fetch_event)(evp, &pt->pt_ev, sizeof(pt->pt_ev))) != 0) ||
                     ((pt->pt_ev.sigev_notify < SIGEV_NONE) ||                      ((pt->pt_ev.sigev_notify < SIGEV_NONE) ||
Line 546  timer_create1(timer_t *tid, clockid_t id
Line 551  timer_create1(timer_t *tid, clockid_t id
                         pool_put(&ptimer_pool, pt);                          pool_put(&ptimer_pool, pt);
                         return (error ? error : EINVAL);                          return (error ? error : EINVAL);
                 }                  }
         } else {          }
   
           /* Find a free timer slot, skipping those reserved for setitimer(). */
           mutex_spin_enter(&timer_lock);
           for (timerid = 3; timerid < TIMER_MAX; timerid++)
                   if (pts->pts_timers[timerid] == NULL)
                           break;
           if (timerid == TIMER_MAX) {
                   mutex_spin_exit(&timer_lock);
                   pool_put(&ptimer_pool, pt);
                   return EAGAIN;
           }
           if (evp == NULL) {
                 pt->pt_ev.sigev_notify = SIGEV_SIGNAL;                  pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
                 switch (id) {                  switch (id) {
                 case CLOCK_REALTIME:                  case CLOCK_REALTIME:
Line 567  timer_create1(timer_t *tid, clockid_t id
Line 584  timer_create1(timer_t *tid, clockid_t id
         pt->pt_info.ksi_pid = p->p_pid;          pt->pt_info.ksi_pid = p->p_pid;
         pt->pt_info.ksi_uid = kauth_cred_getuid(l->l_cred);          pt->pt_info.ksi_uid = kauth_cred_getuid(l->l_cred);
         pt->pt_info.ksi_value = pt->pt_ev.sigev_value;          pt->pt_info.ksi_value = pt->pt_ev.sigev_value;
   
         pt->pt_type = id;          pt->pt_type = id;
         pt->pt_proc = p;          pt->pt_proc = p;
         pt->pt_overruns = 0;          pt->pt_overruns = 0;
         pt->pt_poverruns = 0;          pt->pt_poverruns = 0;
         pt->pt_entry = timerid;          pt->pt_entry = timerid;
           pt->pt_queued = false;
           pt->pt_active = 0;
         timerclear(&pt->pt_time.it_value);          timerclear(&pt->pt_time.it_value);
         if (id == CLOCK_REALTIME)          callout_init(&pt->pt_ch, 0);
                 callout_init(&pt->pt_ch, 0);          pts->pts_timers[timerid] = pt;
         else          mutex_spin_exit(&timer_lock);
                 pt->pt_active = 0;  
   
         p->p_timers->pts_timers[timerid] = pt;  
   
         return copyout(&timerid, tid, sizeof(timerid));          return copyout(&timerid, tid, sizeof(timerid));
 }  }
Line 594  sys_timer_delete(struct lwp *l, const st
Line 609  sys_timer_delete(struct lwp *l, const st
         } */          } */
         struct proc *p = l->l_proc;          struct proc *p = l->l_proc;
         timer_t timerid;          timer_t timerid;
           struct ptimers *pts;
         struct ptimer *pt, *ptn;          struct ptimer *pt, *ptn;
         int s;  
   
         timerid = SCARG(uap, timerid);          timerid = SCARG(uap, timerid);
           pts = p->p_timers;
         if ((p->p_timers == NULL) ||  
             (timerid < 2) || (timerid >= TIMER_MAX) ||          if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
             ((pt = p->p_timers->pts_timers[timerid]) == NULL))  
                 return (EINVAL);                  return (EINVAL);
   
         if (pt->pt_type == CLOCK_REALTIME) {          mutex_spin_enter(&timer_lock);
                 callout_stop(&pt->pt_ch);          if ((pt = pts->pts_timers[timerid]) == NULL) {
                 callout_destroy(&pt->pt_ch);                  mutex_spin_exit(&timer_lock);
         } else if (pt->pt_active) {                  return (EINVAL);
                 s = splclock();          }
           if (pt->pt_active) {
                 ptn = LIST_NEXT(pt, pt_list);                  ptn = LIST_NEXT(pt, pt_list);
                 LIST_REMOVE(pt, pt_list);                  LIST_REMOVE(pt, pt_list);
                 for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list))                  for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list))
                         timeradd(&pt->pt_time.it_value, &ptn->pt_time.it_value,                          timeradd(&pt->pt_time.it_value, &ptn->pt_time.it_value,
                             &ptn->pt_time.it_value);                              &ptn->pt_time.it_value);
                 splx(s);                  pt->pt_active = 0;
         }          }
           itimerfree(pts, timerid);
         p->p_timers->pts_timers[timerid] = NULL;  
         pool_put(&ptimer_pool, pt);  
   
         return (0);          return (0);
 }  }
Line 635  timer_settime(struct ptimer *pt)
Line 648  timer_settime(struct ptimer *pt)
         struct ptimer *ptn, *pptn;          struct ptimer *ptn, *pptn;
         struct ptlist *ptl;          struct ptlist *ptl;
   
           KASSERT(mutex_owned(&timer_lock));
   
         if (pt->pt_type == CLOCK_REALTIME) {          if (pt->pt_type == CLOCK_REALTIME) {
                 callout_stop(&pt->pt_ch);                  callout_stop(&pt->pt_ch);
                 if (timerisset(&pt->pt_time.it_value)) {                  if (timerisset(&pt->pt_time.it_value)) {
Line 690  timer_gettime(struct ptimer *pt, struct 
Line 705  timer_gettime(struct ptimer *pt, struct 
         struct timeval now;          struct timeval now;
         struct ptimer *ptn;          struct ptimer *ptn;
   
           KASSERT(mutex_owned(&timer_lock));
   
         *aitv = pt->pt_time;          *aitv = pt->pt_time;
         if (pt->pt_type == CLOCK_REALTIME) {          if (pt->pt_type == CLOCK_REALTIME) {
                 /*                  /*
Line 759  dotimer_settime(int timerid, struct itim
Line 776  dotimer_settime(int timerid, struct itim
 {  {
         struct timeval now;          struct timeval now;
         struct itimerval val, oval;          struct itimerval val, oval;
           struct ptimers *pts;
         struct ptimer *pt;          struct ptimer *pt;
         int s;  
   
         if ((p->p_timers == NULL) ||          pts = p->p_timers;
             (timerid < 2) || (timerid >= TIMER_MAX) ||  
             ((pt = p->p_timers->pts_timers[timerid]) == NULL))  
                 return (EINVAL);  
   
           if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
                   return EINVAL;
         TIMESPEC_TO_TIMEVAL(&val.it_value, &value->it_value);          TIMESPEC_TO_TIMEVAL(&val.it_value, &value->it_value);
         TIMESPEC_TO_TIMEVAL(&val.it_interval, &value->it_interval);          TIMESPEC_TO_TIMEVAL(&val.it_interval, &value->it_interval);
         if (itimerfix(&val.it_value) || itimerfix(&val.it_interval))          if (itimerfix(&val.it_value) || itimerfix(&val.it_interval))
                 return (EINVAL);                  return (EINVAL);
   
           mutex_spin_enter(&timer_lock);
           if ((pt = pts->pts_timers[timerid]) == NULL) {
                   mutex_spin_exit(&timer_lock);
                   return (EINVAL);
           }
   
         oval = pt->pt_time;          oval = pt->pt_time;
         pt->pt_time = val;          pt->pt_time = val;
   
         s = splclock();  
         /*          /*
          * If we've been passed a relative time for a realtime timer,           * If we've been passed a relative time for a realtime timer,
          * convert it to absolute; if an absolute time for a virtual           * convert it to absolute; if an absolute time for a virtual
Line 805  dotimer_settime(int timerid, struct itim
Line 826  dotimer_settime(int timerid, struct itim
         }          }
   
         timer_settime(pt);          timer_settime(pt);
         splx(s);          mutex_spin_exit(&timer_lock);
   
         if (ovalue) {          if (ovalue) {
                 TIMEVAL_TO_TIMESPEC(&oval.it_value, &ovalue->it_value);                  TIMEVAL_TO_TIMESPEC(&oval.it_value, &ovalue->it_value);
Line 837  sys_timer_gettime(struct lwp *l, const s
Line 858  sys_timer_gettime(struct lwp *l, const s
 int  int
 dotimer_gettime(int timerid, struct proc *p, struct itimerspec *its)  dotimer_gettime(int timerid, struct proc *p, struct itimerspec *its)
 {  {
         int s;  
         struct ptimer *pt;          struct ptimer *pt;
           struct ptimers *pts;
         struct itimerval aitv;          struct itimerval aitv;
   
         if ((p->p_timers == NULL) ||          pts = p->p_timers;
             (timerid < 2) || (timerid >= TIMER_MAX) ||          if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
             ((pt = p->p_timers->pts_timers[timerid]) == NULL))  
                 return (EINVAL);                  return (EINVAL);
           mutex_spin_enter(&timer_lock);
         s = splclock();          if ((pt = pts->pts_timers[timerid]) == NULL) {
                   mutex_spin_exit(&timer_lock);
                   return (EINVAL);
           }
         timer_gettime(pt, &aitv);          timer_gettime(pt, &aitv);
         splx(s);          mutex_spin_exit(&timer_lock);
   
         TIMEVAL_TO_TIMESPEC(&aitv.it_interval, &its->it_interval);          TIMEVAL_TO_TIMESPEC(&aitv.it_interval, &its->it_interval);
         TIMEVAL_TO_TIMESPEC(&aitv.it_value, &its->it_value);          TIMEVAL_TO_TIMESPEC(&aitv.it_value, &its->it_value);
Line 869  sys_timer_getoverrun(struct lwp *l, cons
Line 892  sys_timer_getoverrun(struct lwp *l, cons
                 syscallarg(timer_t) timerid;                  syscallarg(timer_t) timerid;
         } */          } */
         struct proc *p = l->l_proc;          struct proc *p = l->l_proc;
           struct ptimers *pts;
         int timerid;          int timerid;
         struct ptimer *pt;          struct ptimer *pt;
   
         timerid = SCARG(uap, timerid);          timerid = SCARG(uap, timerid);
   
         if ((p->p_timers == NULL) ||          pts = p->p_timers;
             (timerid < 2) || (timerid >= TIMER_MAX) ||          if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
             ((pt = p->p_timers->pts_timers[timerid]) == NULL))  
                 return (EINVAL);                  return (EINVAL);
           mutex_spin_enter(&timer_lock);
           if ((pt = pts->pts_timers[timerid]) == NULL) {
                   mutex_spin_exit(&timer_lock);
                   return (EINVAL);
           }
         *retval = pt->pt_poverruns;          *retval = pt->pt_poverruns;
           mutex_spin_exit(&timer_lock);
   
         return (0);          return (0);
 }  }
Line 897  realtimerexpire(void *arg)
Line 925  realtimerexpire(void *arg)
 {  {
         struct timeval now;          struct timeval now;
         struct ptimer *pt;          struct ptimer *pt;
         int s;  
   
         pt = (struct ptimer *)arg;          pt = arg;
   
           mutex_spin_enter(&timer_lock);
         itimerfire(pt);          itimerfire(pt);
   
         if (!timerisset(&pt->pt_time.it_interval)) {          if (!timerisset(&pt->pt_time.it_interval)) {
                 timerclear(&pt->pt_time.it_value);                  timerclear(&pt->pt_time.it_value);
                   mutex_spin_exit(&timer_lock);
                 return;                  return;
         }          }
         for (;;) {          for (;;) {
                 s = splclock(); /* XXX need spl now? */  
                 timeradd(&pt->pt_time.it_value,                  timeradd(&pt->pt_time.it_value,
                     &pt->pt_time.it_interval, &pt->pt_time.it_value);                      &pt->pt_time.it_interval, &pt->pt_time.it_value);
                 getmicrotime(&now);                  getmicrotime(&now);
Line 919  realtimerexpire(void *arg)
Line 947  realtimerexpire(void *arg)
                          */                           */
                         callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),                          callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
                             realtimerexpire, pt);                              realtimerexpire, pt);
                         splx(s);                          mutex_spin_exit(&timer_lock);
                         return;                          return;
                 }                  }
                 splx(s);                  mutex_spin_exit(&timer_lock);
                 pt->pt_overruns++;                  pt->pt_overruns++;
                   mutex_spin_enter(&timer_lock);
         }          }
 }  }
   
Line 950  sys_getitimer(struct lwp *l, const struc
Line 979  sys_getitimer(struct lwp *l, const struc
 int  int
 dogetitimer(struct proc *p, int which, struct itimerval *itvp)  dogetitimer(struct proc *p, int which, struct itimerval *itvp)
 {  {
         int s;          struct ptimers *pts;
           struct ptimer *pt;
   
         if ((u_int)which > ITIMER_PROF)          if ((u_int)which > ITIMER_PROF)
                 return (EINVAL);                  return (EINVAL);
   
         if ((p->p_timers == NULL) || (p->p_timers->pts_timers[which] == NULL)){          mutex_spin_enter(&timer_lock);
           pts = p->p_timers;
           if (pts == NULL || (pt = pts->pts_timers[which]) == NULL) {
                 timerclear(&itvp->it_value);                  timerclear(&itvp->it_value);
                 timerclear(&itvp->it_interval);                  timerclear(&itvp->it_interval);
         } else {          } else
                 s = splclock();                  timer_gettime(pt, itvp);
                 timer_gettime(p->p_timers->pts_timers[which], itvp);          mutex_spin_exit(&timer_lock);
                 splx(s);  
         }  
   
         return 0;          return 0;
 }  }
Line 1007  int
Line 1037  int
 dosetitimer(struct proc *p, int which, struct itimerval *itvp)  dosetitimer(struct proc *p, int which, struct itimerval *itvp)
 {  {
         struct timeval now;          struct timeval now;
         struct ptimer *pt;          struct ptimers *pts;
         int s;          struct ptimer *pt, *spare;
   
         if (itimerfix(&itvp->it_value) || itimerfix(&itvp->it_interval))          if (itimerfix(&itvp->it_value) || itimerfix(&itvp->it_interval))
                 return (EINVAL);                  return (EINVAL);
Line 1017  dosetitimer(struct proc *p, int which, s
Line 1047  dosetitimer(struct proc *p, int which, s
          * Don't bother allocating data structures if the process just           * Don't bother allocating data structures if the process just
          * wants to clear the timer.           * wants to clear the timer.
          */           */
         if (!timerisset(&itvp->it_value) &&          spare = NULL;
             ((p->p_timers == NULL) ||(p->p_timers->pts_timers[which] == NULL)))          pts = p->p_timers;
    retry:
           if (!timerisset(&itvp->it_value) && (pts == NULL ||
               pts->pts_timers[which] == NULL))
                 return (0);                  return (0);
           if (pts == NULL)
         if (p->p_timers == NULL)                  pts = timers_alloc(p);
                 timers_alloc(p);          mutex_spin_enter(&timer_lock);
         if (p->p_timers->pts_timers[which] == NULL) {          pt = pts->pts_timers[which];
                 pt = pool_get(&ptimer_pool, PR_WAITOK);          if (pt == NULL) {
                   if (spare == NULL) {
                           mutex_spin_exit(&timer_lock);
                           spare = pool_get(&ptimer_pool, PR_WAITOK);
                           goto retry;
                   }
                   pt = spare;
                   spare = NULL;
                 pt->pt_ev.sigev_notify = SIGEV_SIGNAL;                  pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
                 pt->pt_ev.sigev_value.sival_int = which;                  pt->pt_ev.sigev_value.sival_int = which;
                 pt->pt_overruns = 0;                  pt->pt_overruns = 0;
                 pt->pt_proc = p;                  pt->pt_proc = p;
                 pt->pt_type = which;                  pt->pt_type = which;
                 pt->pt_entry = which;                  pt->pt_entry = which;
                   pt->pt_active = 0;
                   pt->pt_queued = false;
                   callout_init(&pt->pt_ch, CALLOUT_MPSAFE);
                 switch (which) {                  switch (which) {
                 case ITIMER_REAL:                  case ITIMER_REAL:
                         callout_init(&pt->pt_ch, 0);  
                         pt->pt_ev.sigev_signo = SIGALRM;                          pt->pt_ev.sigev_signo = SIGALRM;
                         break;                          break;
                 case ITIMER_VIRTUAL:                  case ITIMER_VIRTUAL:
                         pt->pt_active = 0;  
                         pt->pt_ev.sigev_signo = SIGVTALRM;                          pt->pt_ev.sigev_signo = SIGVTALRM;
                         break;                          break;
                 case ITIMER_PROF:                  case ITIMER_PROF:
                         pt->pt_active = 0;  
                         pt->pt_ev.sigev_signo = SIGPROF;                          pt->pt_ev.sigev_signo = SIGPROF;
                         break;                          break;
                 }                  }
         } else                  pts->pts_timers[which] = pt;
                 pt = p->p_timers->pts_timers[which];          }
   
         pt->pt_time = *itvp;          pt->pt_time = *itvp;
         p->p_timers->pts_timers[which] = pt;  
   
         s = splclock();  
         if ((which == ITIMER_REAL) && timerisset(&pt->pt_time.it_value)) {          if ((which == ITIMER_REAL) && timerisset(&pt->pt_time.it_value)) {
                 /* Convert to absolute time */                  /* Convert to absolute time */
                 /* XXX need to wrap in splclock for timecounters case? */                  /* XXX need to wrap in splclock for timecounters case? */
Line 1059  dosetitimer(struct proc *p, int which, s
Line 1096  dosetitimer(struct proc *p, int which, s
                 timeradd(&pt->pt_time.it_value, &now, &pt->pt_time.it_value);                  timeradd(&pt->pt_time.it_value, &now, &pt->pt_time.it_value);
         }          }
         timer_settime(pt);          timer_settime(pt);
         splx(s);          mutex_spin_exit(&timer_lock);
           if (spare != NULL)
                   pool_put(&ptimer_pool, spare);
   
         return (0);          return (0);
 }  }
   
 /* Utility routines to manage the array of pointers to timers. */  /* Utility routines to manage the array of pointers to timers. */
 void  struct ptimers *
 timers_alloc(struct proc *p)  timers_alloc(struct proc *p)
 {  {
         int i;  
         struct ptimers *pts;          struct ptimers *pts;
           int i;
   
         pts = pool_get(&ptimers_pool, PR_WAITOK);          pts = pool_get(&ptimers_pool, PR_WAITOK);
         LIST_INIT(&pts->pts_virtual);          LIST_INIT(&pts->pts_virtual);
Line 1077  timers_alloc(struct proc *p)
Line 1116  timers_alloc(struct proc *p)
         for (i = 0; i < TIMER_MAX; i++)          for (i = 0; i < TIMER_MAX; i++)
                 pts->pts_timers[i] = NULL;                  pts->pts_timers[i] = NULL;
         pts->pts_fired = 0;          pts->pts_fired = 0;
         p->p_timers = pts;          mutex_spin_enter(&timer_lock);
           if (p->p_timers == NULL) {
                   p->p_timers = pts;
                   mutex_spin_exit(&timer_lock);
                   return pts;
           }
           mutex_spin_exit(&timer_lock);
           pool_put(&ptimers_pool, pts);
           return p->p_timers;
 }  }
   
 /*  /*
Line 1090  timers_alloc(struct proc *p)
Line 1137  timers_alloc(struct proc *p)
 void  void
 timers_free(struct proc *p, int which)  timers_free(struct proc *p, int which)
 {  {
         int i, s;  
         struct ptimers *pts;          struct ptimers *pts;
         struct ptimer *pt, *ptn;          struct ptimer *ptn;
         struct timeval tv;          struct timeval tv;
           int i;
   
         if (p->p_timers) {          if (p->p_timers == NULL)
                 pts = p->p_timers;                  return;
                 if (which == TIMERS_ALL)  
                         i = 0;  
                 else {  
                         s = splclock();  
                         timerclear(&tv);  
                         for (ptn = LIST_FIRST(&p->p_timers->pts_virtual);  
                              ptn && ptn != pts->pts_timers[ITIMER_VIRTUAL];  
                              ptn = LIST_NEXT(ptn, pt_list))  
                                 timeradd(&tv, &ptn->pt_time.it_value, &tv);  
                         LIST_FIRST(&p->p_timers->pts_virtual) = NULL;  
                         if (ptn) {  
                                 timeradd(&tv, &ptn->pt_time.it_value,  
                                     &ptn->pt_time.it_value);  
                                 LIST_INSERT_HEAD(&p->p_timers->pts_virtual,  
                                     ptn, pt_list);  
                         }  
   
                         timerclear(&tv);          pts = p->p_timers;
                         for (ptn = LIST_FIRST(&p->p_timers->pts_prof);          mutex_spin_enter(&timer_lock);
                              ptn && ptn != pts->pts_timers[ITIMER_PROF];          if (which == TIMERS_ALL) {
                              ptn = LIST_NEXT(ptn, pt_list))                  p->p_timers = NULL;
                                 timeradd(&tv, &ptn->pt_time.it_value, &tv);                  i = 0;
                         LIST_FIRST(&p->p_timers->pts_prof) = NULL;          } else {
                         if (ptn) {                  timerclear(&tv);
                                 timeradd(&tv, &ptn->pt_time.it_value,                  for (ptn = LIST_FIRST(&pts->pts_virtual);
                                     &ptn->pt_time.it_value);                       ptn && ptn != pts->pts_timers[ITIMER_VIRTUAL];
                                 LIST_INSERT_HEAD(&p->p_timers->pts_prof, ptn,                       ptn = LIST_NEXT(ptn, pt_list))
                                     pt_list);                          timeradd(&tv, &ptn->pt_time.it_value, &tv);
                         }                  LIST_FIRST(&pts->pts_virtual) = NULL;
                         splx(s);                  if (ptn) {
                         i = 3;                          timeradd(&tv, &ptn->pt_time.it_value,
                               &ptn->pt_time.it_value);
                           LIST_INSERT_HEAD(&pts->pts_virtual, ptn, pt_list);
                 }                  }
                 for ( ; i < TIMER_MAX; i++)                  timerclear(&tv);
                         if ((pt = pts->pts_timers[i]) != NULL) {                  for (ptn = LIST_FIRST(&pts->pts_prof);
                                 if (pt->pt_type == CLOCK_REALTIME) {                       ptn && ptn != pts->pts_timers[ITIMER_PROF];
                                         callout_stop(&pt->pt_ch);                       ptn = LIST_NEXT(ptn, pt_list))
                                         callout_destroy(&pt->pt_ch);                          timeradd(&tv, &ptn->pt_time.it_value, &tv);
                                 }                  LIST_FIRST(&pts->pts_prof) = NULL;
                                 pts->pts_timers[i] = NULL;                  if (ptn) {
                                 pool_put(&ptimer_pool, pt);                          timeradd(&tv, &ptn->pt_time.it_value,
                         }                              &ptn->pt_time.it_value);
                 if ((pts->pts_timers[0] == NULL) &&                          LIST_INSERT_HEAD(&pts->pts_prof, ptn, pt_list);
                     (pts->pts_timers[1] == NULL) &&  
                     (pts->pts_timers[2] == NULL)) {  
                         p->p_timers = NULL;  
                         pool_put(&ptimers_pool, pts);  
                 }                  }
                   i = 3;
         }          }
           for ( ; i < TIMER_MAX; i++) {
                   if (pts->pts_timers[i] != NULL) {
                           itimerfree(pts, i);
                           mutex_spin_enter(&timer_lock);
                   }
           }
           if (pts->pts_timers[0] == NULL && pts->pts_timers[1] == NULL &&
               pts->pts_timers[2] == NULL) {
                   p->p_timers = NULL;
                   mutex_spin_exit(&timer_lock);
                   pool_put(&ptimers_pool, pts);
           } else
                   mutex_spin_exit(&timer_lock);
   }
   
   static void
   itimerfree(struct ptimers *pts, int index)
   {
           struct ptimer *pt;
   
           KASSERT(mutex_owned(&timer_lock));
   
           pt = pts->pts_timers[index];
           pts->pts_timers[index] = NULL;
           if (pt->pt_type == CLOCK_REALTIME)
                   callout_halt(&pt->pt_ch, &timer_lock);
           else if (pt->pt_queued)
                   TAILQ_REMOVE(&timer_queue, pt, pt_chain);
           mutex_spin_exit(&timer_lock);
           callout_destroy(&pt->pt_ch);
           pool_put(&ptimer_pool, pt);
 }  }
   
 /*  /*
Line 1157  timers_free(struct proc *p, int which)
Line 1218  timers_free(struct proc *p, int which)
  * that it is called in a context where the timers   * that it is called in a context where the timers
  * on which it is operating cannot change in value.   * on which it is operating cannot change in value.
  */   */
 int  static int
 itimerdecr(struct ptimer *pt, int usec)  itimerdecr(struct ptimer *pt, int usec)
 {  {
         struct itimerval *itp;          struct itimerval *itp;
   
           KASSERT(mutex_owned(&timer_lock));
   
         itp = &pt->pt_time;          itp = &pt->pt_time;
         if (itp->it_value.tv_usec < usec) {          if (itp->it_value.tv_usec < usec) {
                 if (itp->it_value.tv_sec == 0) {                  if (itp->it_value.tv_sec == 0) {
Line 1191  expire:
Line 1254  expire:
         return (0);          return (0);
 }  }
   
 void  static void
 itimerfire(struct ptimer *pt)  itimerfire(struct ptimer *pt)
 {  {
         struct proc *p = pt->pt_proc;  
   
         if (pt->pt_ev.sigev_notify == SIGEV_SIGNAL) {          KASSERT(mutex_owned(&timer_lock));
   
           /*
            * XXX Can overrun, but we don't do signal queueing yet, anyway.
            * XXX Relying on the clock interrupt is stupid.
            */
           if (pt->pt_ev.sigev_notify != SIGEV_SIGNAL || pt->pt_queued)
                   return;
           TAILQ_INSERT_TAIL(&timer_queue, pt, pt_chain);
           pt->pt_queued = true;
           softint_schedule(timer_sih);
   }
   
   void
   timer_tick(lwp_t *l, bool user)
   {
           struct ptimers *pts;
           struct ptimer *pt;
           proc_t *p;
   
           p = l->l_proc;
           if (p->p_timers == NULL)
                   return;
   
           mutex_spin_enter(&timer_lock);
           if ((pts = l->l_proc->p_timers) != NULL) {
                 /*                  /*
                  * No RT signal infrastructure exists at this time;                   * Run current process's virtual and profile time, as needed.
                  * just post the signal number and throw away the  
                  * value.  
                  */                   */
                 if (sigismember(&p->p_sigpend.sp_set, pt->pt_ev.sigev_signo))                  if (user && (pt = LIST_FIRST(&pts->pts_virtual)) != NULL)
                           if (itimerdecr(pt, tick) == 0)
                                   itimerfire(pt);
                   if ((pt = LIST_FIRST(&pts->pts_prof)) != NULL)
                           if (itimerdecr(pt, tick) == 0)
                                   itimerfire(pt);
           }
           mutex_spin_exit(&timer_lock);
   }
   
   static void
   timer_intr(void *cookie)
   {
           ksiginfo_t ksi;
           struct ptimer *pt;
           proc_t *p;
   
           mutex_spin_enter(&timer_lock);
           while ((pt = TAILQ_FIRST(&timer_queue)) != NULL) {
                   TAILQ_REMOVE(&timer_queue, pt, pt_chain);
                   KASSERT(pt->pt_queued);
                   pt->pt_queued = false;
   
                   if (pt->pt_ev.sigev_notify != SIGEV_SIGNAL)
                           continue;
                   p = pt->pt_proc;
                   if (pt->pt_proc->p_timers == NULL) {
                           /* Process is dying. */
                           continue;
                   }
                   if (sigismember(&p->p_sigpend.sp_set, pt->pt_ev.sigev_signo)) {
                         pt->pt_overruns++;                          pt->pt_overruns++;
                 else {                          continue;
                         ksiginfo_t ksi;  
                         KSI_INIT(&ksi);  
                         ksi.ksi_signo = pt->pt_ev.sigev_signo;  
                         ksi.ksi_code = SI_TIMER;  
                         ksi.ksi_value = pt->pt_ev.sigev_value;  
                         pt->pt_poverruns = pt->pt_overruns;  
                         pt->pt_overruns = 0;  
                         mutex_enter(&proclist_mutex);  
                         kpsignal(p, &ksi, NULL);  
                         mutex_exit(&proclist_mutex);  
                 }                  }
   
                   KSI_INIT(&ksi);
                   ksi.ksi_signo = pt->pt_ev.sigev_signo;
                   ksi.ksi_code = SI_TIMER;
                   ksi.ksi_value = pt->pt_ev.sigev_value;
                   pt->pt_poverruns = pt->pt_overruns;
                   pt->pt_overruns = 0;
                   mutex_spin_exit(&timer_lock);
   
                   mutex_enter(proc_lock);
                   kpsignal(p, &ksi, NULL);
                   mutex_exit(proc_lock);
   
                   mutex_spin_enter(&timer_lock);
         }          }
           mutex_spin_exit(&timer_lock);
 }  }
   
 /*  /*

Legend:
Removed from v.1.141  
changed lines
  Added in v.1.141.4.1

CVSweb <webmaster@jp.NetBSD.org>