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;
}