Index: kern_umtx.c =================================================================== --- kern_umtx.c (版本 189550) +++ kern_umtx.c (工作副本) @@ -166,6 +166,7 @@ }; #define UMTXQ_LOCKED_ASSERT(uc) mtx_assert(&(uc)->uc_lock, MA_OWNED) +#define UMTXQ_BUSY_ASSERT(uc) KASSERT(&(uc)->uc_busy, ("umtx chain is not busy")) /* * Don't propagate time-sharing priority, there is a security reason, @@ -461,22 +462,7 @@ return (ret); } - /* - * Wake up specified thread. - */ -static inline void -umtxq_signal_thread(struct umtx_q *uq) -{ - struct umtxq_chain *uc; - - uc = umtxq_getchain(&uq->uq_key); - UMTXQ_LOCKED_ASSERT(uc); - umtxq_remove(uq); - wakeup(uq); -} - -/* * Put thread into sleep state, before sleeping, check if * thread was removed from umtx queue. */ @@ -1392,7 +1378,8 @@ oldpri = pi->pi_owner->td_user_pri; sched_unlend_user_prio(pi->pi_owner, pri); thread_unlock(pi->pi_owner); - umtx_pi_adjust_locked(pi->pi_owner, oldpri); + if (uq_owner->uq_pi_blocked != NULL) + umtx_pi_adjust_locked(pi->pi_owner, oldpri); pi = uq_owner->uq_pi_blocked; } } @@ -1513,6 +1500,7 @@ KASSERT(td == curthread, ("inconsistent uq_thread")); uc = umtxq_getchain(&uq->uq_key); UMTXQ_LOCKED_ASSERT(uc); + UMTXQ_BUSY_ASSERT(uc); umtxq_insert(uq); if (pi->pi_owner == NULL) { /* XXX @@ -1532,9 +1520,12 @@ umtx_pi_setowner(pi, td1); } PROC_UNLOCK(curproc); + umtxq_unbusy(&uq->uq_key); } else { mtx_lock_spin(&umtx_lock); + umtxq_unbusy(&uq->uq_key); } + umtxq_unlock(&uq->uq_key); TAILQ_FOREACH(uq1, &pi->pi_blocked, uq_lockq) { pri = UPRI(uq1->uq_thread); @@ -1551,10 +1542,6 @@ thread_lock(td); td->td_flags |= TDF_UPIBLOCKED; thread_unlock(td); - mtx_unlock_spin(&umtx_lock); - umtxq_unlock(&uq->uq_key); - - mtx_lock_spin(&umtx_lock); umtx_propagate_priority(td); mtx_unlock_spin(&umtx_lock); @@ -1569,9 +1556,9 @@ umtxq_unbusy(&uq->uq_key); } } + mtx_lock_spin(&umtx_lock); umtxq_unlock(&uq->uq_key); - mtx_lock_spin(&umtx_lock); uq->uq_pi_blocked = NULL; thread_lock(td); td->td_flags &= ~TDF_UPIBLOCKED; @@ -1580,8 +1567,6 @@ umtx_unpropagate_priority(pi); mtx_unlock_spin(&umtx_lock); - umtxq_lock(&uq->uq_key); - return (error); } @@ -1606,7 +1591,6 @@ umtx_pi_unref(struct umtx_pi *pi) { struct umtxq_chain *uc; - int free = 0; uc = umtxq_getchain(&pi->pi_key); UMTXQ_LOCKED_ASSERT(uc); @@ -1622,10 +1606,8 @@ ("blocked queue not empty")); mtx_unlock_spin(&umtx_lock); TAILQ_REMOVE(&uc->uc_pi_list, pi, pi_hashlink); - free = 1; - } - if (free) umtx_pi_free(pi); + } } /* @@ -1686,7 +1668,6 @@ if (new_pi == NULL) { umtxq_unlock(&uq->uq_key); new_pi = umtx_pi_alloc(M_WAITOK); - new_pi->pi_key = uq->uq_key; umtxq_lock(&uq->uq_key); pi = umtx_pi_lookup(&uq->uq_key); if (pi != NULL) { @@ -1732,7 +1713,9 @@ if (owner == UMUTEX_CONTESTED) { umtxq_lock(&uq->uq_key); + umtxq_busy(&uq->uq_key); error = umtx_pi_claim(pi, td); + umtxq_unbusy(&uq->uq_key); umtxq_unlock(&uq->uq_key); break; } @@ -1787,7 +1770,6 @@ } umtxq_lock(&uq->uq_key); - umtxq_unbusy(&uq->uq_key); /* * We set the contested bit, sleep. Otherwise the lock changed * and we need to retry or we lost a race to the thread @@ -1796,7 +1778,10 @@ if (old == owner) error = umtxq_sleep_pi(uq, pi, owner & ~UMUTEX_CONTESTED, "umtxpi", timo); - umtxq_unlock(&uq->uq_key); + else { + umtxq_unbusy(&uq->uq_key); + umtxq_unlock(&uq->uq_key); + } } umtxq_lock(&uq->uq_key); @@ -1851,18 +1836,18 @@ umtxq_busy(&key); count = umtxq_count_pi(&key, &uq_first); if (uq_first != NULL) { + mtx_lock_spin(&umtx_lock); pi = uq_first->uq_pi_blocked; if (pi->pi_owner != curthread) { + mtx_unlock_spin(&umtx_lock); umtxq_unbusy(&key); umtxq_unlock(&key); /* userland messed the mutex */ return (EPERM); } uq_me = curthread->td_umtxq; - mtx_lock_spin(&umtx_lock); pi->pi_owner = NULL; TAILQ_REMOVE(&uq_me->uq_pi_contested, pi, pi_link); - uq_first = TAILQ_FIRST(&pi->pi_blocked); pri = PRI_MAX; TAILQ_FOREACH(pi2, &uq_me->uq_pi_contested, pi_link) { uq_first2 = TAILQ_FIRST(&pi2->pi_blocked); @@ -1887,8 +1872,7 @@ count <= 1 ? UMUTEX_UNOWNED : UMUTEX_CONTESTED); umtxq_lock(&key); - if (uq_first != NULL) - umtxq_signal_thread(uq_first); + umtxq_signal(&key, 1); umtxq_unbusy(&key); umtxq_unlock(&key); umtx_key_release(&key);