]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
8ad349bb | 4 | * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ |
1c79356b | 5 | * |
8ad349bb A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the | |
10 | * License may not be used to create, or enable the creation or | |
11 | * redistribution of, unlawful or unlicensed copies of an Apple operating | |
12 | * system, or to circumvent, violate, or enable the circumvention or | |
13 | * violation of, any terms of an Apple operating system software license | |
14 | * agreement. | |
15 | * | |
16 | * Please obtain a copy of the License at | |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
18 | * file. | |
19 | * | |
20 | * The Original Code and all software distributed under the License are | |
21 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
22 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
23 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
25 | * Please see the License for the specific language governing rights and | |
26 | * limitations under the License. | |
27 | * | |
28 | * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ | |
1c79356b | 29 | */ |
1c79356b | 30 | |
91447636 | 31 | #ifdef KERNEL_PRIVATE |
9bccf70c | 32 | |
91447636 A |
33 | #ifndef _KERN_WAIT_QUEUE_H_ |
34 | #define _KERN_WAIT_QUEUE_H_ | |
9bccf70c | 35 | |
91447636 | 36 | #include <mach/mach_types.h> |
1c79356b | 37 | #include <mach/sync_policy.h> |
0b4e3aa0 | 38 | #include <mach/kern_return.h> /* for kern_return_t */ |
1c79356b | 39 | |
9bccf70c A |
40 | #include <kern/kern_types.h> /* for wait_queue_t */ |
41 | ||
91447636 A |
42 | #include <sys/cdefs.h> |
43 | ||
44 | #ifdef MACH_KERNEL_PRIVATE | |
1c79356b A |
45 | |
46 | #include <kern/lock.h> | |
47 | #include <kern/queue.h> | |
91447636 | 48 | #include <machine/cpu_number.h> |
9bccf70c | 49 | |
1c79356b A |
50 | /* |
51 | * wait_queue_t | |
52 | * This is the definition of the common event wait queue | |
53 | * that the scheduler APIs understand. It is used | |
54 | * internally by the gerneralized event waiting mechanism | |
55 | * (assert_wait), and also for items that maintain their | |
56 | * own wait queues (such as ports and semaphores). | |
57 | * | |
58 | * It is not published to other kernel components. They | |
59 | * can create wait queues by calling wait_queue_alloc. | |
60 | * | |
61 | * NOTE: Hardware locks are used to protect event wait | |
62 | * queues since interrupt code is free to post events to | |
63 | * them. | |
64 | */ | |
65 | typedef struct wait_queue { | |
9bccf70c A |
66 | unsigned int /* flags */ |
67 | /* boolean_t */ wq_type:16, /* only public field */ | |
68 | wq_fifo:1, /* fifo wakeup policy? */ | |
69 | wq_isprepost:1, /* is waitq preposted? set only */ | |
70 | :0; /* force to long boundary */ | |
1c79356b | 71 | hw_lock_data_t wq_interlock; /* interlock */ |
9bccf70c | 72 | queue_head_t wq_queue; /* queue of elements */ |
1c79356b A |
73 | } WaitQueue; |
74 | ||
75 | /* | |
9bccf70c A |
76 | * wait_queue_set_t |
77 | * This is the common definition for a set wait queue. | |
1c79356b A |
78 | * These can be linked as members/elements of multiple regular |
79 | * wait queues. They have an additional set of linkages to | |
80 | * identify the linkage structures that point to them. | |
81 | */ | |
9bccf70c A |
82 | typedef struct wait_queue_set { |
83 | WaitQueue wqs_wait_queue; /* our wait queue */ | |
84 | queue_head_t wqs_setlinks; /* links from set perspective */ | |
0b4e3aa0 | 85 | unsigned int wqs_refcount; /* refcount for preposting */ |
9bccf70c | 86 | } WaitQueueSet; |
1c79356b | 87 | |
9bccf70c A |
88 | #define wqs_type wqs_wait_queue.wq_type |
89 | #define wqs_fifo wqs_wait_queue.wq_fifo | |
90 | #define wqs_isprepost wqs_wait_queue.wq_isprepost | |
91 | #define wqs_queue wqs_wait_queue.wq_queue | |
1c79356b A |
92 | |
93 | /* | |
94 | * wait_queue_element_t | |
95 | * This structure describes the elements on an event wait | |
96 | * queue. It is the common first fields in a thread shuttle | |
97 | * and wait_queue_link_t. In that way, a wait queue can | |
98 | * consist of both thread shuttle elements and links off of | |
9bccf70c | 99 | * to other (set) wait queues. |
1c79356b | 100 | * |
9bccf70c A |
101 | * WARNING: These fields correspond to fields in the thread |
102 | * shuttle (run queue links and run queue pointer). Any change in | |
1c79356b A |
103 | * the layout here will have to be matched with a change there. |
104 | */ | |
105 | typedef struct wait_queue_element { | |
106 | queue_chain_t wqe_links; /* link of elements on this queue */ | |
9bccf70c | 107 | void * wqe_type; /* Identifies link vs. thread */ |
1c79356b | 108 | wait_queue_t wqe_queue; /* queue this element is on */ |
9bccf70c | 109 | } WaitQueueElement; |
1c79356b | 110 | |
9bccf70c | 111 | typedef WaitQueueElement *wait_queue_element_t; |
0b4e3aa0 | 112 | |
1c79356b A |
113 | /* |
114 | * wait_queue_link_t | |
9bccf70c | 115 | * Specialized wait queue element type for linking set |
1c79356b A |
116 | * event waits queues onto a wait queue. In this way, an event |
117 | * can be constructed so that any thread waiting on any number | |
118 | * of associated wait queues can handle the event, while letting | |
119 | * the thread only be linked on the single wait queue it blocked on. | |
120 | * | |
121 | * One use: ports in multiple portsets. Each thread is queued up | |
122 | * on the portset that it specifically blocked on during a receive | |
123 | * operation. Each port's event queue links in all the portset | |
124 | * event queues of which it is a member. An IPC event post associated | |
125 | * with that port may wake up any thread from any of those portsets, | |
126 | * or one that was waiting locally on the port itself. | |
127 | */ | |
128 | typedef struct wait_queue_link { | |
9bccf70c A |
129 | WaitQueueElement wql_element; /* element on master */ |
130 | queue_chain_t wql_setlinks; /* element on set */ | |
131 | wait_queue_set_t wql_setqueue; /* set queue */ | |
0b4e3aa0 A |
132 | } WaitQueueLink; |
133 | ||
1c79356b | 134 | #define wql_links wql_element.wqe_links |
9bccf70c | 135 | #define wql_type wql_element.wqe_type |
1c79356b | 136 | #define wql_queue wql_element.wqe_queue |
0b4e3aa0 | 137 | |
9bccf70c A |
138 | #define _WAIT_QUEUE_inited 0xf1d0 |
139 | #define _WAIT_QUEUE_SET_inited 0xf1d1 | |
0b4e3aa0 | 140 | |
9bccf70c A |
141 | #define wait_queue_is_queue(wq) \ |
142 | ((wq)->wq_type == _WAIT_QUEUE_inited) | |
1c79356b | 143 | |
9bccf70c A |
144 | #define wait_queue_is_set(wqs) \ |
145 | ((wqs)->wqs_type == _WAIT_QUEUE_SET_inited) | |
1c79356b | 146 | |
9bccf70c A |
147 | #define wait_queue_is_valid(wq) \ |
148 | (((wq)->wq_type & ~1) == _WAIT_QUEUE_inited) | |
1c79356b | 149 | |
9bccf70c A |
150 | #define wait_queue_empty(wq) (queue_empty(&(wq)->wq_queue)) |
151 | #define wait_queue_held(wq) (hw_lock_held(&(wq)->wq_interlock)) | |
152 | #define wait_queue_lock_try(wq) (hw_lock_try(&(wq)->wq_interlock)) | |
1c79356b | 153 | |
9bccf70c A |
154 | /* |
155 | * Double the standard lock timeout, because wait queues tend | |
156 | * to iterate over a number of threads - locking each. If there is | |
157 | * a problem with a thread lock, it normally times out at the wait | |
158 | * queue level first, hiding the real problem. | |
159 | */ | |
160 | #define wait_queue_lock(wq) \ | |
161 | ((void) (!hw_lock_to(&(wq)->wq_interlock, LockTimeOut * 2) ? \ | |
162 | panic("wait queue deadlock - wq=0x%x, cpu=%d\n", \ | |
163 | wq, cpu_number()) : 0)) | |
1c79356b | 164 | |
9bccf70c A |
165 | #define wait_queue_unlock(wq) \ |
166 | (assert(wait_queue_held(wq)), hw_lock_unlock(&(wq)->wq_interlock)) | |
1c79356b | 167 | |
9bccf70c A |
168 | #define wqs_lock(wqs) wait_queue_lock(&(wqs)->wqs_wait_queue) |
169 | #define wqs_unlock(wqs) wait_queue_unlock(&(wqs)->wqs_wait_queue) | |
170 | #define wqs_lock_try(wqs) wait_queue__try_lock(&(wqs)->wqs_wait_queue) | |
1c79356b A |
171 | |
172 | #define wait_queue_assert_possible(thread) \ | |
173 | ((thread)->wait_queue == WAIT_QUEUE_NULL) | |
174 | ||
1c79356b A |
175 | /******** Decomposed interfaces (to build higher level constructs) ***********/ |
176 | ||
1c79356b | 177 | /* assert intent to wait on a locked wait queue */ |
9bccf70c | 178 | __private_extern__ wait_result_t wait_queue_assert_wait64_locked( |
1c79356b | 179 | wait_queue_t wait_queue, |
9bccf70c A |
180 | event64_t wait_event, |
181 | wait_interrupt_t interruptible, | |
91447636 | 182 | uint64_t deadline, |
55e303ae | 183 | thread_t thread); |
1c79356b A |
184 | |
185 | /* peek to see which thread would be chosen for a wakeup - but keep on queue */ | |
9bccf70c | 186 | __private_extern__ void wait_queue_peek64_locked( |
1c79356b | 187 | wait_queue_t wait_queue, |
9bccf70c | 188 | event64_t event, |
1c79356b A |
189 | thread_t *thread, |
190 | wait_queue_t *found_queue); | |
191 | ||
192 | /* peek to see which thread would be chosen for a wakeup - but keep on queue */ | |
9bccf70c | 193 | __private_extern__ void wait_queue_pull_thread_locked( |
1c79356b A |
194 | wait_queue_t wait_queue, |
195 | thread_t thread, | |
196 | boolean_t unlock); | |
197 | ||
198 | /* wakeup all threads waiting for a particular event on locked queue */ | |
9bccf70c | 199 | __private_extern__ kern_return_t wait_queue_wakeup64_all_locked( |
1c79356b | 200 | wait_queue_t wait_queue, |
9bccf70c A |
201 | event64_t wake_event, |
202 | wait_result_t result, | |
1c79356b A |
203 | boolean_t unlock); |
204 | ||
205 | /* wakeup one thread waiting for a particular event on locked queue */ | |
9bccf70c | 206 | __private_extern__ kern_return_t wait_queue_wakeup64_one_locked( |
1c79356b | 207 | wait_queue_t wait_queue, |
9bccf70c A |
208 | event64_t wake_event, |
209 | wait_result_t result, | |
1c79356b A |
210 | boolean_t unlock); |
211 | ||
1c79356b | 212 | /* return identity of a thread awakened for a particular <wait_queue,event> */ |
9bccf70c | 213 | __private_extern__ thread_t wait_queue_wakeup64_identity_locked( |
1c79356b | 214 | wait_queue_t wait_queue, |
9bccf70c A |
215 | event64_t wake_event, |
216 | wait_result_t result, | |
1c79356b A |
217 | boolean_t unlock); |
218 | ||
219 | /* wakeup thread iff its still waiting for a particular event on locked queue */ | |
9bccf70c | 220 | __private_extern__ kern_return_t wait_queue_wakeup64_thread_locked( |
1c79356b | 221 | wait_queue_t wait_queue, |
9bccf70c | 222 | event64_t wake_event, |
1c79356b | 223 | thread_t thread, |
9bccf70c | 224 | wait_result_t result, |
1c79356b A |
225 | boolean_t unlock); |
226 | ||
91447636 A |
227 | #endif /* MACH_KERNEL_PRIVATE */ |
228 | ||
229 | __BEGIN_DECLS | |
1c79356b | 230 | |
9bccf70c A |
231 | /******** Semi-Public interfaces (not a part of a higher construct) ************/ |
232 | ||
91447636 A |
233 | extern unsigned int wait_queue_set_size(void); |
234 | extern unsigned int wait_queue_link_size(void); | |
235 | ||
9bccf70c A |
236 | extern kern_return_t wait_queue_init( |
237 | wait_queue_t wait_queue, | |
238 | int policy); | |
239 | ||
240 | extern wait_queue_set_t wait_queue_set_alloc( | |
241 | int policy); | |
242 | ||
91447636 A |
243 | extern kern_return_t wait_queue_set_init( |
244 | wait_queue_set_t set_queue, | |
245 | int policy); | |
246 | ||
9bccf70c A |
247 | extern kern_return_t wait_queue_set_free( |
248 | wait_queue_set_t set_queue); | |
249 | ||
250 | extern wait_queue_link_t wait_queue_link_alloc( | |
251 | int policy); | |
252 | ||
253 | extern kern_return_t wait_queue_link_free( | |
254 | wait_queue_link_t link_element); | |
255 | ||
91447636 A |
256 | extern kern_return_t wait_queue_link( |
257 | wait_queue_t wait_queue, | |
258 | wait_queue_set_t set_queue); | |
9bccf70c | 259 | |
91447636 A |
260 | extern kern_return_t wait_queue_link_noalloc( |
261 | wait_queue_t wait_queue, | |
262 | wait_queue_set_t set_queue, | |
263 | wait_queue_link_t link); | |
1c79356b | 264 | |
91447636 | 265 | extern boolean_t wait_queue_member( |
9bccf70c A |
266 | wait_queue_t wait_queue, |
267 | wait_queue_set_t set_queue); | |
268 | ||
269 | extern kern_return_t wait_queue_unlink( | |
270 | wait_queue_t wait_queue, | |
271 | wait_queue_set_t set_queue); | |
272 | ||
273 | extern kern_return_t wait_queue_unlink_all( | |
1c79356b A |
274 | wait_queue_t wait_queue); |
275 | ||
91447636 A |
276 | extern kern_return_t wait_queue_unlinkall_nofree( |
277 | wait_queue_t wait_queue); | |
278 | ||
9bccf70c A |
279 | extern kern_return_t wait_queue_set_unlink_all( |
280 | wait_queue_set_t set_queue); | |
281 | ||
91447636 A |
282 | /* legacy API */ |
283 | kern_return_t wait_queue_sub_init( | |
284 | wait_queue_set_t set_queue, | |
285 | int policy); | |
286 | ||
287 | kern_return_t wait_queue_sub_clearrefs( | |
288 | wait_queue_set_t wq_set); | |
289 | ||
290 | extern kern_return_t wait_subqueue_unlink_all( | |
291 | wait_queue_set_t set_queue); | |
292 | ||
293 | extern wait_queue_t wait_queue_alloc( | |
294 | int policy); | |
295 | ||
296 | extern kern_return_t wait_queue_free( | |
297 | wait_queue_t wait_queue); | |
298 | ||
9bccf70c A |
299 | /* assert intent to wait on <wait_queue,event64> pair */ |
300 | extern wait_result_t wait_queue_assert_wait64( | |
301 | wait_queue_t wait_queue, | |
302 | event64_t wait_event, | |
91447636 A |
303 | wait_interrupt_t interruptible, |
304 | uint64_t deadline); | |
9bccf70c A |
305 | |
306 | /* wakeup the most appropriate thread waiting on <wait_queue,event64> pair */ | |
307 | extern kern_return_t wait_queue_wakeup64_one( | |
308 | wait_queue_t wait_queue, | |
309 | event64_t wake_event, | |
310 | wait_result_t result); | |
311 | ||
312 | /* wakeup all the threads waiting on <wait_queue,event64> pair */ | |
313 | extern kern_return_t wait_queue_wakeup64_all( | |
314 | wait_queue_t wait_queue, | |
315 | event64_t wake_event, | |
316 | wait_result_t result); | |
317 | ||
318 | /* wakeup a specified thread waiting iff waiting on <wait_queue,event64> pair */ | |
319 | extern kern_return_t wait_queue_wakeup64_thread( | |
320 | wait_queue_t wait_queue, | |
321 | event64_t wake_event, | |
322 | thread_t thread, | |
323 | wait_result_t result); | |
324 | ||
9bccf70c A |
325 | /* |
326 | * Compatibility Wait Queue APIs based on pointer events instead of 64bit | |
327 | * integer events. | |
328 | */ | |
1c79356b A |
329 | |
330 | /* assert intent to wait on <wait_queue,event> pair */ | |
9bccf70c | 331 | extern wait_result_t wait_queue_assert_wait( |
1c79356b A |
332 | wait_queue_t wait_queue, |
333 | event_t wait_event, | |
91447636 A |
334 | wait_interrupt_t interruptible, |
335 | uint64_t deadline); | |
1c79356b A |
336 | |
337 | /* wakeup the most appropriate thread waiting on <wait_queue,event> pair */ | |
9bccf70c | 338 | extern kern_return_t wait_queue_wakeup_one( |
1c79356b A |
339 | wait_queue_t wait_queue, |
340 | event_t wake_event, | |
9bccf70c | 341 | wait_result_t result); |
1c79356b A |
342 | |
343 | /* wakeup all the threads waiting on <wait_queue,event> pair */ | |
9bccf70c | 344 | extern kern_return_t wait_queue_wakeup_all( |
1c79356b A |
345 | wait_queue_t wait_queue, |
346 | event_t wake_event, | |
9bccf70c | 347 | wait_result_t result); |
1c79356b A |
348 | |
349 | /* wakeup a specified thread waiting iff waiting on <wait_queue,event> pair */ | |
9bccf70c | 350 | extern kern_return_t wait_queue_wakeup_thread( |
1c79356b A |
351 | wait_queue_t wait_queue, |
352 | event_t wake_event, | |
353 | thread_t thread, | |
9bccf70c A |
354 | wait_result_t result); |
355 | ||
91447636 A |
356 | __END_DECLS |
357 | ||
358 | #endif /* _KERN_WAIT_QUEUE_H_ */ | |
1c79356b | 359 | |
91447636 | 360 | #endif /* KERNEL_PRIVATE */ |