[BACK]Return to mutex.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / sync

Diff for /prex-old/sys/sync/mutex.c between version 1.1.1.1 and 1.1.1.1.2.1

version 1.1.1.1, 2008/06/03 10:38:46 version 1.1.1.1.2.1, 2008/08/13 17:12:33
Line 32 
Line 32 
  */   */
   
 /*  /*
  * A mutex is used to protect un-sharable resources.   * A mutex is used to protect un-sharable resources. A thread
  * A thread can use mutex_lock() to ensure that global resource is not   * can use mutex_lock() to ensure that global resource is not
  * accessed by other thread. The mutex is effective only the threads   * accessed by other thread. The mutex is effective only the
  * belonging to the same task.   * threads belonging to the same task.
  *   *
  * Prex will change the thread priority to prevent priority inversion.   * Prex will change the thread priority to prevent priority inversion.
  *   *
  * <Priority inheritance>   * <Priority inheritance>
  *   The priority is changed at the following conditions.   *   The priority is changed at the following conditions.
  *   *
  *   1. When the current thread can not lock the mutex and its mutex   *   1. When the current thread can not lock the mutex and its
  *      owner has lower priority than current thread, the priority   *      mutex owner has lower priority than current thread, the
  *      of mutex owner is boosted to same priority with current thread.   *      priority of mutex owner is boosted to same priority with
  *      If this mutex owner is waiting for another mutex, such related   *      current thread.  If this mutex owner is waiting for another
  *      mutexes are also processed.   *      mutex, such related mutexes are also processed.
  *   *
  *   2. When the current thread unlocks the mutex and its priority   *   2. When the current thread unlocks the mutex and its priority
  *      has already been inherited, the current priority is reset.   *      has already been inherited, the current priority is reset.
Line 66 
Line 66 
  *   *
  *   2. Even if thread is killed with mutex waiting, the related   *   2. Even if thread is killed with mutex waiting, the related
  *      priority is not adjusted.   *      priority is not adjusted.
  *  
  * <Important>  
  *  Since this implementation does not support recursive lock, a thread  
  *  can not lock the same mutex twice.  
  */   */
   
 #include <kernel.h>  #include <kernel.h>
Line 84 
Line 80 
 #define MAXINHERIT      10  #define MAXINHERIT      10
   
 /* forward declarations */  /* forward declarations */
 static int prio_inherit(thread_t th);  static int      prio_inherit(thread_t th);
 static void prio_uninherit(thread_t th);  static void     prio_uninherit(thread_t th);
   
 /*  /*
  * Initialize a mutex.   * Initialize a mutex.
  *   *
  * If an initialized mutex is reinitialized, undefined behavior   * If an initialized mutex is reinitialized, undefined
  * results. Technically, we can not detect such error condition   * behavior results. Technically, we can not detect such
  * here because we can not touch the passed object in kernel.   * error condition here because we can not touch the passed
    * object in kernel.
  */   */
 int  int
 mutex_init(mutex_t *mtx)  mutex_init(mutex_t *mtx)
Line 128 
Line 125 
         sched_lock();          sched_lock();
         if (umem_copyin(mtx, &m, sizeof(mutex_t))) {          if (umem_copyin(mtx, &m, sizeof(mutex_t))) {
                 err = EFAULT;                  err = EFAULT;
         } else if (!mutex_valid(m)) {                  goto out;
           }
           if (!mutex_valid(m)) {
                 err = EINVAL;                  err = EINVAL;
         } else if (m->owner || event_waiting(&m->event)) {                  goto out;
           }
           if (m->owner || event_waiting(&m->event)) {
                 err = EBUSY;                  err = EBUSY;
         } else {                  goto out;
                 m->magic = 0;  
                 kmem_free(m);  
         }          }
   
           m->magic = 0;
           kmem_free(m);
    out:
         sched_unlock();          sched_unlock();
         ASSERT(err == 0);          ASSERT(err == 0);
         return err;          return err;
Line 144 
Line 147 
 /*  /*
  * Copy mutex from user space.   * Copy mutex from user space.
  * If it is not initialized, create new mutex.   * If it is not initialized, create new mutex.
  * @umtx: pointer to mutex in user space.  
  * @kmtx: pointer to mutex in kernel space.  
  */   */
 static int  static int
 mutex_copyin(mutex_t *umtx, mutex_t *kmtx)  mutex_copyin(mutex_t *umtx, mutex_t *kmtx)
