completion.h revision 1.3.4.2 1 /* $NetBSD: completion.h,v 1.3.4.2 2014/05/22 11:40:42 yamt 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