summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_turnstile.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2003-11-12 23:48:42 +0000
committerjhb <jhb@FreeBSD.org>2003-11-12 23:48:42 +0000
commit989e0408dd51d21255e54cb9fcf2da8c629d743d (patch)
treedf0be5a333993aa24967ff68fee8beefc655e3ee /sys/kern/subr_turnstile.c
parent7c6af783e54f3321bf9cebdec99b32f1088f21ff (diff)
downloadFreeBSD-src-989e0408dd51d21255e54cb9fcf2da8c629d743d.zip
FreeBSD-src-989e0408dd51d21255e54cb9fcf2da8c629d743d.tar.gz
- Close a race where a thread on another CPU could release a contested lock
and empty its turnstile while the blocking threads still pointed to the turnstile. If the thread on the first CPU blocked on a lock owned by one of the threads blocked on the turnstile just woken up, then the first CPU could try to manipulate a bogus thread queue in the turnstile during priority propagation. - Update locking notes for ts_owner and always clear ts_owner, not just under INVARIANTS. Tested by: sam (1)
Diffstat (limited to 'sys/kern/subr_turnstile.c')
-rw-r--r--sys/kern/subr_turnstile.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/sys/kern/subr_turnstile.c b/sys/kern/subr_turnstile.c
index 4596960..8f8de89 100644
--- a/sys/kern/subr_turnstile.c
+++ b/sys/kern/subr_turnstile.c
@@ -115,7 +115,7 @@ struct turnstile {
LIST_ENTRY(turnstile) ts_link; /* (q) Contested locks. */
LIST_HEAD(, turnstile) ts_free; /* (c) Free turnstiles. */
struct lock_object *ts_lockobj; /* (c) Lock we reference. */
- struct thread *ts_owner; /* (q) Who owns the lock. */
+ struct thread *ts_owner; /* (c + q) Who owns the lock. */
};
struct turnstile_chain {
@@ -233,6 +233,16 @@ propagate_priority(struct thread *td)
mtx_lock_spin(&tc->tc_lock);
/*
+ * If this turnstile has no threads on its blocked queue
+ * then it's possible that it was just woken up on another
+ * CPU. If so, we are done.
+ */
+ if (TAILQ_EMPTY(&ts->ts_blocked)) {
+ mtx_unlock_spin(&tc->tc_lock);
+ return;
+ }
+
+ /*
* Check if the thread needs to be moved up on
* the blocked chain. It doesn't need to be moved
* if it is already at the head of the list or if
@@ -594,7 +604,7 @@ turnstile_wakeup(struct turnstile *ts)
td->td_turnstile = ts1;
}
}
-
+
/*
* Wakeup all threads on the pending list and adjust the priority of the
* current thread appropriately. This must be called with the turnstile
@@ -632,9 +642,7 @@ turnstile_unpend(struct turnstile *ts)
* owner.
*/
mtx_lock_spin(&td_contested_lock);
-#ifdef INVARIANTS
ts->ts_owner = NULL;
-#endif
LIST_REMOVE(ts, ts_link);
mtx_unlock_spin(&td_contested_lock);
mtx_unlock_spin(&tc->tc_lock);
OpenPOWER on IntegriCloud