Line 158 
Line 159 
   
         if (m == MUTEX_INITIALIZER) {          if (m == MUTEX_INITIALIZER) {
                 /*                  /*
                  * Allocate mutex.                   * Allocate new mutex, and retreive its id
                    * from the user space.
                  */                   */
                 if ((err = mutex_init(umtx)))                  if ((err = mutex_init(umtx)))
                         return err;                          return err;
Line 174 
Line 176 
 /*  /*
  * Lock a mutex.   * Lock a mutex.
  *   *
  * A current thread is blocked if the mutex has already been locked.   * A current thread is blocked if the mutex has already been
  * If current thread receives any exception while waiting mutex, this   * locked. If current thread receives any exception while
  * routine returns with EINTR in order to invoke exception handler.   * waiting mutex, this routine returns with EINTR in order to
  * But, POSIX thread assumes this function does NOT return with EINTR.   * invoke exception handler. But, POSIX thread assumes this
  * So, system call stub routine in library must call this again if   * function does NOT return with EINTR.  So, system call stub
  * it gets EINTR.   * routine in library must call this again if it gets EINTR.
  */   */
 int  int
 mutex_lock(mutex_t *mtx)  mutex_lock(mutex_t *mtx)
Line 195 
Line 197 
                 /*                  /*
                  * Recursive lock                   * Recursive lock
                  */                   */
                 m->lock_count++;                  m->locks++;
                   ASSERT(m->locks != 0);
         } else {          } else {
                 /*                  /*
                  * Check whether a target mutex is locked.                   * Check whether a target mutex is locked.
Line 220 
Line 223 
                                 goto out;                                  goto out;
                         }                          }
                 }                  }
                 m->lock_count = 1;                  m->locks = 1;
         }          }
         m->owner = cur_thread;          m->owner = cur_thread;
         list_insert(&cur_thread->mutexes, &m->link);          list_insert(&cur_thread->mutexes, &m->link);
Line 242 
Line 245 
         if ((err = mutex_copyin(mtx, &m)))          if ((err = mutex_copyin(mtx, &m)))
                 goto out;                  goto out;
         if (m->owner == cur_thread)          if (m->owner == cur_thread)
                 m->lock_count++;                  m->locks++;
         else {          else {
                 if (m->owner != NULL)                  if (m->owner != NULL)
                         err = EBUSY;                          err = EBUSY;
                 else {                  else {
                         m->lock_count = 1;                          m->locks = 1;
                         m->owner = cur_thread;                          m->owner = cur_thread;
                         list_insert(&cur_thread->mutexes, &m->link);                          list_insert(&cur_thread->mutexes, &m->link);
                 }                  }
Line 270 
Line 273 
         sched_lock();          sched_lock();
         if ((err = mutex_copyin(mtx, &m)))          if ((err = mutex_copyin(mtx, &m)))
                 goto out;                  goto out;
         if (m->owner != cur_thread || m->lock_count <= 0) {          if (m->owner != cur_thread || m->locks <= 0) {
                 err = EPERM;                  err = EPERM;
                 goto out;                  goto out;
         }          }
         if (--m->lock_count == 0) {          if (--m->locks == 0) {
                 list_remove(&m->link);                  list_remove(&m->link);
                 prio_uninherit(cur_thread);                  prio_uninherit(cur_thread);
                 /*                  /*
Line 296 
Line 299 
 /*  /*
  * Clean up mutex.   * Clean up mutex.
  *   *
  * This is called with scheduling locked when thread is terminated.   * This is called with scheduling locked when thread is
  * If a thread is terminated with mutex hold, all waiting threads   * terminated. If a thread is terminated with mutex hold, all
  * keeps waiting forever. So, all mutex locked by terminated thread   * waiting threads keeps waiting forever. So, all mutex locked by
  * must be unlocked. Even if the terminated thread is waiting some   * terminated thread must be unlocked. Even if the terminated
  * mutex, the inherited priority of other mutex owner is not adjusted.   * thread is waiting some mutex, the inherited priority of other
    * mutex owner is not adjusted.
  */   */
 void  void
 mutex_cleanup(thread_t th)  mutex_cleanup(thread_t th)
Line 318 
Line 322 
                  * Release locked mutex.                   * Release locked mutex.
                  */                   */
                 m = list_entry(list_first(head), struct mutex, link);                  m = list_entry(list_first(head), struct mutex, link);
                 m->lock_count = 0;                  m->locks = 0;
                 list_remove(&m->link);                  list_remove(&m->link);
                 /*                  /*
                  * Change the mutex owner if other thread                   * Change the mutex owner if other thread
Line 327 
Line 331 
                 owner = sched_wakeone(&m->event);                  owner = sched_wakeone(&m->event);
                 if (owner) {                  if (owner) {
                         owner->wait_mutex = NULL;                          owner->wait_mutex = NULL;
                         m->lock_count = 1;                          m->locks = 1;
                         list_insert(&owner->mutexes, &m->link);                          list_insert(&owner->mutexes, &m->link);
                 }                  }
                 m->owner = owner;                  m->owner = owner;
Line 347 
Line 351 
   
 /*  /*
  * Inherit priority.   * Inherit priority.
  * @waiter: thread that is about to wait a mutex.  
  *   *
  * To prevent priority inversion, we must ensure the higher priority   * To prevent priority inversion, we must ensure the higher
  * thread does not wait other lower priority thread. So, raise the   * priority thread does not wait other lower priority thread. So,
  * priority of mutex owner which blocks the "waiter" thread. If such   * raise the priority of mutex owner which blocks the "waiter"
  * mutex owner is also waiting for other mutex, that mutex is also   * thread. If such mutex owner is also waiting for other mutex,
  * processed.   * that mutex is also processed. Returns EDEALK if it finds
  * Returns EDEALK if it finds deadlock condition.   * deadlock condition.
  */   */
 static int  static int
 prio_inherit(thread_t waiter)  prio_inherit(thread_t waiter)
Line 371 
Line 374 
                  * causes a deadlock.                   * causes a deadlock.
                  */                   */
                 if (owner == waiter) {                  if (owner == waiter) {
                         printk("Deadlock! mutex=%x owner=%x waiter=%x\n",                          DPRINTF(("Deadlock! mutex=%x owner=%x waiter=%x\n",
                                m, owner, waiter);                                   m, owner, waiter));
                         return EDEADLK;                          return EDEADLK;
                 }                  }
                 /*                  /*
Line 381 
Line 384 
                  * owner's priority.                   * owner's priority.
                  */                   */
                 if (owner->prio > waiter->prio) {                  if (owner->prio > waiter->prio) {
                         sched_setprio(owner, owner->base_prio, waiter->prio);                          sched_setprio(owner, owner->baseprio, waiter->prio);
                         m->prio = waiter->prio;                          m->prio = waiter->prio;
                 }                  }
                 /*                  /*
Line 402 
Line 405 
 /*  /*
  * Un-inherit priority   * Un-inherit priority
  *   *
  * The priority of specified thread is reset to the base priority.   * The priority of specified thread is reset to the base
  * If specified thread locks other mutex and higher priority thread   * priority.  If specified thread locks other mutex and higher
  * is waiting for it, the priority is kept to that level.   * priority thread is waiting for it, the priority is kept to
    * that level.
  */   */
 static void  static void
 prio_uninherit(thread_t th)  prio_uninherit(thread_t th)
Line 414 
Line 418 
         mutex_t m;          mutex_t m;
   
         /* Check if the priority is inherited. */          /* Check if the priority is inherited. */
         if (th->prio == th->base_prio)          if (th->prio == th->baseprio)
                 return;                  return;
   
         top_prio = th->base_prio;          top_prio = th->baseprio;
         /*          /*
          * Find the highest priority thread that is waiting           * Find the highest priority thread that is waiting
          * for the thread. This is done by checking all mutexes           * for the thread. This is done by checking all mutexes
Line 429 
Line 433 
                 if (m->prio < top_prio)                  if (m->prio < top_prio)
                         top_prio = m->prio;                          top_prio = m->prio;
         }          }
         sched_setprio(th, th->base_prio, top_prio);          sched_setprio(th, th->baseprio, top_prio);
 }  }

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.1.2.1

CVSweb