git: 000ffb6f24c4 - stable/14 - runq: More macros; Better and more consistent naming

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Mon, 28 Jul 2025 13:31:13 UTC
The branch stable/14 has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=000ffb6f24c498bc665b887fafdd1bd4e96f598f

commit 000ffb6f24c498bc665b887fafdd1bd4e96f598f
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2024-04-23 11:33:02 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-07-28 13:28:06 +0000

    runq: More macros; Better and more consistent naming
    
    Most existing macros have ambiguous names regarding which index they
    operate on (queue, word, bit?), so have been renamed to improve clarity.
    Use the 'RQSW_' prefix for all macros related to status words, and
    change the status word type name accordingly.
    
    Rename RQB_FFS() to RQSW_BSF() to remove confusion about the return
    value (ffs*() return bit indices starting at 1, or 0 if the input is 0,
    whereas BSF on x86 returns 0-based indices, which is what the current
    code assumes).  While here, add a check (under INVARIANTS) that
    RQSW_BSF() isn't called with 0 as an argument.
    
    Also, rename 'rqb_bits_t' to the more concise 'rqsw_t', 'struct rqbits'
    to 'struct rq_status', its 'rqb_bits' field to 'rq_sw' (it designates an
    array of words, not bits), and the type 'rqhead' to 'rq_queue'
    
    Add macros computing a queue index from a status word index and a bit in
    order to factorize code.  If the precise index of the bit is known,
    callers can use RQSW_TO_QUEUE_IDX() to get the corresponding queue
    index, whereas if they want the one corresponding to the first
    (least-significant): set bit in a given status word (corresponding to
    the non-empty queue with lower index in the status word), they can use
    RQSW_FIRST_QUEUE_IDX() instead.
    
    Add RQSW_BIT_IDX(), which computes the correspond bit's index in the
    corresponding status word.  This allows more code factorization (even if
    most uses will be eliminated in a later commit) and makes what is
    computed clearer.
    
    Reviewed by:    kib
    MFC after:      1 month
    Event:          Kitchener-Waterloo Hackathon 202506
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D45387
    
    (cherry picked from commit 7e2502e3dec989ea31e5300ade759a721718548d)
---
 sys/kern/kern_switch.c | 114 ++++++++++++++++++++++++-------------------------
 sys/kern/sched_4bsd.c  |   2 +-
 sys/kern/sched_ule.c   |  56 ++++++++++++------------
 sys/sys/runq.h         |  40 ++++++++++-------
 4 files changed, 111 insertions(+), 101 deletions(-)

diff --git a/sys/kern/kern_switch.c b/sys/kern/kern_switch.c
index 906efca4bb51..9e63709d0acc 100644
--- a/sys/kern/kern_switch.c
+++ b/sys/kern/kern_switch.c
@@ -281,15 +281,15 @@ runq_init(struct runq *rq)
 static __inline void
 runq_clrbit(struct runq *rq, int idx)
 {
-	struct rqbits *rqb;
+	struct rq_status *rqs;
 
 	CHECK_IDX(idx);
-	rqb = &rq->rq_status;
+	rqs = &rq->rq_status;
 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
-	    rqb->rqb_bits[RQB_WORD(idx)],
-	    rqb->rqb_bits[RQB_WORD(idx)] & ~RQB_BIT(idx),
-	    RQB_BIT(idx), RQB_WORD(idx));
-	rqb->rqb_bits[RQB_WORD(idx)] &= ~RQB_BIT(idx);
+	    rqs->rq_sw[RQSW_IDX(idx)],
+	    rqs->rq_sw[RQSW_IDX(idx)] & ~RQSW_BIT(idx),
+	    RQSW_BIT(idx), RQSW_IDX(idx));
+	rqs->rq_sw[RQSW_IDX(idx)] &= ~RQSW_BIT(idx);
 }
 
 /*
@@ -299,16 +299,16 @@ runq_clrbit(struct runq *rq, int idx)
 static __inline int
 runq_findbit(struct runq *rq)
 {
-	struct rqbits *rqb;
+	struct rq_status *rqs;
 	int idx;
 
-	rqb = &rq->rq_status;
-	for (int i = 0; i < RQB_LEN; i++)
-		if (rqb->rqb_bits[i] != 0) {
-			idx = RQB_FFS(rqb->rqb_bits[i]) + i * RQB_BPW;
+	rqs = &rq->rq_status;
+	for (int i = 0; i < RQSW_NB; i++)
+		if (rqs->rq_sw[i] != 0) {
+			idx = RQSW_FIRST_QUEUE_IDX(i, rqs->rq_sw[i]);
 			CHECK_IDX(idx);
 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d idx=%d",
-			    rqb->rqb_bits[i], i, idx);
+			    rqs->rq_sw[i], i, idx);
 			return (idx);
 		}
 
@@ -318,20 +318,20 @@ runq_findbit(struct runq *rq)
 static __inline int
 runq_findbit_from(struct runq *rq, int idx)
 {
-	struct rqbits *rqb;
-	rqb_word_t mask;
+	struct rq_status *rqs;
+	rqsw_t mask;
 	int i;
 
 	CHECK_IDX(idx);
 	/* Set the mask for the first word so we ignore indices before 'idx'. */
