MFC some comment updates to account for multi-queue support missed earlier

as well as a few other changes (whitespace, style, etc.) to reduce diffs
with HEAD.
This commit is contained in:
jhb 2007-09-27 18:44:16 +00:00
parent bf60b344e1
commit 1248dc42fa
2 changed files with 55 additions and 47 deletions

View File

@ -104,8 +104,9 @@ __FBSDID("$FreeBSD$");
* when it is attached to a lock. The second list to use ts_hash is the
* free list hung off of a turnstile that is attached to a lock.
*
* Each turnstile contains two lists of threads. The ts_blocked list is
* a linked list of threads blocked on the turnstile's lock. The
* Each turnstile contains three lists of threads. The two ts_blocked lists
* are linked list of threads blocked on the turnstile's lock. One list is
* for exclusive waiters, and the other is for shared waiters. The
* ts_pending list is a linked list of threads previously awakened by
* turnstile_signal() or turnstile_wait() that are waiting to be put on
* the run queue.
@ -115,9 +116,8 @@ __FBSDID("$FreeBSD$");
* q - td_contested lock
*/
struct turnstile {
/* struct mtx ts_lock; */ /* Spin lock for self. */
TAILQ_HEAD(, thread) ts_blocked[2]; /* (c + q) Blocked threads. */
TAILQ_HEAD(, thread) ts_pending; /* (c) Pending threads. */
struct threadqueue ts_blocked[2]; /* (c + q) Blocked threads. */
struct threadqueue ts_pending; /* (c) Pending threads. */
LIST_ENTRY(turnstile) ts_hash; /* (c) Chain and free list. */
LIST_ENTRY(turnstile) ts_link; /* (q) Contested locks. */
LIST_HEAD(, turnstile) ts_free; /* (c) Free turnstiles. */
@ -156,6 +156,7 @@ static void init_turnstile_profiling(void *arg);
static void propagate_priority(struct thread *td);
static int turnstile_adjust_thread(struct turnstile *ts,
struct thread *td);
static struct thread *turnstile_first_waiter(struct turnstile *ts);
static void turnstile_setowner(struct turnstile *ts, struct thread *owner);
#ifdef INVARIANTS
static void turnstile_dtor(void *mem, int size, void *arg);
@ -182,9 +183,8 @@ propagate_priority(struct thread *td)
if (td == NULL) {
/*
* This really isn't quite right. Really
* ought to bump priority of thread that
* next acquires the lock.
* This might be a read lock with no owner. There's
* not much we can do, so just bail.
*/
return;
}
@ -447,6 +447,8 @@ turnstile_setowner(struct turnstile *ts, struct thread *owner)
mtx_assert(&td_contested_lock, MA_OWNED);
MPASS(ts->ts_owner == NULL);
/* A shared lock might not have an owner. */
if (owner == NULL)
return;
@ -667,10 +669,10 @@ turnstile_wait_queue(struct lock_object *lock, struct thread *owner, int queue)
TAILQ_INSERT_BEFORE(td1, td, td_lockq);
else
TAILQ_INSERT_TAIL(&ts->ts_blocked[queue], td, td_lockq);
MPASS(owner == ts->ts_owner);
mtx_unlock_spin(&td_contested_lock);
MPASS(td->td_turnstile != NULL);
LIST_INSERT_HEAD(&ts->ts_free, td->td_turnstile, ts_hash);
MPASS(owner == ts->ts_owner);
}
td->td_turnstile = NULL;
mtx_unlock_spin(&tc->tc_lock);
@ -739,10 +741,10 @@ turnstile_signal_queue(struct turnstile *ts, int queue)
MPASS(ts != NULL);
MPASS(curthread->td_proc->p_magic == P_MAGIC);
tc = TC_LOOKUP(ts->ts_lockobj);
mtx_assert(&tc->tc_lock, MA_OWNED);
MPASS(ts->ts_owner == curthread ||
(queue == TS_EXCLUSIVE_QUEUE && ts->ts_owner == NULL));
tc = TC_LOOKUP(ts->ts_lockobj);
mtx_assert(&tc->tc_lock, MA_OWNED);
MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
/*
@ -791,7 +793,7 @@ turnstile_broadcast_queue(struct turnstile *ts, int queue)
MPASS(ts != NULL);
MPASS(curthread->td_proc->p_magic == P_MAGIC);
MPASS(ts->ts_owner == curthread ||
(queue == TS_EXCLUSIVE_QUEUE && ts->ts_owner == NULL));
(queue == TS_EXCLUSIVE_QUEUE && ts->ts_owner == NULL));
tc = TC_LOOKUP(ts->ts_lockobj);
mtx_assert(&tc->tc_lock, MA_OWNED);
MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
@ -805,7 +807,7 @@ turnstile_broadcast_queue(struct turnstile *ts, int queue)
/*
* Give a turnstile to each thread. The last thread gets
* this turnstile.
* this turnstile if the turnstile is empty.
*/
TAILQ_FOREACH(td, &ts->ts_pending, td_lockq) {
if (LIST_EMPTY(&ts->ts_free)) {
@ -832,7 +834,6 @@ turnstile_unpend_queue(struct turnstile *ts, int owner_type)
{
TAILQ_HEAD( ,thread) pending_threads;
struct turnstile_chain *tc;
struct turnstile *nts;
struct thread *td;
u_char cp, pri;
@ -880,8 +881,8 @@ turnstile_unpend_queue(struct turnstile *ts, int owner_type)
pri = PRI_MAX;
mtx_lock_spin(&sched_lock);
mtx_lock_spin(&td_contested_lock);
LIST_FOREACH(nts, &td->td_contested, ts_link) {
cp = turnstile_first_waiter(nts)->td_priority;
LIST_FOREACH(ts, &td->td_contested, ts_link) {
cp = turnstile_first_waiter(ts)->td_priority;
if (cp < pri)
pri = cp;
}
@ -976,13 +977,30 @@ turnstile_head_queue(struct turnstile *ts, int queue)
struct turnstile_chain *tc;
MPASS(ts != NULL);
tc = TC_LOOKUP(ts->ts_lockobj);
MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
tc = TC_LOOKUP(ts->ts_lockobj);
mtx_assert(&tc->tc_lock, MA_OWNED);
#endif
return (TAILQ_FIRST(&ts->ts_blocked[queue]));
}
/*
* Returns true if a sub-queue of a turnstile is empty.
*/
int
turnstile_empty_queue(struct turnstile *ts, int queue)
{
#ifdef INVARIANTS
struct turnstile_chain *tc;
MPASS(ts != NULL);
MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
tc = TC_LOOKUP(ts->ts_lockobj);
mtx_assert(&tc->tc_lock, MA_OWNED);
#endif
return (TAILQ_EMPTY(&ts->ts_blocked[queue]));
}
#ifdef DDB
static int db_pager_quit;
@ -1051,10 +1069,11 @@ DB_SHOW_COMMAND(turnstile, db_show_turnstile)
print_thread(ts->ts_owner, "Lock Owner: ");
else
db_printf("Lock Owner: none\n");
print_queue((struct threadqueue *)&ts->ts_blocked[TS_SHARED_QUEUE], "Shared Waiters", "\t");
print_queue((struct threadqueue *)&ts->ts_blocked[TS_EXCLUSIVE_QUEUE], "Exclusive Waiters", "\t");
print_queue((struct threadqueue *)&ts->ts_pending, "Pending Threads",
"\t");
print_queue(&ts->ts_blocked[TS_SHARED_QUEUE], "Shared Waiters", "\t");
print_queue(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE], "Exclusive Waiters",
"\t");
print_queue(&ts->ts_pending, "Pending Threads", "\t");
}
/*
@ -1276,20 +1295,3 @@ DB_SHOW_COMMAND(locktree, db_show_locktree)
print_waiters(ts, 0);
}
#endif
/*
* Returns true if a turnstile is empty.
*/
int
turnstile_empty_queue(struct turnstile *ts, int queue)
{
#ifdef INVARIANTS
struct turnstile_chain *tc;
MPASS(ts != NULL);
tc = TC_LOOKUP(ts->ts_lockobj);
mtx_assert(&tc->tc_lock, MA_OWNED);
MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
#endif
return (TAILQ_EMPTY(&ts->ts_blocked[queue]));
}

View File

@ -34,7 +34,10 @@
/*
* Turnstile interface. Non-sleepable locks use a turnstile for the
* queue of threads blocked on them when they are contested.
* queue of threads blocked on them when they are contested. Each
* turnstile contains two sub-queues: one for threads waiting for a
* shared, or eread, lock, and one for threads waiting for an
* exclusive, or write, lock.
*
* A thread calls turnstile_lock() to lock the turnstile chain associated
* with a given lock. A thread calls turnstile_wait() when the lock is
@ -50,7 +53,10 @@
* blocked threads. The turnstile_signal() function returns true if the
* turnstile became empty as a result. After the higher level code finishes
* releasing the lock, turnstile_unpend() must be called to wake up the
* pending thread(s).
* pending thread(s) and give up ownership of the turnstile.
*
* Alternatively, if a thread wishes to relinquish ownership of a thread
* without waking up any waiters, it may call turnstile_disown().
*
* When a lock is acquired that already has at least one thread contested
* on it, the new owner of the lock must claim ownership of the turnstile
@ -62,9 +68,9 @@
* released at thread destruction may not be the same turnstile that the
* thread allocated when it was created.
*
* A function can query a turnstile to see if it is empty via
* turnstile_empty(). The highest priority thread blocked on a turnstile
* can be obtained via turnstile_head().
* The highest priority thread blocked on a specified queue of a
* turnstile can be obtained via turnstile_head(). A given queue can
* also be queried to see if it is empty via turnstile_empty().
*/
struct lock_object;
@ -74,12 +80,12 @@ struct turnstile;
#ifdef _KERNEL
/* Which queue to block on or which queue to wakeup one or more threads from. */
#define TS_EXCLUSIVE_QUEUE 0
#define TS_SHARED_QUEUE 1
#define TS_EXCLUSIVE_QUEUE 0
#define TS_SHARED_QUEUE 1
/* The type of lock currently held. */
#define TS_EXCLUSIVE_LOCK TS_EXCLUSIVE_QUEUE
#define TS_SHARED_LOCK TS_SHARED_QUEUE
#define TS_EXCLUSIVE_LOCK TS_EXCLUSIVE_QUEUE
#define TS_SHARED_LOCK TS_SHARED_QUEUE
void init_turnstiles(void);
void turnstile_adjust(struct thread *, u_char);