[BACK]Return to kern_sleepq.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_sleepq.c between version 1.1.2.4 and 1.1.2.5

version 1.1.2.4, 2006/10/24 21:10:21 version 1.1.2.5, 2006/11/17 16:34:36
Line 41 
Line 41 
  * interfaces.   * interfaces.
  */   */
   
 #include "opt_multiprocessor.h"  
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
   #include "opt_multiprocessor.h"
   #include "opt_lockdebug.h"
   #include "opt_ktrace.h"
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/lock.h>  #include <sys/lock.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
Line 58  __KERNEL_RCSID(0, "$NetBSD$");
Line 60  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/savar.h>  #include <sys/savar.h>
 #include <sys/sleepq.h>  #include <sys/sleepq.h>
   
   #ifdef KTRACE
   #include <sys/ktrace.h>
   #endif
   
 int     sleepq_sigtoerror(struct lwp *, int);  int     sleepq_sigtoerror(struct lwp *, int);
 void    sleepq_exit(sleepq_t *, struct lwp *);  
 void    updatepri(struct lwp *);  void    updatepri(struct lwp *);
 void    sa_awaken(struct lwp *);  void    sa_awaken(struct lwp *);
   
 sleepq_t        sleeptab[SLEEPTAB_HASH_SIZE];  /* General purpose sleep table, used by ltsleep() and condition variables. */
 #ifdef MULTIPROCESSOR  sleeptab_t      sleeptab;
 kmutex_t        sleeptab_mutexes[SLEEPTAB_HASH_SIZE];  
 #endif  
   
 /*  /*
  * sleeptab_init:   * sleeptab_init:
  *   *
  *      Initialize the general-purpose sleep queues.   *      Initialize a sleep table.
  */   */
 void  void
 sleeptab_init(void)  sleeptab_init(sleeptab_t *st)
 {  {
         sleepq_t *sq;          sleepq_t *sq;
         int i;          int i;
   
         for (i = 0; i < SLEEPTAB_HASH_SIZE; i++) {          for (i = 0; i < SLEEPTAB_HASH_SIZE; i++) {
                 sq = &sleeptab[i];                  sq = &st->st_queues[i];
 #ifdef MULTIPROCESSOR  #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
                 mutex_init(&sleeptab_mutexes[i], MUTEX_SPIN, IPL_SCHED);                  mutex_init(&st->st_mutexes[i], MUTEX_SPIN, IPL_SCHED);
                 sleepq_init(&sleeptab[i], &sleeptab_mutexes[i]);                  sleepq_init(sq, &st->st_mutexes[i]);
 #else  #else
                 sleepq_init(&sleeptab[i], &sched_mutex);                  sleepq_init(sq, &sched_mutex);
 #endif  #endif
         }          }
 }  }