-	mask = (rqb_word_t)-1 << (idx & (RQB_BPW - 1));
-	rqb = &rq->rq_status;
+	mask = (rqsw_t)-1 << RQSW_BIT_IDX(idx);
+	rqs = &rq->rq_status;
 again:
-	for (i = RQB_WORD(idx); i < RQB_LEN; mask = -1, i++) {
-		mask = rqb->rqb_bits[i] & mask;
+	for (i = RQSW_IDX(idx); i < RQSW_NB; mask = -1, i++) {
+		mask = rqs->rq_sw[i] & mask;
 		if (mask == 0)
 			continue;
-		idx = RQB_FFS(mask) + i * RQB_BPW;
+		idx = RQSW_FIRST_QUEUE_IDX(i, mask);
 		CTR3(KTR_RUNQ, "runq_findbit_from: bits=%#x i=%d idx=%d",
 		    mask, i, idx);
 		return (idx);
@@ -353,15 +353,15 @@ again:
 static __inline void
 runq_setbit(struct runq *rq, int idx)
 {
-	struct rqbits *rqb;
+	struct rq_status *rqs;
 
 	CHECK_IDX(idx);
-	rqb = &rq->rq_status;
+	rqs = &rq->rq_status;
 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
-	    rqb->rqb_bits[RQB_WORD(idx)],
-	    rqb->rqb_bits[RQB_WORD(idx)] | RQB_BIT(idx),
-	    RQB_BIT(idx), RQB_WORD(idx));
-	rqb->rqb_bits[RQB_WORD(idx)] |= RQB_BIT(idx);
+	    rqs->rq_sw[RQSW_IDX(idx)],
+	    rqs->rq_sw[RQSW_IDX(idx)] | RQSW_BIT(idx),
+	    RQSW_BIT(idx), RQSW_IDX(idx));
+	rqs->rq_sw[RQSW_IDX(idx)] |= RQSW_BIT(idx);
 }
 
 /*
@@ -372,13 +372,13 @@ void
 runq_add(struct runq *rq, struct thread *td, int flags)
 {
 
-	runq_add_idx(rq, td, RQ_PRI_TO_IDX(td->td_priority), flags);
+	runq_add_idx(rq, td, RQ_PRI_TO_QUEUE_IDX(td->td_priority), flags);
 }
 
 void
 runq_add_idx(struct runq *rq, struct thread *td, int idx, int flags)
 {
-	struct rqhead *rqh;
+	struct rq_queue *rqq;
 
 	/*
 	 * runq_setbit() asserts 'idx' is non-negative and below 'RQ_NQS', and
@@ -387,13 +387,13 @@ runq_add_idx(struct runq *rq, struct thread *td, int idx, int flags)
 	 */
 	td->td_rqindex = idx;
 	runq_setbit(rq, idx);
