1*d6d1d580Sclaudio /* $OpenBSD: wait.h,v 1.11 2023/07/28 09:46:13 claudio Exp $ */
27f4dd379Sjsg /*
37f4dd379Sjsg * Copyright (c) 2013, 2014, 2015 Mark Kettenis
47f4dd379Sjsg * Copyright (c) 2017 Martin Pieuchot
57f4dd379Sjsg *
67f4dd379Sjsg * Permission to use, copy, modify, and distribute this software for any
77f4dd379Sjsg * purpose with or without fee is hereby granted, provided that the above
87f4dd379Sjsg * copyright notice and this permission notice appear in all copies.
97f4dd379Sjsg *
107f4dd379Sjsg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117f4dd379Sjsg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127f4dd379Sjsg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137f4dd379Sjsg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147f4dd379Sjsg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157f4dd379Sjsg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167f4dd379Sjsg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177f4dd379Sjsg */
187f4dd379Sjsg
197f4dd379Sjsg #ifndef _LINUX_WAIT_H
207f4dd379Sjsg #define _LINUX_WAIT_H
217f4dd379Sjsg
227f4dd379Sjsg #include <sys/param.h>
237f4dd379Sjsg #include <sys/systm.h>
247f4dd379Sjsg #include <sys/mutex.h>
25c0be31d8Sclaudio #include <sys/proc.h>
267f4dd379Sjsg
277f4dd379Sjsg #include <linux/list.h>
287f4dd379Sjsg #include <linux/errno.h>
297f4dd379Sjsg #include <linux/spinlock.h>
307f4dd379Sjsg
317f4dd379Sjsg struct wait_queue_entry {
327f4dd379Sjsg unsigned int flags;
337f4dd379Sjsg void *private;
347f4dd379Sjsg int (*func)(struct wait_queue_entry *, unsigned, int, void *);
357f4dd379Sjsg struct list_head entry;
367f4dd379Sjsg };
377f4dd379Sjsg
387f4dd379Sjsg typedef struct wait_queue_entry wait_queue_entry_t;
397f4dd379Sjsg
407f4dd379Sjsg struct wait_queue_head {
417f4dd379Sjsg struct mutex lock;
427f4dd379Sjsg struct list_head head;
437f4dd379Sjsg };
447f4dd379Sjsg typedef struct wait_queue_head wait_queue_head_t;
457f4dd379Sjsg
46c0be31d8Sclaudio void prepare_to_wait(wait_queue_head_t *, wait_queue_entry_t *, int);
47c0be31d8Sclaudio void finish_wait(wait_queue_head_t *, wait_queue_entry_t *);
48c0be31d8Sclaudio
497f4dd379Sjsg static inline void
init_waitqueue_head(wait_queue_head_t * wqh)507f4dd379Sjsg init_waitqueue_head(wait_queue_head_t *wqh)
517f4dd379Sjsg {
527f4dd379Sjsg mtx_init(&wqh->lock, IPL_TTY);
537f4dd379Sjsg INIT_LIST_HEAD(&wqh->head);
547f4dd379Sjsg }
557f4dd379Sjsg
56ad8b1aafSjsg #define __init_waitqueue_head(wqh, name, key) init_waitqueue_head(wqh)
577f4dd379Sjsg
587f4dd379Sjsg int autoremove_wake_function(struct wait_queue_entry *, unsigned int, int, void *);
597f4dd379Sjsg
607f4dd379Sjsg static inline void
init_wait_entry(wait_queue_entry_t * wqe,int flags)617f4dd379Sjsg init_wait_entry(wait_queue_entry_t *wqe, int flags)
627f4dd379Sjsg {
637f4dd379Sjsg wqe->flags = flags;
64ad8b1aafSjsg wqe->private = curproc;
657f4dd379Sjsg wqe->func = autoremove_wake_function;
667f4dd379Sjsg INIT_LIST_HEAD(&wqe->entry);
677f4dd379Sjsg }
687f4dd379Sjsg
697f4dd379Sjsg static inline void
__add_wait_queue(wait_queue_head_t * wqh,wait_queue_entry_t * wqe)707f4dd379Sjsg __add_wait_queue(wait_queue_head_t *wqh, wait_queue_entry_t *wqe)
717f4dd379Sjsg {
727f4dd379Sjsg list_add(&wqe->entry, &wqh->head);
737f4dd379Sjsg }
747f4dd379Sjsg
757f4dd379Sjsg static inline void
__add_wait_queue_entry_tail(wait_queue_head_t * wqh,wait_queue_entry_t * wqe)767f4dd379Sjsg __add_wait_queue_entry_tail(wait_queue_head_t *wqh, wait_queue_entry_t *wqe)
777f4dd379Sjsg {
787f4dd379Sjsg list_add_tail(&wqe->entry, &wqh->head);
797f4dd379Sjsg }
807f4dd379Sjsg
817f4dd379Sjsg static inline void
add_wait_queue(wait_queue_head_t * head,wait_queue_entry_t * new)827f4dd379Sjsg add_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *new)
837f4dd379Sjsg {
847f4dd379Sjsg mtx_enter(&head->lock);
857f4dd379Sjsg __add_wait_queue(head, new);
867f4dd379Sjsg mtx_leave(&head->lock);
877f4dd379Sjsg }
887f4dd379Sjsg
897f4dd379Sjsg static inline void
__remove_wait_queue(wait_queue_head_t * wqh,wait_queue_entry_t * wqe)907f4dd379Sjsg __remove_wait_queue(wait_queue_head_t *wqh, wait_queue_entry_t *wqe)
917f4dd379Sjsg {
927f4dd379Sjsg list_del(&wqe->entry);
937f4dd379Sjsg }
947f4dd379Sjsg
957f4dd379Sjsg static inline void
remove_wait_queue(wait_queue_head_t * head,wait_queue_entry_t * old)967f4dd379Sjsg remove_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *old)
977f4dd379Sjsg {
987f4dd379Sjsg mtx_enter(&head->lock);
997f4dd379Sjsg __remove_wait_queue(head, old);
1007f4dd379Sjsg mtx_leave(&head->lock);
1017f4dd379Sjsg }
1027f4dd379Sjsg
103ad8b1aafSjsg #define __wait_event_intr_timeout(wqh, condition, timo, prio) \
1047f4dd379Sjsg ({ \
105c0be31d8Sclaudio long __ret = timo; \
106c0be31d8Sclaudio struct wait_queue_entry __wq_entry; \
107c0be31d8Sclaudio \
108c0be31d8Sclaudio init_wait_entry(&__wq_entry, 0); \
1097f4dd379Sjsg do { \
110c0be31d8Sclaudio int __error, __wait; \
111c2a61337Sjsg unsigned long deadline; \
1127f4dd379Sjsg \
1137f4dd379Sjsg KASSERT(!cold); \
1147f4dd379Sjsg \
115c0be31d8Sclaudio prepare_to_wait(&wqh, &__wq_entry, prio); \
116c0be31d8Sclaudio deadline = jiffies + __ret; \
117c0be31d8Sclaudio \
118c0be31d8Sclaudio __wait = !(condition); \
119c0be31d8Sclaudio \
120c0be31d8Sclaudio __error = sleep_finish(__ret, __wait); \
121c0be31d8Sclaudio if ((timo) > 0) \
122c0be31d8Sclaudio __ret = deadline - jiffies; \
123c0be31d8Sclaudio \
1247f4dd379Sjsg if (__error == ERESTART || __error == EINTR) { \
125c0be31d8Sclaudio __ret = -ERESTARTSYS; \
1267f4dd379Sjsg break; \
1277f4dd379Sjsg } \
128c0be31d8Sclaudio if ((timo) > 0 && (__ret <= 0 || __error == EWOULDBLOCK)) { \
129c0be31d8Sclaudio __ret = ((condition)) ? 1 : 0; \
1307f4dd379Sjsg break; \
1317f4dd379Sjsg } \
132c0be31d8Sclaudio } while (__ret > 0 && !(condition)); \
133c0be31d8Sclaudio finish_wait(&wqh, &__wq_entry); \
134c0be31d8Sclaudio __ret; \
1357f4dd379Sjsg })
1367f4dd379Sjsg
1377f4dd379Sjsg /*
1387f4dd379Sjsg * Sleep until `condition' gets true.
1397f4dd379Sjsg */
140ad8b1aafSjsg #define wait_event(wqh, condition) \
1417f4dd379Sjsg do { \
1427f4dd379Sjsg if (!(condition)) \
143ad8b1aafSjsg __wait_event_intr_timeout(wqh, condition, 0, 0); \
1447f4dd379Sjsg } while (0)
1457f4dd379Sjsg
146ad8b1aafSjsg #define wait_event_killable(wqh, condition) \
147c349dbc7Sjsg ({ \
148c349dbc7Sjsg int __ret = 0; \
149e45ba1fbSjsg if (!(condition)) \
150ad8b1aafSjsg __ret = __wait_event_intr_timeout(wqh, condition, 0, PCATCH); \
151c349dbc7Sjsg __ret; \
152c349dbc7Sjsg })
153e45ba1fbSjsg
154ad8b1aafSjsg #define wait_event_interruptible(wqh, condition) \
1557f4dd379Sjsg ({ \
1567f4dd379Sjsg int __ret = 0; \
1577f4dd379Sjsg if (!(condition)) \
158ad8b1aafSjsg __ret = __wait_event_intr_timeout(wqh, condition, 0, PCATCH); \
1597f4dd379Sjsg __ret; \
1607f4dd379Sjsg })
1617f4dd379Sjsg
162*d6d1d580Sclaudio #define __wait_event_intr_locked(wqh, condition) \
163*d6d1d580Sclaudio ({ \
164*d6d1d580Sclaudio struct wait_queue_entry __wq_entry; \
165*d6d1d580Sclaudio int __error; \
166*d6d1d580Sclaudio \
167*d6d1d580Sclaudio init_wait_entry(&__wq_entry, 0); \
168*d6d1d580Sclaudio do { \
169*d6d1d580Sclaudio KASSERT(!cold); \
170*d6d1d580Sclaudio \
171*d6d1d580Sclaudio if (list_empty(&__wq_entry.entry)) \
172*d6d1d580Sclaudio __add_wait_queue_entry_tail(&wqh, &__wq_entry); \
173*d6d1d580Sclaudio set_current_state(TASK_INTERRUPTIBLE); \
174*d6d1d580Sclaudio \
175*d6d1d580Sclaudio mtx_leave(&(wqh).lock); \
176*d6d1d580Sclaudio __error = sleep_finish(0, 1); \
177*d6d1d580Sclaudio mtx_enter(&(wqh).lock); \
178*d6d1d580Sclaudio if (__error == ERESTART || __error == EINTR) { \
179*d6d1d580Sclaudio __error = -ERESTARTSYS; \
180*d6d1d580Sclaudio break; \
181*d6d1d580Sclaudio } \
182*d6d1d580Sclaudio } while (!(condition)); \
183*d6d1d580Sclaudio __remove_wait_queue(&(wqh), &__wq_entry); \
184*d6d1d580Sclaudio __set_current_state(TASK_RUNNING); \
185*d6d1d580Sclaudio __error; \
186*d6d1d580Sclaudio })
187*d6d1d580Sclaudio
188ad8b1aafSjsg #define wait_event_interruptible_locked(wqh, condition) \
1897f4dd379Sjsg ({ \
1907f4dd379Sjsg int __ret = 0; \
1917f4dd379Sjsg if (!(condition)) \
192*d6d1d580Sclaudio __ret = __wait_event_intr_locked(wqh, condition); \
1937f4dd379Sjsg __ret; \
1947f4dd379Sjsg })
1957f4dd379Sjsg
1967f4dd379Sjsg /*
1977f4dd379Sjsg * Sleep until `condition' gets true or `timo' expires.
1987f4dd379Sjsg *
1997f4dd379Sjsg * Returns 0 if `condition' is still false when `timo' expires or
200c2a61337Sjsg * the remaining (>=1) jiffies otherwise.
2017f4dd379Sjsg */
202ad8b1aafSjsg #define wait_event_timeout(wqh, condition, timo) \
2037f4dd379Sjsg ({ \
2047f4dd379Sjsg long __ret = timo; \
2057f4dd379Sjsg if (!(condition)) \
206ad8b1aafSjsg __ret = __wait_event_intr_timeout(wqh, condition, timo, 0); \
2077f4dd379Sjsg __ret; \
2087f4dd379Sjsg })
2097f4dd379Sjsg
2107f4dd379Sjsg /*
2117f4dd379Sjsg * Sleep until `condition' gets true, `timo' expires or the process
2127f4dd379Sjsg * receives a signal.
2137f4dd379Sjsg *
2147f4dd379Sjsg * Returns -ERESTARTSYS if interrupted by a signal.
2157f4dd379Sjsg * Returns 0 if `condition' is still false when `timo' expires or
216c2a61337Sjsg * the remaining (>=1) jiffies otherwise.
2177f4dd379Sjsg */
218ad8b1aafSjsg #define wait_event_interruptible_timeout(wqh, condition, timo) \
2197f4dd379Sjsg ({ \
2207f4dd379Sjsg long __ret = timo; \
2217f4dd379Sjsg if (!(condition)) \
222ad8b1aafSjsg __ret = __wait_event_intr_timeout(wqh, condition, timo, PCATCH);\
2237f4dd379Sjsg __ret; \
2247f4dd379Sjsg })
2257f4dd379Sjsg
2261bb76ff1Sjsg #define __wait_event_lock_irq(wqh, condition, mtx) \
2271bb76ff1Sjsg ({ \
228c0be31d8Sclaudio struct wait_queue_entry __wq_entry; \
229c0be31d8Sclaudio \
230c0be31d8Sclaudio init_wait_entry(&__wq_entry, 0); \
2311bb76ff1Sjsg do { \
232c0be31d8Sclaudio int __wait; \
233c0be31d8Sclaudio \
2341bb76ff1Sjsg KASSERT(!cold); \
2351bb76ff1Sjsg \
236c0be31d8Sclaudio prepare_to_wait(&wqh, &__wq_entry, 0); \
237c0be31d8Sclaudio \
238c0be31d8Sclaudio __wait = !(condition); \
239c0be31d8Sclaudio \
2401bb76ff1Sjsg mtx_leave(&(mtx)); \
241c0be31d8Sclaudio sleep_finish(0, __wait); \
2421bb76ff1Sjsg mtx_enter(&(mtx)); \
2431bb76ff1Sjsg } while (!(condition)); \
244c0be31d8Sclaudio finish_wait(&wqh, &__wq_entry); \
2451bb76ff1Sjsg })
2461bb76ff1Sjsg
2471bb76ff1Sjsg /*
2481bb76ff1Sjsg * Sleep until `condition' gets true.
2491bb76ff1Sjsg * called locked, condition checked under lock
2501bb76ff1Sjsg */
2511bb76ff1Sjsg #define wait_event_lock_irq(wqh, condition, mtx) \
2521bb76ff1Sjsg do { \
2531bb76ff1Sjsg if (!(condition)) \
2541bb76ff1Sjsg __wait_event_lock_irq(wqh, condition, mtx); \
2551bb76ff1Sjsg } while (0)
2561bb76ff1Sjsg
2577f4dd379Sjsg static inline void
wake_up(wait_queue_head_t * wqh)2588c00de5eSvisa wake_up(wait_queue_head_t *wqh)
2597f4dd379Sjsg {
2607f4dd379Sjsg wait_queue_entry_t *wqe;
2617f4dd379Sjsg wait_queue_entry_t *tmp;
2628c00de5eSvisa mtx_enter(&wqh->lock);
2637f4dd379Sjsg
2647f4dd379Sjsg list_for_each_entry_safe(wqe, tmp, &wqh->head, entry) {
265ad8b1aafSjsg KASSERT(wqe->func != NULL);
2667f4dd379Sjsg if (wqe->func != NULL)
2677f4dd379Sjsg wqe->func(wqe, 0, wqe->flags, NULL);
2687f4dd379Sjsg }
2698c00de5eSvisa mtx_leave(&wqh->lock);
2707f4dd379Sjsg }
2717f4dd379Sjsg
272ad8b1aafSjsg #define wake_up_all(wqh) wake_up(wqh)
2737f4dd379Sjsg
2747f4dd379Sjsg static inline void
wake_up_all_locked(wait_queue_head_t * wqh)2757f4dd379Sjsg wake_up_all_locked(wait_queue_head_t *wqh)
2767f4dd379Sjsg {
2777f4dd379Sjsg wait_queue_entry_t *wqe;
2787f4dd379Sjsg wait_queue_entry_t *tmp;
2797f4dd379Sjsg
2807f4dd379Sjsg list_for_each_entry_safe(wqe, tmp, &wqh->head, entry) {
281ad8b1aafSjsg KASSERT(wqe->func != NULL);
2827f4dd379Sjsg if (wqe->func != NULL)
2837f4dd379Sjsg wqe->func(wqe, 0, wqe->flags, NULL);
2847f4dd379Sjsg }
2857f4dd379Sjsg }
2867f4dd379Sjsg
287ad8b1aafSjsg #define wake_up_interruptible(wqh) wake_up(wqh)
288ad8b1aafSjsg #define wake_up_interruptible_poll(wqh, flags) wake_up(wqh)
2897f4dd379Sjsg
2907f4dd379Sjsg #define DEFINE_WAIT(name) \
2917f4dd379Sjsg struct wait_queue_entry name = { \
292ad8b1aafSjsg .private = curproc, \
2937f4dd379Sjsg .func = autoremove_wake_function, \
2947f4dd379Sjsg .entry = LIST_HEAD_INIT((name).entry), \
2957f4dd379Sjsg }
2967f4dd379Sjsg
2977f4dd379Sjsg #endif
298