Allow sleepq_signal() to drop the lock.

Introduce SLEEPQ_DROP sleepq_signal() flag, allowing one to drop the
sleep queue chain lock before returning.  Reduced lock scope allows
significantly reduce lock contention inside taskqueue_enqueue() for
ZFS worker threads doing ~350K disk reads/s on 40-thread system.

MFC after:	2 weeks
Sponsored by:	iXsystems, Inc.
This commit is contained in:
Alexander Motin 2021-06-25 13:52:58 -04:00
parent 520a2401a6
commit 6df35af4d8
3 changed files with 10 additions and 7 deletions

View File

@ -366,8 +366,7 @@ wakeup_one(const void *ident)
int wakeup_swapper;
sleepq_lock(ident);
wakeup_swapper = sleepq_signal(ident, SLEEPQ_SLEEP, 0, 0);
sleepq_release(ident);
wakeup_swapper = sleepq_signal(ident, SLEEPQ_SLEEP | SLEEPQ_DROP, 0, 0);
if (wakeup_swapper)
kick_proc0();
}
@ -378,9 +377,8 @@ wakeup_any(const void *ident)
int wakeup_swapper;
sleepq_lock(ident);
wakeup_swapper = sleepq_signal(ident, SLEEPQ_SLEEP | SLEEPQ_UNFAIR,
0, 0);
sleepq_release(ident);
wakeup_swapper = sleepq_signal(ident, SLEEPQ_SLEEP | SLEEPQ_UNFAIR |
SLEEPQ_DROP, 0, 0);
if (wakeup_swapper)
kick_proc0();
}

View File

@ -927,8 +927,11 @@ sleepq_signal(const void *wchan, int flags, int pri, int queue)
KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
MPASS((queue >= 0) && (queue < NR_SLEEPQS));
sq = sleepq_lookup(wchan);
if (sq == NULL)
if (sq == NULL) {
if (flags & SLEEPQ_DROP)
sleepq_release(wchan);
return (0);
}
KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE),
("%s: mismatch between sleep/wakeup and cv_*", __func__));
@ -961,7 +964,8 @@ sleepq_signal(const void *wchan, int flags, int pri, int queue)
}
}
MPASS(besttd != NULL);
wakeup_swapper = sleepq_resume_thread(sq, besttd, pri, SRQ_HOLD);
wakeup_swapper = sleepq_resume_thread(sq, besttd, pri,
(flags & SLEEPQ_DROP) ? 0 : SRQ_HOLD);
return (wakeup_swapper);
}

View File

@ -85,6 +85,7 @@ struct thread;
#define SLEEPQ_LK 0x04 /* Used by a lockmgr. */
#define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */
#define SLEEPQ_UNFAIR 0x200 /* Unfair wakeup order. */
#define SLEEPQ_DROP 0x400 /* Return without lock held. */
void init_sleepqueues(void);
int sleepq_abort(struct thread *td, int intrval);