summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-03-04 09:29:25 +0000
committerkib <kib@FreeBSD.org>2015-03-04 09:29:25 +0000
commit17814a5b03ddffbc09f04c52fe17412399efcd2f (patch)
tree3568fa9932a6969185caea74d1c376c131d04cc7
parente28f1e3a99a10a7ff33771dad3d6adccaea8c93c (diff)
downloadFreeBSD-src-17814a5b03ddffbc09f04c52fe17412399efcd2f.zip
FreeBSD-src-17814a5b03ddffbc09f04c52fe17412399efcd2f.tar.gz
MFC r279282:
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.
-rw-r--r--sys/kern/kern_umtx.c35
1 files changed, 33 insertions, 2 deletions
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
index e59fe7e..c5f90e0 100644
--- a/sys/kern/kern_umtx.c
+++ b/sys/kern/kern_umtx.c
@@ -1810,6 +1810,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.
*/
@@ -2226,8 +2239,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 &&
@@ -2248,6 +2260,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);
OpenPOWER on IntegriCloud