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