Module Name:    src
Committed By:   riastradh
Date:           Sun Dec 19 12:36:09 UTC 2021

Modified Files:
        src/sys/external/bsd/drm2/include/linux: wait_bit.h
        src/sys/external/bsd/drm2/linux: linux_wait_bit.c

Log Message:
linux: Fix wait_bit semantics.

- wait_on_bit is supposed to wait until the bit is cleared, not set.

- wait_on_bit_timeout is supposed to return 0 on success, -EAGAIN on
  faiure.

Omit wake_up_bit; nothing uses it and clear_and_wake_up_bit is a more
semantically coherent operation.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/include/linux/wait_bit.h
cvs rdiff -u -r1.4 -r1.5 src/sys/external/bsd/drm2/linux/linux_wait_bit.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/external/bsd/drm2/include/linux/wait_bit.h
diff -u src/sys/external/bsd/drm2/include/linux/wait_bit.h:1.3 src/sys/external/bsd/drm2/include/linux/wait_bit.h:1.4
--- src/sys/external/bsd/drm2/include/linux/wait_bit.h:1.3	Sun Dec 19 11:26:50 2021
+++ src/sys/external/bsd/drm2/include/linux/wait_bit.h	Sun Dec 19 12:36:08 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: wait_bit.h,v 1.3 2021/12/19 11:26:50 riastradh Exp $	*/
+/*	$NetBSD: wait_bit.h,v 1.4 2021/12/19 12:36:08 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -35,12 +35,10 @@
 #define	clear_and_wake_up_bit	linux_clear_and_wake_up_bit
 #define	wait_on_bit		linux_wait_on_bit
 #define	wait_on_bit_timeout	linux_wait_on_bit_timeout
-#define	wake_up_bit		linux_wake_up_bit
 
 int	linux_wait_bit_init(void);
 void	linux_wait_bit_fini(void);
 
-void	wake_up_bit(const volatile unsigned long *, unsigned);
 void	clear_and_wake_up_bit(int, volatile unsigned long *);
 int	wait_on_bit(const volatile unsigned long *, unsigned, int);
 int	wait_on_bit_timeout(const volatile unsigned long *, unsigned, int,

Index: src/sys/external/bsd/drm2/linux/linux_wait_bit.c
diff -u src/sys/external/bsd/drm2/linux/linux_wait_bit.c:1.4 src/sys/external/bsd/drm2/linux/linux_wait_bit.c:1.5
--- src/sys/external/bsd/drm2/linux/linux_wait_bit.c:1.4	Sun Dec 19 11:26:50 2021
+++ src/sys/external/bsd/drm2/linux/linux_wait_bit.c	Sun Dec 19 12:36:09 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: linux_wait_bit.c,v 1.4 2021/12/19 11:26:50 riastradh Exp $	*/
+/*	$NetBSD: linux_wait_bit.c,v 1.5 2021/12/19 12:36:09 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_wait_bit.c,v 1.4 2021/12/19 11:26:50 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_wait_bit.c,v 1.5 2021/12/19 12:36:09 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -104,16 +104,13 @@ wait_bit_exit(struct waitbitentry *wbe)
 	mutex_exit(&wbe->lock);
 }
 
-void
-wake_up_bit(const volatile unsigned long *bitmap, unsigned bit)
-{
-	struct waitbitentry *wbe;
-
-	wbe = wait_bit_enter(bitmap, bit);
-	cv_broadcast(&wbe->cv);
-	wait_bit_exit(wbe);
-}
-
+/*
+ * clear_and_wake_up_bit(bit, bitmap)
+ *
+ *	Clear the specified bit in the bitmap and wake any waiters in
+ *	wait_on_bit or wait_on_bit_timeout that were waiting for it to
+ *	clear.
+ */
 void
 clear_and_wake_up_bit(int bit, volatile unsigned long *bitmap)
 {
@@ -125,38 +122,55 @@ clear_and_wake_up_bit(int bit, volatile 
 	wait_bit_exit(wbe);
 }
 
+/*
+ * wait_on_bit(bitmap, bit, flags)
+ *
+ *	Wait for the specified bit in bitmap to be cleared.  Returns 0
+ *	on success, -EINTR on signal, unless flags has
+ *	TASK_UNINTERRUPTIBLE set.
+ */
 int
 wait_on_bit(const volatile unsigned long *bitmap, unsigned bit, int flags)
 {
 	struct waitbitentry *wbe;
 	int error, ret;
 
-	if (test_bit(bit, bitmap))
+	if (test_bit(bit, bitmap) == 0)
 		return 0;
 
 	wbe = wait_bit_enter(bitmap, bit);
 
-	while (!test_bit(bit, bitmap)) {
+	while (test_bit(bit, bitmap)) {
 		if (flags & TASK_UNINTERRUPTIBLE) {
 			cv_wait(&wbe->cv, &wbe->lock);
 		} else {
 			error = cv_wait_sig(&wbe->cv, &wbe->lock);
-			if (error == EINTR || error == ERESTART)
-				ret = -ERESTARTSYS;
-			else if (error != 0)
-				ret = -error;
-			if (ret)
+			if (error) {
+				/* cv_wait_sig can only fail on signal.  */
+				KASSERTMSG(error == EINTR || error == ERESTART,
+				    "error=%d", error);
+				ret = -EINTR;
 				goto out;
+			}
 		}
 	}
 
-	/* Bit is set.  Return zero on success.   */
+	/* Bit is clear.  Return zero on success.   */
+	KASSERT(test_bit(bit, bitmap) == 0);
 	ret = 0;
 
-out:	wait_bit_exit(wbe);
+out:	KASSERT(test_bit(bit, bitmap) == 0 || ret != 0);
+	wait_bit_exit(wbe);
 	return ret;
 }
 
+/*
+ * wait_on_bit_timeout(bitmap, bit, flags, timeout)
+ *
+ *	Wait for the specified bit in bitmap to be cleared.  Returns 0
+ *	on success, -EINTR on signal unless flags has
+ *	TASK_UNINTERRUPTIBLE set, or -EAGAIN on timeout.
+ */
 int
 wait_on_bit_timeout(const volatile unsigned long *bitmap, unsigned bit,
     int flags, unsigned long timeout)
@@ -164,42 +178,55 @@ wait_on_bit_timeout(const volatile unsig
 	struct waitbitentry *wbe;
 	int error, ret;
 
-	if (test_bit(bit, bitmap))
-		return timeout;
+	if (test_bit(bit, bitmap) == 0)
+		return 0;
 
 	wbe = wait_bit_enter(bitmap, bit);
 
-	while (!test_bit(bit, bitmap)) {
+	while (test_bit(bit, bitmap)) {
 		unsigned starttime, endtime;
 
-		starttime = hardclock_ticks;
+		if (timeout == 0) {
+			ret = -EAGAIN;
+			goto out;
+		}
+
+		starttime = getticks();
 		if (flags & TASK_UNINTERRUPTIBLE) {
 			error = cv_timedwait(&wbe->cv, &wbe->lock,
-			    MIN(INT_MAX, timeout));
+			    MIN(timeout, INT_MAX/2));
 		} else {
 			error = cv_timedwait_sig(&wbe->cv, &wbe->lock,
-			    MIN(INT_MAX, timeout));
-		}
-		endtime = hardclock_ticks;
-
-		/* If we timed out, return zero time left.  */
-		if (error == EWOULDBLOCK || endtime - starttime < timeout) {
-			ret = 0;
-			goto out;
+			    MIN(timeout, INT_MAX/2));
 		}
+		endtime = getticks();
 
-		/* If we were interrupted, return -ERESTARTSYS.  */
-		if (error == EINTR || error == ERESTART) {
-			ret = -ERESTARTSYS;
+		/*
+		 * If we were interrupted or timed out, massage the
+		 * error return and stop here.
+		 */
+		if (error) {
+			KASSERTMSG((error == EINTR || error == ERESTART ||
+				error == EWOULDBLOCK), "error=%d", error);
+			if (error == EINTR || error == ERESTART) {
+				ret = -EINTR;
+			} else if (error == EWOULDBLOCK) {
+				ret = -EAGAIN;
+			} else {
+				panic("invalid error=%d", error);
+			}
 			goto out;
 		}
 
 		/* Otherwise, debit the time spent.  */
-		timeout -= (endtime - starttime);
+		timeout -= MIN(timeout, (endtime - starttime));
 	}
-	/* Bit is set.  Return the time left.  */
+
+	/* Bit is clear.  Return zero on success.  */
+	KASSERT(test_bit(bit, bitmap) == 0);
 	ret = timeout;
 
-out:	wait_bit_exit(wbe);
+out:	KASSERT(test_bit(bit, bitmap) == 0 || ret != 0);
+	wait_bit_exit(wbe);
 	return ret;
 }

Reply via email to