summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2003-07-02 16:14:09 +0000
committerjhb <jhb@FreeBSD.org>2003-07-02 16:14:09 +0000
commit58598b39f8391903edf076ddb2ab3edbaf9b31bc (patch)
treebc1fddb51548caeb15727f95b183dcd1df563597
parent17958a749f60b50092d0ae5d6171bdc924cbed02 (diff)
downloadFreeBSD-src-58598b39f8391903edf076ddb2ab3edbaf9b31bc.zip
FreeBSD-src-58598b39f8391903edf076ddb2ab3edbaf9b31bc.tar.gz
- Add comments about the maintenance of the per-thread list of contested
locks held by each thread. - Fix a bug in the original BSD/OS code where a contested lock was not properly handed off from the old thread to the new thread when a contested lock with more than one blocked thread was transferred from one thread to another. - Don't use an atomic operation to write the MTX_CONTESTED value to mtx_lock in the aforementioned special case. The memory barriers and exclusion provided by sched_lock are sufficient. Spotted by: alc (2)
-rw-r--r--sys/kern/kern_mutex.c13
-rw-r--r--sys/kern/subr_turnstile.c13
2 files changed, 18 insertions, 8 deletions
diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c
index fb7b88f..18dcc7e 100644
--- a/sys/kern/kern_mutex.c
+++ b/sys/kern/kern_mutex.c
@@ -524,12 +524,15 @@ _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
/*
* The mutex was marked contested on release. This means that
- * there are threads blocked on it.
+ * there are other threads blocked on it. Grab ownership of
+ * it and propagate its priority to the current thread if
+ * necessary.
*/
if (v == MTX_CONTESTED) {
td1 = TAILQ_FIRST(&m->mtx_blocked);
MPASS(td1 != NULL);
m->mtx_lock = (uintptr_t)td | MTX_CONTESTED;
+ LIST_INSERT_HEAD(&td->td_contested, m, mtx_contested);
if (td1->td_priority < td->td_priority)
td->td_priority = td1->td_priority;
@@ -593,7 +596,9 @@ _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
#endif
/*
- * Put us on the list of threads blocked on this mutex.
+ * Put us on the list of threads blocked on this mutex
+ * and add this mutex to the owning thread's list of
+ * contested mutexes if needed.
*/
if (TAILQ_EMPTY(&m->mtx_blocked)) {
td1 = mtx_owner(m);
@@ -744,13 +749,13 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
TAILQ_REMOVE(&m->mtx_blocked, td1, td_lockq);
+ LIST_REMOVE(m, mtx_contested);
if (TAILQ_EMPTY(&m->mtx_blocked)) {
- LIST_REMOVE(m, mtx_contested);
_release_lock_quick(m);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p not held", m);
} else
- atomic_store_rel_ptr(&m->mtx_lock, (void *)MTX_CONTESTED);
+ m->mtx_lock = MTX_CONTESTED;
pri = PRI_MAX;
LIST_FOREACH(m1, &td->td_contested, mtx_contested) {
diff --git a/sys/kern/subr_turnstile.c b/sys/kern/subr_turnstile.c
index fb7b88f..18dcc7e 100644
--- a/sys/kern/subr_turnstile.c
+++ b/sys/kern/subr_turnstile.c
@@ -524,12 +524,15 @@ _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
/*
* The mutex was marked contested on release. This means that
- * there are threads blocked on it.
+ * there are other threads blocked on it. Grab ownership of
+ * it and propagate its priority to the current thread if
+ * necessary.
*/
if (v == MTX_CONTESTED) {
td1 = TAILQ_FIRST(&m->mtx_blocked);
MPASS(td1 != NULL);
m->mtx_lock = (uintptr_t)td | MTX_CONTESTED;
+ LIST_INSERT_HEAD(&td->td_contested, m, mtx_contested);
if (td1->td_priority < td->td_priority)
td->td_priority = td1->td_priority;
@@ -593,7 +596,9 @@ _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
#endif
/*
- * Put us on the list of threads blocked on this mutex.
+ * Put us on the list of threads blocked on this mutex
+ * and add this mutex to the owning thread's list of
+ * contested mutexes if needed.
*/
if (TAILQ_EMPTY(&m->mtx_blocked)) {
td1 = mtx_owner(m);
@@ -744,13 +749,13 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
TAILQ_REMOVE(&m->mtx_blocked, td1, td_lockq);
+ LIST_REMOVE(m, mtx_contested);
if (TAILQ_EMPTY(&m->mtx_blocked)) {
- LIST_REMOVE(m, mtx_contested);
_release_lock_quick(m);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p not held", m);
} else
- atomic_store_rel_ptr(&m->mtx_lock, (void *)MTX_CONTESTED);
+ m->mtx_lock = MTX_CONTESTED;
pri = PRI_MAX;
LIST_FOREACH(m1, &td->td_contested, mtx_contested) {
OpenPOWER on IntegriCloud