2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * @OSF_FREE_COPYRIGHT@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
65 * File: ipc/ipc_port.c
69 * Functions to manipulate IPC ports.
72 #include <zone_debug.h>
73 #include <mach_assert.h>
75 #include <mach/port.h>
76 #include <mach/kern_return.h>
77 #include <kern/ipc_kobject.h>
78 #include <kern/thread.h>
79 #include <kern/misc_protos.h>
80 #include <kern/waitq.h>
81 #include <ipc/ipc_entry.h>
82 #include <ipc/ipc_space.h>
83 #include <ipc/ipc_object.h>
84 #include <ipc/ipc_port.h>
85 #include <ipc/ipc_pset.h>
86 #include <ipc/ipc_kmsg.h>
87 #include <ipc/ipc_mqueue.h>
88 #include <ipc/ipc_notify.h>
89 #include <ipc/ipc_table.h>
90 #include <ipc/ipc_importance.h>
92 #include <security/mac_mach_internal.h>
96 decl_lck_spin_data(, ipc_port_multiple_lock_data
)
97 ipc_port_timestamp_t ipc_port_timestamp_data
;
101 void ipc_port_init_debug(
103 uintptr_t *callstack
,
104 unsigned int callstack_max
);
106 void ipc_port_callstack_init_debug(
107 uintptr_t *callstack
,
108 unsigned int callstack_max
);
110 #endif /* MACH_ASSERT */
113 ipc_port_release(ipc_port_t port
)
119 ipc_port_reference(ipc_port_t port
)
125 * Routine: ipc_port_timestamp
127 * Retrieve a timestamp value.
131 ipc_port_timestamp(void)
133 return OSIncrementAtomic(&ipc_port_timestamp_data
);
137 * Routine: ipc_port_request_alloc
139 * Try to allocate a request slot.
140 * If successful, returns the request index.
141 * Otherwise returns zero.
143 * The port is locked and active.
145 * KERN_SUCCESS A request index was found.
146 * KERN_NO_SPACE No index allocated.
149 #if IMPORTANCE_INHERITANCE
151 ipc_port_request_alloc(
153 mach_port_name_t name
,
155 boolean_t send_possible
,
157 ipc_port_request_index_t
*indexp
,
158 boolean_t
*importantp
)
161 ipc_port_request_alloc(
163 mach_port_name_t name
,
165 boolean_t send_possible
,
167 ipc_port_request_index_t
*indexp
)
168 #endif /* IMPORTANCE_INHERITANCE */
170 ipc_port_request_t ipr
, table
;
171 ipc_port_request_index_t index
;
174 #if IMPORTANCE_INHERITANCE
176 #endif /* IMPORTANCE_INHERITANCE */
178 assert(ip_active(port
));
179 assert(name
!= MACH_PORT_NULL
);
180 assert(soright
!= IP_NULL
);
182 table
= port
->ip_requests
;
184 if (table
== IPR_NULL
)
185 return KERN_NO_SPACE
;
187 index
= table
->ipr_next
;
189 return KERN_NO_SPACE
;
192 assert(ipr
->ipr_name
== MACH_PORT_NULL
);
194 table
->ipr_next
= ipr
->ipr_next
;
195 ipr
->ipr_name
= name
;
198 mask
|= IPR_SOR_SPREQ_MASK
;
200 mask
|= IPR_SOR_SPARM_MASK
;
201 if (port
->ip_sprequests
== 0) {
202 port
->ip_sprequests
= 1;
203 #if IMPORTANCE_INHERITANCE
204 /* TODO: Live importance support in send-possible */
205 if (port
->ip_impdonation
!= 0 &&
206 port
->ip_spimportant
== 0 &&
207 (task_is_importance_donor(current_task()))) {
208 port
->ip_spimportant
= 1;
211 #endif /* IMPORTANCE_INHERTANCE */
215 ipr
->ipr_soright
= IPR_SOR_MAKE(soright
, mask
);
223 * Routine: ipc_port_request_grow
225 * Grow a port's table of requests.
227 * The port must be locked and active.
228 * Nothing else locked; will allocate memory.
229 * Upon return the port is unlocked.
231 * KERN_SUCCESS Grew the table.
232 * KERN_SUCCESS Somebody else grew the table.
233 * KERN_SUCCESS The port died.
234 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
235 * KERN_NO_SPACE Couldn't grow to desired size
239 ipc_port_request_grow(
241 ipc_table_elems_t target_size
)
243 ipc_table_size_t its
;
244 ipc_port_request_t otable
, ntable
;
246 assert(ip_active(port
));
248 otable
= port
->ip_requests
;
249 if (otable
== IPR_NULL
)
250 its
= &ipc_table_requests
[0];
252 its
= otable
->ipr_size
+ 1;
254 if (target_size
!= ITS_SIZE_NONE
) {
255 if ((otable
!= IPR_NULL
) &&
256 (target_size
<= otable
->ipr_size
->its_size
)) {
260 while ((its
->its_size
) && (its
->its_size
< target_size
)) {
263 if (its
->its_size
== 0) {
265 return KERN_NO_SPACE
;
272 if ((its
->its_size
== 0) ||
273 ((ntable
= it_requests_alloc(its
)) == IPR_NULL
)) {
275 return KERN_RESOURCE_SHORTAGE
;
281 * Check that port is still active and that nobody else
282 * has slipped in and grown the table on us. Note that
283 * just checking if the current table pointer == otable
284 * isn't sufficient; must check ipr_size.
287 if (ip_active(port
) && (port
->ip_requests
== otable
) &&
288 ((otable
== IPR_NULL
) || (otable
->ipr_size
+1 == its
))) {
289 ipc_table_size_t oits
;
290 ipc_table_elems_t osize
, nsize
;
291 ipc_port_request_index_t free
, i
;
293 /* copy old table to new table */
295 if (otable
!= IPR_NULL
) {
296 oits
= otable
->ipr_size
;
297 osize
= oits
->its_size
;
298 free
= otable
->ipr_next
;
300 (void) memcpy((void *)(ntable
+ 1),
301 (const void *)(otable
+ 1),
302 (osize
- 1) * sizeof(struct ipc_port_request
));
309 nsize
= its
->its_size
;
310 assert(nsize
> osize
);
312 /* add new elements to the new table's free list */
314 for (i
= osize
; i
< nsize
; i
++) {
315 ipc_port_request_t ipr
= &ntable
[i
];
317 ipr
->ipr_name
= MACH_PORT_NULL
;
318 ipr
->ipr_next
= free
;
322 ntable
->ipr_next
= free
;
323 ntable
->ipr_size
= its
;
324 port
->ip_requests
= ntable
;
328 if (otable
!= IPR_NULL
) {
329 it_requests_free(oits
, otable
);
334 it_requests_free(its
, ntable
);
341 * Routine: ipc_port_request_sparm
343 * Arm delayed send-possible request.
345 * The port must be locked and active.
347 * Returns TRUE if the request was armed
348 * (or armed with importance in that version).
351 #if IMPORTANCE_INHERITANCE
353 ipc_port_request_sparm(
355 __assert_only mach_port_name_t name
,
356 ipc_port_request_index_t index
,
357 mach_msg_option_t option
)
360 ipc_port_request_sparm(
362 __assert_only mach_port_name_t name
,
363 ipc_port_request_index_t index
)
364 #endif /* IMPORTANCE_INHERITANCE */
366 if (index
!= IE_REQ_NONE
) {
367 ipc_port_request_t ipr
, table
;
369 assert(ip_active(port
));
371 table
= port
->ip_requests
;
372 assert(table
!= IPR_NULL
);
375 assert(ipr
->ipr_name
== name
);
377 if (IPR_SOR_SPREQ(ipr
->ipr_soright
)) {
378 ipr
->ipr_soright
= IPR_SOR_MAKE(ipr
->ipr_soright
, IPR_SOR_SPARM_MASK
);
379 port
->ip_sprequests
= 1;
380 #if IMPORTANCE_INHERITANCE
381 if (((option
& MACH_SEND_NOIMPORTANCE
) == 0) &&
382 (port
->ip_impdonation
!= 0) &&
383 (port
->ip_spimportant
== 0) &&
384 (((option
& MACH_SEND_IMPORTANCE
) != 0) ||
385 (task_is_importance_donor(current_task())))) {
386 port
->ip_spimportant
= 1;
391 #endif /* IMPORTANCE_INHERITANCE */
398 * Routine: ipc_port_request_type
400 * Determine the type(s) of port requests enabled for a name.
402 * The port must be locked or inactive (to avoid table growth).
403 * The index must not be IE_REQ_NONE and for the name in question.
406 ipc_port_request_type(
408 __assert_only mach_port_name_t name
,
409 ipc_port_request_index_t index
)
411 ipc_port_request_t ipr
, table
;
412 mach_port_type_t type
= 0;
414 table
= port
->ip_requests
;
415 assert (table
!= IPR_NULL
);
417 assert(index
!= IE_REQ_NONE
);
419 assert(ipr
->ipr_name
== name
);
421 if (IP_VALID(IPR_SOR_PORT(ipr
->ipr_soright
))) {
422 type
|= MACH_PORT_TYPE_DNREQUEST
;
424 if (IPR_SOR_SPREQ(ipr
->ipr_soright
)) {
425 type
|= MACH_PORT_TYPE_SPREQUEST
;
427 if (!IPR_SOR_SPARMED(ipr
->ipr_soright
)) {
428 type
|= MACH_PORT_TYPE_SPREQUEST_DELAYED
;
436 * Routine: ipc_port_request_cancel
438 * Cancel a dead-name/send-possible request and return the send-once right.
440 * The port must be locked and active.
441 * The index must not be IPR_REQ_NONE and must correspond with name.
445 ipc_port_request_cancel(
447 __assert_only mach_port_name_t name
,
448 ipc_port_request_index_t index
)
450 ipc_port_request_t ipr
, table
;
451 ipc_port_t request
= IP_NULL
;
453 assert(ip_active(port
));
454 table
= port
->ip_requests
;
455 assert(table
!= IPR_NULL
);
457 assert (index
!= IE_REQ_NONE
);
459 assert(ipr
->ipr_name
== name
);
460 request
= IPR_SOR_PORT(ipr
->ipr_soright
);
462 /* return ipr to the free list inside the table */
463 ipr
->ipr_name
= MACH_PORT_NULL
;
464 ipr
->ipr_next
= table
->ipr_next
;
465 table
->ipr_next
= index
;
471 * Routine: ipc_port_pdrequest
473 * Make a port-deleted request, returning the
474 * previously registered send-once right.
475 * Just cancels the previous request if notify is IP_NULL.
477 * The port is locked and active. It is unlocked.
478 * Consumes a ref for notify (if non-null), and
479 * returns previous with a ref (if non-null).
486 ipc_port_t
*previousp
)
490 assert(ip_active(port
));
492 previous
= port
->ip_pdrequest
;
493 port
->ip_pdrequest
= notify
;
496 *previousp
= previous
;
500 * Routine: ipc_port_nsrequest
502 * Make a no-senders request, returning the
503 * previously registered send-once right.
504 * Just cancels the previous request if notify is IP_NULL.
506 * The port is locked and active. It is unlocked.
507 * Consumes a ref for notify (if non-null), and
508 * returns previous with a ref (if non-null).
514 mach_port_mscount_t sync
,
516 ipc_port_t
*previousp
)
519 mach_port_mscount_t mscount
;
521 assert(ip_active(port
));
523 previous
= port
->ip_nsrequest
;
524 mscount
= port
->ip_mscount
;
526 if ((port
->ip_srights
== 0) && (sync
<= mscount
) &&
527 (notify
!= IP_NULL
)) {
528 port
->ip_nsrequest
= IP_NULL
;
530 ipc_notify_no_senders(notify
, mscount
);
532 port
->ip_nsrequest
= notify
;
536 *previousp
= previous
;
541 * Routine: ipc_port_clear_receiver
543 * Prepares a receive right for transmission/destruction.
545 * The port is locked and active.
549 ipc_port_clear_receiver(
554 assert(ip_active(port
));
557 * pull ourselves from any sets.
559 if (port
->ip_in_pset
!= 0) {
560 ipc_pset_remove_from_all(port
);
561 assert(port
->ip_in_pset
== 0);
565 * Send anyone waiting on the port's queue directly away.
566 * Also clear the mscount and seqno.
569 imq_lock(&port
->ip_messages
);
570 ipc_mqueue_changed(&port
->ip_messages
);
571 ipc_port_set_mscount(port
, 0);
572 port
->ip_messages
.imq_seqno
= 0;
573 port
->ip_context
= port
->ip_guarded
= port
->ip_strict_guard
= 0;
574 imq_unlock(&port
->ip_messages
);
579 * Routine: ipc_port_init
581 * Initializes a newly-allocated port.
582 * Doesn't touch the ip_object fields.
589 mach_port_name_t name
)
591 /* port->ip_kobject doesn't have to be initialized */
593 port
->ip_receiver
= space
;
594 port
->ip_receiver_name
= name
;
596 port
->ip_mscount
= 0;
597 port
->ip_srights
= 0;
598 port
->ip_sorights
= 0;
600 port
->ip_nsrequest
= IP_NULL
;
601 port
->ip_pdrequest
= IP_NULL
;
602 port
->ip_requests
= IPR_NULL
;
604 port
->ip_premsg
= IKM_NULL
;
605 port
->ip_context
= 0;
607 port
->ip_sprequests
= 0;
608 port
->ip_spimportant
= 0;
609 port
->ip_impdonation
= 0;
610 port
->ip_tempowner
= 0;
612 port
->ip_guarded
= 0;
613 port
->ip_strict_guard
= 0;
614 port
->ip_impcount
= 0;
616 port
->ip_reserved
= 0;
618 ipc_mqueue_init(&port
->ip_messages
,
619 FALSE
/* !set */, NULL
/* no reserved link */);
623 * Routine: ipc_port_alloc
627 * Nothing locked. If successful, the port is returned
628 * locked. (The caller doesn't have a reference.)
630 * KERN_SUCCESS The port is allocated.
631 * KERN_INVALID_TASK The space is dead.
632 * KERN_NO_SPACE No room for an entry in the space.
633 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
639 mach_port_name_t
*namep
,
643 mach_port_name_t name
;
647 uintptr_t buf
[IP_CALLSTACK_MAX
];
648 ipc_port_callstack_init_debug(&buf
[0], IP_CALLSTACK_MAX
);
649 #endif /* MACH_ASSERT */
651 kr
= ipc_object_alloc(space
, IOT_PORT
,
652 MACH_PORT_TYPE_RECEIVE
, 0,
653 &name
, (ipc_object_t
*) &port
);
654 if (kr
!= KERN_SUCCESS
)
657 /* port and space are locked */
658 ipc_port_init(port
, space
, name
);
661 ipc_port_init_debug(port
, &buf
[0], IP_CALLSTACK_MAX
);
662 #endif /* MACH_ASSERT */
664 /* unlock space after init */
665 is_write_unlock(space
);
674 * Routine: ipc_port_alloc_name
676 * Allocate a port, with a specific name.
678 * Nothing locked. If successful, the port is returned
679 * locked. (The caller doesn't have a reference.)
681 * KERN_SUCCESS The port is allocated.
682 * KERN_INVALID_TASK The space is dead.
683 * KERN_NAME_EXISTS The name already denotes a right.
684 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
690 mach_port_name_t name
,
697 uintptr_t buf
[IP_CALLSTACK_MAX
];
698 ipc_port_callstack_init_debug(&buf
[0], IP_CALLSTACK_MAX
);
699 #endif /* MACH_ASSERT */
701 kr
= ipc_object_alloc_name(space
, IOT_PORT
,
702 MACH_PORT_TYPE_RECEIVE
, 0,
703 name
, (ipc_object_t
*) &port
);
704 if (kr
!= KERN_SUCCESS
)
709 ipc_port_init(port
, space
, name
);
712 ipc_port_init_debug(port
, &buf
[0], IP_CALLSTACK_MAX
);
713 #endif /* MACH_ASSERT */
721 * Routine: ipc_port_spnotify
723 * Generate send-possible port notifications.
725 * Nothing locked, reference held on port.
731 ipc_port_request_index_t index
= 0;
732 ipc_table_elems_t size
= 0;
733 #if IMPORTANCE_INHERITANCE
734 boolean_t dropassert
= FALSE
;
735 #endif /* IMPORTANCE_INHERITANCE */
738 * If the port has no send-possible request
739 * armed, don't bother to lock the port.
741 if (port
->ip_sprequests
== 0)
746 #if IMPORTANCE_INHERITANCE
747 if (port
->ip_spimportant
!= 0) {
748 port
->ip_spimportant
= 0;
749 if (ipc_port_impcount_delta(port
, -1, IP_NULL
) == -1) {
753 #endif /* IMPORTANCE_INHERITANCE */
755 if (port
->ip_sprequests
== 0) {
759 port
->ip_sprequests
= 0;
762 if (ip_active(port
)) {
763 ipc_port_request_t requests
;
765 /* table may change each time port unlocked (reload) */
766 requests
= port
->ip_requests
;
767 assert(requests
!= IPR_NULL
);
770 * no need to go beyond table size when first
771 * we entered - those are future notifications.
774 size
= requests
->ipr_size
->its_size
;
776 /* no need to backtrack either */
777 while (++index
< size
) {
778 ipc_port_request_t ipr
= &requests
[index
];
779 mach_port_name_t name
= ipr
->ipr_name
;
780 ipc_port_t soright
= IPR_SOR_PORT(ipr
->ipr_soright
);
781 boolean_t armed
= IPR_SOR_SPARMED(ipr
->ipr_soright
);
783 if (MACH_PORT_VALID(name
) && armed
&& IP_VALID(soright
)) {
784 /* claim send-once right - slot still inuse */
785 ipr
->ipr_soright
= IP_NULL
;
788 ipc_notify_send_possible(soright
, name
);
797 #if IMPORTANCE_INHERITANCE
798 if (dropassert
== TRUE
&& ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base
)) {
799 /* drop internal assertion */
800 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base
, 1);
802 #endif /* IMPORTANCE_INHERITANCE */
807 * Routine: ipc_port_dnnotify
809 * Generate dead name notifications for
810 * all outstanding dead-name and send-
814 * Port must be inactive.
815 * Reference held on port.
821 ipc_port_request_t requests
= port
->ip_requests
;
823 assert(!ip_active(port
));
824 if (requests
!= IPR_NULL
) {
825 ipc_table_size_t its
= requests
->ipr_size
;
826 ipc_table_elems_t size
= its
->its_size
;
827 ipc_port_request_index_t index
;
828 for (index
= 1; index
< size
; index
++) {
829 ipc_port_request_t ipr
= &requests
[index
];
830 mach_port_name_t name
= ipr
->ipr_name
;
831 ipc_port_t soright
= IPR_SOR_PORT(ipr
->ipr_soright
);
833 if (MACH_PORT_VALID(name
) && IP_VALID(soright
)) {
834 ipc_notify_dead_name(soright
, name
);
842 * Routine: ipc_port_destroy
844 * Destroys a port. Cleans up queued messages.
846 * If the port has a backup, it doesn't get destroyed,
847 * but is sent in a port-destroyed notification to the backup.
849 * The port is locked and alive; nothing else locked.
850 * The caller has a reference, which is consumed.
851 * Afterwards, the port is unlocked and dead.
858 ipc_port_t pdrequest
, nsrequest
;
862 #if IMPORTANCE_INHERITANCE
863 ipc_importance_task_t release_imp_task
= IIT_NULL
;
864 thread_t self
= current_thread();
865 boolean_t top
= (self
->ith_assertions
== 0);
866 natural_t assertcnt
= 0;
867 #endif /* IMPORTANCE_INHERITANCE */
869 assert(ip_active(port
));
870 /* port->ip_receiver_name is garbage */
871 /* port->ip_receiver/port->ip_destination is garbage */
872 assert(port
->ip_in_pset
== 0);
873 assert(port
->ip_mscount
== 0);
875 /* check for a backup port */
876 pdrequest
= port
->ip_pdrequest
;
878 #if IMPORTANCE_INHERITANCE
879 /* determine how many assertions to drop and from whom */
880 if (port
->ip_tempowner
!= 0) {
882 release_imp_task
= port
->ip_imp_task
;
883 if (IIT_NULL
!= release_imp_task
) {
884 port
->ip_imp_task
= IIT_NULL
;
885 assertcnt
= port
->ip_impcount
;
887 /* Otherwise, nothing to drop */
889 assertcnt
= port
->ip_impcount
;
890 if (pdrequest
!= IP_NULL
)
891 /* mark in limbo for the journey */
892 port
->ip_tempowner
= 1;
896 self
->ith_assertions
= assertcnt
;
897 #endif /* IMPORTANCE_INHERITANCE */
899 if (pdrequest
!= IP_NULL
) {
900 /* we assume the ref for pdrequest */
901 port
->ip_pdrequest
= IP_NULL
;
903 /* make port be in limbo */
904 port
->ip_receiver_name
= MACH_PORT_NULL
;
905 port
->ip_destination
= IP_NULL
;
908 /* consumes our refs for port and pdrequest */
909 ipc_notify_port_destroyed(pdrequest
, port
);
911 goto drop_assertions
;
914 /* once port is dead, we don't need to keep it locked */
916 port
->ip_object
.io_bits
&= ~IO_BITS_ACTIVE
;
917 port
->ip_timestamp
= ipc_port_timestamp();
918 nsrequest
= port
->ip_nsrequest
;
921 * If the port has a preallocated message buffer and that buffer
922 * is not inuse, free it. If it has an inuse one, then the kmsg
923 * free will detect that we freed the association and it can free it
924 * like a normal buffer.
926 if (IP_PREALLOC(port
)) {
927 ipc_port_t inuse_port
;
929 kmsg
= port
->ip_premsg
;
930 assert(kmsg
!= IKM_NULL
);
931 inuse_port
= ikm_prealloc_inuse_port(kmsg
);
932 IP_CLEAR_PREALLOC(port
, kmsg
);
934 if (inuse_port
!= IP_NULL
) {
935 assert(inuse_port
== port
);
943 /* throw away no-senders request */
944 if (nsrequest
!= IP_NULL
)
945 ipc_notify_send_once(nsrequest
); /* consumes ref */
947 /* destroy any queued messages */
948 mqueue
= &port
->ip_messages
;
949 ipc_mqueue_destroy(mqueue
);
951 /* cleanup waitq related resources */
952 ipc_mqueue_deinit(mqueue
);
954 /* generate dead-name notifications */
955 ipc_port_dnnotify(port
);
957 ipc_kobject_destroy(port
);
959 ip_release(port
); /* consume caller's ref */
962 #if IMPORTANCE_INHERITANCE
963 if (release_imp_task
!= IIT_NULL
) {
966 self
->ith_assertions
= 0;
967 assert(ipc_importance_task_is_any_receiver_type(release_imp_task
));
968 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
970 ipc_importance_task_release(release_imp_task
);
972 } else if (assertcnt
> 0) {
974 self
->ith_assertions
= 0;
975 release_imp_task
= current_task()->task_imp_base
;
976 if (ipc_importance_task_is_any_receiver_type(release_imp_task
)) {
977 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
981 #endif /* IMPORTANCE_INHERITANCE */
985 * Routine: ipc_port_check_circularity
987 * Check if queueing "port" in a message for "dest"
988 * would create a circular group of ports and messages.
990 * If no circularity (FALSE returned), then "port"
991 * is changed from "in limbo" to "in transit".
993 * That is, we want to set port->ip_destination == dest,
994 * but guaranteeing that this doesn't create a circle
995 * port->ip_destination->ip_destination->... == port
997 * Additionally, if port was successfully changed to "in transit",
998 * propagate boost assertions from the "in limbo" port to all
999 * the ports in the chain, and, if the destination task accepts
1000 * boosts, to the destination task.
1003 * No ports locked. References held for "port" and "dest".
1007 ipc_port_check_circularity(
1013 #if IMPORTANCE_INHERITANCE
1014 ipc_importance_task_t imp_task
= IIT_NULL
;
1015 ipc_importance_task_t release_imp_task
= IIT_NULL
;
1017 #endif /* IMPORTANCE_INHERITANCE */
1019 assert(port
!= IP_NULL
);
1020 assert(dest
!= IP_NULL
);
1027 * First try a quick check that can run in parallel.
1028 * No circularity if dest is not in transit.
1032 if (ip_lock_try(dest
)) {
1033 if (!ip_active(dest
) ||
1034 (dest
->ip_receiver_name
!= MACH_PORT_NULL
) ||
1035 (dest
->ip_destination
== IP_NULL
))
1038 /* dest is in transit; further checking necessary */
1044 ipc_port_multiple_lock(); /* massive serialization */
1047 * Search for the end of the chain (a port not in transit),
1048 * acquiring locks along the way.
1054 if (!ip_active(base
) ||
1055 (base
->ip_receiver_name
!= MACH_PORT_NULL
) ||
1056 (base
->ip_destination
== IP_NULL
))
1059 base
= base
->ip_destination
;
1062 /* all ports in chain from dest to base, inclusive, are locked */
1065 /* circularity detected! */
1067 ipc_port_multiple_unlock();
1069 /* port (== base) is in limbo */
1071 assert(ip_active(port
));
1072 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
1073 assert(port
->ip_destination
== IP_NULL
);
1075 while (dest
!= IP_NULL
) {
1078 /* dest is in transit or in limbo */
1080 assert(ip_active(dest
));
1081 assert(dest
->ip_receiver_name
== MACH_PORT_NULL
);
1083 next
= dest
->ip_destination
;
1092 * The guarantee: lock port while the entire chain is locked.
1093 * Once port is locked, we can take a reference to dest,
1094 * add port to the chain, and unlock everything.
1098 ipc_port_multiple_unlock();
1102 /* port is in limbo */
1104 assert(ip_active(port
));
1105 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
1106 assert(port
->ip_destination
== IP_NULL
);
1109 port
->ip_destination
= dest
;
1111 #if IMPORTANCE_INHERITANCE
1112 /* must have been in limbo or still bound to a task */
1113 assert(port
->ip_tempowner
!= 0);
1116 * We delayed dropping assertions from a specific task.
1117 * Cache that info now (we'll drop assertions and the
1118 * task reference below).
1120 release_imp_task
= port
->ip_imp_task
;
1121 if (IIT_NULL
!= release_imp_task
) {
1122 port
->ip_imp_task
= IIT_NULL
;
1124 assertcnt
= port
->ip_impcount
;
1126 /* take the port out of limbo w.r.t. assertions */
1127 port
->ip_tempowner
= 0;
1129 #endif /* IMPORTANCE_INHERITANCE */
1131 /* now unlock chain */
1137 #if IMPORTANCE_INHERITANCE
1138 /* every port along chain track assertions behind it */
1139 dest
->ip_impcount
+= assertcnt
;
1140 #endif /* IMPORTANCE_INHERITANCE */
1145 /* port is in transit */
1147 assert(ip_active(dest
));
1148 assert(dest
->ip_receiver_name
== MACH_PORT_NULL
);
1149 assert(dest
->ip_destination
!= IP_NULL
);
1151 #if IMPORTANCE_INHERITANCE
1152 assert(dest
->ip_tempowner
== 0);
1153 #endif /* IMPORTANCE_INHERITANCE */
1155 port
= dest
->ip_destination
;
1160 /* base is not in transit */
1161 assert(!ip_active(base
) ||
1162 (base
->ip_receiver_name
!= MACH_PORT_NULL
) ||
1163 (base
->ip_destination
== IP_NULL
));
1165 #if IMPORTANCE_INHERITANCE
1167 * Find the task to boost (if any).
1168 * We will boost "through" ports that don't know
1169 * about inheritance to deliver receive rights that
1172 if (ip_active(base
) && (assertcnt
> 0)) {
1173 if (base
->ip_tempowner
!= 0) {
1174 if (IIT_NULL
!= base
->ip_imp_task
) {
1175 /* specified tempowner task */
1176 imp_task
= base
->ip_imp_task
;
1177 assert(ipc_importance_task_is_any_receiver_type(imp_task
));
1179 /* otherwise don't boost current task */
1181 } else if (base
->ip_receiver_name
!= MACH_PORT_NULL
) {
1182 ipc_space_t space
= base
->ip_receiver
;
1184 /* only spaces with boost-accepting tasks */
1185 if (space
->is_task
!= TASK_NULL
&&
1186 ipc_importance_task_is_any_receiver_type(space
->is_task
->task_imp_base
))
1187 imp_task
= space
->is_task
->task_imp_base
;
1190 /* take reference before unlocking base */
1191 if (imp_task
!= IIT_NULL
) {
1192 ipc_importance_task_reference(imp_task
);
1195 #endif /* IMPORTANCE_INHERITANCE */
1199 #if IMPORTANCE_INHERITANCE
1201 * Transfer assertions now that the ports are unlocked.
1202 * Avoid extra overhead if transferring to/from the same task.
1204 boolean_t transfer_assertions
= (imp_task
!= release_imp_task
) ? TRUE
: FALSE
;
1206 if (imp_task
!= IIT_NULL
) {
1207 if (transfer_assertions
)
1208 ipc_importance_task_hold_internal_assertion(imp_task
, assertcnt
);
1209 ipc_importance_task_release(imp_task
);
1210 imp_task
= IIT_NULL
;
1213 if (release_imp_task
!= IIT_NULL
) {
1214 if (transfer_assertions
)
1215 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
1216 ipc_importance_task_release(release_imp_task
);
1217 release_imp_task
= IIT_NULL
;
1219 #endif /* IMPORTANCE_INHERITANCE */
1225 * Routine: ipc_port_impcount_delta
1227 * Adjust only the importance count associated with a port.
1228 * If there are any adjustments to be made to receiver task,
1229 * those are handled elsewhere.
1231 * For now, be defensive during deductions to make sure the
1232 * impcount for the port doesn't underflow zero. This will
1233 * go away when the port boost addition is made atomic (see
1234 * note in ipc_port_importance_delta()).
1236 * The port is referenced and locked.
1237 * Nothing else is locked.
1240 ipc_port_impcount_delta(
1242 mach_port_delta_t delta
,
1243 ipc_port_t __unused base
)
1245 mach_port_delta_t absdelta
;
1247 if (!ip_active(port
)) {
1251 /* adding/doing nothing is easy */
1253 port
->ip_impcount
+= delta
;
1257 absdelta
= 0 - delta
;
1258 //assert(port->ip_impcount >= absdelta);
1259 /* if we have enough to deduct, we're done */
1260 if (port
->ip_impcount
>= absdelta
) {
1261 port
->ip_impcount
-= absdelta
;
1265 #if DEVELOPMENT || DEBUG
1266 if (port
->ip_receiver_name
!= MACH_PORT_NULL
) {
1267 task_t target_task
= port
->ip_receiver
->is_task
;
1268 ipc_importance_task_t target_imp
= target_task
->task_imp_base
;
1269 const char *target_procname
;
1272 if (target_imp
!= IIT_NULL
) {
1273 target_procname
= target_imp
->iit_procname
;
1274 target_pid
= target_imp
->iit_bsd_pid
;
1276 target_procname
= "unknown";
1279 printf("Over-release of importance assertions for port 0x%x receiver pid %d (%s), "
1280 "dropping %d assertion(s) but port only has %d remaining.\n",
1281 port
->ip_receiver_name
,
1282 target_imp
->iit_bsd_pid
, target_imp
->iit_procname
,
1283 absdelta
, port
->ip_impcount
);
1285 } else if (base
!= IP_NULL
) {
1286 task_t target_task
= base
->ip_receiver
->is_task
;
1287 ipc_importance_task_t target_imp
= target_task
->task_imp_base
;
1288 const char *target_procname
;
1291 if (target_imp
!= IIT_NULL
) {
1292 target_procname
= target_imp
->iit_procname
;
1293 target_pid
= target_imp
->iit_bsd_pid
;
1295 target_procname
= "unknown";
1298 printf("Over-release of importance assertions for port %p "
1299 "enqueued on port 0x%x with receiver pid %d (%s), "
1300 "dropping %d assertion(s) but port only has %d remaining.\n",
1301 port
, base
->ip_receiver_name
,
1302 target_imp
->iit_bsd_pid
, target_imp
->iit_procname
,
1303 absdelta
, port
->ip_impcount
);
1306 delta
= 0 - port
->ip_impcount
;
1307 port
->ip_impcount
= 0;
1312 * Routine: ipc_port_importance_delta_internal
1314 * Adjust the importance count through the given port.
1315 * If the port is in transit, apply the delta throughout
1316 * the chain. Determine if the there is a task at the
1317 * base of the chain that wants/needs to be adjusted,
1318 * and if so, apply the delta.
1320 * The port is referenced and locked on entry.
1321 * Nothing else is locked.
1322 * The lock may be dropped on exit.
1323 * Returns TRUE if lock was dropped.
1325 #if IMPORTANCE_INHERITANCE
1328 ipc_port_importance_delta_internal(
1330 mach_port_delta_t
*deltap
,
1331 ipc_importance_task_t
*imp_task
)
1333 ipc_port_t next
, base
;
1334 boolean_t dropped
= FALSE
;
1336 *imp_task
= IIT_NULL
;
1343 /* if port is in transit, have to search for end of chain */
1344 if (ip_active(port
) &&
1345 port
->ip_destination
!= IP_NULL
&&
1346 port
->ip_receiver_name
== MACH_PORT_NULL
) {
1351 ipc_port_multiple_lock(); /* massive serialization */
1354 while(ip_active(base
) &&
1355 base
->ip_destination
!= IP_NULL
&&
1356 base
->ip_receiver_name
== MACH_PORT_NULL
) {
1358 base
= base
->ip_destination
;
1361 ipc_port_multiple_unlock();
1364 /* unlock down to the base, adding a boost at each level */
1367 * JMM TODO - because of the port unlock to grab the multiple lock
1368 * above, a subsequent drop of importance could race and beat
1369 * the "previous" increase - causing the port impcount to go
1370 * negative briefly. The defensive deduction performed by
1371 * ipc_port_impcount_delta() defeats that, and therefore can
1372 * cause an importance leak once the increase finally arrives.
1374 * Need to rework the importance delta logic to be more like
1375 * ipc_importance_inherit_from() where it locks all it needs in
1376 * one pass to avoid any lock drops - to keep that race from
1379 *deltap
= ipc_port_impcount_delta(port
, *deltap
, base
);
1385 /* port is in transit */
1386 assert(port
->ip_tempowner
== 0);
1387 next
= port
->ip_destination
;
1392 /* find the task (if any) to boost according to the base */
1393 if (ip_active(base
)) {
1394 if (base
->ip_tempowner
!= 0) {
1395 if (IIT_NULL
!= base
->ip_imp_task
)
1396 *imp_task
= base
->ip_imp_task
;
1397 /* otherwise don't boost */
1399 } else if (base
->ip_receiver_name
!= MACH_PORT_NULL
) {
1400 ipc_space_t space
= base
->ip_receiver
;
1402 /* only spaces with boost-accepting tasks */
1403 if (space
->is_task
!= TASK_NULL
&&
1404 ipc_importance_task_is_any_receiver_type(space
->is_task
->task_imp_base
)) {
1405 *imp_task
= space
->is_task
->task_imp_base
;
1411 * Only the base is locked. If we have to hold or drop task
1412 * importance assertions, we'll have to drop that lock as well.
1414 if (*imp_task
!= IIT_NULL
) {
1415 /* take a reference before unlocking base */
1416 ipc_importance_task_reference(*imp_task
);
1419 if (dropped
== TRUE
) {
1425 #endif /* IMPORTANCE_INHERITANCE */
1428 * Routine: ipc_port_importance_delta
1430 * Adjust the importance count through the given port.
1431 * If the port is in transit, apply the delta throughout
1434 * If there is a task at the base of the chain that wants/needs
1435 * to be adjusted, apply the delta.
1437 * The port is referenced and locked on entry.
1438 * Nothing else is locked.
1439 * The lock may be dropped on exit.
1440 * Returns TRUE if lock was dropped.
1442 #if IMPORTANCE_INHERITANCE
1445 ipc_port_importance_delta(
1447 mach_port_delta_t delta
)
1449 ipc_importance_task_t imp_task
= IIT_NULL
;
1452 dropped
= ipc_port_importance_delta_internal(port
, &delta
, &imp_task
);
1454 if (IIT_NULL
== imp_task
)
1462 assert(ipc_importance_task_is_any_receiver_type(imp_task
));
1465 ipc_importance_task_hold_internal_assertion(imp_task
, delta
);
1467 ipc_importance_task_drop_internal_assertion(imp_task
, -delta
);
1469 ipc_importance_task_release(imp_task
);
1472 #endif /* IMPORTANCE_INHERITANCE */
1475 * Routine: ipc_port_lookup_notify
1477 * Make a send-once notify port from a receive right.
1478 * Returns IP_NULL if name doesn't denote a receive right.
1480 * The space must be locked (read or write) and active.
1481 * Being the active space, we can rely on thread server_id
1482 * context to give us the proper server level sub-order
1487 ipc_port_lookup_notify(
1489 mach_port_name_t name
)
1494 assert(is_active(space
));
1496 entry
= ipc_entry_lookup(space
, name
);
1497 if (entry
== IE_NULL
)
1499 if ((entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1502 __IGNORE_WCASTALIGN(port
= (ipc_port_t
) entry
->ie_object
);
1503 assert(port
!= IP_NULL
);
1506 assert(ip_active(port
));
1507 assert(port
->ip_receiver_name
== name
);
1508 assert(port
->ip_receiver
== space
);
1511 port
->ip_sorights
++;
1518 * Routine: ipc_port_make_send_locked
1520 * Make a naked send right from a receive right.
1523 * port locked and active.
1526 ipc_port_make_send_locked(
1529 assert(ip_active(port
));
1537 * Routine: ipc_port_make_send
1539 * Make a naked send right from a receive right.
1547 if (!IP_VALID(port
))
1551 if (ip_active(port
)) {
1563 * Routine: ipc_port_copy_send
1565 * Make a naked send right from another naked send right.
1566 * IP_NULL -> IP_NULL
1567 * IP_DEAD -> IP_DEAD
1568 * dead port -> IP_DEAD
1569 * live port -> port + ref
1571 * Nothing locked except possibly a space.
1580 if (!IP_VALID(port
))
1584 if (ip_active(port
)) {
1585 assert(port
->ip_srights
> 0);
1598 * Routine: ipc_port_copyout_send
1600 * Copyout a naked send right (possibly null/dead),
1601 * or if that fails, destroy the right.
1607 ipc_port_copyout_send(
1611 mach_port_name_t name
;
1613 if (IP_VALID(sright
)) {
1616 kr
= ipc_object_copyout(space
, (ipc_object_t
) sright
,
1617 MACH_MSG_TYPE_PORT_SEND
, TRUE
, &name
);
1618 if (kr
!= KERN_SUCCESS
) {
1619 ipc_port_release_send(sright
);
1621 if (kr
== KERN_INVALID_CAPABILITY
)
1622 name
= MACH_PORT_DEAD
;
1624 name
= MACH_PORT_NULL
;
1627 name
= CAST_MACH_PORT_TO_NAME(sright
);
1633 * Routine: ipc_port_release_send
1635 * Release a naked send right.
1636 * Consumes a ref for the port.
1642 ipc_port_release_send(
1645 ipc_port_t nsrequest
= IP_NULL
;
1646 mach_port_mscount_t mscount
;
1648 if (!IP_VALID(port
))
1653 assert(port
->ip_srights
> 0);
1656 if (!ip_active(port
)) {
1662 if (port
->ip_srights
== 0 &&
1663 port
->ip_nsrequest
!= IP_NULL
) {
1664 nsrequest
= port
->ip_nsrequest
;
1665 port
->ip_nsrequest
= IP_NULL
;
1666 mscount
= port
->ip_mscount
;
1669 ipc_notify_no_senders(nsrequest
, mscount
);
1677 * Routine: ipc_port_make_sonce_locked
1679 * Make a naked send-once right from a receive right.
1681 * The port is locked and active.
1685 ipc_port_make_sonce_locked(
1688 assert(ip_active(port
));
1689 port
->ip_sorights
++;
1695 * Routine: ipc_port_make_sonce
1697 * Make a naked send-once right from a receive right.
1699 * The port is not locked.
1703 ipc_port_make_sonce(
1706 if (!IP_VALID(port
))
1710 if (ip_active(port
)) {
1711 port
->ip_sorights
++;
1721 * Routine: ipc_port_release_sonce
1723 * Release a naked send-once right.
1724 * Consumes a ref for the port.
1726 * In normal situations, this is never used.
1727 * Send-once rights are only consumed when
1728 * a message (possibly a send-once notification)
1731 * Nothing locked except possibly a space.
1735 ipc_port_release_sonce(
1738 if (!IP_VALID(port
))
1743 assert(port
->ip_sorights
> 0);
1745 port
->ip_sorights
--;
1752 * Routine: ipc_port_release_receive
1754 * Release a naked (in limbo or in transit) receive right.
1755 * Consumes a ref for the port; destroys the port.
1761 ipc_port_release_receive(
1766 if (!IP_VALID(port
))
1770 assert(ip_active(port
));
1771 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
1772 dest
= port
->ip_destination
;
1774 ipc_port_destroy(port
); /* consumes ref, unlocks */
1776 if (dest
!= IP_NULL
)
1781 * Routine: ipc_port_alloc_special
1783 * Allocate a port in a special space.
1784 * The new port is returned with one ref.
1785 * If unsuccessful, IP_NULL is returned.
1791 ipc_port_alloc_special(
1796 __IGNORE_WCASTALIGN(port
= (ipc_port_t
) io_alloc(IOT_PORT
));
1797 if (port
== IP_NULL
)
1801 uintptr_t buf
[IP_CALLSTACK_MAX
];
1802 ipc_port_callstack_init_debug(&buf
[0], IP_CALLSTACK_MAX
);
1803 #endif /* MACH_ASSERT */
1805 bzero((char *)port
, sizeof(*port
));
1806 io_lock_init(&port
->ip_object
);
1807 port
->ip_references
= 1;
1808 port
->ip_object
.io_bits
= io_makebits(TRUE
, IOT_PORT
, 0);
1810 ipc_port_init(port
, space
, 1);
1813 ipc_port_init_debug(port
, &buf
[0], IP_CALLSTACK_MAX
);
1814 #endif /* MACH_ASSERT */
1820 * Routine: ipc_port_dealloc_special
1822 * Deallocate a port in a special space.
1823 * Consumes one ref for the port.
1829 ipc_port_dealloc_special(
1831 __assert_only ipc_space_t space
)
1834 assert(ip_active(port
));
1835 // assert(port->ip_receiver_name != MACH_PORT_NULL);
1836 assert(port
->ip_receiver
== space
);
1839 * We clear ip_receiver_name and ip_receiver to simplify
1840 * the ipc_space_kernel check in ipc_mqueue_send.
1843 port
->ip_receiver_name
= MACH_PORT_NULL
;
1844 port
->ip_receiver
= IS_NULL
;
1846 /* relevant part of ipc_port_clear_receiver */
1847 ipc_port_set_mscount(port
, 0);
1848 port
->ip_messages
.imq_seqno
= 0;
1850 ipc_port_destroy(port
);
1854 * Routine: ipc_port_finalize
1856 * Called on last reference deallocate to
1857 * free any remaining data associated with the
1866 ipc_port_request_t requests
= port
->ip_requests
;
1868 assert(!ip_active(port
));
1869 if (requests
!= IPR_NULL
) {
1870 ipc_table_size_t its
= requests
->ipr_size
;
1871 it_requests_free(its
, requests
);
1872 port
->ip_requests
= IPR_NULL
;
1875 ipc_mqueue_deinit(&port
->ip_messages
);
1878 ipc_port_track_dealloc(port
);
1879 #endif /* MACH_ASSERT */
1883 #include <kern/machine.h>
1886 * Keep a list of all allocated ports.
1887 * Allocation is intercepted via ipc_port_init;
1888 * deallocation is intercepted via io_free.
1891 queue_head_t port_alloc_queue
;
1892 lck_spin_t port_alloc_queue_lock
;
1895 unsigned long port_count
= 0;
1896 unsigned long port_count_warning
= 20000;
1897 unsigned long port_timestamp
= 0;
1899 void db_port_stack_trace(
1904 unsigned int verbose
,
1905 unsigned int display
,
1906 unsigned int ref_search
,
1907 unsigned int ref_target
);
1910 * Initialize global state needed for run-time
1914 ipc_port_debug_init(void)
1917 queue_init(&port_alloc_queue
);
1918 lck_spin_init(&port_alloc_queue_lock
, &ipc_lck_grp
, &ipc_lck_attr
);
1921 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt
, sizeof (ipc_portbt
)))
1926 extern int proc_pid(struct proc
*);
1927 #endif /* MACH_BSD */
1930 * Initialize all of the debugging state in a port.
1931 * Insert the port into a global list of all allocated ports.
1934 ipc_port_init_debug(
1936 uintptr_t *callstack
,
1937 unsigned int callstack_max
)
1941 port
->ip_thread
= current_thread();
1942 port
->ip_timetrack
= port_timestamp
++;
1943 for (i
= 0; i
< callstack_max
; ++i
)
1944 port
->ip_callstack
[i
] = callstack
[i
];
1945 for (i
= 0; i
< IP_NSPARES
; ++i
)
1946 port
->ip_spares
[i
] = 0;
1949 task_t task
= current_task();
1950 if (task
!= TASK_NULL
) {
1951 struct proc
* proc
= (struct proc
*) get_bsdtask_info(task
);
1953 port
->ip_spares
[0] = proc_pid(proc
);
1955 #endif /* MACH_BSD */
1958 lck_spin_lock(&port_alloc_queue_lock
);
1960 if (port_count_warning
> 0 && port_count
>= port_count_warning
)
1961 assert(port_count
< port_count_warning
);
1962 queue_enter(&port_alloc_queue
, port
, ipc_port_t
, ip_port_links
);
1963 lck_spin_unlock(&port_alloc_queue_lock
);
1968 * Routine: ipc_port_callstack_init_debug
1970 * Calls the machine-dependent routine to
1971 * fill in an array with up to IP_CALLSTACK_MAX
1972 * levels of return pc information
1974 * May block (via copyin)
1977 ipc_port_callstack_init_debug(
1978 uintptr_t *callstack
,
1979 unsigned int callstack_max
)
1983 /* guarantee the callstack is initialized */
1984 for (i
=0; i
< callstack_max
; i
++)
1988 machine_callstack(callstack
, callstack_max
);
1992 * Remove a port from the queue of allocated ports.
1993 * This routine should be invoked JUST prior to
1994 * deallocating the actual memory occupied by the port.
1998 ipc_port_track_dealloc(
1999 __unused ipc_port_t port
)
2004 ipc_port_track_dealloc(
2007 lck_spin_lock(&port_alloc_queue_lock
);
2008 assert(port_count
> 0);
2010 queue_remove(&port_alloc_queue
, port
, ipc_port_t
, ip_port_links
);
2011 lck_spin_unlock(&port_alloc_queue_lock
);
2016 #endif /* MACH_ASSERT */