xref: /openbsd-src/sys/dev/pci/drm/include/linux/wait.h (revision d6d1d580bbad0ce6f2186f18fbb3293862741cd0)
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