-	rqh = &rq->rq_queues[idx];
-	CTR4(KTR_RUNQ, "runq_add_idx: td=%p pri=%d idx=%d rqh=%p",
-	    td, td->td_priority, idx, rqh);
+	rqq = &rq->rq_queues[idx];
+	CTR4(KTR_RUNQ, "runq_add_idx: td=%p pri=%d idx=%d rqq=%p",
+	    td, td->td_priority, idx, rqq);
 	if (flags & SRQ_PREEMPTED)
-		TAILQ_INSERT_HEAD(rqh, td, td_runq);
+		TAILQ_INSERT_HEAD(rqq, td, td_runq);
 	else
-		TAILQ_INSERT_TAIL(rqh, td, td_runq);
+		TAILQ_INSERT_TAIL(rqq, td, td_runq);
 }
 
 /*
@@ -403,13 +403,13 @@ runq_add_idx(struct runq *rq, struct thread *td, int idx, int flags)
 bool
 runq_not_empty(struct runq *rq)
 {
-	struct rqbits *rqb;
+	struct rq_status *rqs;
 
-	rqb = &rq->rq_status;
-	for (int i = 0; i < RQB_LEN; i++)
-		if (rqb->rqb_bits[i] != 0) {
+	rqs = &rq->rq_status;
+	for (int i = 0; i < RQSW_NB; i++)
+		if (rqs->rq_sw[i] != 0) {
 			CTR2(KTR_RUNQ, "runq_not_empty: bits=%#x i=%d",
-			    rqb->rqb_bits[i], i);
+			    rqs->rq_sw[i], i);
 			return (true);
 		}
 	CTR0(KTR_RUNQ, "runq_not_empty: empty");
@@ -423,13 +423,13 @@ runq_not_empty(struct runq *rq)
 struct thread *
 runq_choose_fuzz(struct runq *rq, int fuzz)
 {
-	struct rqhead *rqh;
+	struct rq_queue *rqq;
 	struct thread *td;
 	int idx;
 
 	idx = runq_findbit(rq);
 	if (idx != -1) {
-		rqh = &rq->rq_queues[idx];
+		rqq = &rq->rq_queues[idx];
 		/* fuzz == 1 is normal.. 0 or less are ignored */
 		if (fuzz > 1) {
 			/*
@@ -439,7 +439,7 @@ runq_choose_fuzz(struct runq *rq, int fuzz)
 			int count = fuzz;
 			int cpu = PCPU_GET(cpuid);
 			struct thread *td2;
-			td2 = td = TAILQ_FIRST(rqh);
+			td2 = td = TAILQ_FIRST(rqq);
 
 			while (count-- && td2) {
 				if (td2->td_lastcpu == cpu) {
@@ -449,10 +449,10 @@ runq_choose_fuzz(struct runq *rq, int fuzz)
 				td2 = TAILQ_NEXT(td2, td_runq);
 			}
 		} else
-			td = TAILQ_FIRST(rqh);
+			td = TAILQ_FIRST(rqq);
 		KASSERT(td != NULL, ("runq_choose_fuzz: no proc on busy queue"));
 		CTR3(KTR_RUNQ,
-		    "runq_choose_fuzz: idx=%d thread=%p rqh=%p", idx, td, rqh);
+		    "runq_choose_fuzz: idx=%d thread=%p rqq=%p", idx, td, rqq);
 		return (td);
 	}
 	CTR1(KTR_RUNQ, "runq_choose_fuzz: idleproc idx=%d", idx);
@@ -466,17 +466,17 @@ runq_choose_fuzz(struct runq *rq, int fuzz)
 struct thread *
 runq_choose(struct runq *rq)
 {
-	struct rqhead *rqh;
+	struct rq_queue *rqq;
 	struct thread *td;
 	int idx;
 
 	idx = runq_findbit(rq);
 	if (idx != -1) {
-		rqh = &rq->rq_queues[idx];
-		td = TAILQ_FIRST(rqh);
+		rqq = &rq->rq_queues[idx];
+		td = TAILQ_FIRST(rqq);
 		KASSERT(td != NULL, ("runq_choose: no thread on busy queue"));
 		CTR3(KTR_RUNQ,
-		    "runq_choose: idx=%d thread=%p rqh=%p", idx, td, rqh);
+		    "runq_choose: idx=%d thread=%p rqq=%p", idx, td, rqq);
 		return (td);
 	}
 	CTR1(KTR_RUNQ, "runq_choose: idlethread idx=%d", idx);
@@ -487,17 +487,17 @@ runq_choose(struct runq *rq)
 struct thread *
 runq_choose_from(struct runq *rq, int from_idx)
 {
-	struct rqhead *rqh;
+	struct rq_queue *rqq;
 	struct thread *td;
 	int idx;
 
 	if ((idx = runq_findbit_from(rq, from_idx)) != -1) {
-		rqh = &rq->rq_queues[idx];
-		td = TAILQ_FIRST(rqh);
+		rqq = &rq->rq_queues[idx];
+		td = TAILQ_FIRST(rqq);
 		KASSERT(td != NULL, ("runq_choose: no thread on busy queue"));
 		CTR4(KTR_RUNQ,
-		    "runq_choose_from: idx=%d thread=%p idx=%d rqh=%p",
-		    idx, td, td->td_rqindex, rqh);
+		    "runq_choose_from: idx=%d thread=%p idx=%d rqq=%p",
+		    idx, td, td->td_rqindex, rqq);
 		return (td);
 	}
 	CTR1(KTR_RUNQ, "runq_choose_from: idlethread idx=%d", idx);
@@ -513,17 +513,17 @@ runq_choose_from(struct runq *rq, int from_idx)
 bool
 runq_remove(struct runq *rq, struct thread *td)
 {
-	struct rqhead *rqh;
+	struct rq_queue *rqq;
 	int idx;
 
 	KASSERT(td->td_flags & TDF_INMEM, ("runq_remove: Thread swapped out"));
 	idx = td->td_rqindex;
 	CHECK_IDX(idx);
-	rqh = &rq->rq_queues[idx];
-	CTR4(KTR_RUNQ, "runq_remove: td=%p pri=%d idx=%d rqh=%p",
-	    td, td->td_priority, idx, rqh);
-	TAILQ_REMOVE(rqh, td, td_runq);
-	if (TAILQ_EMPTY(rqh)) {
+	rqq = &rq->rq_queues[idx];
+	CTR4(KTR_RUNQ, "runq_remove: td=%p pri=%d idx=%d rqq=%p",
+	    td, td->td_priority, idx, rqq);
+	TAILQ_REMOVE(rqq, td, td_runq);
+	if (TAILQ_EMPTY(rqq)) {
 		runq_clrbit(rq, idx);
 		CTR1(KTR_RUNQ, "runq_remove: queue at idx=%d now empty", idx);
 		return (true);
diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c
index c6b789d060c3..c204e4a5676e 100644
--- a/sys/kern/sched_4bsd.c
+++ b/sys/kern/sched_4bsd.c
@@ -873,7 +873,7 @@ sched_priority(struct thread *td, u_char prio)
 	if (td->td_priority == prio)
 		return;
 	td->td_priority = prio;
-	if (TD_ON_RUNQ(td) && td->td_rqindex != RQ_PRI_TO_IDX(prio)) {
+	if (TD_ON_RUNQ(td) && td->td_rqindex != RQ_PRI_TO_QUEUE_IDX(prio)) {
 		sched_rem(td);
 		sched_add(td, SRQ_BORING | SRQ_HOLDTD);
 	}
diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c
index 13bef8ca9c1c..8fdc71c21e64 100644
--- a/sys/kern/sched_ule.c
+++ b/sys/kern/sched_ule.c
@@ -387,20 +387,20 @@ SDT_PROBE_DEFINE2(sched, , , surrender, "struct thread *",
 static void
 runq_print(struct runq *rq)
 {
-	struct rqhead *rqh;
+	struct rq_queue *rqq;
 	struct thread *td;
 	int pri;
 	int j;
 	int i;
 
-	for (i = 0; i < RQB_LEN; i++) {
+	for (i = 0; i < RQSW_NB; i++) {
 		printf("\t\trunq bits %d 0x%zx\n",
-		    i, rq->rq_status.rqb_bits[i]);
-		for (j = 0; j < RQB_BPW; j++)
-			if (rq->rq_status.rqb_bits[i] & (1ul << j)) {
-				pri = j + i * RQB_BPW;
-				rqh = &rq->rq_queues[pri];
-				TAILQ_FOREACH(td, rqh, td_runq) {
+		    i, rq->rq_status.rq_sw[i]);
+		for (j = 0; j < RQSW_BPW; j++)
+			if (rq->rq_status.rq_sw[i] & (1ul << j)) {
+				pri = RQSW_TO_QUEUE_IDX(i, j);
+				rqq = &rq->rq_queues[pri];
+				TAILQ_FOREACH(td, rqq, td_runq) {
 					printf("\t\t\ttd %p(%s) priority %d rqindex %d pri %d\n",
 					    td, td->td_name, td->td_priority,
 					    td->td_rqindex, pri);
@@ -1190,26 +1190,26 @@ tdq_notify(struct tdq *tdq, int lowpri)
 static struct thread *
 runq_steal_from(struct runq *rq, int cpu, u_char start)
 {
-	struct rqbits *rqb;
-	struct rqhead *rqh;
+	struct rq_status *rqs;
+	struct rq_queue *rqq;
 	struct thread *td, *first;
 	int bit;
 	int i;
 
-	rqb = &rq->rq_status;
-	bit = start & (RQB_BPW -1);
+	rqs = &rq->rq_status;
+	bit = RQSW_BIT_IDX(start);
 	first = NULL;
 again:
-	for (i = RQB_WORD(start); i < RQB_LEN; bit = 0, i++) {
-		if (rqb->rqb_bits[i] == 0)
+	for (i = RQSW_IDX(start); i < RQSW_NB; bit = 0, i++) {
+		if (rqs->rq_sw[i] == 0)
 			continue;
 		if (bit == 0)
-			bit = RQB_FFS(rqb->rqb_bits[i]);
-		for (; bit < RQB_BPW; bit++) {
-			if ((rqb->rqb_bits[i] & (1ul << bit)) == 0)
+			bit = RQSW_BSF(rqs->rq_sw[i]);
+		for (; bit < RQSW_BPW; bit++) {
+			if ((rqs->rq_sw[i] & (1ul << bit)) == 0)
 				continue;
-			rqh = &rq->rq_queues[bit + i * RQB_BPW];
-			TAILQ_FOREACH(td, rqh, td_runq) {
+			rqq = &rq->rq_queues[RQSW_TO_QUEUE_IDX(i, bit)];
+			TAILQ_FOREACH(td, rqq, td_runq) {
 				if (first) {
 					if (THREAD_CAN_MIGRATE(td) &&
 					    THREAD_CAN_SCHED(td, cpu))
@@ -1236,21 +1236,21 @@ again:
 static struct thread *
 runq_steal(struct runq *rq, int cpu)
 {
-	struct rqhead *rqh;
-	struct rqbits *rqb;
+	struct rq_queue *rqq;
+	struct rq_status *rqs;
 	struct thread *td;
 	int word;
 	int bit;
 
-	rqb = &rq->rq_status;
-	for (word = 0; word < RQB_LEN; word++) {
-		if (rqb->rqb_bits[word] == 0)
+	rqs = &rq->rq_status;
+	for (word = 0; word < RQSW_NB; word++) {
+		if (rqs->rq_sw[word] == 0)
 			continue;
-		for (bit = 0; bit < RQB_BPW; bit++) {
-			if ((rqb->rqb_bits[word] & (1ul << bit)) == 0)
+		for (bit = 0; bit < RQSW_BPW; bit++) {
+			if ((rqs->rq_sw[word] & (1ul << bit)) == 0)
 				continue;
-			rqh = &rq->rq_queues[bit + word * RQB_BPW];
-			TAILQ_FOREACH(td, rqh, td_runq)
+			rqq = &rq->rq_queues[RQSW_TO_QUEUE_IDX(word, bit)];
+			TAILQ_FOREACH(td, rqq, td_runq)
 				if (THREAD_CAN_MIGRATE(td) &&
 				    THREAD_CAN_SCHED(td, cpu))
 					return (td);
diff --git a/sys/sys/runq.h b/sys/sys/runq.h
index 030b4bb370a8..80a1fad0a089 100644
--- a/sys/sys/runq.h
+++ b/sys/sys/runq.h
@@ -47,16 +47,26 @@
 /*
  * Deduced from the above parameters and machine ones.
  */
-typedef	unsigned long	rqb_word_t;	/* runq's status words type. */
-
 #define	RQ_NQS	(howmany(RQ_MAX_PRIO + 1, RQ_PPQ)) /* Number of run queues. */
-#define	RQ_PRI_TO_IDX(pri)	((pri) / RQ_PPQ) /* Priority to queue index. */
-
-#define	RQB_BPW	(sizeof(rqb_word_t) * NBBY) /* Bits per runq word. */
-#define	RQB_LEN	(howmany(RQ_NQS, RQB_BPW)) /* Words to cover RQ_NQS queues. */
-#define	RQB_WORD(idx)	((idx) / RQB_BPW)
-#define	RQB_BIT(idx)	(1ul << ((idx) % RQB_BPW))
-#define	RQB_FFS(word)	(ffsl((long)(word)) - 1) /* Assumes two-complement. */
+#define	RQ_PRI_TO_QUEUE_IDX(pri) ((pri) / RQ_PPQ) /* Priority to queue index. */
+
+typedef unsigned long	rqsw_t;		/* runq's status words type. */
+#define	RQSW_BPW	(sizeof(rqsw_t) * NBBY) /* Bits per runq word. */
+
+/* Number of status words to cover RQ_NQS queues. */
+#define	RQSW_NB			(howmany(RQ_NQS, RQSW_BPW))
+#define	RQSW_IDX(idx)		((idx) / RQSW_BPW)
+#define	RQSW_BIT_IDX(idx)	((idx) % RQSW_BPW)
+#define	RQSW_BIT(idx)		(1ul << RQSW_BIT_IDX(idx))
+#define	RQSW_BSF(word)		__extension__ ({			\
+	int _res = ffsl((long)(word)); /* Assumes two-complement. */	\
+	MPASS(_res > 0);						\
+	_res - 1;							\
+})
+#define	RQSW_TO_QUEUE_IDX(word_idx, bit_idx)				\
+	(((word_idx) * RQSW_BPW) + (bit_idx))
+#define	RQSW_FIRST_QUEUE_IDX(word_idx, word)				\
+	RQSW_TO_QUEUE_IDX(word_idx, RQSW_BSF(word))
 
 
 #ifdef _KERNEL
@@ -66,16 +76,16 @@ typedef	unsigned long	rqb_word_t;	/* runq's status words type. */
 struct thread;
 
 /*
- * Head of run queues.
+ * The queue for a given index as a list of threads.
  */
-TAILQ_HEAD(rqhead, thread);
+TAILQ_HEAD(rq_queue, thread);
 
 /*
  * Bit array which maintains the status of a run queue.  When a queue is
  * non-empty the bit corresponding to the queue number will be set.
  */
-struct rqbits {
-	rqb_word_t rqb_bits[RQB_LEN];
+struct rq_status {
+	rqsw_t rq_sw[RQSW_NB];
 };
 
 /*
@@ -83,8 +93,8 @@ struct rqbits {
  * are placed, and a structure to maintain the status of each queue.
  */
 struct runq {
-	struct	rqbits rq_status;
-	struct	rqhead rq_queues[RQ_NQS];
+	struct rq_status	rq_status;
+	struct rq_queue		rq_queues[RQ_NQS];
 };
 
 void	runq_add(struct runq *, struct thread *, int _flags);