Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2/linux linux: Fix wait_bit semantics.



details:   https://anonhg.NetBSD.org/src/rev/2a489092d9d4
branches:  trunk
changeset: 1028967:2a489092d9d4
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun Dec 19 12:36:08 2021 +0000

description:
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.

diffstat:

 sys/external/bsd/drm2/include/linux/wait_bit.h |    4 +-
 sys/external/bsd/drm2/linux/linux_wait_bit.c   |  113 +++++++++++++++---------
 2 files changed, 71 insertions(+), 46 deletions(-)

diffs (207 lines):

diff -r 52043fb851ce -r 2a489092d9d4 sys/external/bsd/drm2/include/linux/wait_bit.h
--- a/sys/external/bsd/drm2/include/linux/wait_bit.h    Sun Dec 19 12:36:02 2021 +0000
+++ b/sys/external/bsd/drm2/include/linux/wait_bit.h    Sun Dec 19 12:36:08 2021 +0000
@@ -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,
diff -r 52043fb851ce -r 2a489092d9d4 sys/external/bsd/drm2/linux/linux_wait_bit.c
--- a/sys/external/bsd/drm2/linux/linux_wait_bit.c      Sun Dec 19 12:36:02 2021 +0000
+++ b/sys/external/bsd/drm2/linux/linux_wait_bit.c      Sun Dec 19 12:36:08 2021 +0000
@@ -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 @@
        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 @@
        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 @@
        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 (flags & TASK_UNINTERRUPTIBLE) {
-                       error = cv_timedwait(&wbe->cv, &wbe->lock,
-                           MIN(INT_MAX, timeout));
-               } 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;
+               if (timeout == 0) {
+                       ret = -EAGAIN;
                        goto out;
                }
 
-               /* If we were interrupted, return -ERESTARTSYS.  */
-               if (error == EINTR || error == ERESTART) {
-                       ret = -ERESTARTSYS;
+               starttime = getticks();
+               if (flags & TASK_UNINTERRUPTIBLE) {
+                       error = cv_timedwait(&wbe->cv, &wbe->lock,
+                           MIN(timeout, INT_MAX/2));
+               } else {
+                       error = cv_timedwait_sig(&wbe->cv, &wbe->lock,
+                           MIN(timeout, INT_MAX/2));
+               }
+               endtime = getticks();
+
+               /*
+                * 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;
 }



Home | Main Index | Thread Index | Old Index