1 /* $NetBSD: completion.h,v 1.6 2017/01/11 11:42:09 skrll 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/condvar.h> 51 #include <sys/mutex.h> 52 53 #include <machine/limits.h> 54 55 #include <linux/errno.h> 56 57 struct completion { 58 kmutex_t c_lock; 59 kcondvar_t c_cv; 60 61 /* 62 * c_done is either 63 * 64 * . -1, meaning it's open season and we're done for good and 65 * nobody need wait any more; 66 * 67 * . 0, meaning nothing is done, so waiters must block; or 68 * 69 * . a positive integer, meaning that many waiters can 70 * proceed before further waiters must block. 71 * 72 * Negative values other than -1 are not allowed. 73 */ 74 int c_done; 75 }; 76 77 /* 78 * Initialize a new completion object. 79 */ 80 static inline void 81 init_completion(struct completion *completion) 82 { 83 84 mutex_init(&completion->c_lock, MUTEX_DEFAULT, IPL_SCHED); 85 cv_init(&completion->c_cv, "lnxcmplt"); 86 completion->c_done = 0; 87 } 88 89 /* 90 * re-initialize a completion object. 91 */ 92 static inline void 93 reinit_completion(struct completion *completion) 94 { 95 96 completion->c_done = 0; 97 } 98 99 /* 100 * Destroy a completion object. 101 */ 102 static inline void 103 destroy_completion(struct completion *completion) 104 { 105 KASSERT(!cv_has_waiters(&completion->c_cv)); 106 cv_destroy(&completion->c_cv); 107 mutex_destroy(&completion->c_lock); 108 } 109 110 /* 111 * Notify one waiter of completion, but not any future ones. 112 */ 113 static inline void 114 complete(struct completion *completion) 115 { 116 117 mutex_enter(&completion->c_lock); 118 119 /* If it's not open season, wake one waiter. */ 120 if (completion->c_done >= 0) { 121 KASSERT(completion->c_done < INT_MAX); /* XXX check */ 122 completion->c_done++; 123 cv_signal(&completion->c_cv); 124 } else { 125 KASSERT(completion->c_done == -1); 126 } 127 128 mutex_exit(&completion->c_lock); 129 } 130 131 /* 132 * Notify all waiters, present and future (until INIT_COMPLETION), of 133 * completion. 134 */ 135 static inline void 136 complete_all(struct completion *completion) 137 { 138 139 mutex_enter(&completion->c_lock); 140 141 /* If it's not open season, make it open season and wake everyone. */ 142 if (completion->c_done >= 0) { 143 completion->c_done = -1; 144 cv_broadcast(&completion->c_cv); 145 } else { 146 KASSERT(completion->c_done == -1); 147 } 148 149 mutex_exit(&completion->c_lock); 150 } 151 152 /* 153 * Reverse the effect of complete_all so that subsequent waiters block 154 * until someone calls complete or complete_all. 155 * 156 * This operation is very different from its lowercase counterpart. 157 * 158 * For some reason this works on the completion object itself, not on a 159 * pointer thereto, so it must be a macro. 160 */ 161 #define INIT_COMPLETION(COMPLETION) INIT_COMPLETION_blorp(&(COMPLETION)) 162 163 static inline void 164 INIT_COMPLETION_blorp(struct completion *completion) 165 { 166 167 mutex_enter(&completion->c_lock); 168 completion->c_done = 0; 169 /* No notify -- waiters are interested only in nonzero values. */ 170 mutex_exit(&completion->c_lock); 171 } 172 173 static inline void 174 _completion_claim(struct completion *completion) 175 { 176 177 KASSERT(mutex_owned(&completion->c_lock)); 178 KASSERT(completion->c_done != 0); 179 if (completion->c_done > 0) 180 completion->c_done--; 181 else 182 KASSERT(completion->c_done == -1); 183 } 184 185 /* 186 * Wait interruptibly with a timeout for someone to call complete or 187 * complete_all. 188 */ 189 static inline int 190 wait_for_completion_interruptible_timeout(struct completion *completion, 191 unsigned long ticks) 192 { 193 /* XXX Arithmetic overflow...? */ 194 unsigned int start = hardclock_ticks, now; 195 int error; 196 197 mutex_enter(&completion->c_lock); 198 199 /* Wait until c_done is nonzero. */ 200 while (completion->c_done == 0) { 201 error = cv_timedwait_sig(&completion->c_cv, 202 &completion->c_lock, ticks); 203 if (error) 204 goto out; 205 now = hardclock_ticks; 206 if (ticks < (now - start)) { 207 error = EWOULDBLOCK; 208 goto out; 209 } 210 ticks -= (now - start); 211 start = now; 212 } 213 214 /* Success! */ 215 _completion_claim(completion); 216 error = 0; 217 218 out: mutex_exit(&completion->c_lock); 219 if (error == EWOULDBLOCK) { 220 return 0; 221 } else if ((error == EINTR) || (error == ERESTART)) { 222 return -ERESTARTSYS; 223 } else { 224 KASSERTMSG((error == 0), "error = %d", error); 225 return ticks; 226 } 227 } 228 229 /* 230 * Wait interruptibly for someone to call complete or complete_all. 231 */ 232 static inline int 233 wait_for_completion_interruptible(struct completion *completion) 234 { 235 int error; 236 237 mutex_enter(&completion->c_lock); 238 239 /* Wait until c_done is nonzero. */ 240 while (completion->c_done == 0) { 241 error = cv_wait_sig(&completion->c_cv, &completion->c_lock); 242 if (error) 243 goto out; 244 } 245 246 /* Success! */ 247 _completion_claim(completion); 248 error = 0; 249 250 out: mutex_exit(&completion->c_lock); 251 if ((error == EINTR) || (error == ERESTART)) 252 error = -ERESTARTSYS; 253 return error; 254 } 255 256 /* 257 * Wait uninterruptibly, except by SIGKILL, for someone to call 258 * complete or complete_all. 259 * 260 * XXX In this implementation, any signal will actually wake us, not 261 * just SIGKILL. 262 */ 263 static inline int 264 wait_for_completion_killable(struct completion *completion) 265 { 266 267 return wait_for_completion_interruptible(completion); 268 } 269 270 /* 271 * Try to claim a completion immediately. Return true on success, false 272 * if it would block. 273 */ 274 static inline bool 275 try_wait_for_completion(struct completion *completion) 276 { 277 bool ok; 278 279 mutex_enter(&completion->c_lock); 280 if (completion->c_done == 0) { 281 ok = false; 282 } else { 283 _completion_claim(completion); 284 ok = true; 285 } 286 mutex_exit(&completion->c_lock); 287 288 return ok; 289 } 290 291 #endif /* _LINUX_COMPLETION_H_ */ 292