]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/sync_sema.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / osfmk / kern / sync_sema.c
CommitLineData
1c79356b 1/*
6d2010ae 2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 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>
3e170ce0 57#include <kern/waitq.h>
1c79356b
A
58#include <kern/zalloc.h>
59#include <kern/mach_param.h>
60
316670eb
A
61#include <libkern/OSAtomic.h>
62
9bccf70c 63static unsigned int semaphore_event;
cf7d32b8 64#define SEMAPHORE_EVENT CAST_EVENT64_T(&semaphore_event)
1c79356b
A
65
66zone_t semaphore_zone;
b0d623f7 67unsigned int semaphore_max;
1c79356b 68
91447636
A
69/* Forward declarations */
70
71
72kern_return_t
73semaphore_wait_trap_internal(
74 mach_port_name_t name,
75 void (*caller_cont)(kern_return_t));
76
77kern_return_t
78semaphore_wait_signal_trap_internal(
79 mach_port_name_t wait_name,
80 mach_port_name_t signal_name,
81 void (*caller_cont)(kern_return_t));
82
83kern_return_t
84semaphore_timedwait_trap_internal(
85 mach_port_name_t name,
86 unsigned int sec,
87 clock_res_t nsec,
88 void (*caller_cont)(kern_return_t));
89
90kern_return_t
91semaphore_timedwait_signal_trap_internal(
92 mach_port_name_t wait_name,
93 mach_port_name_t signal_name,
94 unsigned int sec,
95 clock_res_t nsec,
96 void (*caller_cont)(kern_return_t));
97
2d21ac55
A
98kern_return_t
99semaphore_signal_internal_trap(mach_port_name_t sema_name);
91447636
A
100
101kern_return_t
102semaphore_signal_internal(
103 semaphore_t semaphore,
104 thread_t thread,
105 int options);
106
107kern_return_t
108semaphore_convert_wait_result(
109 int wait_result);
110
111void
112semaphore_wait_continue(void);
113
b0d623f7 114static kern_return_t
91447636
A
115semaphore_wait_internal(
116 semaphore_t wait_semaphore,
117 semaphore_t signal_semaphore,
b0d623f7
A
118 uint64_t deadline,
119 int option,
91447636
A
120 void (*caller_cont)(kern_return_t));
121
b0d623f7
A
122static __inline__ uint64_t
123semaphore_deadline(
124 unsigned int sec,
125 clock_res_t nsec)
126{
127 uint64_t abstime;
128
129 nanoseconds_to_absolutetime((uint64_t)sec * NSEC_PER_SEC + nsec, &abstime);
130 clock_absolutetime_interval_to_deadline(abstime, &abstime);
131
132 return (abstime);
133}
134
1c79356b
A
135/*
136 * ROUTINE: semaphore_init [private]
137 *
138 * Initialize the semaphore mechanisms.
139 * Right now, we only need to initialize the semaphore zone.
140 */
141void
142semaphore_init(void)
143{
144 semaphore_zone = zinit(sizeof(struct semaphore),
145 semaphore_max * sizeof(struct semaphore),
146 sizeof(struct semaphore),
147 "semaphores");
0b4c1975 148 zone_change(semaphore_zone, Z_NOENCRYPT, TRUE);
1c79356b
A
149}
150
151/*
152 * Routine: semaphore_create
153 *
154 * Creates a semaphore.
155 * The port representing the semaphore is returned as a parameter.
156 */
157kern_return_t
158semaphore_create(
159 task_t task,
160 semaphore_t *new_semaphore,
161 int policy,
162 int value)
163{
164 semaphore_t s = SEMAPHORE_NULL;
b0d623f7 165 kern_return_t kret;
1c79356b
A
166
167
b0d623f7
A
168 *new_semaphore = SEMAPHORE_NULL;
169 if (task == TASK_NULL || value < 0 || policy > SYNC_POLICY_MAX)
1c79356b 170 return KERN_INVALID_ARGUMENT;
1c79356b
A
171
172 s = (semaphore_t) zalloc (semaphore_zone);
173
b0d623f7 174 if (s == SEMAPHORE_NULL)
1c79356b 175 return KERN_RESOURCE_SHORTAGE;
b0d623f7 176
3e170ce0 177 kret = waitq_init(&s->waitq, policy | SYNC_POLICY_DISABLE_IRQ); /* also inits lock */
b0d623f7
A
178 if (kret != KERN_SUCCESS) {
179 zfree(semaphore_zone, s);
180 return kret;
1c79356b
A
181 }
182
1c79356b 183 /*
3e170ce0 184 * Initialize the semaphore values.
1c79356b 185 */
3e170ce0
A
186 s->port = IP_NULL;
187 s->ref_count = 1;
188 s->count = value;
189 s->active = TRUE;
190 s->owner = task;
1c79356b
A
191
192 /*
193 * Associate the new semaphore with the task by adding
194 * the new semaphore to the task's semaphore list.
1c79356b
A
195 */
196 task_lock(task);
197 enqueue_head(&task->semaphore_list, (queue_entry_t) s);
198 task->semaphores_owned++;
1c79356b
A
199 task_unlock(task);
200
201 *new_semaphore = s;
202
203 return KERN_SUCCESS;
204}
205
206/*
3e170ce0 207 * Routine: semaphore_destroy_internal
1c79356b 208 *
4bd07ac2
A
209 * Disassociate a semaphore from its owning task, mark it inactive,
210 * and set any waiting threads running with THREAD_RESTART.
1c79356b 211 *
4bd07ac2
A
212 * Conditions:
213 * task is locked
214 * semaphore is locked
215 * semaphore is owned by the specified task
216 * Returns:
217 * with semaphore unlocked
1c79356b 218 */
4bd07ac2 219static void
3e170ce0 220semaphore_destroy_internal(
1c79356b
A
221 task_t task,
222 semaphore_t semaphore)
223{
3e170ce0 224 int old_count;
3e170ce0 225
4bd07ac2
A
226 /* unlink semaphore from owning task */
227 assert(semaphore->owner == task);
6d2010ae 228 remqueue((queue_entry_t) semaphore);
1c79356b
A
229 semaphore->owner = TASK_NULL;
230 task->semaphores_owned--;
1c79356b 231
1c79356b
A
232 /*
233 * Deactivate semaphore
234 */
235 assert(semaphore->active);
236 semaphore->active = FALSE;
237
238 /*
239 * Wakeup blocked threads
240 */
241 old_count = semaphore->count;
242 semaphore->count = 0;
243
244 if (old_count < 0) {
3e170ce0
A
245 waitq_wakeup64_all_locked(&semaphore->waitq,
246 SEMAPHORE_EVENT,
247 THREAD_RESTART, NULL,
248 WAITQ_ALL_PRIORITIES,
249 WAITQ_UNLOCK);
250 /* waitq/semaphore is unlocked */
1c79356b
A
251 } else {
252 semaphore_unlock(semaphore);
253 }
1c79356b
A
254}
255
3e170ce0
A
256/*
257 * Routine: semaphore_destroy
258 *
259 * Destroys a semaphore and consume the caller's reference on the
260 * semaphore.
261 */
262kern_return_t
263semaphore_destroy(
264 task_t task,
265 semaphore_t semaphore)
266{
4bd07ac2 267 spl_t spl_level;
3e170ce0
A
268
269 if (semaphore == SEMAPHORE_NULL)
270 return KERN_INVALID_ARGUMENT;
271
272 if (task == TASK_NULL) {
4bd07ac2
A
273 semaphore_dereference(semaphore);
274 return KERN_INVALID_ARGUMENT;
275 }
276
277 task_lock(task);
278 spl_level = splsched();
279 semaphore_lock(semaphore);
280
281 if (semaphore->owner != task) {
282 semaphore_unlock(semaphore);
283 splx(spl_level);
284 task_unlock(task);
285 return KERN_INVALID_ARGUMENT;
3e170ce0 286 }
4bd07ac2
A
287
288 semaphore_destroy_internal(task, semaphore);
289 /* semaphore unlocked */
290
291 splx(spl_level);
292 task_unlock(task);
293
3e170ce0 294 semaphore_dereference(semaphore);
4bd07ac2
A
295 return KERN_SUCCESS;
296}
297
298/*
299 * Routine: semaphore_destroy_all
300 *
301 * Destroy all the semaphores associated with a given task.
302 */
303#define SEMASPERSPL 20 /* max number of semaphores to destroy per spl hold */
304
305void
306semaphore_destroy_all(
307 task_t task)
308{
309 uint32_t count;
310 spl_t spl_level;
311
312 count = 0;
313 task_lock(task);
314 while (!queue_empty(&task->semaphore_list)) {
315 semaphore_t semaphore;
316
317 semaphore = (semaphore_t) queue_first(&task->semaphore_list);
318
319 if (count == 0)
320 spl_level = splsched();
321 semaphore_lock(semaphore);
322
323 semaphore_destroy_internal(task, semaphore);
324 /* semaphore unlocked */
325
326 /* throttle number of semaphores per interrupt disablement */
327 if (++count == SEMASPERSPL) {
328 count = 0;
329 splx(spl_level);
330 }
331 }
332 if (count != 0)
333 splx(spl_level);
334
335 task_unlock(task);
3e170ce0
A
336}
337
1c79356b
A
338/*
339 * Routine: semaphore_signal_internal
340 *
341 * Signals the semaphore as direct.
342 * Assumptions:
343 * Semaphore is locked.
344 */
345kern_return_t
346semaphore_signal_internal(
347 semaphore_t semaphore,
91447636
A
348 thread_t thread,
349 int options)
1c79356b
A
350{
351 kern_return_t kr;
352 spl_t spl_level;
353
354 spl_level = splsched();
355 semaphore_lock(semaphore);
356
357 if (!semaphore->active) {
358 semaphore_unlock(semaphore);
359 splx(spl_level);
360 return KERN_TERMINATED;
361 }
362
91447636 363 if (thread != THREAD_NULL) {
1c79356b 364 if (semaphore->count < 0) {
3e170ce0
A
365 kr = waitq_wakeup64_thread_locked(
366 &semaphore->waitq,
1c79356b 367 SEMAPHORE_EVENT,
91447636 368 thread,
1c79356b 369 THREAD_AWAKENED,
3e170ce0
A
370 WAITQ_UNLOCK);
371 /* waitq/semaphore is unlocked */
1c79356b 372 } else {
1c79356b 373 kr = KERN_NOT_WAITING;
3e170ce0 374 semaphore_unlock(semaphore);
1c79356b
A
375 }
376 splx(spl_level);
377 return kr;
378 }
379
380 if (options & SEMAPHORE_SIGNAL_ALL) {
381 int old_count = semaphore->count;
382
3e170ce0 383 kr = KERN_NOT_WAITING;
1c79356b
A
384 if (old_count < 0) {
385 semaphore->count = 0; /* always reset */
3e170ce0
A
386 kr = waitq_wakeup64_all_locked(
387 &semaphore->waitq,
1c79356b 388 SEMAPHORE_EVENT,
3e170ce0
A
389 THREAD_AWAKENED, NULL,
390 WAITQ_ALL_PRIORITIES,
391 WAITQ_UNLOCK);
392 /* waitq / semaphore is unlocked */
1c79356b
A
393 } else {
394 if (options & SEMAPHORE_SIGNAL_PREPOST)
395 semaphore->count++;
1c79356b 396 kr = KERN_SUCCESS;
3e170ce0 397 semaphore_unlock(semaphore);
1c79356b
A
398 }
399 splx(spl_level);
400 return kr;
401 }
402
403 if (semaphore->count < 0) {
3e170ce0
A
404 kr = waitq_wakeup64_one_locked(
405 &semaphore->waitq,
1c79356b 406 SEMAPHORE_EVENT,
3e170ce0
A
407 THREAD_AWAKENED, NULL,
408 WAITQ_ALL_PRIORITIES,
409 WAITQ_KEEP_LOCKED);
410 if (kr == KERN_SUCCESS) {
1c79356b
A
411 semaphore_unlock(semaphore);
412 splx(spl_level);
413 return KERN_SUCCESS;
3e170ce0 414 } else {
1c79356b 415 semaphore->count = 0; /* all waiters gone */
3e170ce0 416 }
1c79356b
A
417 }
418
419 if (options & SEMAPHORE_SIGNAL_PREPOST) {
420 semaphore->count++;
421 }
422
423 semaphore_unlock(semaphore);
424 splx(spl_level);
425 return KERN_NOT_WAITING;
426}
427
428/*
429 * Routine: semaphore_signal_thread
430 *
91447636
A
431 * If the specified thread is blocked on the semaphore, it is
432 * woken up. If a NULL thread was supplied, then any one
1c79356b
A
433 * thread is woken up. Otherwise the caller gets KERN_NOT_WAITING
434 * and the semaphore is unchanged.
435 */
436kern_return_t
437semaphore_signal_thread(
438 semaphore_t semaphore,
91447636 439 thread_t thread)
1c79356b
A
440{
441 kern_return_t ret;
442
443 if (semaphore == SEMAPHORE_NULL)
444 return KERN_INVALID_ARGUMENT;
445
446 ret = semaphore_signal_internal(semaphore,
91447636 447 thread,
1c79356b
A
448 SEMAPHORE_OPTION_NONE);
449 return ret;
450}
451
452/*
453 * Routine: semaphore_signal_thread_trap
454 *
455 * Trap interface to the semaphore_signal_thread function.
456 */
457kern_return_t
458semaphore_signal_thread_trap(
91447636 459 struct semaphore_signal_thread_trap_args *args)
1c79356b 460{
91447636
A
461 mach_port_name_t sema_name = args->signal_name;
462 mach_port_name_t thread_name = args->thread_name;
1c79356b 463 semaphore_t semaphore;
91447636 464 thread_t thread;
1c79356b
A
465 kern_return_t kr;
466
467 /*
468 * MACH_PORT_NULL is not an error. It means that we want to
469 * select any one thread that is already waiting, but not to
470 * pre-post the semaphore.
471 */
472 if (thread_name != MACH_PORT_NULL) {
91447636
A
473 thread = port_name_to_thread(thread_name);
474 if (thread == THREAD_NULL)
1c79356b
A
475 return KERN_INVALID_ARGUMENT;
476 } else
91447636 477 thread = THREAD_NULL;
1c79356b
A
478
479 kr = port_name_to_semaphore(sema_name, &semaphore);
91447636
A
480 if (kr == KERN_SUCCESS) {
481 kr = semaphore_signal_internal(semaphore,
482 thread,
483 SEMAPHORE_OPTION_NONE);
484 semaphore_dereference(semaphore);
485 }
486 if (thread != THREAD_NULL) {
487 thread_deallocate(thread);
1c79356b 488 }
1c79356b
A
489 return kr;
490}
491
492
493
494/*
495 * Routine: semaphore_signal
496 *
497 * Traditional (in-kernel client and MIG interface) semaphore
498 * signal routine. Most users will access the trap version.
499 *
500 * This interface in not defined to return info about whether
501 * this call found a thread waiting or not. The internal
502 * routines (and future external routines) do. We have to
503 * convert those into plain KERN_SUCCESS returns.
504 */
505kern_return_t
506semaphore_signal(
507 semaphore_t semaphore)
508{
509 kern_return_t kr;
510
511 if (semaphore == SEMAPHORE_NULL)
512 return KERN_INVALID_ARGUMENT;
513
514 kr = semaphore_signal_internal(semaphore,
91447636 515 THREAD_NULL,
1c79356b
A
516 SEMAPHORE_SIGNAL_PREPOST);
517 if (kr == KERN_NOT_WAITING)
518 return KERN_SUCCESS;
519 return kr;
520}
521
522/*
523 * Routine: semaphore_signal_trap
524 *
525 * Trap interface to the semaphore_signal function.
526 */
527kern_return_t
528semaphore_signal_trap(
91447636 529 struct semaphore_signal_trap_args *args)
1c79356b 530{
91447636 531 mach_port_name_t sema_name = args->signal_name;
2d21ac55
A
532
533 return (semaphore_signal_internal_trap(sema_name));
534}
535
536kern_return_t
537semaphore_signal_internal_trap(mach_port_name_t sema_name)
538{
1c79356b
A
539 semaphore_t semaphore;
540 kern_return_t kr;
541
542 kr = port_name_to_semaphore(sema_name, &semaphore);
91447636
A
543 if (kr == KERN_SUCCESS) {
544 kr = semaphore_signal_internal(semaphore,
545 THREAD_NULL,
546 SEMAPHORE_SIGNAL_PREPOST);
547 semaphore_dereference(semaphore);
548 if (kr == KERN_NOT_WAITING)
549 kr = KERN_SUCCESS;
1c79356b 550 }
1c79356b
A
551 return kr;
552}
553
554/*
555 * Routine: semaphore_signal_all
556 *
557 * Awakens ALL threads currently blocked on the semaphore.
558 * The semaphore count returns to zero.
559 */
560kern_return_t
561semaphore_signal_all(
562 semaphore_t semaphore)
563{
564 kern_return_t kr;
565
566 if (semaphore == SEMAPHORE_NULL)
567 return KERN_INVALID_ARGUMENT;
568
569 kr = semaphore_signal_internal(semaphore,
91447636 570 THREAD_NULL,
1c79356b
A
571 SEMAPHORE_SIGNAL_ALL);
572 if (kr == KERN_NOT_WAITING)
573 return KERN_SUCCESS;
574 return kr;
575}
576
577/*
578 * Routine: semaphore_signal_all_trap
579 *
580 * Trap interface to the semaphore_signal_all function.
581 */
582kern_return_t
583semaphore_signal_all_trap(
91447636 584 struct semaphore_signal_all_trap_args *args)
1c79356b 585{
91447636 586 mach_port_name_t sema_name = args->signal_name;
1c79356b
A
587 semaphore_t semaphore;
588 kern_return_t kr;
589
590 kr = port_name_to_semaphore(sema_name, &semaphore);
91447636
A
591 if (kr == KERN_SUCCESS) {
592 kr = semaphore_signal_internal(semaphore,
593 THREAD_NULL,
594 SEMAPHORE_SIGNAL_ALL);
595 semaphore_dereference(semaphore);
596 if (kr == KERN_NOT_WAITING)
597 kr = KERN_SUCCESS;
1c79356b 598 }
1c79356b
A
599 return kr;
600}
601
602/*
603 * Routine: semaphore_convert_wait_result
604 *
605 * Generate the return code after a semaphore wait/block. It
606 * takes the wait result as an input and coverts that to an
607 * appropriate result.
608 */
609kern_return_t
610semaphore_convert_wait_result(int wait_result)
611{
612 switch (wait_result) {
613 case THREAD_AWAKENED:
614 return KERN_SUCCESS;
615
616 case THREAD_TIMED_OUT:
617 return KERN_OPERATION_TIMED_OUT;
618
619 case THREAD_INTERRUPTED:
620 return KERN_ABORTED;
621
622 case THREAD_RESTART:
623 return KERN_TERMINATED;
624
625 default:
626 panic("semaphore_block\n");
627 return KERN_FAILURE;
628 }
629}
630
631/*
632 * Routine: semaphore_wait_continue
633 *
634 * Common continuation routine after waiting on a semphore.
635 * It returns directly to user space.
636 */
637void
638semaphore_wait_continue(void)
639{
640 thread_t self = current_thread();
641 int wait_result = self->wait_result;
642 void (*caller_cont)(kern_return_t) = self->sth_continuation;
643
644 assert(self->sth_waitsemaphore != SEMAPHORE_NULL);
645 semaphore_dereference(self->sth_waitsemaphore);
646 if (self->sth_signalsemaphore != SEMAPHORE_NULL)
647 semaphore_dereference(self->sth_signalsemaphore);
648
649 assert(caller_cont != (void (*)(kern_return_t))0);
650 (*caller_cont)(semaphore_convert_wait_result(wait_result));
651}
652
1c79356b
A
653/*
654 * Routine: semaphore_wait_internal
655 *
656 * Decrements the semaphore count by one. If the count is
657 * negative after the decrement, the calling thread blocks
658 * (possibly at a continuation and/or with a timeout).
659 *
660 * Assumptions:
661 * The reference
662 * A reference is held on the signal semaphore.
663 */
b0d623f7 664static kern_return_t
1c79356b
A
665semaphore_wait_internal(
666 semaphore_t wait_semaphore,
667 semaphore_t signal_semaphore,
b0d623f7
A
668 uint64_t deadline,
669 int option,
1c79356b
A
670 void (*caller_cont)(kern_return_t))
671{
91447636
A
672 int wait_result;
673 spl_t spl_level;
1c79356b
A
674 kern_return_t kr = KERN_ALREADY_WAITING;
675
676 spl_level = splsched();
677 semaphore_lock(wait_semaphore);
678
1c79356b
A
679 if (!wait_semaphore->active) {
680 kr = KERN_TERMINATED;
681 } else if (wait_semaphore->count > 0) {
682 wait_semaphore->count--;
683 kr = KERN_SUCCESS;
b0d623f7 684 } else if (option & SEMAPHORE_TIMEOUT_NOBLOCK) {
1c79356b 685 kr = KERN_OPERATION_TIMED_OUT;
55e303ae 686 } else {
91447636 687 thread_t self = current_thread();
55e303ae 688
1c79356b 689 wait_semaphore->count = -1; /* we don't keep an actual count */
813fb2f6
A
690
691 thread_set_pending_block_hint(self, kThreadWaitSemaphore);
3e170ce0
A
692 (void)waitq_assert_wait64_locked(
693 &wait_semaphore->waitq,
9bccf70c 694 SEMAPHORE_EVENT,
39236c6e
A
695 THREAD_ABORTSAFE,
696 TIMEOUT_URGENCY_USER_NORMAL,
3e170ce0 697 deadline, TIMEOUT_NO_LEEWAY,
55e303ae 698 self);
1c79356b
A
699 }
700 semaphore_unlock(wait_semaphore);
701 splx(spl_level);
702
703 /*
704 * wait_semaphore is unlocked so we are free to go ahead and
705 * signal the signal_semaphore (if one was provided).
706 */
707 if (signal_semaphore != SEMAPHORE_NULL) {
708 kern_return_t signal_kr;
709
710 /*
711 * lock the signal semaphore reference we got and signal it.
712 * This will NOT block (we cannot block after having asserted
713 * our intention to wait above).
714 */
715 signal_kr = semaphore_signal_internal(signal_semaphore,
91447636 716 THREAD_NULL,
1c79356b
A
717 SEMAPHORE_SIGNAL_PREPOST);
718
719 if (signal_kr == KERN_NOT_WAITING)
720 signal_kr = KERN_SUCCESS;
721 else if (signal_kr == KERN_TERMINATED) {
722 /*
723 * Uh!Oh! The semaphore we were to signal died.
724 * We have to get ourselves out of the wait in
725 * case we get stuck here forever (it is assumed
726 * that the semaphore we were posting is gating
727 * the decision by someone else to post the
728 * semaphore we are waiting on). People will
729 * discover the other dead semaphore soon enough.
730 * If we got out of the wait cleanly (someone
731 * already posted a wakeup to us) then return that
732 * (most important) result. Otherwise,
733 * return the KERN_TERMINATED status.
734 */
735 thread_t self = current_thread();
736
737 clear_wait(self, THREAD_INTERRUPTED);
738 kr = semaphore_convert_wait_result(self->wait_result);
739 if (kr == KERN_ABORTED)
740 kr = KERN_TERMINATED;
741 }
742 }
743
744 /*
745 * If we had an error, or we didn't really need to wait we can
746 * return now that we have signalled the signal semaphore.
747 */
748 if (kr != KERN_ALREADY_WAITING)
749 return kr;
1c79356b
A
750
751 /*
752 * Now, we can block. If the caller supplied a continuation
753 * pointer of his own for after the block, block with the
754 * appropriate semaphore continuation. Thiswill gather the
755 * semaphore results, release references on the semaphore(s),
756 * and then call the caller's continuation.
757 */
758 if (caller_cont) {
759 thread_t self = current_thread();
760
761 self->sth_continuation = caller_cont;
762 self->sth_waitsemaphore = wait_semaphore;
763 self->sth_signalsemaphore = signal_semaphore;
91447636
A
764 wait_result = thread_block((thread_continue_t)semaphore_wait_continue);
765 }
766 else {
9bccf70c 767 wait_result = thread_block(THREAD_CONTINUE_NULL);
1c79356b
A
768 }
769
1c79356b
A
770 return (semaphore_convert_wait_result(wait_result));
771}
772
773
774/*
775 * Routine: semaphore_wait
776 *
777 * Traditional (non-continuation) interface presented to
778 * in-kernel clients to wait on a semaphore.
779 */
780kern_return_t
781semaphore_wait(
782 semaphore_t semaphore)
783{
784
785 if (semaphore == SEMAPHORE_NULL)
786 return KERN_INVALID_ARGUMENT;
787
788 return(semaphore_wait_internal(semaphore,
b0d623f7
A
789 SEMAPHORE_NULL,
790 0ULL, SEMAPHORE_OPTION_NONE,
791 (void (*)(kern_return_t))0));
792}
793
794kern_return_t
795semaphore_wait_noblock(
796 semaphore_t semaphore)
797{
798
799 if (semaphore == SEMAPHORE_NULL)
800 return KERN_INVALID_ARGUMENT;
801
802 return(semaphore_wait_internal(semaphore,
803 SEMAPHORE_NULL,
804 0ULL, SEMAPHORE_TIMEOUT_NOBLOCK,
805 (void (*)(kern_return_t))0));
806}
807
808kern_return_t
809semaphore_wait_deadline(
810 semaphore_t semaphore,
811 uint64_t deadline)
812{
813
814 if (semaphore == SEMAPHORE_NULL)
815 return KERN_INVALID_ARGUMENT;
816
817 return(semaphore_wait_internal(semaphore,
818 SEMAPHORE_NULL,
819 deadline, SEMAPHORE_OPTION_NONE,
1c79356b
A
820 (void (*)(kern_return_t))0));
821}
822
823/*
824 * Trap: semaphore_wait_trap
825 *
826 * Trap version of semaphore wait. Called on behalf of user-level
827 * clients.
828 */
91447636 829
1c79356b
A
830kern_return_t
831semaphore_wait_trap(
91447636
A
832 struct semaphore_wait_trap_args *args)
833{
834 return(semaphore_wait_trap_internal(args->wait_name, thread_syscall_return));
835}
836
837
838
839kern_return_t
840semaphore_wait_trap_internal(
841 mach_port_name_t name,
842 void (*caller_cont)(kern_return_t))
1c79356b
A
843{
844 semaphore_t semaphore;
845 kern_return_t kr;
846
847 kr = port_name_to_semaphore(name, &semaphore);
91447636
A
848 if (kr == KERN_SUCCESS) {
849 kr = semaphore_wait_internal(semaphore,
850 SEMAPHORE_NULL,
b0d623f7 851 0ULL, SEMAPHORE_OPTION_NONE,
91447636
A
852 caller_cont);
853 semaphore_dereference(semaphore);
854 }
1c79356b
A
855 return kr;
856}
857
858/*
859 * Routine: semaphore_timedwait
860 *
861 * Traditional (non-continuation) interface presented to
862 * in-kernel clients to wait on a semaphore with a timeout.
863 *
864 * A timeout of {0,0} is considered non-blocking.
865 */
866kern_return_t
867semaphore_timedwait(
868 semaphore_t semaphore,
869 mach_timespec_t wait_time)
b0d623f7
A
870{
871 int option = SEMAPHORE_OPTION_NONE;
872 uint64_t deadline = 0;
873
1c79356b
A
874 if (semaphore == SEMAPHORE_NULL)
875 return KERN_INVALID_ARGUMENT;
876
877 if(BAD_MACH_TIMESPEC(&wait_time))
878 return KERN_INVALID_VALUE;
b0d623f7
A
879
880 if (wait_time.tv_sec == 0 && wait_time.tv_nsec == 0)
881 option = SEMAPHORE_TIMEOUT_NOBLOCK;
882 else
883 deadline = semaphore_deadline(wait_time.tv_sec, wait_time.tv_nsec);
1c79356b
A
884
885 return (semaphore_wait_internal(semaphore,
886 SEMAPHORE_NULL,
b0d623f7 887 deadline, option,
1c79356b
A
888 (void(*)(kern_return_t))0));
889
890}
891
892/*
893 * Trap: semaphore_timedwait_trap
894 *
895 * Trap version of a semaphore_timedwait. The timeout parameter
896 * is passed in two distinct parts and re-assembled on this side
897 * of the trap interface (to accomodate calling conventions that
898 * pass structures as pointers instead of inline in registers without
899 * having to add a copyin).
900 *
901 * A timeout of {0,0} is considered non-blocking.
902 */
903kern_return_t
904semaphore_timedwait_trap(
91447636 905 struct semaphore_timedwait_trap_args *args)
1c79356b 906{
91447636
A
907
908 return(semaphore_timedwait_trap_internal(args->wait_name, args->sec, args->nsec, thread_syscall_return));
909}
910
911
912kern_return_t
913semaphore_timedwait_trap_internal(
914 mach_port_name_t name,
915 unsigned int sec,
916 clock_res_t nsec,
917 void (*caller_cont)(kern_return_t))
918{
1c79356b
A
919 semaphore_t semaphore;
920 mach_timespec_t wait_time;
921 kern_return_t kr;
922
923 wait_time.tv_sec = sec;
924 wait_time.tv_nsec = nsec;
925 if(BAD_MACH_TIMESPEC(&wait_time))
926 return KERN_INVALID_VALUE;
927
928 kr = port_name_to_semaphore(name, &semaphore);
91447636 929 if (kr == KERN_SUCCESS) {
b0d623f7
A
930 int option = SEMAPHORE_OPTION_NONE;
931 uint64_t deadline = 0;
932
933 if (sec == 0 && nsec == 0)
934 option = SEMAPHORE_TIMEOUT_NOBLOCK;
935 else
936 deadline = semaphore_deadline(sec, nsec);
937
91447636
A
938 kr = semaphore_wait_internal(semaphore,
939 SEMAPHORE_NULL,
b0d623f7 940 deadline, option,
91447636
A
941 caller_cont);
942 semaphore_dereference(semaphore);
943 }
1c79356b
A
944 return kr;
945}
946
947/*
948 * Routine: semaphore_wait_signal
949 *
950 * Atomically register a wait on a semaphore and THEN signal
951 * another. This is the in-kernel entry point that does not
952 * block at a continuation and does not free a signal_semaphore
953 * reference.
954 */
955kern_return_t
956semaphore_wait_signal(
957 semaphore_t wait_semaphore,
958 semaphore_t signal_semaphore)
959{
960 if (wait_semaphore == SEMAPHORE_NULL)
961 return KERN_INVALID_ARGUMENT;
962
963 return(semaphore_wait_internal(wait_semaphore,
964 signal_semaphore,
b0d623f7 965 0ULL, SEMAPHORE_OPTION_NONE,
1c79356b
A
966 (void(*)(kern_return_t))0));
967}
968
969/*
970 * Trap: semaphore_wait_signal_trap
971 *
972 * Atomically register a wait on a semaphore and THEN signal
973 * another. This is the trap version from user space.
974 */
975kern_return_t
976semaphore_wait_signal_trap(
91447636
A
977 struct semaphore_wait_signal_trap_args *args)
978{
979 return(semaphore_wait_signal_trap_internal(args->wait_name, args->signal_name, thread_syscall_return));
980}
981
982kern_return_t
983semaphore_wait_signal_trap_internal(
984 mach_port_name_t wait_name,
985 mach_port_name_t signal_name,
986 void (*caller_cont)(kern_return_t))
1c79356b
A
987{
988 semaphore_t wait_semaphore;
989 semaphore_t signal_semaphore;
990 kern_return_t kr;
991
992 kr = port_name_to_semaphore(signal_name, &signal_semaphore);
91447636
A
993 if (kr == KERN_SUCCESS) {
994 kr = port_name_to_semaphore(wait_name, &wait_semaphore);
995 if (kr == KERN_SUCCESS) {
996 kr = semaphore_wait_internal(wait_semaphore,
997 signal_semaphore,
b0d623f7 998 0ULL, SEMAPHORE_OPTION_NONE,
91447636
A
999 caller_cont);
1000 semaphore_dereference(wait_semaphore);
1001 }
1c79356b 1002 semaphore_dereference(signal_semaphore);
1c79356b 1003 }
1c79356b
A
1004 return kr;
1005}
1006
1007
1008/*
1009 * Routine: semaphore_timedwait_signal
1010 *
1011 * Atomically register a wait on a semaphore and THEN signal
1012 * another. This is the in-kernel entry point that does not
1013 * block at a continuation.
1014 *
1015 * A timeout of {0,0} is considered non-blocking.
1016 */
1017kern_return_t
1018semaphore_timedwait_signal(
1019 semaphore_t wait_semaphore,
1020 semaphore_t signal_semaphore,
1021 mach_timespec_t wait_time)
1022{
b0d623f7
A
1023 int option = SEMAPHORE_OPTION_NONE;
1024 uint64_t deadline = 0;
1025
1c79356b
A
1026 if (wait_semaphore == SEMAPHORE_NULL)
1027 return KERN_INVALID_ARGUMENT;
1028
1029 if(BAD_MACH_TIMESPEC(&wait_time))
1030 return KERN_INVALID_VALUE;
b0d623f7
A
1031
1032 if (wait_time.tv_sec == 0 && wait_time.tv_nsec == 0)
1033 option = SEMAPHORE_TIMEOUT_NOBLOCK;
1034 else
1035 deadline = semaphore_deadline(wait_time.tv_sec, wait_time.tv_nsec);
1c79356b
A
1036
1037 return(semaphore_wait_internal(wait_semaphore,
1038 signal_semaphore,
b0d623f7 1039 deadline, option,
1c79356b
A
1040 (void(*)(kern_return_t))0));
1041}
1042
1043/*
1044 * Trap: semaphore_timedwait_signal_trap
1045 *
1046 * Atomically register a timed wait on a semaphore and THEN signal
1047 * another. This is the trap version from user space.
1048 */
1049kern_return_t
1050semaphore_timedwait_signal_trap(
91447636
A
1051 struct semaphore_timedwait_signal_trap_args *args)
1052{
1053 return(semaphore_timedwait_signal_trap_internal(args->wait_name, args->signal_name, args->sec, args->nsec, thread_syscall_return));
1054}
1055
1056kern_return_t
1057semaphore_timedwait_signal_trap_internal(
1058 mach_port_name_t wait_name,
1059 mach_port_name_t signal_name,
1060 unsigned int sec,
1061 clock_res_t nsec,
1062 void (*caller_cont)(kern_return_t))
1c79356b
A
1063{
1064 semaphore_t wait_semaphore;
1065 semaphore_t signal_semaphore;
1066 mach_timespec_t wait_time;
1067 kern_return_t kr;
1068
1069 wait_time.tv_sec = sec;
1070 wait_time.tv_nsec = nsec;
1071 if(BAD_MACH_TIMESPEC(&wait_time))
1072 return KERN_INVALID_VALUE;
1073
1074 kr = port_name_to_semaphore(signal_name, &signal_semaphore);
91447636
A
1075 if (kr == KERN_SUCCESS) {
1076 kr = port_name_to_semaphore(wait_name, &wait_semaphore);
1077 if (kr == KERN_SUCCESS) {
b0d623f7
A
1078 int option = SEMAPHORE_OPTION_NONE;
1079 uint64_t deadline = 0;
1080
1081 if (sec == 0 && nsec == 0)
1082 option = SEMAPHORE_TIMEOUT_NOBLOCK;
1083 else
1084 deadline = semaphore_deadline(sec, nsec);
1085
91447636
A
1086 kr = semaphore_wait_internal(wait_semaphore,
1087 signal_semaphore,
b0d623f7 1088 deadline, option,
91447636
A
1089 caller_cont);
1090 semaphore_dereference(wait_semaphore);
1091 }
1c79356b 1092 semaphore_dereference(signal_semaphore);
1c79356b 1093 }
1c79356b
A
1094 return kr;
1095}
1096
1097
1098/*
1099 * Routine: semaphore_reference
1100 *
1101 * Take out a reference on a semaphore. This keeps the data structure
1102 * in existence (but the semaphore may be deactivated).
1103 */
1104void
1105semaphore_reference(
1106 semaphore_t semaphore)
1107{
b0d623f7 1108 (void)hw_atomic_add(&semaphore->ref_count, 1);
1c79356b
A
1109}
1110
1111/*
1112 * Routine: semaphore_dereference
1113 *
1114 * Release a reference on a semaphore. If this is the last reference,
1115 * the semaphore data structure is deallocated.
1116 */
1117void
1118semaphore_dereference(
1119 semaphore_t semaphore)
1120{
4bd07ac2
A
1121 uint32_t collisions;
1122 spl_t spl_level;
1123
3e170ce0
A
1124 if (semaphore == NULL)
1125 return;
1126
1127 if (hw_atomic_sub(&semaphore->ref_count, 1) != 0)
1128 return;
1129
1130 /*
1131 * Last ref, clean up the port [if any]
1132 * associated with the semaphore, destroy
1133 * it (if still active) and then free
1134 * the semaphore.
1135 */
1136 ipc_port_t port = semaphore->port;
1137
1138 if (IP_VALID(port)) {
1139 assert(!port->ip_srights);
1140 ipc_port_dealloc_kernel(port);
1141 }
4bd07ac2
A
1142
1143 /*
1144 * Lock the semaphore to lock in the owner task reference.
1145 * Then continue to try to lock the task (inverse order).
1146 */
1147 spl_level = splsched();
1148 semaphore_lock(semaphore);
1149 for (collisions = 0; semaphore->active; collisions++) {
1150 task_t task = semaphore->owner;
1151
1152 assert(task != TASK_NULL);
1153
1154 if (task_lock_try(task)) {
1155 semaphore_destroy_internal(task, semaphore);
1156 /* semaphore unlocked */
1157 splx(spl_level);
1158 task_unlock(task);
1159 goto out;
1160 }
1161
1162 /* failed to get out-of-order locks */
1163 semaphore_unlock(semaphore);
1164 splx(spl_level);
1165 mutex_pause(collisions);
1166 spl_level = splsched();
1167 semaphore_lock(semaphore);
1c79356b 1168 }
4bd07ac2
A
1169 semaphore_unlock(semaphore);
1170 splx(spl_level);
1171
1172 out:
3e170ce0 1173 zfree(semaphore_zone, semaphore);
1c79356b 1174}
3e170ce0 1175
813fb2f6
A
1176#define WAITQ_TO_SEMA(wq) ((semaphore_t) ((uintptr_t)(wq) - offsetof(struct semaphore, waitq)))
1177void
1178kdp_sema_find_owner(struct waitq * waitq, __assert_only event64_t event, thread_waitinfo_t * waitinfo)
1179{
1180 semaphore_t sem = WAITQ_TO_SEMA(waitq);
1181 assert(event == SEMAPHORE_EVENT);
1182 assert(kdp_is_in_zone(sem, "semaphores"));
3e170ce0 1183
813fb2f6
A
1184 waitinfo->context = VM_KERNEL_UNSLIDE_OR_PERM(sem->port);
1185 if (sem->owner)
1186 waitinfo->owner = pid_from_task(sem->owner);
1187}