1 /* $NetBSD: completion.h,v 1.12 2021/12/19 12:35:37 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R. Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Notes on porting: 34 * 35 * - Linux does not have destroy_completion. You must add it yourself 36 * in the appropriate place. 37 * 38 * - Some Linux code does `completion->done++' or similar. Convert 39 * that to complete(completion) and suggest the same change upstream, 40 * unless it turns out there actually is a good reason to do that, in 41 * which case the Linux completion API should be extended with a 42 * sensible name for this that doesn't expose the guts of `struct 43 * completion'. 44 */ 45 46 #ifndef _LINUX_COMPLETION_H_ 47 #define _LINUX_COMPLETION_H_ 48 49 #include <sys/types.h> 50 #include <sys/param.h> 51 #include <sys/kernel.h> 52 #include <sys/condvar.h> 53 #include <sys/mutex.h> 54 55 #include <machine/limits.h> 56 57 #include <linux/errno.h> 58 59 struct completion { 60 kmutex_t c_lock; 61 kcondvar_t c_cv; 62 63 /* 64 * c_done is either 65 * 66 * . -1, meaning it's open season and we're done for good and 67 * nobody need wait any more; 68 * 69 * . 0, meaning nothing is done, so waiters must block; or 70 * 71 * . a positive integer, meaning that many waiters can 72 * proceed before further waiters must block. 73 * 74 * Negative values other than -1 are not allowed. 75 */ 76 int c_done; 77 }; 78 79 /* 80 * Initialize a new completion object. 81 */ 82 static inline void 83 init_completion(struct completion *completion) 84 { 85 86 mutex_init(&completion->c_lock, MUTEX_DEFAULT, IPL_SCHED); 87 cv_init(&completion->c_cv, "lnxcmplt"); 88 completion->c_done = 0; 89 } 90 91 /* 92 * re-initialize a completion object. 93 */ 94 static inline void 95 reinit_completion(struct completion *completion) 96 { 97 98 completion->c_done = 0; 99 } 100 101 /* 102 * Destroy a completion object. 103 */ 104 static inline void 105 destroy_completion(struct completion *completion) 106 { 107 KASSERT(!cv_has_waiters(&completion->c_cv)); 108 cv_destroy(&completion->c_cv); 109 mutex_destroy(&completion->c_lock); 110 } 111 112 /* 113 * Notify one waiter of completion, but not any future ones. 114 */ 115 static inline void 116 complete(struct completion *completion) 117 { 118 119 mutex_enter(&completion->c_lock); 120 121 /* If it's not open season, wake one waiter. */ 122 if (completion->c_done >= 0) { 123 KASSERT(completion->c_done < INT_MAX); /* XXX check */ 124 completion->c_done++; 125 cv_signal(&completion->c_cv); 126 } else { 127 KASSERT(completion->c_done == -1); 128 } 129 130 mutex_exit(&completion->c_lock); 131 } 132 133 /* 134 * Notify all waiters, present and future (until INIT_COMPLETION), of 135 * completion. 136 */ 137 static inline void 138 complete_all(struct completion *completion) 139 { 140 141 mutex_enter(&completion->c_lock); 142 143 /* If it's not open season, make it open season and wake everyone. */ 144 if (completion->c_done >= 0) { 145 completion->c_done = -1; 146 cv_broadcast(&completion->c_cv); 147 } else { 148 KASSERT(completion->c_done == -1); 149 } 150 151 mutex_exit(&completion->c_lock); 152 } 153 154 /* 155 * Reverse the effect of complete_all so that subsequent waiters block 156 * until someone calls complete or complete_all. 157 * 158 * This operation is very different from its lowercase counterpart. 159 * 160 * For some reason this works on the completion object itself, not on a 161 * pointer thereto, so it must be a macro. 162 */ 163 #define INIT_COMPLETION(COMPLETION) INIT_COMPLETION_blorp(&(COMPLETION)) 164 165 static inline void 166 INIT_COMPLETION_blorp(struct completion *completion) 167 { 168 169 mutex_enter(&completion->c_lock); 170 completion->c_done = 0; 171 /* No notify -- waiters are interested only in nonzero values. */ 172 mutex_exit(&completion->c_lock); 173 } 174 175 static inline void 176 _completion_claim(struct completion *completion) 177 { 178 179 KASSERT(mutex_owned(&completion->c_lock)); 180 KASSERT(completion->c_done != 0); 181 if (completion->c_done > 0) 182 completion->c_done--; 183 else 184 KASSERT(completion->c_done == -1); 185 } 186 187 /* 188 * Wait interruptibly with a timeout for someone to call complete or 189 * complete_all. 190 */ 191 static inline int 192 wait_for_completion_interruptible_timeout(struct completion *completion, 193 unsigned long ticks) 194 { 195 /* XXX Arithmetic overflow...? */ 196 unsigned int start = getticks(), now; 197 int error; 198 199 mutex_enter(&completion->c_lock); 200 201 /* Wait until c_done is nonzero, timeout, or signal. */ 202 while (completion->c_done == 0) { 203 if (ticks == 0) { 204 error = EWOULDBLOCK; 205 goto out; 206 } 207 error = cv_timedwait_sig(&completion->c_cv, 208 &completion->c_lock, MIN(ticks, INT_MAX/2)); 209 now = getticks(); 210 if (error) 211 goto out; 212 ticks -= MIN(ticks, (now - start)); 213 start = now; 214 } 215 216 /* Success! */ 217 _completion_claim(completion); 218 error = 0; 219 220 out: mutex_exit(&completion->c_lock); 221 if (error == EWOULDBLOCK) { 222 return 0; 223 } else if ((error == EINTR) || (error == ERESTART)) { 224 return -ERESTARTSYS; 225 } else { 226 KASSERTMSG((error == 0), "error = %d", error); 227 return MAX(1, MIN(ticks, INT_MAX/2)); 228 } 229 } 230 231 static inline int 232 wait_for_completion_timeout(struct completion *completion, unsigned long ticks) 233 { 234 /* XXX Arithmetic overflow...? */ 235 unsigned int start = getticks(), now; 236 int error; 237 238 mutex_enter(&completion->c_lock); 239 240 /* Wait until c_done is nonzero or timeout. */ 241 while (completion->c_done == 0) { 242 if (ticks == 0) { 243 error = EWOULDBLOCK; 244 goto out; 245 } 246 error = cv_timedwait(&completion->c_cv, &completion->c_lock, 247 MIN(ticks, INT_MAX/2)); 248 now = getticks(); 249 if (error) 250 goto out; 251 ticks -= MIN(ticks, (now - start)); 252 start = now; 253 } 254 255 /* Success! */ 256 _completion_claim(completion); 257 error = 0; 258 259 out: mutex_exit(&completion->c_lock); 260 if (error == EWOULDBLOCK) { 261 return 0; 262 } else { 263 KASSERTMSG((error == 0), "error = %d", error); 264 return MAX(1, MIN(ticks, INT_MAX/2)); 265 } 266 } 267 268 /* 269 * Wait interruptibly for someone to call complete or complete_all. 270 */ 271 static inline int 272 wait_for_completion_interruptible(struct completion *completion) 273 { 274 int error; 275 276 mutex_enter(&completion->c_lock); 277 278 /* Wait until c_done is nonzero or signal. */ 279 while (completion->c_done == 0) { 280 error = cv_wait_sig(&completion->c_cv, &completion->c_lock); 281 if (error) 282 goto out; 283 } 284 285 /* Success! */ 286 _completion_claim(completion); 287 error = 0; 288 289 out: mutex_exit(&completion->c_lock); 290 if ((error == EINTR) || (error == ERESTART)) { 291 return -ERESTARTSYS; 292 } else { 293 KASSERTMSG((error == 0), "error = %d", error); 294 return 0; 295 } 296 } 297 298 /* 299 * Wait uninterruptibly, except by SIGKILL, for someone to call 300 * complete or complete_all. 301 * 302 * XXX In this implementation, any signal will actually wake us, not 303 * just SIGKILL. 304 */ 305 static inline int 306 wait_for_completion_killable(struct completion *completion) 307 { 308 309 return wait_for_completion_interruptible(completion); 310 } 311 312 static inline void 313 wait_for_completion(struct completion *completion) 314 { 315 316 mutex_enter(&completion->c_lock); 317 while (completion->c_done == 0) 318 cv_wait(&completion->c_cv, &completion->c_lock); 319 _completion_claim(completion); 320 mutex_exit(&completion->c_lock); 321 } 322 323 /* 324 * Try to claim a completion immediately. Return true on success, false 325 * if it would block. 326 */ 327 static inline bool 328 try_wait_for_completion(struct completion *completion) 329 { 330 bool ok; 331 332 mutex_enter(&completion->c_lock); 333 if (completion->c_done == 0) { 334 ok = false; 335 } else { 336 _completion_claim(completion); 337 ok = true; 338 } 339 mutex_exit(&completion->c_lock); 340 341 return ok; 342 } 343 344 #endif /* _LINUX_COMPLETION_H_ */ 345