svn commit: r279282 - head/sys/kern
Konstantin Belousov
kib at FreeBSD.org
Wed Feb 25 16:12:57 UTC 2015
Author: kib
Date: Wed Feb 25 16:12:56 2015
New Revision: 279282
URL: https://svnweb.freebsd.org/changeset/base/279282
Log:
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 at dell.com>
with advice from: Elliott Rabe and Jim Muchow, also at Dell Inc.
Obtained from: Dell Inc.
PR: 198914
Modified:
head/sys/kern/kern_umtx.c
Modified: head/sys/kern/kern_umtx.c
==============================================================================
--- head/sys/kern/kern_umtx.c Wed Feb 25 13:58:43 2015 (r279281)
+++ head/sys/kern/kern_umtx.c Wed Feb 25 16:12:56 2015 (r279282)
@@ -1445,6 +1445,19 @@ umtx_pi_setowner(struct umtx_pi *pi, str
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 u
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 u
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);
More information about the svn-src-head
mailing list