Properly emulate wait_event_interruptible_locked().
authorclaudio <claudio@openbsd.org>
Fri, 28 Jul 2023 09:46:13 +0000 (09:46 +0000)
committerclaudio <claudio@openbsd.org>
Fri, 28 Jul 2023 09:46:13 +0000 (09:46 +0000)
This function is called with the wait_queue_head locked, so the code
can not use prepare_to_wait()/finish_wait() since these assume the
wqh is unlocked. Also the lock needs to be held right up to the
schedule()/sleep_finish() call.
OK kettenis@ jsg@

sys/dev/pci/drm/include/linux/wait.h

index e8b9f0c..4523483 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: wait.h,v 1.10 2023/07/18 06:58:59 claudio Exp $       */
+/*     $OpenBSD: wait.h,v 1.11 2023/07/28 09:46:13 claudio Exp $       */
 /*
  * Copyright (c) 2013, 2014, 2015 Mark Kettenis
  * Copyright (c) 2017 Martin Pieuchot
@@ -159,11 +159,37 @@ do {                                              \
        __ret;                                  \
 })
 
+#define __wait_event_intr_locked(wqh, condition)                       \
+({                                                                     \
+       struct wait_queue_entry __wq_entry;                             \
+       int __error;                                                    \
+                                                                       \
+       init_wait_entry(&__wq_entry, 0);                                \
+       do {                                                            \
+               KASSERT(!cold);                                         \
+                                                                       \
+               if (list_empty(&__wq_entry.entry))                      \
+                       __add_wait_queue_entry_tail(&wqh, &__wq_entry); \
+               set_current_state(TASK_INTERRUPTIBLE);                  \
+                                                                       \
+               mtx_leave(&(wqh).lock);                                 \
+               __error = sleep_finish(0, 1);                           \
+               mtx_enter(&(wqh).lock);                                 \
+               if (__error == ERESTART || __error == EINTR) {          \
+                       __error = -ERESTARTSYS;                         \
+                       break;                                          \
+               }                                                       \
+       } while (!(condition));                                         \
+       __remove_wait_queue(&(wqh), &__wq_entry);                       \
+       __set_current_state(TASK_RUNNING);                              \
+       __error;                                                        \
+})
+
 #define wait_event_interruptible_locked(wqh, condition)                \
 ({                                             \
        int __ret = 0;                          \
        if (!(condition))                       \
-               __ret = __wait_event_intr_timeout(wqh, condition, 0, PCATCH); \
+               __ret = __wait_event_intr_locked(wqh, condition);       \
        __ret;                                  \
 })