Module Name:    src
Committed By:   riastradh
Date:           Wed Mar  5 14:01:34 UTC 2025

Modified Files:
        src/sys/kern: sys_futex.c

Log Message:
futex(2): Rename various parameters to clarify correspondence.

No functional change intended.

I have spent way too much time puzzling over what val/val2/val3 mean
for each operation; let's just give them all meaningful names and
write down the correspondence in the dispatch switch in do_futex.

Prompted by how much time I spent scratching my head for:

PR kern/59129: futex(3): missing sign extension in FUTEX_WAKE_OP


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/sys/kern/sys_futex.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/sys_futex.c
diff -u src/sys/kern/sys_futex.c:1.24 src/sys/kern/sys_futex.c:1.25
--- src/sys/kern/sys_futex.c:1.24	Wed Mar  5 14:01:20 2025
+++ src/sys/kern/sys_futex.c	Wed Mar  5 14:01:34 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_futex.c,v 1.24 2025/03/05 14:01:20 riastradh Exp $	*/
+/*	$NetBSD: sys_futex.c,v 1.25 2025/03/05 14:01:34 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_futex.c,v 1.24 2025/03/05 14:01:20 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_futex.c,v 1.25 2025/03/05 14:01:34 riastradh Exp $");
 
 /*
  * Futexes
@@ -1196,12 +1196,17 @@ futex_queue_unlock2(struct futex *f, str
 }
 
 /*
- * futex_func_wait(uaddr, val, val3, timeout, clkid, clkflags, retval)
+ * futex_func_wait(uaddr, cmpval@val, bitset@val3, timeout, clkid, clkflags,
+ *     retval)
  *
- *	Implement futex(FUTEX_WAIT).
+ *	Implement futex(FUTEX_WAIT) and futex(FUTEX_WAIT_BITSET): If
+ *	*uaddr == cmpval, wait until futex-woken on any of the bits in
+ *	bitset.  But if *uaddr != cmpval, fail with EAGAIN.
+ *
+ *	For FUTEX_WAIT, bitset has all bits set and val3 is ignored.
  */
 static int
