mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-18 10:35:55 +00:00
Fix the turnstile_lock() KPI.
turnstile_{lock,unlock}() were added for use in epoch. turnstile_lock() returned NULL to indicate that the calling thread had lost a race and the turnstile was no longer associated with the given lock, or the lock owner. However, reader-writer locks may not have a designated owner, in which case turnstile_lock() would return NULL and epoch_block_handler_preempt() would leak spinlocks as a result. Apply a minimal fix: return the lock owner as a separate return value. Reviewed by: kib MFC after: 3 days Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21048
This commit is contained in:
parent
ae5f2ca7b9
commit
2fb62b1a46
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=350310
@ -438,26 +438,20 @@ epoch_block_handler_preempt(struct ck_epoch *global __unused,
|
||||
*/
|
||||
critical_enter();
|
||||
thread_unlock(td);
|
||||
owner = turnstile_lock(ts, &lock);
|
||||
/*
|
||||
* The owner pointer indicates that the lock succeeded.
|
||||
* Only in case we hold the lock and the turnstile we
|
||||
* locked is still the one that curwaittd is blocked on
|
||||
* can we continue. Otherwise the turnstile pointer has
|
||||
* been changed out from underneath us, as in the case
|
||||
* where the lock holder has signalled curwaittd,
|
||||
* and we need to continue.
|
||||
*/
|
||||
if (owner != NULL && ts == curwaittd->td_blocked) {
|
||||
MPASS(TD_IS_INHIBITED(curwaittd) &&
|
||||
TD_ON_LOCK(curwaittd));
|
||||
critical_exit();
|
||||
turnstile_wait(ts, owner, curwaittd->td_tsqueue);
|
||||
counter_u64_add(turnstile_count, 1);
|
||||
thread_lock(td);
|
||||
return;
|
||||
} else if (owner != NULL)
|
||||
|
||||
if (turnstile_lock(ts, &lock, &owner)) {
|
||||
if (ts == curwaittd->td_blocked) {
|
||||
MPASS(TD_IS_INHIBITED(curwaittd) &&
|
||||
TD_ON_LOCK(curwaittd));
|
||||
critical_exit();
|
||||
turnstile_wait(ts, owner,
|
||||
curwaittd->td_tsqueue);
|
||||
counter_u64_add(turnstile_count, 1);
|
||||
thread_lock(td);
|
||||
return;
|
||||
}
|
||||
turnstile_unlock(ts, lock);
|
||||
}
|
||||
thread_lock(td);
|
||||
critical_exit();
|
||||
KASSERT(td->td_locks == locksheld,
|
||||
|
@ -566,24 +566,26 @@ turnstile_trywait(struct lock_object *lock)
|
||||
return (ts);
|
||||
}
|
||||
|
||||
struct thread *
|
||||
turnstile_lock(struct turnstile *ts, struct lock_object **lockp)
|
||||
bool
|
||||
turnstile_lock(struct turnstile *ts, struct lock_object **lockp,
|
||||
struct thread **tdp)
|
||||
{
|
||||
struct turnstile_chain *tc;
|
||||
struct lock_object *lock;
|
||||
|
||||
if ((lock = ts->ts_lockobj) == NULL)
|
||||
return (NULL);
|
||||
return (false);
|
||||
tc = TC_LOOKUP(lock);
|
||||
mtx_lock_spin(&tc->tc_lock);
|
||||
mtx_lock_spin(&ts->ts_lock);
|
||||
if (__predict_false(lock != ts->ts_lockobj)) {
|
||||
mtx_unlock_spin(&tc->tc_lock);
|
||||
mtx_unlock_spin(&ts->ts_lock);
|
||||
return (NULL);
|
||||
return (false);
|
||||
}
|
||||
*lockp = lock;
|
||||
return (ts->ts_owner);
|
||||
*tdp = ts->ts_owner;
|
||||
return (true);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -99,7 +99,8 @@ int turnstile_signal(struct turnstile *, int);
|
||||
struct turnstile *turnstile_trywait(struct lock_object *);
|
||||
void turnstile_unpend(struct turnstile *);
|
||||
void turnstile_wait(struct turnstile *, struct thread *, int);
|
||||
struct thread *turnstile_lock(struct turnstile *, struct lock_object **);
|
||||
bool turnstile_lock(struct turnstile *, struct lock_object **,
|
||||
struct thread **);
|
||||
void turnstile_unlock(struct turnstile *, struct lock_object *);
|
||||
void turnstile_assert(struct turnstile *);
|
||||
#endif /* _KERNEL */
|
||||
|
Loading…
Reference in New Issue
Block a user