jcs's openbsd hax
openbsd
1/* $OpenBSD: wait.h,v 1.15 2025/12/01 09:25:03 jsg Exp $ */
2/*
3 * Copyright (c) 2013, 2014, 2015 Mark Kettenis
4 * Copyright (c) 2017 Martin Pieuchot
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#ifndef _LINUX_WAIT_H
20#define _LINUX_WAIT_H
21
22#include <sys/param.h>
23#include <sys/systm.h>
24#include <sys/mutex.h>
25#include <sys/proc.h>
26
27#include <linux/list.h>
28#include <linux/errno.h>
29#include <linux/spinlock.h>
30
31struct wait_queue_entry {
32 unsigned int flags;
33 void *private;
34 int (*func)(struct wait_queue_entry *, unsigned, int, void *);
35 struct list_head entry;
36};
37
38#define WQ_FLAG_WOKEN (1 << 1)
39
40typedef struct wait_queue_entry wait_queue_entry_t;
41
42struct wait_queue_head {
43 struct mutex lock;
44 struct list_head head;
45};
46typedef struct wait_queue_head wait_queue_head_t;
47
48void prepare_to_wait(wait_queue_head_t *, wait_queue_entry_t *, int);
49void finish_wait(wait_queue_head_t *, wait_queue_entry_t *);
50
51static inline void
52init_waitqueue_head(wait_queue_head_t *wqh)
53{
54 mtx_init(&wqh->lock, IPL_TTY);
55 INIT_LIST_HEAD(&wqh->head);
56}
57
58#define __init_waitqueue_head(wqh, name, key) init_waitqueue_head(wqh)
59
60int autoremove_wake_function(struct wait_queue_entry *, unsigned int, int, void *);
61int woken_wake_function(struct wait_queue_entry *, unsigned int, int, void *);
62
63static inline void
64init_wait_entry(wait_queue_entry_t *wqe, int flags)
65{
66 wqe->flags = flags;
67 wqe->private = curproc;
68 wqe->func = autoremove_wake_function;
69 INIT_LIST_HEAD(&wqe->entry);
70}
71
72static inline void
73__add_wait_queue(wait_queue_head_t *wqh, wait_queue_entry_t *wqe)
74{
75 list_add(&wqe->entry, &wqh->head);
76}
77
78static inline void
79__add_wait_queue_entry_tail(wait_queue_head_t *wqh, wait_queue_entry_t *wqe)
80{
81 list_add_tail(&wqe->entry, &wqh->head);
82}
83
84static inline void
85add_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *new)
86{
87 mtx_enter(&head->lock);
88 __add_wait_queue(head, new);
89 mtx_leave(&head->lock);
90}
91
92static inline void
93__remove_wait_queue(wait_queue_head_t *wqh, wait_queue_entry_t *wqe)
94{
95 list_del(&wqe->entry);
96}
97
98static inline void
99remove_wait_queue(wait_queue_head_t *head, wait_queue_entry_t *old)
100{
101 mtx_enter(&head->lock);
102 __remove_wait_queue(head, old);
103 mtx_leave(&head->lock);
104}
105
106#define __wait_event_intr(wqh, condition, prio) \
107({ \
108 long __ret = 0; \
109 struct wait_queue_entry __wq_entry; \
110 \
111 init_wait_entry(&__wq_entry, 0); \
112 do { \
113 int __error, __wait; \
114 \
115 KASSERT(!cold); \
116 \
117 prepare_to_wait(&wqh, &__wq_entry, prio); \
118 \
119 __wait = !(condition); \
120 \
121 __error = sleep_finish(INFSLP, __wait); \
122 \
123 if (__error == ERESTART || __error == EINTR) { \
124 __ret = -ERESTARTSYS; \
125 break; \
126 } \
127 } while (!(condition)); \
128 finish_wait(&wqh, &__wq_entry); \
129 __ret; \
130})
131
132#define __wait_event_intr_timeout(wqh, condition, timo, prio) \
133({ \
134 long __ret = timo; \
135 struct wait_queue_entry __wq_entry; \
136 \
137 init_wait_entry(&__wq_entry, 0); \
138 do { \
139 int __error, __wait; \
140 unsigned long deadline; \
141 uint64_t nsecs = jiffies_to_nsecs(__ret); \
142 \
143 KASSERT(!cold); \
144 \
145 prepare_to_wait(&wqh, &__wq_entry, prio); \
146 deadline = jiffies + __ret; \
147 \
148 __wait = !(condition); \
149 \
150 __error = sleep_finish(nsecs, __wait); \
151 if ((timo) > 0) \
152 __ret = deadline - jiffies; \
153 \
154 if (__error == ERESTART || __error == EINTR) { \
155 __ret = -ERESTARTSYS; \
156 break; \
157 } \
158 if ((timo) > 0 && (__ret <= 0 || __error == EWOULDBLOCK)) { \
159 __ret = ((condition)) ? 1 : 0; \
160 break; \
161 } \
162 } while (__ret > 0 && !(condition)); \
163 finish_wait(&wqh, &__wq_entry); \
164 __ret; \
165})
166
167/*
168 * Sleep until `condition' gets true.
169 */
170#define wait_event(wqh, condition) \
171do { \
172 if (!(condition)) \
173 __wait_event_intr(wqh, condition, 0); \
174} while (0)
175
176#define wait_event_killable(wqh, condition) \
177({ \
178 int __ret = 0; \
179 if (!(condition)) \
180 __ret = __wait_event_intr(wqh, condition, PCATCH); \
181 __ret; \
182})
183
184#define wait_event_interruptible(wqh, condition) \
185({ \
186 int __ret = 0; \
187 if (!(condition)) \
188 __ret = __wait_event_intr(wqh, condition, PCATCH); \
189 __ret; \
190})
191
192#define __wait_event_intr_locked(wqh, condition) \
193({ \
194 struct wait_queue_entry __wq_entry; \
195 int __error; \
196 \
197 init_wait_entry(&__wq_entry, 0); \
198 do { \
199 KASSERT(!cold); \
200 \
201 if (list_empty(&__wq_entry.entry)) \
202 __add_wait_queue_entry_tail(&wqh, &__wq_entry); \
203 set_current_state(TASK_INTERRUPTIBLE); \
204 \
205 mtx_leave(&(wqh).lock); \
206 __error = sleep_finish(INFSLP, 1); \
207 mtx_enter(&(wqh).lock); \
208 if (__error == ERESTART || __error == EINTR) { \
209 __error = -ERESTARTSYS; \
210 break; \
211 } \
212 } while (!(condition)); \
213 __remove_wait_queue(&(wqh), &__wq_entry); \
214 __set_current_state(TASK_RUNNING); \
215 __error; \
216})
217
218#define wait_event_interruptible_locked(wqh, condition) \
219({ \
220 int __ret = 0; \
221 if (!(condition)) \
222 __ret = __wait_event_intr_locked(wqh, condition); \
223 __ret; \
224})
225
226/*
227 * Sleep until `condition' gets true or `timo' expires.
228 *
229 * Returns 0 if `condition' is still false when `timo' expires or
230 * the remaining (>=1) jiffies otherwise.
231 */
232#define wait_event_timeout(wqh, condition, timo) \
233({ \
234 long __ret = timo; \
235 if (!(condition)) \
236 __ret = __wait_event_intr_timeout(wqh, condition, timo, 0); \
237 __ret; \
238})
239
240/*
241 * Sleep until `condition' gets true, `timo' expires or the process
242 * receives a signal.
243 *
244 * Returns -ERESTARTSYS if interrupted by a signal.
245 * Returns 0 if `condition' is still false when `timo' expires or
246 * the remaining (>=1) jiffies otherwise.
247 */
248#define wait_event_interruptible_timeout(wqh, condition, timo) \
249({ \
250 long __ret = timo; \
251 if (!(condition)) \
252 __ret = __wait_event_intr_timeout(wqh, condition, timo, PCATCH);\
253 __ret; \
254})
255
256#define __wait_event_lock_irq(wqh, condition, mtx) \
257({ \
258 struct wait_queue_entry __wq_entry; \
259 \
260 init_wait_entry(&__wq_entry, 0); \
261 do { \
262 int __wait; \
263 \
264 KASSERT(!cold); \
265 \
266 prepare_to_wait(&wqh, &__wq_entry, 0); \
267 \
268 __wait = !(condition); \
269 \
270 mtx_leave(&(mtx)); \
271 sleep_finish(INFSLP, __wait); \
272 mtx_enter(&(mtx)); \
273 } while (!(condition)); \
274 finish_wait(&wqh, &__wq_entry); \
275})
276
277/*
278 * Sleep until `condition' gets true.
279 * called locked, condition checked under lock
280 */
281#define wait_event_lock_irq(wqh, condition, mtx) \
282do { \
283 if (!(condition)) \
284 __wait_event_lock_irq(wqh, condition, mtx); \
285} while (0)
286
287static inline void
288wake_up(wait_queue_head_t *wqh)
289{
290 wait_queue_entry_t *wqe;
291 wait_queue_entry_t *tmp;
292 mtx_enter(&wqh->lock);
293
294 list_for_each_entry_safe(wqe, tmp, &wqh->head, entry) {
295 KASSERT(wqe->func != NULL);
296 if (wqe->func != NULL)
297 wqe->func(wqe, 0, wqe->flags, NULL);
298 }
299 mtx_leave(&wqh->lock);
300}
301
302#define wake_up_all(wqh) wake_up(wqh)
303
304static inline void
305wake_up_all_locked(wait_queue_head_t *wqh)
306{
307 wait_queue_entry_t *wqe;
308 wait_queue_entry_t *tmp;
309
310 list_for_each_entry_safe(wqe, tmp, &wqh->head, entry) {
311 KASSERT(wqe->func != NULL);
312 if (wqe->func != NULL)
313 wqe->func(wqe, 0, wqe->flags, NULL);
314 }
315}
316
317#define wake_up_interruptible(wqh) wake_up(wqh)
318#define wake_up_interruptible_poll(wqh, flags) wake_up(wqh)
319
320#define DEFINE_WAIT(name) \
321 struct wait_queue_entry name = { \
322 .private = curproc, \
323 .func = autoremove_wake_function, \
324 .entry = LIST_HEAD_INIT((name).entry), \
325 }
326
327#define DEFINE_WAIT_FUNC(name, fn) \
328 struct wait_queue_entry name = { \
329 .private = curproc, \
330 .func = fn, \
331 .entry = LIST_HEAD_INIT((name).entry), \
332 }
333#endif