Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Jun 2025 02:42:54 GMT
From:      Olivier Certner <olce@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: be8e84c2e924 - main - runq: runq_not_empty() to support racy lookups again
Message-ID:  <202506200242.55K2gsup093663@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by olce:

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

commit be8e84c2e9240110ce99bb8d14259073340e4ef6
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2025-06-20 02:36:09 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-06-20 02:42:16 +0000

    runq: runq_not_empty() to support racy lookups again
    
    The 4BSD assumes that its sched_runnable(), which then calls
    runq_not_empty(), can be called racily (another CPU may be grabbing
    a thread from the global queue at the same time).
    
    This makes runq_not_empty() trip on an assertion in runq_find()
    detecting a mismatch between some bit in the status word and the state
    of the corresponding queue (empty/not empty).
    
    Re-implement runq_not_empty() in an independent and simpler way as an
    alternative to removing the assertion, which remains useful to detect
    races when removing or adding a thread in some runqueue.
    
    Fixes:          79f68322c892 ("runq: runq_check(): Re-implement on top of runq_findq()")
    MFC after:      1 month
    Event:          Kitchener-Waterloo Hackathon 202506
    Sponsored by:   The FreeBSD Foundation
---
 sys/kern/kern_switch.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/sys/kern/kern_switch.c b/sys/kern/kern_switch.c
index 917f73682564..42fee61a99a0 100644
--- a/sys/kern/kern_switch.c
+++ b/sys/kern/kern_switch.c
@@ -493,7 +493,7 @@ int
 runq_findq(struct runq *const rq, const int lvl_min, const int lvl_max,
     runq_pred_t *const pred, void *const pred_data)
 {
-	rqsw_t const (*const rqsw)[RQSW_NB] = &rq->rq_status.rq_sw;
+	const rqsw_t (*const rqsw)[RQSW_NB] = &rq->rq_status.rq_sw;
 	rqsw_t w;
 	int i, last, idx;
 
@@ -568,20 +568,27 @@ runq_first_thread(struct runq *const rq)
 
 /*
  * Return true if there are some processes of any priority on the run queue,
- * false otherwise.  Has no side effects.
+ * false otherwise.  Has no side effects.  Supports racy lookups (required by
+ * 4BSD).
  */
 bool
 runq_not_empty(struct runq *rq)
 {
-	struct thread *const td = runq_first_thread(rq);
+	const rqsw_t (*const rqsw)[RQSW_NB] = &rq->rq_status.rq_sw;
+	int sw_idx;
 
-	if (td != NULL) {
-		CTR2(KTR_RUNQ, "runq_not_empty: idx=%d, td=%p",
-		    td->td_rqindex, td);
-		return (true);
+	for (sw_idx = 0; sw_idx < RQSW_NB; ++sw_idx) {
+		const rqsw_t w = (*rqsw)[sw_idx];
+
+		if (w != 0) {
+			CTR3(KTR_RUNQ, "runq_not_empty: not empty; "
+			    "rq=%p, sw_idx=%d, bits=" RQSW_PRI,
+			    rq, sw_idx, w);
+			return (true);
+		}
 	}
 
-	CTR0(KTR_RUNQ, "runq_not_empty: empty");
+	CTR1(KTR_RUNQ, "runq_not_empty: empty; rq=%p", rq);
 	return (false);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202506200242.55K2gsup093663>