Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 25 Feb 2015 16:12:57 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r279282 - head/sys/kern
Message-ID:  <201502251612.t1PGCvvQ086369@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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@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);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201502251612.t1PGCvvQ086369>