-futex_func_wait(bool shared, int *uaddr, int val, int val3,
+futex_func_wait(bool shared, int *uaddr, int cmpval, int bitset,
     const struct timespec *timeout, clockid_t clkid, int clkflags,
     register_t *retval)
 {
@@ -1215,11 +1220,11 @@ futex_func_wait(bool shared, int *uaddr,
 	 * If there's nothing to wait for, and nobody will ever wake
 	 * us, then don't set anything up to wait -- just stop here.
 	 */
-	if (val3 == 0)
+	if (bitset == 0)
 		return EINVAL;
 
 	/* Optimistically test before anything else.  */
-	if (!futex_test(uaddr, val))
+	if (!futex_test(uaddr, cmpval))
 		return EAGAIN;
 
 	/* Determine a deadline on the specified clock.  */
@@ -1240,7 +1245,7 @@ futex_func_wait(bool shared, int *uaddr,
 	KASSERT(f);
 
 	/* Get ready to wait.  */
-	futex_wait_init(fw, val3);
+	futex_wait_init(fw, bitset);
 
 	/*
 	 * Under the queue lock, check the value again: if it has
@@ -1250,7 +1255,7 @@ futex_func_wait(bool shared, int *uaddr,
 	 * is immaterial.
 	 */
 	futex_queue_lock(f);
-	if (!futex_test(uaddr, val)) {
+	if (!futex_test(uaddr, cmpval)) {
 		futex_queue_unlock(f);
 		error = EAGAIN;
 		goto out;
@@ -1283,19 +1288,26 @@ out:	if (f != NULL)
 }
 
 /*
- * futex_func_wake(uaddr, val, val3, retval)
+ * futex_func_wake(uaddr, nwake@val, bitset@val3, retval)
+ *
+ *	Implement futex(FUTEX_WAKE) and futex(FUTEX_WAKE_BITSET): Wake
+ *	up to nwake waiters on uaddr waiting on any of the bits in
+ *	bitset.
+ *
+ *	Return the number of waiters woken.
  *
- *	Implement futex(FUTEX_WAKE) and futex(FUTEX_WAKE_BITSET).
+ *	For FUTEX_WAKE, bitset has all bits set and val3 is ignored.
  */
 static int
-futex_func_wake(bool shared, int *uaddr, int val, int val3, register_t *retval)
+futex_func_wake(bool shared, int *uaddr, int nwake, int bitset,
+    register_t *retval)
 {
 	struct futex *f;
 	unsigned int nwoken = 0;
 	int error = 0;
 
 	/* Reject negative number of wakeups.  */
-	if (val < 0) {
+	if (nwake < 0) {
 		error = EINVAL;
 		goto out;
 	}
@@ -1314,8 +1326,7 @@ futex_func_wake(bool shared, int *uaddr,
 	 * number woken.
 	 */
 	futex_queue_lock(f);
-	nwoken = futex_wake(f, /*nwake*/val, NULL, /*nrequeue*/0,
-	    /*bitset*/val3);
+	nwoken = futex_wake(f, nwake, NULL, /*nrequeue*/0, bitset);
 	futex_queue_unlock(f);
 
 	/* Release the futex.  */
@@ -1330,20 +1341,29 @@ out:
 }
 
 /*
- * futex_func_requeue(op, uaddr, val, uaddr2, val2, val3, retval)
+ * futex_func_requeue(op, uaddr, nwake@val, uaddr2, nrequeue@val2,
+ *     cmpval@val3, retval)
+ *
+ *	Implement futex(FUTEX_REQUEUE) and futex(FUTEX_CMP_REQUEUE): If
+ *	*uaddr == cmpval or if op == FUTEX_REQUEUE, wake up to nwake
+ *	waiters at uaddr and then requeue up to nrequeue waiters from
+ *	uaddr to uaddr2.
  *
- *	Implement futex(FUTEX_REQUEUE) and futex(FUTEX_CMP_REQUEUE).
+ *	Return the number of waiters woken or requeued.
+ *
+ *	For FUTEX_CMP_REQUEUE, if *uaddr != cmpval, fail with EAGAIN
+ *	and no wakeups.
  */
 static int
-futex_func_requeue(bool shared, int op, int *uaddr, int val, int *uaddr2,
-    int val2, int val3, register_t *retval)
+futex_func_requeue(bool shared, int op, int *uaddr, int nwake, int *uaddr2,
+    int nrequeue, int cmpval, register_t *retval)
 {
 	struct futex *f = NULL, *f2 = NULL;
 	unsigned nwoken_or_requeued = 0; /* default to zero on early return */
 	int error;
 
 	/* Reject negative number of wakeups or requeues. */
-	if (val < 0 || val2 < 0) {
+	if (nwake < 0 || nrequeue < 0) {
 		error = EINVAL;
 		goto out;
 	}
@@ -1376,15 +1396,15 @@ futex_func_requeue(bool shared, int op, 
 
 	/*
 	 * Under the futexes' queue locks, check the value; if
-	 * unchanged from val3, wake the waiters.
+	 * unchanged from cmpval, or if this is the unconditional
+	 * FUTEX_REQUEUE operation, wake the waiters.
 	 */
 	futex_queue_lock2(f, f2);
-	if (op == FUTEX_CMP_REQUEUE && !futex_test(uaddr, val3)) {
+	if (op == FUTEX_CMP_REQUEUE && !futex_test(uaddr, cmpval)) {
 		error = EAGAIN;
 	} else {
 		error = 0;
-		nwoken_or_requeued = futex_wake(f, /*nwake*/val,
-		    f2, /*nrequeue*/val2,
+		nwoken_or_requeued = futex_wake(f, nwake, f2, nrequeue,
 		    FUTEX_BITSET_MATCH_ANY);
 	}
 	futex_queue_unlock2(f, f2);
@@ -1418,19 +1438,19 @@ futex_opcmp_arg(int arg)
 }
 
 /*
- * futex_validate_op_cmp(val3)
+ * futex_validate_op_cmp(opcmp)
  *
  *	Validate an op/cmp argument for FUTEX_WAKE_OP.
  */
 static int
-futex_validate_op_cmp(int val3)
+futex_validate_op_cmp(int opcmp)
 {
-	int op = __SHIFTOUT(val3, FUTEX_OP_OP_MASK);
-	int cmp = __SHIFTOUT(val3, FUTEX_OP_CMP_MASK);
+	int op = __SHIFTOUT(opcmp, FUTEX_OP_OP_MASK);
+	int cmp = __SHIFTOUT(opcmp, FUTEX_OP_CMP_MASK);
 
 	if (op & FUTEX_OP_OPARG_SHIFT) {
 		int oparg =
-		    futex_opcmp_arg(__SHIFTOUT(val3, FUTEX_OP_OPARG_MASK));
+		    futex_opcmp_arg(__SHIFTOUT(opcmp, FUTEX_OP_OPARG_MASK));
 		if (oparg < 0)
 			return EINVAL;
 		if (oparg >= 32)
@@ -1465,15 +1485,15 @@ futex_validate_op_cmp(int val3)
 }
 
 /*
- * futex_compute_op(oldval, val3)
+ * futex_compute_op(oldval, opcmp)
  *
  *	Apply a FUTEX_WAKE_OP operation to oldval.
  */
 static int
-futex_compute_op(int oldval, int val3)
+futex_compute_op(int oldval, int opcmp)
 {
-	int op = __SHIFTOUT(val3, FUTEX_OP_OP_MASK);
-	int oparg = futex_opcmp_arg(__SHIFTOUT(val3, FUTEX_OP_OPARG_MASK));
+	int op = __SHIFTOUT(opcmp, FUTEX_OP_OP_MASK);
+	int oparg = futex_opcmp_arg(__SHIFTOUT(opcmp, FUTEX_OP_OPARG_MASK));
 
 	if (op & FUTEX_OP_OPARG_SHIFT) {
 		KASSERT(oparg >= 0);
@@ -1509,15 +1529,15 @@ futex_compute_op(int oldval, int val3)
 }
 
 /*
- * futex_compute_cmp(oldval, val3)
+ * futex_compute_cmp(oldval, opcmp)
  *
  *	Apply a FUTEX_WAKE_OP comparison to oldval.
  */
 static bool
-futex_compute_cmp(int oldval, int val3)
+futex_compute_cmp(int oldval, int opcmp)
 {
-	int cmp = __SHIFTOUT(val3, FUTEX_OP_CMP_MASK);
-	int cmparg = futex_opcmp_arg(__SHIFTOUT(val3, FUTEX_OP_CMPARG_MASK));
+	int cmp = __SHIFTOUT(opcmp, FUTEX_OP_CMP_MASK);
+	int cmparg = futex_opcmp_arg(__SHIFTOUT(opcmp, FUTEX_OP_CMPARG_MASK));
 
 	switch (cmp) {
 	case FUTEX_OP_CMP_EQ:
@@ -1544,13 +1564,23 @@ futex_compute_cmp(int oldval, int val3)
 }
 
 /*
- * futex_func_wake_op(uaddr, val, uaddr2, val2, val3, retval)
+ * futex_func_wake_op(uaddr, nwake@val, uaddr2, nwake2@val2, opcmp@val3,
+ *     retval)
+ *
+ *	Implement futex(FUTEX_WAKE_OP):
+ *
+ *	1. Update *uaddr2 according to the r/m/w operation specified in
+ *	   opcmp.
+ *
+ *	2. If uaddr is nonnull, wake up to nwake waiters at uaddr.
  *
- *	Implement futex(FUTEX_WAKE_OP).
+ *	3. If what was previously at *uaddr2 matches the comparison
+ *	   operation specified in opcmp, additionally wake up to nwake2
+ *	   waiters at uaddr2.
  */
 static int
-futex_func_wake_op(bool shared, int *uaddr, int val, int *uaddr2, int val2,
-    int val3, register_t *retval)
+futex_func_wake_op(bool shared, int *uaddr, int nwake, int *uaddr2, int nwake2,
+    int opcmp, register_t *retval)
 {
 	struct futex *f = NULL, *f2 = NULL;
 	int oldval, newval, actual;
@@ -1558,13 +1588,13 @@ futex_func_wake_op(bool shared, int *uad
 	int error;
 
 	/* Reject negative number of wakeups.  */
-	if (val < 0 || val2 < 0) {
+	if (nwake < 0 || nwake2 < 0) {
 		error = EINVAL;
 		goto out;
 	}
 
 	/* Reject invalid operations before we start doing things.  */
-	if ((error = futex_validate_op_cmp(val3)) != 0)
+	if ((error = futex_validate_op_cmp(opcmp)) != 0)
 		goto out;
 
 	/* Look up the first futex, if any.  */
@@ -1580,16 +1610,17 @@ futex_func_wake_op(bool shared, int *uad
 	/*
 	 * Under the queue locks:
 	 *
-	 * 1. Read/modify/write: *uaddr2 op= oparg.
+	 * 1. Read/modify/write: *uaddr2 op= oparg, as in opcmp.
 	 * 2. Unconditionally wake uaddr.
-	 * 3. Conditionally wake uaddr2, if it previously matched val2.
+	 * 3. Conditionally wake uaddr2, if it previously matched the
+	 *    comparison in opcmp.
 	 */
 	futex_queue_lock2(f, f2);
 	do {
 		error = futex_load(uaddr2, &oldval);
 		if (error)
 			goto out_unlock;
-		newval = futex_compute_op(oldval, val3);
+		newval = futex_compute_op(oldval, opcmp);
 		error = ucas_int(uaddr2, oldval, newval, &actual);
 		if (error)
 			goto out_unlock;
@@ -1597,11 +1628,11 @@ futex_func_wake_op(bool shared, int *uad
 	if (f == NULL) {
 		nwoken = 0;
 	} else {
-		nwoken = futex_wake(f, /*nwake*/val, NULL, /*nrequeue*/0,
+		nwoken = futex_wake(f, nwake, NULL, /*nrequeue*/0,
 		    FUTEX_BITSET_MATCH_ANY);
 	}
-	if (f2 && futex_compute_cmp(oldval, val3)) {
-		nwoken += futex_wake(f2, /*nwake*/val2, NULL, /*nrequeue*/0,
+	if (f2 && futex_compute_cmp(oldval, opcmp)) {
+		nwoken += futex_wake(f2, nwake2, NULL, /*nrequeue*/0,
 		    FUTEX_BITSET_MATCH_ANY);
 	}
 
@@ -1639,30 +1670,49 @@ do_futex(int *uaddr, int op, int val, co
 	op &= FUTEX_CMD_MASK;
 
 	switch (op) {
-	case FUTEX_WAIT:
-		return futex_func_wait(shared, uaddr, val,
-		    FUTEX_BITSET_MATCH_ANY, timeout, clkid, TIMER_RELTIME,
-		    retval);
-
-	case FUTEX_WAKE:
-		val3 = FUTEX_BITSET_MATCH_ANY;
-		/* FALLTHROUGH */
-	case FUTEX_WAKE_BITSET:
-		return futex_func_wake(shared, uaddr, val, val3, retval);
+	case FUTEX_WAIT: {
+		const int cmpval = val;
+		const int bitset = FUTEX_BITSET_MATCH_ANY;
 
+		return futex_func_wait(shared, uaddr, cmpval, bitset, timeout,
+		    clkid, TIMER_RELTIME, retval);
+	}
+	case FUTEX_WAKE: {
+		const int nwake = val;
+		const int bitset = FUTEX_BITSET_MATCH_ANY;
+
+		return futex_func_wake(shared, uaddr, nwake, bitset, retval);
+	}
+	case FUTEX_WAKE_BITSET: {
+		const int nwake = val;
+		const int bitset = val3;
+
+		return futex_func_wake(shared, uaddr, nwake, bitset, retval);
+	}
 	case FUTEX_REQUEUE:
-	case FUTEX_CMP_REQUEUE:
-		return futex_func_requeue(shared, op, uaddr, val, uaddr2,
-		    val2, val3, retval);
+	case FUTEX_CMP_REQUEUE: {
+		const int nwake = val;
+		const int nrequeue = val2;
+		const int cmpval = val3; /* ignored if op=FUTEX_REQUEUE */
+
+		return futex_func_requeue(shared, op, uaddr, nwake, uaddr2,
+		    nrequeue, cmpval, retval);
+	}
+	case FUTEX_WAIT_BITSET: {
+		const int cmpval = val;
+		const int bitset = val3;
 
-	case FUTEX_WAIT_BITSET:
-		return futex_func_wait(shared, uaddr, val, val3, timeout,
+		return futex_func_wait(shared, uaddr, cmpval, bitset, timeout,
 		    clkid, TIMER_ABSTIME, retval);
+	}
+	case FUTEX_WAKE_OP: {
+		const int nwake = val;
+		const int nwake2 = val2;
+		const int opcmp = val3;
 
-	case FUTEX_WAKE_OP:
-		return futex_func_wake_op(shared, uaddr, val, uaddr2, val2,
-		    val3, retval);
-
+		return futex_func_wake_op(shared, uaddr, nwake, uaddr2, nwake2,
+		    opcmp, retval);
+	}
 	case FUTEX_FD:
 	default:
 		return ENOSYS;

Reply via email to