]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
e5568f75 A |
6 | * The contents of this file constitute Original Code as defined in and |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
1c79356b | 11 | * |
e5568f75 A |
12 | * This Original Code and all software distributed under the License are |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
e5568f75 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
1c79356b A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * @OSF_COPYRIGHT@ | |
24 | * | |
25 | */ | |
26 | /* | |
27 | * File: kern/sync_sema.c | |
28 | * Author: Joseph CaraDonna | |
29 | * | |
30 | * Contains RT distributed semaphore synchronization services. | |
31 | */ | |
32 | ||
33 | #include <mach/mach_types.h> | |
91447636 | 34 | #include <mach/mach_traps.h> |
1c79356b A |
35 | #include <mach/kern_return.h> |
36 | #include <mach/semaphore.h> | |
37 | #include <mach/sync_policy.h> | |
91447636 | 38 | #include <mach/task.h> |
1c79356b A |
39 | |
40 | #include <kern/misc_protos.h> | |
41 | #include <kern/sync_sema.h> | |
42 | #include <kern/spl.h> | |
43 | #include <kern/ipc_kobject.h> | |
44 | #include <kern/ipc_sync.h> | |
45 | #include <kern/ipc_tt.h> | |
46 | #include <kern/thread.h> | |
47 | #include <kern/clock.h> | |
48 | #include <ipc/ipc_port.h> | |
49 | #include <ipc/ipc_space.h> | |
50 | #include <kern/host.h> | |
51 | #include <kern/wait_queue.h> | |
52 | #include <kern/zalloc.h> | |
53 | #include <kern/mach_param.h> | |
54 | ||
9bccf70c A |
55 | static unsigned int semaphore_event; |
56 | #define SEMAPHORE_EVENT ((event64_t)&semaphore_event) | |
1c79356b A |
57 | |
58 | zone_t semaphore_zone; | |
59 | unsigned int semaphore_max = SEMAPHORE_MAX; | |
60 | ||
91447636 A |
61 | /* Forward declarations */ |
62 | ||
63 | ||
64 | kern_return_t | |
65 | semaphore_wait_trap_internal( | |
66 | mach_port_name_t name, | |
67 | void (*caller_cont)(kern_return_t)); | |
68 | ||
69 | kern_return_t | |
70 | semaphore_wait_signal_trap_internal( | |
71 | mach_port_name_t wait_name, | |
72 | mach_port_name_t signal_name, | |
73 | void (*caller_cont)(kern_return_t)); | |
74 | ||
75 | kern_return_t | |
76 | semaphore_timedwait_trap_internal( | |
77 | mach_port_name_t name, | |
78 | unsigned int sec, | |
79 | clock_res_t nsec, | |
80 | void (*caller_cont)(kern_return_t)); | |
81 | ||
82 | kern_return_t | |
83 | semaphore_timedwait_signal_trap_internal( | |
84 | mach_port_name_t wait_name, | |
85 | mach_port_name_t signal_name, | |
86 | unsigned int sec, | |
87 | clock_res_t nsec, | |
88 | void (*caller_cont)(kern_return_t)); | |
89 | ||
90 | ||
91 | kern_return_t | |
92 | semaphore_signal_internal( | |
93 | semaphore_t semaphore, | |
94 | thread_t thread, | |
95 | int options); | |
96 | ||
97 | kern_return_t | |
98 | semaphore_convert_wait_result( | |
99 | int wait_result); | |
100 | ||
101 | void | |
102 | semaphore_wait_continue(void); | |
103 | ||
104 | kern_return_t | |
105 | semaphore_wait_internal( | |
106 | semaphore_t wait_semaphore, | |
107 | semaphore_t signal_semaphore, | |
108 | mach_timespec_t *wait_timep, | |
109 | void (*caller_cont)(kern_return_t)); | |
110 | ||
1c79356b A |
111 | /* |
112 | * ROUTINE: semaphore_init [private] | |
113 | * | |
114 | * Initialize the semaphore mechanisms. | |
115 | * Right now, we only need to initialize the semaphore zone. | |
116 | */ | |
117 | void | |
118 | semaphore_init(void) | |
119 | { | |
120 | semaphore_zone = zinit(sizeof(struct semaphore), | |
121 | semaphore_max * sizeof(struct semaphore), | |
122 | sizeof(struct semaphore), | |
123 | "semaphores"); | |
124 | } | |
125 | ||
126 | /* | |
127 | * Routine: semaphore_create | |
128 | * | |
129 | * Creates a semaphore. | |
130 | * The port representing the semaphore is returned as a parameter. | |
131 | */ | |
132 | kern_return_t | |
133 | semaphore_create( | |
134 | task_t task, | |
135 | semaphore_t *new_semaphore, | |
136 | int policy, | |
137 | int value) | |
138 | { | |
139 | semaphore_t s = SEMAPHORE_NULL; | |
140 | ||
141 | ||
142 | ||
143 | if (task == TASK_NULL || value < 0 || policy > SYNC_POLICY_MAX) { | |
144 | *new_semaphore = SEMAPHORE_NULL; | |
145 | return KERN_INVALID_ARGUMENT; | |
146 | } | |
147 | ||
148 | s = (semaphore_t) zalloc (semaphore_zone); | |
149 | ||
150 | if (s == SEMAPHORE_NULL) { | |
151 | *new_semaphore = SEMAPHORE_NULL; | |
152 | return KERN_RESOURCE_SHORTAGE; | |
153 | } | |
154 | ||
155 | wait_queue_init(&s->wait_queue, policy); /* also inits lock */ | |
156 | s->count = value; | |
157 | s->ref_count = 1; | |
158 | ||
159 | /* | |
160 | * Create and initialize the semaphore port | |
161 | */ | |
162 | s->port = ipc_port_alloc_kernel(); | |
163 | if (s->port == IP_NULL) { | |
164 | /* This will deallocate the semaphore */ | |
165 | semaphore_dereference(s); | |
166 | *new_semaphore = SEMAPHORE_NULL; | |
167 | return KERN_RESOURCE_SHORTAGE; | |
168 | } | |
169 | ||
170 | ipc_kobject_set (s->port, (ipc_kobject_t) s, IKOT_SEMAPHORE); | |
171 | ||
172 | /* | |
173 | * Associate the new semaphore with the task by adding | |
174 | * the new semaphore to the task's semaphore list. | |
175 | * | |
176 | * Associate the task with the new semaphore by having the | |
177 | * semaphores task pointer point to the owning task's structure. | |
178 | */ | |
179 | task_lock(task); | |
180 | enqueue_head(&task->semaphore_list, (queue_entry_t) s); | |
181 | task->semaphores_owned++; | |
182 | s->owner = task; | |
183 | s->active = TRUE; | |
184 | task_unlock(task); | |
185 | ||
186 | *new_semaphore = s; | |
187 | ||
188 | return KERN_SUCCESS; | |
189 | } | |
190 | ||
191 | /* | |
192 | * Routine: semaphore_destroy | |
193 | * | |
194 | * Destroys a semaphore. This call will only succeed if the | |
195 | * specified task is the SAME task name specified at the semaphore's | |
196 | * creation. | |
197 | * | |
198 | * All threads currently blocked on the semaphore are awoken. These | |
199 | * threads will return with the KERN_TERMINATED error. | |
200 | */ | |
201 | kern_return_t | |
202 | semaphore_destroy( | |
203 | task_t task, | |
204 | semaphore_t semaphore) | |
205 | { | |
206 | int old_count; | |
1c79356b A |
207 | spl_t spl_level; |
208 | ||
209 | ||
210 | if (task == TASK_NULL || semaphore == SEMAPHORE_NULL) | |
211 | return KERN_INVALID_ARGUMENT; | |
212 | ||
213 | /* | |
214 | * Disown semaphore | |
215 | */ | |
216 | task_lock(task); | |
217 | if (semaphore->owner != task) { | |
218 | task_unlock(task); | |
219 | return KERN_INVALID_ARGUMENT; | |
220 | } | |
221 | remqueue(&task->semaphore_list, (queue_entry_t) semaphore); | |
222 | semaphore->owner = TASK_NULL; | |
223 | task->semaphores_owned--; | |
224 | task_unlock(task); | |
225 | ||
226 | spl_level = splsched(); | |
227 | semaphore_lock(semaphore); | |
228 | ||
229 | /* | |
230 | * Deactivate semaphore | |
231 | */ | |
232 | assert(semaphore->active); | |
233 | semaphore->active = FALSE; | |
234 | ||
235 | /* | |
236 | * Wakeup blocked threads | |
237 | */ | |
238 | old_count = semaphore->count; | |
239 | semaphore->count = 0; | |
240 | ||
241 | if (old_count < 0) { | |
9bccf70c | 242 | wait_queue_wakeup64_all_locked(&semaphore->wait_queue, |
1c79356b A |
243 | SEMAPHORE_EVENT, |
244 | THREAD_RESTART, | |
245 | TRUE); /* unlock? */ | |
246 | } else { | |
247 | semaphore_unlock(semaphore); | |
248 | } | |
249 | splx(spl_level); | |
250 | ||
251 | /* | |
252 | * Deallocate | |
253 | * | |
254 | * Drop the semaphore reference, which in turn deallocates the | |
255 | * semaphore structure if the reference count goes to zero. | |
256 | */ | |
257 | ipc_port_dealloc_kernel(semaphore->port); | |
258 | semaphore_dereference(semaphore); | |
259 | return KERN_SUCCESS; | |
260 | } | |
261 | ||
262 | /* | |
263 | * Routine: semaphore_signal_internal | |
264 | * | |
265 | * Signals the semaphore as direct. | |
266 | * Assumptions: | |
267 | * Semaphore is locked. | |
268 | */ | |
269 | kern_return_t | |
270 | semaphore_signal_internal( | |
271 | semaphore_t semaphore, | |
91447636 A |
272 | thread_t thread, |
273 | int options) | |
1c79356b A |
274 | { |
275 | kern_return_t kr; | |
276 | spl_t spl_level; | |
277 | ||
278 | spl_level = splsched(); | |
279 | semaphore_lock(semaphore); | |
280 | ||
281 | if (!semaphore->active) { | |
282 | semaphore_unlock(semaphore); | |
283 | splx(spl_level); | |
284 | return KERN_TERMINATED; | |
285 | } | |
286 | ||
91447636 | 287 | if (thread != THREAD_NULL) { |
1c79356b | 288 | if (semaphore->count < 0) { |
9bccf70c | 289 | kr = wait_queue_wakeup64_thread_locked( |
1c79356b A |
290 | &semaphore->wait_queue, |
291 | SEMAPHORE_EVENT, | |
91447636 | 292 | thread, |
1c79356b A |
293 | THREAD_AWAKENED, |
294 | TRUE); /* unlock? */ | |
295 | } else { | |
296 | semaphore_unlock(semaphore); | |
297 | kr = KERN_NOT_WAITING; | |
298 | } | |
299 | splx(spl_level); | |
300 | return kr; | |
301 | } | |
302 | ||
303 | if (options & SEMAPHORE_SIGNAL_ALL) { | |
304 | int old_count = semaphore->count; | |
305 | ||
306 | if (old_count < 0) { | |
307 | semaphore->count = 0; /* always reset */ | |
9bccf70c | 308 | kr = wait_queue_wakeup64_all_locked( |
1c79356b A |
309 | &semaphore->wait_queue, |
310 | SEMAPHORE_EVENT, | |
311 | THREAD_AWAKENED, | |
312 | TRUE); /* unlock? */ | |
313 | } else { | |
314 | if (options & SEMAPHORE_SIGNAL_PREPOST) | |
315 | semaphore->count++; | |
316 | semaphore_unlock(semaphore); | |
317 | kr = KERN_SUCCESS; | |
318 | } | |
319 | splx(spl_level); | |
320 | return kr; | |
321 | } | |
322 | ||
323 | if (semaphore->count < 0) { | |
9bccf70c | 324 | if (wait_queue_wakeup64_one_locked( |
1c79356b A |
325 | &semaphore->wait_queue, |
326 | SEMAPHORE_EVENT, | |
327 | THREAD_AWAKENED, | |
328 | FALSE) == KERN_SUCCESS) { | |
329 | semaphore_unlock(semaphore); | |
330 | splx(spl_level); | |
331 | return KERN_SUCCESS; | |
332 | } else | |
333 | semaphore->count = 0; /* all waiters gone */ | |
334 | } | |
335 | ||
336 | if (options & SEMAPHORE_SIGNAL_PREPOST) { | |
337 | semaphore->count++; | |
338 | } | |
339 | ||
340 | semaphore_unlock(semaphore); | |
341 | splx(spl_level); | |
342 | return KERN_NOT_WAITING; | |
343 | } | |
344 | ||
345 | /* | |
346 | * Routine: semaphore_signal_thread | |
347 | * | |
91447636 A |
348 | * If the specified thread is blocked on the semaphore, it is |
349 | * woken up. If a NULL thread was supplied, then any one | |
1c79356b A |
350 | * thread is woken up. Otherwise the caller gets KERN_NOT_WAITING |
351 | * and the semaphore is unchanged. | |
352 | */ | |
353 | kern_return_t | |
354 | semaphore_signal_thread( | |
355 | semaphore_t semaphore, | |
91447636 | 356 | thread_t thread) |
1c79356b A |
357 | { |
358 | kern_return_t ret; | |
359 | ||
360 | if (semaphore == SEMAPHORE_NULL) | |
361 | return KERN_INVALID_ARGUMENT; | |
362 | ||
363 | ret = semaphore_signal_internal(semaphore, | |
91447636 | 364 | thread, |
1c79356b A |
365 | SEMAPHORE_OPTION_NONE); |
366 | return ret; | |
367 | } | |
368 | ||
369 | /* | |
370 | * Routine: semaphore_signal_thread_trap | |
371 | * | |
372 | * Trap interface to the semaphore_signal_thread function. | |
373 | */ | |
374 | kern_return_t | |
375 | semaphore_signal_thread_trap( | |
91447636 | 376 | struct semaphore_signal_thread_trap_args *args) |
1c79356b | 377 | { |
91447636 A |
378 | mach_port_name_t sema_name = args->signal_name; |
379 | mach_port_name_t thread_name = args->thread_name; | |
1c79356b | 380 | semaphore_t semaphore; |
91447636 | 381 | thread_t thread; |
1c79356b A |
382 | kern_return_t kr; |
383 | ||
384 | /* | |
385 | * MACH_PORT_NULL is not an error. It means that we want to | |
386 | * select any one thread that is already waiting, but not to | |
387 | * pre-post the semaphore. | |
388 | */ | |
389 | if (thread_name != MACH_PORT_NULL) { | |
91447636 A |
390 | thread = port_name_to_thread(thread_name); |
391 | if (thread == THREAD_NULL) | |
1c79356b A |
392 | return KERN_INVALID_ARGUMENT; |
393 | } else | |
91447636 | 394 | thread = THREAD_NULL; |
1c79356b A |
395 | |
396 | kr = port_name_to_semaphore(sema_name, &semaphore); | |
91447636 A |
397 | if (kr == KERN_SUCCESS) { |
398 | kr = semaphore_signal_internal(semaphore, | |
399 | thread, | |
400 | SEMAPHORE_OPTION_NONE); | |
401 | semaphore_dereference(semaphore); | |
402 | } | |
403 | if (thread != THREAD_NULL) { | |
404 | thread_deallocate(thread); | |
1c79356b | 405 | } |
1c79356b A |
406 | return kr; |
407 | } | |
408 | ||
409 | ||
410 | ||
411 | /* | |
412 | * Routine: semaphore_signal | |
413 | * | |
414 | * Traditional (in-kernel client and MIG interface) semaphore | |
415 | * signal routine. Most users will access the trap version. | |
416 | * | |
417 | * This interface in not defined to return info about whether | |
418 | * this call found a thread waiting or not. The internal | |
419 | * routines (and future external routines) do. We have to | |
420 | * convert those into plain KERN_SUCCESS returns. | |
421 | */ | |
422 | kern_return_t | |
423 | semaphore_signal( | |
424 | semaphore_t semaphore) | |
425 | { | |
426 | kern_return_t kr; | |
427 | ||
428 | if (semaphore == SEMAPHORE_NULL) | |
429 | return KERN_INVALID_ARGUMENT; | |
430 | ||
431 | kr = semaphore_signal_internal(semaphore, | |
91447636 | 432 | THREAD_NULL, |
1c79356b A |
433 | SEMAPHORE_SIGNAL_PREPOST); |
434 | if (kr == KERN_NOT_WAITING) | |
435 | return KERN_SUCCESS; | |
436 | return kr; | |
437 | } | |
438 | ||
439 | /* | |
440 | * Routine: semaphore_signal_trap | |
441 | * | |
442 | * Trap interface to the semaphore_signal function. | |
443 | */ | |
444 | kern_return_t | |
445 | semaphore_signal_trap( | |
91447636 | 446 | struct semaphore_signal_trap_args *args) |
1c79356b | 447 | { |
91447636 | 448 | mach_port_name_t sema_name = args->signal_name; |
1c79356b A |
449 | semaphore_t semaphore; |
450 | kern_return_t kr; | |
451 | ||
452 | kr = port_name_to_semaphore(sema_name, &semaphore); | |
91447636 A |
453 | if (kr == KERN_SUCCESS) { |
454 | kr = semaphore_signal_internal(semaphore, | |
455 | THREAD_NULL, | |
456 | SEMAPHORE_SIGNAL_PREPOST); | |
457 | semaphore_dereference(semaphore); | |
458 | if (kr == KERN_NOT_WAITING) | |
459 | kr = KERN_SUCCESS; | |
1c79356b | 460 | } |
1c79356b A |
461 | return kr; |
462 | } | |
463 | ||
464 | /* | |
465 | * Routine: semaphore_signal_all | |
466 | * | |
467 | * Awakens ALL threads currently blocked on the semaphore. | |
468 | * The semaphore count returns to zero. | |
469 | */ | |
470 | kern_return_t | |
471 | semaphore_signal_all( | |
472 | semaphore_t semaphore) | |
473 | { | |
474 | kern_return_t kr; | |
475 | ||
476 | if (semaphore == SEMAPHORE_NULL) | |
477 | return KERN_INVALID_ARGUMENT; | |
478 | ||
479 | kr = semaphore_signal_internal(semaphore, | |
91447636 | 480 | THREAD_NULL, |
1c79356b A |
481 | SEMAPHORE_SIGNAL_ALL); |
482 | if (kr == KERN_NOT_WAITING) | |
483 | return KERN_SUCCESS; | |
484 | return kr; | |
485 | } | |
486 | ||
487 | /* | |
488 | * Routine: semaphore_signal_all_trap | |
489 | * | |
490 | * Trap interface to the semaphore_signal_all function. | |
491 | */ | |
492 | kern_return_t | |
493 | semaphore_signal_all_trap( | |
91447636 | 494 | struct semaphore_signal_all_trap_args *args) |
1c79356b | 495 | { |
91447636 | 496 | mach_port_name_t sema_name = args->signal_name; |
1c79356b A |
497 | semaphore_t semaphore; |
498 | kern_return_t kr; | |
499 | ||
500 | kr = port_name_to_semaphore(sema_name, &semaphore); | |
91447636 A |
501 | if (kr == KERN_SUCCESS) { |
502 | kr = semaphore_signal_internal(semaphore, | |
503 | THREAD_NULL, | |
504 | SEMAPHORE_SIGNAL_ALL); | |
505 | semaphore_dereference(semaphore); | |
506 | if (kr == KERN_NOT_WAITING) | |
507 | kr = KERN_SUCCESS; | |
1c79356b | 508 | } |
1c79356b A |
509 | return kr; |
510 | } | |
511 | ||
512 | /* | |
513 | * Routine: semaphore_convert_wait_result | |
514 | * | |
515 | * Generate the return code after a semaphore wait/block. It | |
516 | * takes the wait result as an input and coverts that to an | |
517 | * appropriate result. | |
518 | */ | |
519 | kern_return_t | |
520 | semaphore_convert_wait_result(int wait_result) | |
521 | { | |
522 | switch (wait_result) { | |
523 | case THREAD_AWAKENED: | |
524 | return KERN_SUCCESS; | |
525 | ||
526 | case THREAD_TIMED_OUT: | |
527 | return KERN_OPERATION_TIMED_OUT; | |
528 | ||
529 | case THREAD_INTERRUPTED: | |
530 | return KERN_ABORTED; | |
531 | ||
532 | case THREAD_RESTART: | |
533 | return KERN_TERMINATED; | |
534 | ||
535 | default: | |
536 | panic("semaphore_block\n"); | |
537 | return KERN_FAILURE; | |
538 | } | |
539 | } | |
540 | ||
541 | /* | |
542 | * Routine: semaphore_wait_continue | |
543 | * | |
544 | * Common continuation routine after waiting on a semphore. | |
545 | * It returns directly to user space. | |
546 | */ | |
547 | void | |
548 | semaphore_wait_continue(void) | |
549 | { | |
550 | thread_t self = current_thread(); | |
551 | int wait_result = self->wait_result; | |
552 | void (*caller_cont)(kern_return_t) = self->sth_continuation; | |
553 | ||
554 | assert(self->sth_waitsemaphore != SEMAPHORE_NULL); | |
555 | semaphore_dereference(self->sth_waitsemaphore); | |
556 | if (self->sth_signalsemaphore != SEMAPHORE_NULL) | |
557 | semaphore_dereference(self->sth_signalsemaphore); | |
558 | ||
559 | assert(caller_cont != (void (*)(kern_return_t))0); | |
560 | (*caller_cont)(semaphore_convert_wait_result(wait_result)); | |
561 | } | |
562 | ||
1c79356b A |
563 | /* |
564 | * Routine: semaphore_wait_internal | |
565 | * | |
566 | * Decrements the semaphore count by one. If the count is | |
567 | * negative after the decrement, the calling thread blocks | |
568 | * (possibly at a continuation and/or with a timeout). | |
569 | * | |
570 | * Assumptions: | |
571 | * The reference | |
572 | * A reference is held on the signal semaphore. | |
573 | */ | |
574 | kern_return_t | |
575 | semaphore_wait_internal( | |
576 | semaphore_t wait_semaphore, | |
577 | semaphore_t signal_semaphore, | |
578 | mach_timespec_t *wait_timep, | |
579 | void (*caller_cont)(kern_return_t)) | |
580 | { | |
91447636 A |
581 | boolean_t nonblocking; |
582 | int wait_result; | |
583 | spl_t spl_level; | |
1c79356b A |
584 | kern_return_t kr = KERN_ALREADY_WAITING; |
585 | ||
586 | spl_level = splsched(); | |
587 | semaphore_lock(wait_semaphore); | |
588 | ||
589 | /* | |
590 | * Decide if we really have to wait. | |
591 | */ | |
592 | nonblocking = (wait_timep != (mach_timespec_t *)0) ? | |
593 | (wait_timep->tv_sec == 0 && wait_timep->tv_nsec == 0) : | |
594 | FALSE; | |
595 | ||
596 | if (!wait_semaphore->active) { | |
597 | kr = KERN_TERMINATED; | |
598 | } else if (wait_semaphore->count > 0) { | |
599 | wait_semaphore->count--; | |
600 | kr = KERN_SUCCESS; | |
601 | } else if (nonblocking) { | |
602 | kr = KERN_OPERATION_TIMED_OUT; | |
55e303ae | 603 | } else { |
91447636 A |
604 | uint64_t abstime; |
605 | thread_t self = current_thread(); | |
55e303ae | 606 | |
1c79356b | 607 | wait_semaphore->count = -1; /* we don't keep an actual count */ |
55e303ae | 608 | thread_lock(self); |
91447636 A |
609 | |
610 | /* | |
611 | * If it is a timed wait, calculate the wake up deadline. | |
612 | */ | |
613 | if (wait_timep != (mach_timespec_t *)0) { | |
614 | nanoseconds_to_absolutetime((uint64_t)wait_timep->tv_sec * | |
615 | NSEC_PER_SEC + wait_timep->tv_nsec, &abstime); | |
616 | clock_absolutetime_interval_to_deadline(abstime, &abstime); | |
617 | } | |
618 | else | |
619 | abstime = 0; | |
620 | ||
9bccf70c A |
621 | (void)wait_queue_assert_wait64_locked( |
622 | &wait_semaphore->wait_queue, | |
623 | SEMAPHORE_EVENT, | |
91447636 | 624 | THREAD_ABORTSAFE, abstime, |
55e303ae A |
625 | self); |
626 | thread_unlock(self); | |
1c79356b A |
627 | } |
628 | semaphore_unlock(wait_semaphore); | |
629 | splx(spl_level); | |
630 | ||
631 | /* | |
632 | * wait_semaphore is unlocked so we are free to go ahead and | |
633 | * signal the signal_semaphore (if one was provided). | |
634 | */ | |
635 | if (signal_semaphore != SEMAPHORE_NULL) { | |
636 | kern_return_t signal_kr; | |
637 | ||
638 | /* | |
639 | * lock the signal semaphore reference we got and signal it. | |
640 | * This will NOT block (we cannot block after having asserted | |
641 | * our intention to wait above). | |
642 | */ | |
643 | signal_kr = semaphore_signal_internal(signal_semaphore, | |
91447636 | 644 | THREAD_NULL, |
1c79356b A |
645 | SEMAPHORE_SIGNAL_PREPOST); |
646 | ||
647 | if (signal_kr == KERN_NOT_WAITING) | |
648 | signal_kr = KERN_SUCCESS; | |
649 | else if (signal_kr == KERN_TERMINATED) { | |
650 | /* | |
651 | * Uh!Oh! The semaphore we were to signal died. | |
652 | * We have to get ourselves out of the wait in | |
653 | * case we get stuck here forever (it is assumed | |
654 | * that the semaphore we were posting is gating | |
655 | * the decision by someone else to post the | |
656 | * semaphore we are waiting on). People will | |
657 | * discover the other dead semaphore soon enough. | |
658 | * If we got out of the wait cleanly (someone | |
659 | * already posted a wakeup to us) then return that | |
660 | * (most important) result. Otherwise, | |
661 | * return the KERN_TERMINATED status. | |
662 | */ | |
663 | thread_t self = current_thread(); | |
664 | ||
665 | clear_wait(self, THREAD_INTERRUPTED); | |
666 | kr = semaphore_convert_wait_result(self->wait_result); | |
667 | if (kr == KERN_ABORTED) | |
668 | kr = KERN_TERMINATED; | |
669 | } | |
670 | } | |
671 | ||
672 | /* | |
673 | * If we had an error, or we didn't really need to wait we can | |
674 | * return now that we have signalled the signal semaphore. | |
675 | */ | |
676 | if (kr != KERN_ALREADY_WAITING) | |
677 | return kr; | |
1c79356b A |
678 | |
679 | /* | |
680 | * Now, we can block. If the caller supplied a continuation | |
681 | * pointer of his own for after the block, block with the | |
682 | * appropriate semaphore continuation. Thiswill gather the | |
683 | * semaphore results, release references on the semaphore(s), | |
684 | * and then call the caller's continuation. | |
685 | */ | |
686 | if (caller_cont) { | |
687 | thread_t self = current_thread(); | |
688 | ||
689 | self->sth_continuation = caller_cont; | |
690 | self->sth_waitsemaphore = wait_semaphore; | |
691 | self->sth_signalsemaphore = signal_semaphore; | |
91447636 A |
692 | wait_result = thread_block((thread_continue_t)semaphore_wait_continue); |
693 | } | |
694 | else { | |
9bccf70c | 695 | wait_result = thread_block(THREAD_CONTINUE_NULL); |
1c79356b A |
696 | } |
697 | ||
1c79356b A |
698 | return (semaphore_convert_wait_result(wait_result)); |
699 | } | |
700 | ||
701 | ||
702 | /* | |
703 | * Routine: semaphore_wait | |
704 | * | |
705 | * Traditional (non-continuation) interface presented to | |
706 | * in-kernel clients to wait on a semaphore. | |
707 | */ | |
708 | kern_return_t | |
709 | semaphore_wait( | |
710 | semaphore_t semaphore) | |
711 | { | |
712 | ||
713 | if (semaphore == SEMAPHORE_NULL) | |
714 | return KERN_INVALID_ARGUMENT; | |
715 | ||
716 | return(semaphore_wait_internal(semaphore, | |
717 | SEMAPHORE_NULL, | |
718 | (mach_timespec_t *)0, | |
719 | (void (*)(kern_return_t))0)); | |
720 | } | |
721 | ||
722 | /* | |
723 | * Trap: semaphore_wait_trap | |
724 | * | |
725 | * Trap version of semaphore wait. Called on behalf of user-level | |
726 | * clients. | |
727 | */ | |
91447636 | 728 | |
1c79356b A |
729 | kern_return_t |
730 | semaphore_wait_trap( | |
91447636 A |
731 | struct semaphore_wait_trap_args *args) |
732 | { | |
733 | return(semaphore_wait_trap_internal(args->wait_name, thread_syscall_return)); | |
734 | } | |
735 | ||
736 | ||
737 | ||
738 | kern_return_t | |
739 | semaphore_wait_trap_internal( | |
740 | mach_port_name_t name, | |
741 | void (*caller_cont)(kern_return_t)) | |
1c79356b A |
742 | { |
743 | semaphore_t semaphore; | |
744 | kern_return_t kr; | |
745 | ||
746 | kr = port_name_to_semaphore(name, &semaphore); | |
91447636 A |
747 | if (kr == KERN_SUCCESS) { |
748 | kr = semaphore_wait_internal(semaphore, | |
749 | SEMAPHORE_NULL, | |
750 | (mach_timespec_t *)0, | |
751 | caller_cont); | |
752 | semaphore_dereference(semaphore); | |
753 | } | |
1c79356b A |
754 | return kr; |
755 | } | |
756 | ||
757 | /* | |
758 | * Routine: semaphore_timedwait | |
759 | * | |
760 | * Traditional (non-continuation) interface presented to | |
761 | * in-kernel clients to wait on a semaphore with a timeout. | |
762 | * | |
763 | * A timeout of {0,0} is considered non-blocking. | |
764 | */ | |
765 | kern_return_t | |
766 | semaphore_timedwait( | |
767 | semaphore_t semaphore, | |
768 | mach_timespec_t wait_time) | |
769 | { | |
770 | if (semaphore == SEMAPHORE_NULL) | |
771 | return KERN_INVALID_ARGUMENT; | |
772 | ||
773 | if(BAD_MACH_TIMESPEC(&wait_time)) | |
774 | return KERN_INVALID_VALUE; | |
775 | ||
776 | return (semaphore_wait_internal(semaphore, | |
777 | SEMAPHORE_NULL, | |
778 | &wait_time, | |
779 | (void(*)(kern_return_t))0)); | |
780 | ||
781 | } | |
782 | ||
783 | /* | |
784 | * Trap: semaphore_timedwait_trap | |
785 | * | |
786 | * Trap version of a semaphore_timedwait. The timeout parameter | |
787 | * is passed in two distinct parts and re-assembled on this side | |
788 | * of the trap interface (to accomodate calling conventions that | |
789 | * pass structures as pointers instead of inline in registers without | |
790 | * having to add a copyin). | |
791 | * | |
792 | * A timeout of {0,0} is considered non-blocking. | |
793 | */ | |
794 | kern_return_t | |
795 | semaphore_timedwait_trap( | |
91447636 | 796 | struct semaphore_timedwait_trap_args *args) |
1c79356b | 797 | { |
91447636 A |
798 | |
799 | return(semaphore_timedwait_trap_internal(args->wait_name, args->sec, args->nsec, thread_syscall_return)); | |
800 | } | |
801 | ||
802 | ||
803 | kern_return_t | |
804 | semaphore_timedwait_trap_internal( | |
805 | mach_port_name_t name, | |
806 | unsigned int sec, | |
807 | clock_res_t nsec, | |
808 | void (*caller_cont)(kern_return_t)) | |
809 | { | |
810 | ||
1c79356b A |
811 | semaphore_t semaphore; |
812 | mach_timespec_t wait_time; | |
813 | kern_return_t kr; | |
814 | ||
815 | wait_time.tv_sec = sec; | |
816 | wait_time.tv_nsec = nsec; | |
817 | if(BAD_MACH_TIMESPEC(&wait_time)) | |
818 | return KERN_INVALID_VALUE; | |
819 | ||
820 | kr = port_name_to_semaphore(name, &semaphore); | |
91447636 A |
821 | if (kr == KERN_SUCCESS) { |
822 | kr = semaphore_wait_internal(semaphore, | |
823 | SEMAPHORE_NULL, | |
824 | &wait_time, | |
825 | caller_cont); | |
826 | semaphore_dereference(semaphore); | |
827 | } | |
1c79356b A |
828 | return kr; |
829 | } | |
830 | ||
831 | /* | |
832 | * Routine: semaphore_wait_signal | |
833 | * | |
834 | * Atomically register a wait on a semaphore and THEN signal | |
835 | * another. This is the in-kernel entry point that does not | |
836 | * block at a continuation and does not free a signal_semaphore | |
837 | * reference. | |
838 | */ | |
839 | kern_return_t | |
840 | semaphore_wait_signal( | |
841 | semaphore_t wait_semaphore, | |
842 | semaphore_t signal_semaphore) | |
843 | { | |
844 | if (wait_semaphore == SEMAPHORE_NULL) | |
845 | return KERN_INVALID_ARGUMENT; | |
846 | ||
847 | return(semaphore_wait_internal(wait_semaphore, | |
848 | signal_semaphore, | |
849 | (mach_timespec_t *)0, | |
850 | (void(*)(kern_return_t))0)); | |
851 | } | |
852 | ||
853 | /* | |
854 | * Trap: semaphore_wait_signal_trap | |
855 | * | |
856 | * Atomically register a wait on a semaphore and THEN signal | |
857 | * another. This is the trap version from user space. | |
858 | */ | |
859 | kern_return_t | |
860 | semaphore_wait_signal_trap( | |
91447636 A |
861 | struct semaphore_wait_signal_trap_args *args) |
862 | { | |
863 | return(semaphore_wait_signal_trap_internal(args->wait_name, args->signal_name, thread_syscall_return)); | |
864 | } | |
865 | ||
866 | kern_return_t | |
867 | semaphore_wait_signal_trap_internal( | |
868 | mach_port_name_t wait_name, | |
869 | mach_port_name_t signal_name, | |
870 | void (*caller_cont)(kern_return_t)) | |
1c79356b A |
871 | { |
872 | semaphore_t wait_semaphore; | |
873 | semaphore_t signal_semaphore; | |
874 | kern_return_t kr; | |
875 | ||
876 | kr = port_name_to_semaphore(signal_name, &signal_semaphore); | |
91447636 A |
877 | if (kr == KERN_SUCCESS) { |
878 | kr = port_name_to_semaphore(wait_name, &wait_semaphore); | |
879 | if (kr == KERN_SUCCESS) { | |
880 | kr = semaphore_wait_internal(wait_semaphore, | |
881 | signal_semaphore, | |
882 | (mach_timespec_t *)0, | |
883 | caller_cont); | |
884 | semaphore_dereference(wait_semaphore); | |
885 | } | |
1c79356b | 886 | semaphore_dereference(signal_semaphore); |
1c79356b | 887 | } |
1c79356b A |
888 | return kr; |
889 | } | |
890 | ||
891 | ||
892 | /* | |
893 | * Routine: semaphore_timedwait_signal | |
894 | * | |
895 | * Atomically register a wait on a semaphore and THEN signal | |
896 | * another. This is the in-kernel entry point that does not | |
897 | * block at a continuation. | |
898 | * | |
899 | * A timeout of {0,0} is considered non-blocking. | |
900 | */ | |
901 | kern_return_t | |
902 | semaphore_timedwait_signal( | |
903 | semaphore_t wait_semaphore, | |
904 | semaphore_t signal_semaphore, | |
905 | mach_timespec_t wait_time) | |
906 | { | |
907 | if (wait_semaphore == SEMAPHORE_NULL) | |
908 | return KERN_INVALID_ARGUMENT; | |
909 | ||
910 | if(BAD_MACH_TIMESPEC(&wait_time)) | |
911 | return KERN_INVALID_VALUE; | |
912 | ||
913 | return(semaphore_wait_internal(wait_semaphore, | |
914 | signal_semaphore, | |
915 | &wait_time, | |
916 | (void(*)(kern_return_t))0)); | |
917 | } | |
918 | ||
919 | /* | |
920 | * Trap: semaphore_timedwait_signal_trap | |
921 | * | |
922 | * Atomically register a timed wait on a semaphore and THEN signal | |
923 | * another. This is the trap version from user space. | |
924 | */ | |
925 | kern_return_t | |
926 | semaphore_timedwait_signal_trap( | |
91447636 A |
927 | struct semaphore_timedwait_signal_trap_args *args) |
928 | { | |
929 | return(semaphore_timedwait_signal_trap_internal(args->wait_name, args->signal_name, args->sec, args->nsec, thread_syscall_return)); | |
930 | } | |
931 | ||
932 | kern_return_t | |
933 | semaphore_timedwait_signal_trap_internal( | |
934 | mach_port_name_t wait_name, | |
935 | mach_port_name_t signal_name, | |
936 | unsigned int sec, | |
937 | clock_res_t nsec, | |
938 | void (*caller_cont)(kern_return_t)) | |
1c79356b A |
939 | { |
940 | semaphore_t wait_semaphore; | |
941 | semaphore_t signal_semaphore; | |
942 | mach_timespec_t wait_time; | |
943 | kern_return_t kr; | |
944 | ||
945 | wait_time.tv_sec = sec; | |
946 | wait_time.tv_nsec = nsec; | |
947 | if(BAD_MACH_TIMESPEC(&wait_time)) | |
948 | return KERN_INVALID_VALUE; | |
949 | ||
950 | kr = port_name_to_semaphore(signal_name, &signal_semaphore); | |
91447636 A |
951 | if (kr == KERN_SUCCESS) { |
952 | kr = port_name_to_semaphore(wait_name, &wait_semaphore); | |
953 | if (kr == KERN_SUCCESS) { | |
954 | kr = semaphore_wait_internal(wait_semaphore, | |
955 | signal_semaphore, | |
956 | &wait_time, | |
957 | caller_cont); | |
958 | semaphore_dereference(wait_semaphore); | |
959 | } | |
1c79356b | 960 | semaphore_dereference(signal_semaphore); |
1c79356b | 961 | } |
1c79356b A |
962 | return kr; |
963 | } | |
964 | ||
965 | ||
966 | /* | |
967 | * Routine: semaphore_reference | |
968 | * | |
969 | * Take out a reference on a semaphore. This keeps the data structure | |
970 | * in existence (but the semaphore may be deactivated). | |
971 | */ | |
972 | void | |
973 | semaphore_reference( | |
974 | semaphore_t semaphore) | |
975 | { | |
976 | spl_t spl_level; | |
977 | ||
978 | spl_level = splsched(); | |
979 | semaphore_lock(semaphore); | |
980 | ||
981 | semaphore->ref_count++; | |
982 | ||
983 | semaphore_unlock(semaphore); | |
984 | splx(spl_level); | |
985 | } | |
986 | ||
987 | /* | |
988 | * Routine: semaphore_dereference | |
989 | * | |
990 | * Release a reference on a semaphore. If this is the last reference, | |
991 | * the semaphore data structure is deallocated. | |
992 | */ | |
993 | void | |
994 | semaphore_dereference( | |
995 | semaphore_t semaphore) | |
996 | { | |
997 | int ref_count; | |
998 | spl_t spl_level; | |
999 | ||
1000 | if (semaphore != NULL) { | |
1001 | spl_level = splsched(); | |
1002 | semaphore_lock(semaphore); | |
1003 | ||
1004 | ref_count = --(semaphore->ref_count); | |
1005 | ||
1006 | semaphore_unlock(semaphore); | |
1007 | splx(spl_level); | |
1008 | ||
1009 | if (ref_count == 0) { | |
1010 | assert(wait_queue_empty(&semaphore->wait_queue)); | |
91447636 | 1011 | zfree(semaphore_zone, semaphore); |
1c79356b A |
1012 | } |
1013 | } | |
1014 | } |