1 /* $OpenBSD: completion.h,v 1.10 2024/01/06 09:33:08 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2015, 2018 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #ifndef _LINUX_COMPLETION_H 19 #define _LINUX_COMPLETION_H 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/mutex.h> 24 #include <linux/wait.h> 25 26 struct completion { 27 u_int done; 28 struct mutex lock; 29 }; 30 31 #define DECLARE_COMPLETION_ONSTACK(name) \ 32 struct completion name = { 0, MUTEX_INITIALIZER(IPL_TTY) } 33 34 static inline void 35 init_completion(struct completion *x) 36 { 37 x->done = 0; 38 mtx_init(&x->lock, IPL_TTY); 39 } 40 41 static inline void 42 reinit_completion(struct completion *x) 43 { 44 x->done = 0; 45 } 46 47 static inline u_long 48 wait_for_completion_timeout(struct completion *x, u_long timo) 49 { 50 int ret; 51 52 KASSERT(!cold); 53 54 mtx_enter(&x->lock); 55 while (x->done == 0) { 56 ret = msleep(x, &x->lock, 0, "wfct", timo); 57 if (ret) { 58 mtx_leave(&x->lock); 59 /* timeout */ 60 return 0; 61 } 62 } 63 if (x->done != UINT_MAX) 64 x->done--; 65 mtx_leave(&x->lock); 66 67 return 1; 68 } 69 70 static inline void 71 wait_for_completion(struct completion *x) 72 { 73 KASSERT(!cold); 74 75 mtx_enter(&x->lock); 76 while (x->done == 0) { 77 msleep_nsec(x, &x->lock, 0, "wfcom", INFSLP); 78 } 79 if (x->done != UINT_MAX) 80 x->done--; 81 mtx_leave(&x->lock); 82 } 83 84 static inline u_long 85 wait_for_completion_interruptible(struct completion *x) 86 { 87 int ret; 88 89 KASSERT(!cold); 90 91 mtx_enter(&x->lock); 92 while (x->done == 0) { 93 ret = msleep_nsec(x, &x->lock, PCATCH, "wfci", INFSLP); 94 if (ret) { 95 mtx_leave(&x->lock); 96 if (ret == EWOULDBLOCK) 97 return 0; 98 return -ERESTARTSYS; 99 } 100 } 101 if (x->done != UINT_MAX) 102 x->done--; 103 mtx_leave(&x->lock); 104 105 return 0; 106 } 107 108 static inline u_long 109 wait_for_completion_interruptible_timeout(struct completion *x, u_long timo) 110 { 111 int ret; 112 113 KASSERT(!cold); 114 115 mtx_enter(&x->lock); 116 while (x->done == 0) { 117 ret = msleep(x, &x->lock, PCATCH, "wfcit", timo); 118 if (ret) { 119 mtx_leave(&x->lock); 120 if (ret == EWOULDBLOCK) 121 return 0; 122 return -ERESTARTSYS; 123 } 124 } 125 if (x->done != UINT_MAX) 126 x->done--; 127 mtx_leave(&x->lock); 128 129 return 1; 130 } 131 132 static inline void 133 complete(struct completion *x) 134 { 135 mtx_enter(&x->lock); 136 if (x->done != UINT_MAX) 137 x->done++; 138 mtx_leave(&x->lock); 139 wakeup_one(x); 140 } 141 142 static inline void 143 complete_all(struct completion *x) 144 { 145 mtx_enter(&x->lock); 146 x->done = UINT_MAX; 147 mtx_leave(&x->lock); 148 wakeup(x); 149 } 150 151 static inline bool 152 try_wait_for_completion(struct completion *x) 153 { 154 mtx_enter(&x->lock); 155 if (x->done == 0) { 156 mtx_leave(&x->lock); 157 return false; 158 } 159 if (x->done != UINT_MAX) 160 x->done--; 161 mtx_leave(&x->lock); 162 return true; 163 } 164 165 #endif 166