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