When unlocking a contested PI pthread mutex, if the queue of waiters
is empty, look up the umtx_pi and disown it if the current thread owns it. This can happen if a signal or timeout removed the last waiter from the queue, but there is still a thread in do_lock_pi() holding a reference on the umtx_pi. The unlocking thread might not own the umtx_pi in this case, but if it does, it must disown it to keep the ownership consistent between the umtx_pi and the umutex. Submitted by: Eric van Gyzen <eric_van_gyzen@dell.com> with advice from: Elliott Rabe and Jim Muchow, also at Dell Inc. Obtained from: Dell Inc. PR: 198914
This commit is contained in:
parent
9c0f6aa762
commit
cc876d2c5c
@ -1445,6 +1445,19 @@ umtx_pi_setowner(struct umtx_pi *pi, struct thread *owner)
|
||||
TAILQ_INSERT_TAIL(&uq_owner->uq_pi_contested, pi, pi_link);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Disown a PI mutex, and remove it from the owned list.
|
||||
*/
|
||||
static void
|
||||
umtx_pi_disown(struct umtx_pi *pi)
|
||||
{
|
||||
|
||||
mtx_assert(&umtx_lock, MA_OWNED);
|
||||
TAILQ_REMOVE(&pi->pi_owner->td_umtxq->uq_pi_contested, pi, pi_link);
|
||||
pi->pi_owner = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Claim ownership of a PI mutex.
|
||||
*/
|
||||
@ -1861,8 +1874,7 @@ do_unlock_pi(struct thread *td, struct umutex *m, uint32_t flags)
|
||||
return (EPERM);
|
||||
}
|
||||
uq_me = curthread->td_umtxq;
|
||||
pi->pi_owner = NULL;
|
||||
TAILQ_REMOVE(&uq_me->uq_pi_contested, pi, pi_link);
|
||||
umtx_pi_disown(pi);
|
||||
/* get highest priority thread which is still sleeping. */
|
||||
uq_first = TAILQ_FIRST(&pi->pi_blocked);
|
||||
while (uq_first != NULL &&
|
||||
@ -1883,6 +1895,25 @@ do_unlock_pi(struct thread *td, struct umutex *m, uint32_t flags)
|
||||
mtx_unlock_spin(&umtx_lock);
|
||||
if (uq_first)
|
||||
umtxq_signal_thread(uq_first);
|
||||
} else {
|
||||
pi = umtx_pi_lookup(&key);
|
||||
/*
|
||||
* A umtx_pi can exist if a signal or timeout removed the
|
||||
* last waiter from the umtxq, but there is still
|
||||
* a thread in do_lock_pi() holding the umtx_pi.
|
||||
*/
|
||||
if (pi != NULL) {
|
||||
/*
|
||||
* The umtx_pi can be unowned, such as when a thread
|
||||
* has just entered do_lock_pi(), allocated the
|
||||
* umtx_pi, and unlocked the umtxq.
|
||||
* If the current thread owns it, it must disown it.
|
||||
*/
|
||||
mtx_lock_spin(&umtx_lock);
|
||||
if (pi->pi_owner == td)
|
||||
umtx_pi_disown(pi);
|
||||
mtx_unlock_spin(&umtx_lock);
|
||||
}
|
||||
}
|
||||
umtxq_unlock(&key);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user