Line 117  sleepq_remove(sleepq_t *sq, struct lwp *
Line 120  sleepq_remove(sleepq_t *sq, struct lwp *
         struct cpu_info *ci;          struct cpu_info *ci;
   
         LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));          LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));
         LOCK_ASSERT(mutex_owned(&sched_mutex));  
         KASSERT(sq->sq_waiters > 0);          KASSERT(sq->sq_waiters > 0);
           KASSERT(l->l_stat == LSSLEEP);
   
         sq->sq_waiters--;          sq->sq_waiters--;
         TAILQ_REMOVE(&sq->sq_queue, l, l_sleepq);          TAILQ_REMOVE(&sq->sq_queue, l, l_sleepchain);
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if (sq->sq_waiters == 0)          if (sq->sq_waiters == 0)
Line 130  sleepq_remove(sleepq_t *sq, struct lwp *
Line 133  sleepq_remove(sleepq_t *sq, struct lwp *
                 KASSERT(TAILQ_FIRST(&sq->sq_queue) != NULL);                  KASSERT(TAILQ_FIRST(&sq->sq_queue) != NULL);
 #endif  #endif
   
           l->l_syncobj = &sched_syncobj;
         l->l_wchan = NULL;          l->l_wchan = NULL;
           l->l_sleepq = NULL;
         l->l_flag &= ~L_SINTR;          l->l_flag &= ~L_SINTR;
   
         /*          sched_lock(1);
          * If not sleeping, the LWP must have been suspended.  Let whoever  
          * holds it stopped set it running again.  
          */  
         if (l->l_stat != LSSLEEP) {  
                 KASSERT(l->l_stat == LSSTOP || l->l_stat == LSSUSPENDED);  
                 return 0;  
         }  
   
         if (l->l_proc->p_sa)  
                 sa_awaken(l);  
   
         lwp_setlock(l, &sched_mutex);          lwp_setlock(l, &sched_mutex);
   
         /*          /*
Line 154  sleepq_remove(sleepq_t *sq, struct lwp *
Line 148  sleepq_remove(sleepq_t *sq, struct lwp *
         if ((ci = l->l_cpu) != NULL && ci->ci_curlwp == l) {          if ((ci = l->l_cpu) != NULL && ci->ci_curlwp == l) {
                 l->l_stat = LSONPROC;                  l->l_stat = LSONPROC;
                 l->l_slptime = 0;                  l->l_slptime = 0;
                   sched_unlock(1);
                 return 0;                  return 0;
         }          }
   
           if (l->l_proc->p_sa)
                   sa_awaken(l);
   
         /*          /*
          * Set it running.  We'll try to get the last CPU that ran           * Set it running.  We'll try to get the last CPU that ran
          * this LWP to pick it up again.           * this LWP to pick it up again.
          */           */
         l->l_stat = LSRUN;          if (l->l_stat == LSSLEEP)
                   l->l_stat = LSRUN;
         if (l->l_slptime > 1)          if (l->l_slptime > 1)
                 updatepri(l);                  updatepri(l);
         l->l_slptime = 0;          l->l_slptime = 0;
         if ((l->l_flag & L_INMEM) != 0) {          if ((l->l_flag & L_INMEM) != 0) {
                 setrunqueue(l);                  setrunqueue(l);
                 cpu_need_resched(l->l_cpu);                  if (l->l_priority < ci->ci_schedstate.spc_curpriority)
                           cpu_need_resched(ci);
                   sched_unlock(1);
                 return 0;                  return 0;
         }          }
   
           sched_unlock(1);
         return 1;          return 1;
 }  }
   
 /*  /*
    * sleepq_insert:
    *
    *      Insert an LWP into the sleep queue, optionally sorting by priority.
    */
   static inline void
   sleepq_insert(sleepq_t *sq, struct lwp *l, int pri, syncobj_t *sobj)
   {
           struct lwp *l2, *l3 = NULL;
   
           if ((sobj->sobj_flag & SOBJ_SLEEPQ_SORTED) != 0) {
                   TAILQ_FOREACH(l2, &sq->sq_queue, l_sleepchain) {
                           l3 = l2;
                           if (l2->l_priority > pri)
                                   break;
                   }
           }
   
           if (l3 == NULL)
                   TAILQ_INSERT_HEAD(&sq->sq_queue, l, l_sleepchain);
           else
                   TAILQ_INSERT_BEFORE(l3, l, l_sleepchain);
   }
   
   /*
  * sleepq_enter:   * sleepq_enter:
  *   *
  *      Enter an LWP into the sleep queue and prepare for sleep.  Any interlocking   *      Enter an LWP into the sleep queue and prepare for sleep.  Any interlocking
Line 183  sleepq_remove(sleepq_t *sq, struct lwp *
Line 209  sleepq_remove(sleepq_t *sq, struct lwp *
  */   */
 void  void
 sleepq_enter(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg, int timo,  sleepq_enter(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg, int timo,
              int catch)               int catch, syncobj_t *sobj)
 {  {
         struct lwp *l = curlwp;          struct lwp *l = curlwp;
   
         LOCK_ASSERT(mutex_owned(sq->sq_mutex));          LOCK_ASSERT(mutex_owned(sq->sq_mutex));
           KASSERT(l->l_stat == LSONPROC);
           KASSERT(l->l_wchan == NULL && l->l_sleepq == NULL);
   
 #ifdef KTRACE  #ifdef KTRACE
         if (KTRPOINT(p, KTR_CSW))          if (KTRPOINT(l->l_proc, KTR_CSW))
                 ktrcsw(l, 1, 0);                  ktrcsw(l, 1, 0);
 #endif  #endif
   
         sq->sq_waiters++;          sq->sq_waiters++;
         TAILQ_INSERT_TAIL(&sq->sq_queue, l, l_sleepq);  
   
   #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
         /*          /*
          * Acquire the per-LWP mutex.           * Acquire the per-LWP mutex and sort it into the sleep queue.  Once
            * we have that lock, we can release the kernel lock.  XXXSMP Not
            * yet, since checking for signals may call pool_put().  Otherwise
            * this is OK.
          */           */
         lwp_lock(l);          lwp_lock(l);
   
         KASSERT(l->l_wchan == NULL);  #ifdef notyet
           l->l_biglocks = KERNEL_UNLOCK(0, l);
   #endif
   #endif
   
           l->l_syncobj = sobj;
         l->l_wchan = wchan;          l->l_wchan = wchan;
           l->l_sleepq = sq;
         l->l_wmesg = wmesg;          l->l_wmesg = wmesg;
         l->l_slptime = 0;          l->l_slptime = 0;
         l->l_priority = pri & PRIMASK;          l->l_priority = pri;
         l->l_flag &= ~L_CANCELLED;          l->l_stat = LSSLEEP;
           l->l_nvcsw++;
   
         if (catch)          if (catch)
                 l->l_flag |= L_SINTR;                  l->l_flag |= L_SINTR;
         if (l->l_stat == LSONPROC)  
                 l->l_stat = LSSLEEP;          sleepq_insert(sq, l, pri, sobj);
         l->l_nvcsw++;  
   
         if (timo)          if (timo)
                 callout_reset(&l->l_tsleep_ch, timo, sleepq_timeout, l);                  callout_reset(&l->l_tsleep_ch, timo, sleepq_timeout, l);
   
   #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
         /*          /*
          * The LWP is now on the sleep queue.  Release its old mutex and           * The LWP is now on the sleep queue.  Release its old mutex and
          * lend it ours for the duration of the sleep.           * lend it ours for the duration of the sleep.
          */           */
         lwp_setlock_unlock(l, sq->sq_mutex);          lwp_unlock_to(l, sq->sq_mutex);
 }  
   
 /*  
  * sleepq_exit:  
  *  
  *      Remove the current LWP from a sleep queue after the sleep has been  
  *      interrupted.  
  */  
 void  
 sleepq_exit(sleepq_t *sq, struct lwp *l)  
 {  
   
         LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));  
         KASSERT(sq->sq_waiters > 0);  
         KASSERT(l->l_stat == LSSLEEP);  
   
         l->l_wchan = NULL;  
         l->l_slptime = 0;  
         l->l_flag &= ~L_SINTR;  
   
         sq->sq_waiters--;  
         TAILQ_REMOVE(&sq->sq_queue, l, l_sleepq);  
   
 #ifdef DIAGNOSTIC  
         if (sq->sq_waiters == 0)  
                 KASSERT(TAILQ_FIRST(&sq->sq_queue) == NULL);  
         else  
                 KASSERT(TAILQ_FIRST(&sq->sq_queue) != NULL);  
 #endif  #endif
   
         l->l_stat = LSONPROC;  
   
         lwp_setlock_unlock(l, &sched_mutex);  
 }  }
   
 /*  /*
Line 276  sleepq_block(sleepq_t *sq, int timo)
Line 282  sleepq_block(sleepq_t *sq, int timo)
   
         LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));          LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));
   
           p = l->l_proc;
         flag = l->l_flag;          flag = l->l_flag;
         error = 0;          error = 0;
   
Line 286  sleepq_block(sleepq_t *sq, int timo)
Line 293  sleepq_block(sleepq_t *sq, int timo)
         if ((flag & L_SINTR) != 0) {          if ((flag & L_SINTR) != 0) {
                 while ((l->l_flag & L_PENDSIG) != 0 && error == 0) {                  while ((l->l_flag & L_PENDSIG) != 0 && error == 0) {
                         lwp_unlock(l);                          lwp_unlock(l);
                         p = l->l_proc;  
                         mutex_enter(&p->p_smutex);                          mutex_enter(&p->p_smutex);
                         if ((sig = issignal(l)) != 0)                          if ((sig = issignal(l)) != 0)
                                 error = sleepq_sigtoerror(l, sig);                                  error = sleepq_sigtoerror(l, sig);
Line 294  sleepq_block(sleepq_t *sq, int timo)
Line 300  sleepq_block(sleepq_t *sq, int timo)
                         lwp_lock(l);                          lwp_lock(l);
                 }                  }
   
                 if ((l->l_flag & (L_CANCELLED | L_WEXIT | L_WCORE)) != 0)                  if ((l->l_flag & (L_CANCELLED | L_WEXIT | L_WCORE)) != 0) {
                           l->l_flag &= ~L_CANCELLED;
                         error = EINTR;                          error = EINTR;
                   }
   
                   if (l->l_wchan != NULL) {
                           if (error != 0) {
                                   KASSERT(l->l_stat == LSSLEEP);
                                   sleepq_remove(sq, l);
                                   mutex_exit(sq->sq_mutex);
                           }
                   } else {
                           KASSERT(l->l_stat == LSONPROC);
                           lwp_unlock(l);
                   }
         }          }
   
         if (error != 0 && l->l_stat == LSSLEEP)          if (l->l_stat == LSSLEEP) {
                 sleepq_exit(sq, l);                  KASSERT(l->l_wchan != NULL);
         else if (l->l_stat != LSONPROC) {  
                 if ((flag & L_SA) != 0) {                  if ((flag & L_SA) != 0)
                         sa_switch(l, sadata_upcall_alloc(0), SA_UPCALL_BLOCKED);                          sa_switch(l, sadata_upcall_alloc(0), SA_UPCALL_BLOCKED);
                         /* XXXAD verify sa_switch restores SPL. */                  else {
                 } else {  
                         mi_switch(l, NULL);                          mi_switch(l, NULL);
                         l->l_cpu->ci_schedstate.spc_curpriority = l->l_usrpri;                          l->l_cpu->ci_schedstate.spc_curpriority = l->l_usrpri;
                 }                  }
         }          }
   
         KASSERT(l->l_wchan == NULL);          /* When we reach this point, the LWP is unlocked. */
   
           KASSERT(l->l_wchan == NULL && l->l_sleepq == NULL);
   
         if (timo) {          if (timo) {
                 /*                  /*
Line 320  sleepq_block(sleepq_t *sq, int timo)
Line 340  sleepq_block(sleepq_t *sq, int timo)
                 expired = callout_expired(&l->l_tsleep_ch);                  expired = callout_expired(&l->l_tsleep_ch);
                 callout_stop(&l->l_tsleep_ch);                  callout_stop(&l->l_tsleep_ch);
                 if (expired && error == 0)                  if (expired && error == 0)
                         return EWOULDBLOCK;                          error = EWOULDBLOCK;
         }          }
   
         if (error == 0 && (flag & L_SINTR) != 0) {          if (error == 0 && (flag & L_SINTR) != 0) {
                 if ((l->l_flag & (L_CANCELLED | L_WEXIT | L_WCORE)) != 0)                  if ((l->l_flag & (L_CANCELLED | L_WEXIT | L_WCORE)) != 0)
                         error = EINTR;                          error = EINTR;
                 else if ((l->l_flag & L_PENDSIG) != 0) {                  else if ((l->l_flag & L_PENDSIG) != 0) {
                         p = l->l_proc;  
                         mutex_enter(&p->p_smutex);                          mutex_enter(&p->p_smutex);
                         if ((sig = issignal(l)) != 0)                          if ((sig = issignal(l)) != 0)
                                 error = sleepq_sigtoerror(l, sig);                                  error = sleepq_sigtoerror(l, sig);
Line 335  sleepq_block(sleepq_t *sq, int timo)
Line 354  sleepq_block(sleepq_t *sq, int timo)
                 }                  }
         }          }
   
           return error;
   }
   
   /*
    * sleepq_unblock:
    *
    *      After any intermediate step such as updating statistics, re-acquire
    *      the kernel lock and record the switch for ktrace.  Note that we are
    *      no longer on the sleep queue at this point.
    */
   void
   sleepq_unblock(void)
   {
           struct lwp *l = curlwp;
   
   #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
   #ifdef notyet
           /*
            * Re-acquire the kernel lock.  XXXSMP Let mi_switch() take care of
            * it, until we can release the lock in sleepq_block().
            */
           KERNEL_LOCK(l->l_biglocks, l);
   #endif
   #endif
   
 #ifdef KTRACE  #ifdef KTRACE
         if (KTRPOINT(p, KTR_CSW))          if (KTRPOINT(l->l_proc, KTR_CSW))
                 ktrcsw(l, 0, 0);                  ktrcsw(l, 0, 0);
 #endif  #endif
         return error;  
 }  }
   
 /*  /*
  * sleepq_wakeone:   * sleepq_wakeone:
  *   *
  *      Remove one LWP from the sleep queue and wake it.  We search among   *      Remove the highest priority LWP from the sleep queue and wake it.
  *      the higest priority LWPs waiting on a single wait channel, and pick  
  *      the longest waiting one.  
  */   */
 void  void
 sleepq_wakeone(sleepq_t *sq, wchan_t wchan)  sleepq_wakeone(sleepq_t *sq, wchan_t wchan)
 {  {
         struct lwp *l, *bl;          struct lwp *l;
         int bpri, swapin;          int swapin;
   
         LOCK_ASSERT(mutex_owned(sq->sq_mutex));          LOCK_ASSERT(mutex_owned(sq->sq_mutex));
   
         swapin = 0;          swapin = 0;
         bpri = MAXPRI;  
         bl = NULL;  
   
         TAILQ_FOREACH(l, &sq->sq_queue, l_sleepq) {          if ((l = TAILQ_FIRST(&sq->sq_queue)) != NULL)
                 if (l->l_wchan != wchan || l->l_priority > bpri)                  swapin = sleepq_remove(sq, l);
                         continue;  
                 bl = l;  
                 bpri = l->l_priority;  
         }  
   
         if (bl != NULL) {  
                 sched_lock();  
                 swapin = sleepq_remove(sq, bl);  
                 sched_unlock();  
         }  
   
         mutex_exit(sq->sq_mutex);          mutex_exit(sq->sq_mutex);
   
Line 393  sleepq_wakeall(sleepq_t *sq, wchan_t wch
Line 422  sleepq_wakeall(sleepq_t *sq, wchan_t wch
   
         LOCK_ASSERT(mutex_owned(sq->sq_mutex));          LOCK_ASSERT(mutex_owned(sq->sq_mutex));
   
         sched_lock();  
         for (l = TAILQ_FIRST(&sq->sq_queue); l != NULL; l = next) {          for (l = TAILQ_FIRST(&sq->sq_queue); l != NULL; l = next) {
                 next = TAILQ_NEXT(l, l_sleepq);                  KASSERT(l->l_sleepq == sq);
                   next = TAILQ_NEXT(l, l_sleepchain);
                 if (l->l_wchan != wchan)                  if (l->l_wchan != wchan)
                         continue;                          continue;
                 swapin |= sleepq_remove(sq, l);                  swapin |= sleepq_remove(sq, l);
                 if (--expected == 0)                  if (--expected == 0)
                         break;                          break;
         }          }
         sched_unlock();  
   
         LOCK_ASSERT(mutex_owned(sq->sq_mutex));          LOCK_ASSERT(mutex_owned(sq->sq_mutex));
         mutex_exit(sq->sq_mutex);          mutex_exit(sq->sq_mutex);
Line 425  sleepq_wakeall(sleepq_t *sq, wchan_t wch
Line 453  sleepq_wakeall(sleepq_t *sq, wchan_t wch
 void  void
 sleepq_unsleep(struct lwp *l)  sleepq_unsleep(struct lwp *l)
 {  {
         sleepq_t *sq;          sleepq_t *sq = l->l_sleepq;
         int swapin;          int swapin;
   
         sq = &sleeptab[SLEEPTAB_HASH(l->l_wchan)];          LOCK_ASSERT(lwp_locked(l, NULL));
         KASSERT(l->l_wchan != NULL);          KASSERT(l->l_wchan != NULL);
         KASSERT(l->l_mutex == sq->sq_mutex);          KASSERT(l->l_mutex == sq->sq_mutex);
   
         sched_lock();  
         swapin = sleepq_remove(sq, l);          swapin = sleepq_remove(sq, l);
         sched_unlock();  
   
         mutex_exit(sq->sq_mutex);          mutex_exit(sq->sq_mutex);
   
         if (swapin)          if (swapin)
Line 465  sleepq_timeout(void *arg)
Line 490  sleepq_timeout(void *arg)
                 return;                  return;
         }          }
   
         sleepq_unsleep(arg);          sleepq_unsleep(l);
 }  }
   
 /*  /*
Line 514  sleepq_abort(kmutex_t *mtx, int unlock)
Line 539  sleepq_abort(kmutex_t *mtx, int unlock)
   
         return 0;          return 0;
 }  }
   
   /*
    * sleepq_changepri:
    *
    *      Adjust the priority of an LWP residing on a sleepq.
    */
   void
   sleepq_changepri(struct lwp *l, int pri)
   {
           sleepq_t *sq = l->l_sleepq;
   
           KASSERT(lwp_locked(l, sq->sq_mutex));
   
           TAILQ_REMOVE(&sq->sq_queue, l, l_sleepchain);
           sleepq_insert(sq, l, pri, l->l_syncobj);
   }

Legend:
Removed from v.1.1.2.4  
changed lines
  Added in v.1.1.2.5

CVSweb <webmaster@jp.NetBSD.org>