--- //depot/projects/smpng/sys/kern/kern_mutex.c 2004/09/03 14:14:21 +++ //depot/user/jhb/lock/kern/kern_mutex.c 2004/09/10 21:27:32 @@ -423,7 +431,6 @@ _mtx_lock_sleep(struct mtx *m, struct thread *td, int opts, const char *file, int line) { - struct turnstile *ts; #if defined(SMP) && !defined(NO_ADAPTIVE_MUTEXES) struct thread *owner; #endif @@ -459,7 +466,7 @@ contested = 1; atomic_add_int(&m->mtx_contest_holding, 1); #endif - ts = turnstile_lookup(&m->mtx_object); + turnstile_lock(&m->mtx_object); v = m->mtx_lock; /* @@ -482,9 +489,8 @@ * necessary. */ if (v == MTX_CONTESTED) { - MPASS(ts != NULL); m->mtx_lock = (uintptr_t)td | MTX_CONTESTED; - turnstile_claim(ts); + turnstile_claim(&m->mtx_object); break; } #endif @@ -540,7 +546,7 @@ /* * Block on the turnstile. */ - turnstile_wait(ts, &m->mtx_object, mtx_owner(m)); + turnstile_wait(&m->mtx_object, mtx_owner(m)); } #ifdef KTR @@ -630,6 +636,7 @@ return; } + turnstile_lock(&m->mtx_object); ts = turnstile_lookup(&m->mtx_object); if (LOCK_LOG_TEST(&m->mtx_object, opts)) CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p contested", m); --- //depot/projects/smpng/sys/kern/subr_turnstile.c 2004/09/03 14:14:21 +++ //depot/user/jhb/lock/kern/subr_turnstile.c 2004/09/10 21:27:32 @@ -397,6 +417,18 @@ } /* + * Lock the turnstile chain associated with the specified lock. + */ +void +turnstile_lock(struct lock_object *lock) +{ + struct turnstile_chain *tc; + + tc = TC_LOOKUP(lock); + mtx_lock_spin(&tc->tc_lock); +} + +/* * Look up the turnstile for a lock in the hash table locking the associated * turnstile chain along the way. Return with the turnstile chain locked. * If no turnstile is found in the hash table, NULL is returned. @@ -408,7 +440,7 @@ struct turnstile *ts; tc = TC_LOOKUP(lock); - mtx_lock_spin(&tc->tc_lock); + mtx_assert(&tc->tc_lock, MA_OWNED); LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash) if (ts->ts_lockobj == lock) return (ts); @@ -432,13 +464,16 @@ * owner appropriately. */ void -turnstile_claim(struct turnstile *ts) +turnstile_claim(struct lock_object *lock) { struct turnstile_chain *tc; + struct turnstile *ts; struct thread *td, *owner; - tc = TC_LOOKUP(ts->ts_lockobj); + tc = TC_LOOKUP(lock); mtx_assert(&tc->tc_lock, MA_OWNED); + ts = turnstile_lookup(lock); + MPASS(ts != NULL); owner = curthread; mtx_lock_spin(&td_contested_lock); @@ -460,16 +495,16 @@ } /* - * Block the current thread on the turnstile ts. This function will context - * switch and not return until this thread has been woken back up. This - * function must be called with the appropriate turnstile chain locked and - * will return with it unlocked. + * Block the current thread on the turnstile assicated with 'lock'. This + * function will context switch and not return until this thread has been + * woken back up. This function must be called with the appropriate + * turnstile chain locked and will return with it unlocked. */ void -turnstile_wait(struct turnstile *ts, struct lock_object *lock, - struct thread *owner) +turnstile_wait(struct lock_object *lock, struct thread *owner) { struct turnstile_chain *tc; + struct turnstile *ts; struct thread *td, *td1; td = curthread; @@ -479,7 +514,14 @@ MPASS(owner != NULL); MPASS(owner->td_proc->p_magic == P_MAGIC); - /* If the passed in turnstile is NULL, use this thread's turnstile. */ + /* Look up the turnstile associated with the lock 'lock'. */ + ts = turnstile_lookup(lock); + + /* + * If the lock does not already have a turnstile, use this thread's + * turnstile. Otherwise insert the current thread into the + * turnstile already in use by this lock. + */ if (ts == NULL) { #ifdef TURNSTILE_PROFILING tc->tc_depth++; --- //depot/projects/smpng/sys/sys/turnstile.h 2004/04/16 18:42:25 +++ //depot/user/jhb/lock/sys/turnstile.h 2004/09/03 13:50:28 @@ -36,20 +36,21 @@ * Turnstile interface. Non-sleepable locks use a turnstile for the * queue of threads blocked on them when they are contested. * - * A thread calls turnstile_lookup() to look up the proper turnstile in - * the hash table. This function returns a pointer to the turnstile and - * locks the associated turnstile chain. A thread calls turnstile_wait() - * when the lock is contested to be put on the queue and block. If a - * thread needs to retry a lock operation instead of blocking, it should - * call turnstile_release() to unlock the associated turnstile chain 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 + * contested to be put on the queue and block. If a thread needs to retry + * a lock operation instead of blocking, it should call turnstile_release() + * to unlock the associated turnstile chain lock. * - * When a lock is released, either turnstile_signal() or turnstile_broadcast() - * is called to mark blocked threads for a pending wakeup. - * turnstile_signal() marks the highest priority blocked thread while - * turnstile_broadcast() marks all 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 wakeup the pending thread(s). + * When a lock is released, the thread calls turnstile_lookup() to loop + * up the turnstile associated with the given lock in the hash table. Then + * it calls either turnstile_signal() or turnstile_broadcast() to mark + * blocked threads for a pending wakeup. turnstile_signal() marks the + * highest priority blocked thread while turnstile_broadcast() marks all + * 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). * * 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 @@ -75,16 +76,16 @@ void init_turnstiles(void); struct turnstile *turnstile_alloc(void); void turnstile_broadcast(struct turnstile *); -void turnstile_claim(struct turnstile *); +void turnstile_claim(struct lock_object *); int turnstile_empty(struct turnstile *); void turnstile_free(struct turnstile *); struct thread *turnstile_head(struct turnstile *); +void turnstile_lock(struct lock_object *); struct turnstile *turnstile_lookup(struct lock_object *); void turnstile_release(struct lock_object *); int turnstile_signal(struct turnstile *); void turnstile_unpend(struct turnstile *); -void turnstile_wait(struct turnstile *, struct lock_object *, - struct thread *); +void turnstile_wait(struct lock_object *, struct thread *); #endif /* _KERNEL */ #endif /* _SYS_TURNSTILE_H_ */