jcs's openbsd hax
openbsd
at jcs 333 lines 8.6 kB view raw
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