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/wait_queue.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(
555 assert(ip_active(port
));
558 * pull ourselves from any sets.
560 if (port
->ip_pset_count
!= 0) {
561 ipc_pset_remove_from_all(port
, links
);
562 assert(port
->ip_pset_count
== 0);
566 * Send anyone waiting on the port's queue directly away.
567 * Also clear the mscount and seqno.
570 imq_lock(&port
->ip_messages
);
571 ipc_mqueue_changed(&port
->ip_messages
);
572 ipc_port_set_mscount(port
, 0);
573 port
->ip_messages
.imq_seqno
= 0;
574 port
->ip_context
= port
->ip_guarded
= port
->ip_strict_guard
= 0;
575 imq_unlock(&port
->ip_messages
);
580 * Routine: ipc_port_init
582 * Initializes a newly-allocated port.
583 * Doesn't touch the ip_object fields.
590 mach_port_name_t name
)
592 /* port->ip_kobject doesn't have to be initialized */
594 port
->ip_receiver
= space
;
595 port
->ip_receiver_name
= name
;
597 port
->ip_mscount
= 0;
598 port
->ip_srights
= 0;
599 port
->ip_sorights
= 0;
601 port
->ip_nsrequest
= IP_NULL
;
602 port
->ip_pdrequest
= IP_NULL
;
603 port
->ip_requests
= IPR_NULL
;
605 port
->ip_pset_count
= 0;
606 port
->ip_premsg
= IKM_NULL
;
607 port
->ip_context
= 0;
609 port
->ip_sprequests
= 0;
610 port
->ip_spimportant
= 0;
611 port
->ip_impdonation
= 0;
612 port
->ip_tempowner
= 0;
614 port
->ip_guarded
= 0;
615 port
->ip_strict_guard
= 0;
616 port
->ip_impcount
= 0;
618 port
->ip_reserved
= 0;
620 ipc_mqueue_init(&port
->ip_messages
, FALSE
/* set */);
624 * Routine: ipc_port_alloc
628 * Nothing locked. If successful, the port is returned
629 * locked. (The caller doesn't have a reference.)
631 * KERN_SUCCESS The port is allocated.
632 * KERN_INVALID_TASK The space is dead.
633 * KERN_NO_SPACE No room for an entry in the space.
634 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
640 mach_port_name_t
*namep
,
644 mach_port_name_t name
;
648 uintptr_t buf
[IP_CALLSTACK_MAX
];
649 ipc_port_callstack_init_debug(&buf
[0], IP_CALLSTACK_MAX
);
650 #endif /* MACH_ASSERT */
652 kr
= ipc_object_alloc(space
, IOT_PORT
,
653 MACH_PORT_TYPE_RECEIVE
, 0,
654 &name
, (ipc_object_t
*) &port
);
655 if (kr
!= KERN_SUCCESS
)
658 /* port and space are locked */
659 ipc_port_init(port
, space
, name
);
662 ipc_port_init_debug(port
, &buf
[0], IP_CALLSTACK_MAX
);
663 #endif /* MACH_ASSERT */
665 /* unlock space after init */
666 is_write_unlock(space
);
675 * Routine: ipc_port_alloc_name
677 * Allocate a port, with a specific name.
679 * Nothing locked. If successful, the port is returned
680 * locked. (The caller doesn't have a reference.)
682 * KERN_SUCCESS The port is allocated.
683 * KERN_INVALID_TASK The space is dead.
684 * KERN_NAME_EXISTS The name already denotes a right.
685 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
691 mach_port_name_t name
,
698 uintptr_t buf
[IP_CALLSTACK_MAX
];
699 ipc_port_callstack_init_debug(&buf
[0], IP_CALLSTACK_MAX
);
700 #endif /* MACH_ASSERT */
702 kr
= ipc_object_alloc_name(space
, IOT_PORT
,
703 MACH_PORT_TYPE_RECEIVE
, 0,
704 name
, (ipc_object_t
*) &port
);
705 if (kr
!= KERN_SUCCESS
)
710 ipc_port_init(port
, space
, name
);
713 ipc_port_init_debug(port
, &buf
[0], IP_CALLSTACK_MAX
);
714 #endif /* MACH_ASSERT */
722 * Routine: ipc_port_spnotify
724 * Generate send-possible port notifications.
726 * Nothing locked, reference held on port.
732 ipc_port_request_index_t index
= 0;
733 ipc_table_elems_t size
= 0;
734 #if IMPORTANCE_INHERITANCE
735 boolean_t dropassert
= FALSE
;
736 #endif /* IMPORTANCE_INHERITANCE */
739 * If the port has no send-possible request
740 * armed, don't bother to lock the port.
742 if (port
->ip_sprequests
== 0)
747 #if IMPORTANCE_INHERITANCE
748 if (port
->ip_spimportant
!= 0) {
749 port
->ip_spimportant
= 0;
750 if (ipc_port_impcount_delta(port
, -1, IP_NULL
) == -1) {
754 #endif /* IMPORTANCE_INHERITANCE */
756 if (port
->ip_sprequests
== 0) {
760 port
->ip_sprequests
= 0;
763 if (ip_active(port
)) {
764 ipc_port_request_t requests
;
766 /* table may change each time port unlocked (reload) */
767 requests
= port
->ip_requests
;
768 assert(requests
!= IPR_NULL
);
771 * no need to go beyond table size when first
772 * we entered - those are future notifications.
775 size
= requests
->ipr_size
->its_size
;
777 /* no need to backtrack either */
778 while (++index
< size
) {
779 ipc_port_request_t ipr
= &requests
[index
];
780 mach_port_name_t name
= ipr
->ipr_name
;
781 ipc_port_t soright
= IPR_SOR_PORT(ipr
->ipr_soright
);
782 boolean_t armed
= IPR_SOR_SPARMED(ipr
->ipr_soright
);
784 if (MACH_PORT_VALID(name
) && armed
&& IP_VALID(soright
)) {
785 /* claim send-once right - slot still inuse */
786 ipr
->ipr_soright
= IP_NULL
;
789 ipc_notify_send_possible(soright
, name
);
798 #if IMPORTANCE_INHERITANCE
799 if (dropassert
== TRUE
&& ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base
)) {
800 /* drop internal assertion */
801 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base
, 1);
803 #endif /* IMPORTANCE_INHERITANCE */
808 * Routine: ipc_port_dnnotify
810 * Generate dead name notifications for
811 * all outstanding dead-name and send-
815 * Port must be inactive.
816 * Reference held on port.
822 ipc_port_request_t requests
= port
->ip_requests
;
824 assert(!ip_active(port
));
825 if (requests
!= IPR_NULL
) {
826 ipc_table_size_t its
= requests
->ipr_size
;
827 ipc_table_elems_t size
= its
->its_size
;
828 ipc_port_request_index_t index
;
829 for (index
= 1; index
< size
; index
++) {
830 ipc_port_request_t ipr
= &requests
[index
];
831 mach_port_name_t name
= ipr
->ipr_name
;
832 ipc_port_t soright
= IPR_SOR_PORT(ipr
->ipr_soright
);
834 if (MACH_PORT_VALID(name
) && IP_VALID(soright
)) {
835 ipc_notify_dead_name(soright
, name
);
843 * Routine: ipc_port_destroy
845 * Destroys a port. Cleans up queued messages.
847 * If the port has a backup, it doesn't get destroyed,
848 * but is sent in a port-destroyed notification to the backup.
850 * The port is locked and alive; nothing else locked.
851 * The caller has a reference, which is consumed.
852 * Afterwards, the port is unlocked and dead.
859 ipc_port_t pdrequest
, nsrequest
;
863 #if IMPORTANCE_INHERITANCE
864 ipc_importance_task_t release_imp_task
= IIT_NULL
;
865 thread_t self
= current_thread();
866 boolean_t top
= (self
->ith_assertions
== 0);
867 natural_t assertcnt
= 0;
868 #endif /* IMPORTANCE_INHERITANCE */
870 assert(ip_active(port
));
871 /* port->ip_receiver_name is garbage */
872 /* port->ip_receiver/port->ip_destination is garbage */
873 assert(port
->ip_pset_count
== 0);
874 assert(port
->ip_mscount
== 0);
876 /* check for a backup port */
877 pdrequest
= port
->ip_pdrequest
;
879 #if IMPORTANCE_INHERITANCE
880 /* determine how many assertions to drop and from whom */
881 if (port
->ip_tempowner
!= 0) {
883 release_imp_task
= port
->ip_imp_task
;
884 if (IIT_NULL
!= release_imp_task
) {
885 port
->ip_imp_task
= IIT_NULL
;
886 assertcnt
= port
->ip_impcount
;
888 /* Otherwise, nothing to drop */
890 assertcnt
= port
->ip_impcount
;
891 if (pdrequest
!= IP_NULL
)
892 /* mark in limbo for the journey */
893 port
->ip_tempowner
= 1;
897 self
->ith_assertions
= assertcnt
;
898 #endif /* IMPORTANCE_INHERITANCE */
900 if (pdrequest
!= IP_NULL
) {
901 /* we assume the ref for pdrequest */
902 port
->ip_pdrequest
= IP_NULL
;
904 /* make port be in limbo */
905 port
->ip_receiver_name
= MACH_PORT_NULL
;
906 port
->ip_destination
= IP_NULL
;
909 /* consumes our refs for port and pdrequest */
910 ipc_notify_port_destroyed(pdrequest
, port
);
912 goto drop_assertions
;
915 /* once port is dead, we don't need to keep it locked */
917 port
->ip_object
.io_bits
&= ~IO_BITS_ACTIVE
;
918 port
->ip_timestamp
= ipc_port_timestamp();
919 nsrequest
= port
->ip_nsrequest
;
922 * If the port has a preallocated message buffer and that buffer
923 * is not inuse, free it. If it has an inuse one, then the kmsg
924 * free will detect that we freed the association and it can free it
925 * like a normal buffer.
927 if (IP_PREALLOC(port
)) {
928 ipc_port_t inuse_port
;
930 kmsg
= port
->ip_premsg
;
931 assert(kmsg
!= IKM_NULL
);
932 inuse_port
= ikm_prealloc_inuse_port(kmsg
);
933 IP_CLEAR_PREALLOC(port
, kmsg
);
935 if (inuse_port
!= IP_NULL
) {
936 assert(inuse_port
== port
);
944 /* throw away no-senders request */
945 if (nsrequest
!= IP_NULL
)
946 ipc_notify_send_once(nsrequest
); /* consumes ref */
948 /* destroy any queued messages */
949 mqueue
= &port
->ip_messages
;
950 ipc_mqueue_destroy(mqueue
);
952 /* generate dead-name notifications */
953 ipc_port_dnnotify(port
);
955 ipc_kobject_destroy(port
);
957 ip_release(port
); /* consume caller's ref */
960 #if IMPORTANCE_INHERITANCE
961 if (release_imp_task
!= IIT_NULL
) {
964 self
->ith_assertions
= 0;
965 assert(ipc_importance_task_is_any_receiver_type(release_imp_task
));
966 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
968 ipc_importance_task_release(release_imp_task
);
970 } else if (assertcnt
> 0) {
972 self
->ith_assertions
= 0;
973 release_imp_task
= current_task()->task_imp_base
;
974 if (ipc_importance_task_is_any_receiver_type(release_imp_task
)) {
975 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
979 #endif /* IMPORTANCE_INHERITANCE */
983 * Routine: ipc_port_check_circularity
985 * Check if queueing "port" in a message for "dest"
986 * would create a circular group of ports and messages.
988 * If no circularity (FALSE returned), then "port"
989 * is changed from "in limbo" to "in transit".
991 * That is, we want to set port->ip_destination == dest,
992 * but guaranteeing that this doesn't create a circle
993 * port->ip_destination->ip_destination->... == port
995 * Additionally, if port was successfully changed to "in transit",
996 * propagate boost assertions from the "in limbo" port to all
997 * the ports in the chain, and, if the destination task accepts
998 * boosts, to the destination task.
1001 * No ports locked. References held for "port" and "dest".
1005 ipc_port_check_circularity(
1011 #if IMPORTANCE_INHERITANCE
1012 ipc_importance_task_t imp_task
= IIT_NULL
;
1013 ipc_importance_task_t release_imp_task
= IIT_NULL
;
1015 #endif /* IMPORTANCE_INHERITANCE */
1017 assert(port
!= IP_NULL
);
1018 assert(dest
!= IP_NULL
);
1025 * First try a quick check that can run in parallel.
1026 * No circularity if dest is not in transit.
1030 if (ip_lock_try(dest
)) {
1031 if (!ip_active(dest
) ||
1032 (dest
->ip_receiver_name
!= MACH_PORT_NULL
) ||
1033 (dest
->ip_destination
== IP_NULL
))
1036 /* dest is in transit; further checking necessary */
1042 ipc_port_multiple_lock(); /* massive serialization */
1045 * Search for the end of the chain (a port not in transit),
1046 * acquiring locks along the way.
1052 if (!ip_active(base
) ||
1053 (base
->ip_receiver_name
!= MACH_PORT_NULL
) ||
1054 (base
->ip_destination
== IP_NULL
))
1057 base
= base
->ip_destination
;
1060 /* all ports in chain from dest to base, inclusive, are locked */
1063 /* circularity detected! */
1065 ipc_port_multiple_unlock();
1067 /* port (== base) is in limbo */
1069 assert(ip_active(port
));
1070 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
1071 assert(port
->ip_destination
== IP_NULL
);
1073 while (dest
!= IP_NULL
) {
1076 /* dest is in transit or in limbo */
1078 assert(ip_active(dest
));
1079 assert(dest
->ip_receiver_name
== MACH_PORT_NULL
);
1081 next
= dest
->ip_destination
;
1090 * The guarantee: lock port while the entire chain is locked.
1091 * Once port is locked, we can take a reference to dest,
1092 * add port to the chain, and unlock everything.
1096 ipc_port_multiple_unlock();
1100 /* port is in limbo */
1102 assert(ip_active(port
));
1103 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
1104 assert(port
->ip_destination
== IP_NULL
);
1107 port
->ip_destination
= dest
;
1109 #if IMPORTANCE_INHERITANCE
1110 /* must have been in limbo or still bound to a task */
1111 assert(port
->ip_tempowner
!= 0);
1114 * We delayed dropping assertions from a specific task.
1115 * Cache that info now (we'll drop assertions and the
1116 * task reference below).
1118 release_imp_task
= port
->ip_imp_task
;
1119 if (IIT_NULL
!= release_imp_task
) {
1120 port
->ip_imp_task
= IIT_NULL
;
1122 assertcnt
= port
->ip_impcount
;
1124 /* take the port out of limbo w.r.t. assertions */
1125 port
->ip_tempowner
= 0;
1127 #endif /* IMPORTANCE_INHERITANCE */
1129 /* now unlock chain */
1135 #if IMPORTANCE_INHERITANCE
1136 /* every port along chain track assertions behind it */
1137 dest
->ip_impcount
+= assertcnt
;
1138 #endif /* IMPORTANCE_INHERITANCE */
1143 /* port is in transit */
1145 assert(ip_active(dest
));
1146 assert(dest
->ip_receiver_name
== MACH_PORT_NULL
);
1147 assert(dest
->ip_destination
!= IP_NULL
);
1149 #if IMPORTANCE_INHERITANCE
1150 assert(dest
->ip_tempowner
== 0);
1151 #endif /* IMPORTANCE_INHERITANCE */
1153 port
= dest
->ip_destination
;
1158 /* base is not in transit */
1159 assert(!ip_active(base
) ||
1160 (base
->ip_receiver_name
!= MACH_PORT_NULL
) ||
1161 (base
->ip_destination
== IP_NULL
));
1163 #if IMPORTANCE_INHERITANCE
1165 * Find the task to boost (if any).
1166 * We will boost "through" ports that don't know
1167 * about inheritance to deliver receive rights that
1170 if (ip_active(base
) && (assertcnt
> 0)) {
1171 if (base
->ip_tempowner
!= 0) {
1172 if (IIT_NULL
!= base
->ip_imp_task
) {
1173 /* specified tempowner task */
1174 imp_task
= base
->ip_imp_task
;
1175 assert(ipc_importance_task_is_any_receiver_type(imp_task
));
1177 /* otherwise don't boost current task */
1179 } else if (base
->ip_receiver_name
!= MACH_PORT_NULL
) {
1180 ipc_space_t space
= base
->ip_receiver
;
1182 /* only spaces with boost-accepting tasks */
1183 if (space
->is_task
!= TASK_NULL
&&
1184 ipc_importance_task_is_any_receiver_type(space
->is_task
->task_imp_base
))
1185 imp_task
= space
->is_task
->task_imp_base
;
1188 /* take reference before unlocking base */
1189 if (imp_task
!= IIT_NULL
) {
1190 ipc_importance_task_reference(imp_task
);
1193 #endif /* IMPORTANCE_INHERITANCE */
1197 #if IMPORTANCE_INHERITANCE
1199 * Transfer assertions now that the ports are unlocked.
1200 * Avoid extra overhead if transferring to/from the same task.
1202 boolean_t transfer_assertions
= (imp_task
!= release_imp_task
) ? TRUE
: FALSE
;
1204 if (imp_task
!= IIT_NULL
) {
1205 if (transfer_assertions
)
1206 ipc_importance_task_hold_internal_assertion(imp_task
, assertcnt
);
1207 ipc_importance_task_release(imp_task
);
1208 imp_task
= IIT_NULL
;
1211 if (release_imp_task
!= IIT_NULL
) {
1212 if (transfer_assertions
)
1213 ipc_importance_task_drop_internal_assertion(release_imp_task
, assertcnt
);
1214 ipc_importance_task_release(release_imp_task
);
1215 release_imp_task
= IIT_NULL
;
1217 #endif /* IMPORTANCE_INHERITANCE */
1223 * Routine: ipc_port_impcount_delta
1225 * Adjust only the importance count associated with a port.
1226 * If there are any adjustments to be made to receiver task,
1227 * those are handled elsewhere.
1229 * For now, be defensive during deductions to make sure the
1230 * impcount for the port doesn't underflow zero. This will
1231 * go away when the port boost addition is made atomic (see
1232 * note in ipc_port_importance_delta()).
1234 * The port is referenced and locked.
1235 * Nothing else is locked.
1238 ipc_port_impcount_delta(
1240 mach_port_delta_t delta
,
1241 ipc_port_t __unused base
)
1243 mach_port_delta_t absdelta
;
1245 if (!ip_active(port
)) {
1249 /* adding/doing nothing is easy */
1251 port
->ip_impcount
+= delta
;
1255 absdelta
= 0 - delta
;
1256 //assert(port->ip_impcount >= absdelta);
1257 /* if we have enough to deduct, we're done */
1258 if (port
->ip_impcount
>= absdelta
) {
1259 port
->ip_impcount
-= absdelta
;
1263 #if DEVELOPMENT || DEBUG
1264 if (port
->ip_receiver_name
!= MACH_PORT_NULL
) {
1265 task_t target_task
= port
->ip_receiver
->is_task
;
1266 ipc_importance_task_t target_imp
= target_task
->task_imp_base
;
1267 const char *target_procname
;
1270 if (target_imp
!= IIT_NULL
) {
1271 target_procname
= target_imp
->iit_procname
;
1272 target_pid
= target_imp
->iit_bsd_pid
;
1274 target_procname
= "unknown";
1277 printf("Over-release of importance assertions for port 0x%x receiver pid %d (%s), "
1278 "dropping %d assertion(s) but port only has %d remaining.\n",
1279 port
->ip_receiver_name
,
1280 target_imp
->iit_bsd_pid
, target_imp
->iit_procname
,
1281 absdelta
, port
->ip_impcount
);
1283 } else if (base
!= IP_NULL
) {
1284 task_t target_task
= base
->ip_receiver
->is_task
;
1285 ipc_importance_task_t target_imp
= target_task
->task_imp_base
;
1286 const char *target_procname
;
1289 if (target_imp
!= IIT_NULL
) {
1290 target_procname
= target_imp
->iit_procname
;
1291 target_pid
= target_imp
->iit_bsd_pid
;
1293 target_procname
= "unknown";
1296 printf("Over-release of importance assertions for port %p "
1297 "enqueued on port 0x%x with receiver pid %d (%s), "
1298 "dropping %d assertion(s) but port only has %d remaining.\n",
1299 port
, base
->ip_receiver_name
,
1300 target_imp
->iit_bsd_pid
, target_imp
->iit_procname
,
1301 absdelta
, port
->ip_impcount
);
1304 delta
= 0 - port
->ip_impcount
;
1305 port
->ip_impcount
= 0;
1310 * Routine: ipc_port_importance_delta_internal
1312 * Adjust the importance count through the given port.
1313 * If the port is in transit, apply the delta throughout
1314 * the chain. Determine if the there is a task at the
1315 * base of the chain that wants/needs to be adjusted,
1316 * and if so, apply the delta.
1318 * The port is referenced and locked on entry.
1319 * Nothing else is locked.
1320 * The lock may be dropped on exit.
1321 * Returns TRUE if lock was dropped.
1323 #if IMPORTANCE_INHERITANCE
1326 ipc_port_importance_delta_internal(
1328 mach_port_delta_t
*deltap
,
1329 ipc_importance_task_t
*imp_task
)
1331 ipc_port_t next
, base
;
1332 boolean_t dropped
= FALSE
;
1334 *imp_task
= IIT_NULL
;
1341 /* if port is in transit, have to search for end of chain */
1342 if (ip_active(port
) &&
1343 port
->ip_destination
!= IP_NULL
&&
1344 port
->ip_receiver_name
== MACH_PORT_NULL
) {
1349 ipc_port_multiple_lock(); /* massive serialization */
1352 while(ip_active(base
) &&
1353 base
->ip_destination
!= IP_NULL
&&
1354 base
->ip_receiver_name
== MACH_PORT_NULL
) {
1356 base
= base
->ip_destination
;
1359 ipc_port_multiple_unlock();
1362 /* unlock down to the base, adding a boost at each level */
1365 * JMM TODO - because of the port unlock to grab the multiple lock
1366 * above, a subsequent drop of importance could race and beat
1367 * the "previous" increase - causing the port impcount to go
1368 * negative briefly. The defensive deduction performed by
1369 * ipc_port_impcount_delta() defeats that, and therefore can
1370 * cause an importance leak once the increase finally arrives.
1372 * Need to rework the importance delta logic to be more like
1373 * ipc_importance_inherit_from() where it locks all it needs in
1374 * one pass to avoid any lock drops - to keep that race from
1377 *deltap
= ipc_port_impcount_delta(port
, *deltap
, base
);
1383 /* port is in transit */
1384 assert(port
->ip_tempowner
== 0);
1385 next
= port
->ip_destination
;
1390 /* find the task (if any) to boost according to the base */
1391 if (ip_active(base
)) {
1392 if (base
->ip_tempowner
!= 0) {
1393 if (IIT_NULL
!= base
->ip_imp_task
)
1394 *imp_task
= base
->ip_imp_task
;
1395 /* otherwise don't boost */
1397 } else if (base
->ip_receiver_name
!= MACH_PORT_NULL
) {
1398 ipc_space_t space
= base
->ip_receiver
;
1400 /* only spaces with boost-accepting tasks */
1401 if (space
->is_task
!= TASK_NULL
&&
1402 ipc_importance_task_is_any_receiver_type(space
->is_task
->task_imp_base
)) {
1403 *imp_task
= space
->is_task
->task_imp_base
;
1409 * Only the base is locked. If we have to hold or drop task
1410 * importance assertions, we'll have to drop that lock as well.
1412 if (*imp_task
!= IIT_NULL
) {
1413 /* take a reference before unlocking base */
1414 ipc_importance_task_reference(*imp_task
);
1417 if (dropped
== TRUE
) {
1423 #endif /* IMPORTANCE_INHERITANCE */
1426 * Routine: ipc_port_importance_delta
1428 * Adjust the importance count through the given port.
1429 * If the port is in transit, apply the delta throughout
1432 * If there is a task at the base of the chain that wants/needs
1433 * to be adjusted, apply the delta.
1435 * The port is referenced and locked on entry.
1436 * Nothing else is locked.
1437 * The lock may be dropped on exit.
1438 * Returns TRUE if lock was dropped.
1440 #if IMPORTANCE_INHERITANCE
1443 ipc_port_importance_delta(
1445 mach_port_delta_t delta
)
1447 ipc_importance_task_t imp_task
= IIT_NULL
;
1450 dropped
= ipc_port_importance_delta_internal(port
, &delta
, &imp_task
);
1452 if (IIT_NULL
== imp_task
)
1460 assert(ipc_importance_task_is_any_receiver_type(imp_task
));
1463 ipc_importance_task_hold_internal_assertion(imp_task
, delta
);
1465 ipc_importance_task_drop_internal_assertion(imp_task
, -delta
);
1467 ipc_importance_task_release(imp_task
);
1470 #endif /* IMPORTANCE_INHERITANCE */
1473 * Routine: ipc_port_lookup_notify
1475 * Make a send-once notify port from a receive right.
1476 * Returns IP_NULL if name doesn't denote a receive right.
1478 * The space must be locked (read or write) and active.
1479 * Being the active space, we can rely on thread server_id
1480 * context to give us the proper server level sub-order
1485 ipc_port_lookup_notify(
1487 mach_port_name_t name
)
1492 assert(is_active(space
));
1494 entry
= ipc_entry_lookup(space
, name
);
1495 if (entry
== IE_NULL
)
1497 if ((entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
) == 0)
1500 port
= (ipc_port_t
) entry
->ie_object
;
1501 assert(port
!= IP_NULL
);
1504 assert(ip_active(port
));
1505 assert(port
->ip_receiver_name
== name
);
1506 assert(port
->ip_receiver
== space
);
1509 port
->ip_sorights
++;
1516 * Routine: ipc_port_make_send_locked
1518 * Make a naked send right from a receive right.
1521 * port locked and active.
1524 ipc_port_make_send_locked(
1527 assert(ip_active(port
));
1535 * Routine: ipc_port_make_send
1537 * Make a naked send right from a receive right.
1545 if (!IP_VALID(port
))
1549 if (ip_active(port
)) {
1561 * Routine: ipc_port_copy_send
1563 * Make a naked send right from another naked send right.
1564 * IP_NULL -> IP_NULL
1565 * IP_DEAD -> IP_DEAD
1566 * dead port -> IP_DEAD
1567 * live port -> port + ref
1569 * Nothing locked except possibly a space.
1578 if (!IP_VALID(port
))
1582 if (ip_active(port
)) {
1583 assert(port
->ip_srights
> 0);
1596 * Routine: ipc_port_copyout_send
1598 * Copyout a naked send right (possibly null/dead),
1599 * or if that fails, destroy the right.
1605 ipc_port_copyout_send(
1609 mach_port_name_t name
;
1611 if (IP_VALID(sright
)) {
1614 kr
= ipc_object_copyout(space
, (ipc_object_t
) sright
,
1615 MACH_MSG_TYPE_PORT_SEND
, TRUE
, &name
);
1616 if (kr
!= KERN_SUCCESS
) {
1617 ipc_port_release_send(sright
);
1619 if (kr
== KERN_INVALID_CAPABILITY
)
1620 name
= MACH_PORT_DEAD
;
1622 name
= MACH_PORT_NULL
;
1625 name
= CAST_MACH_PORT_TO_NAME(sright
);
1631 * Routine: ipc_port_release_send
1633 * Release a naked send right.
1634 * Consumes a ref for the port.
1640 ipc_port_release_send(
1643 ipc_port_t nsrequest
= IP_NULL
;
1644 mach_port_mscount_t mscount
;
1646 if (!IP_VALID(port
))
1651 assert(port
->ip_srights
> 0);
1654 if (!ip_active(port
)) {
1660 if (port
->ip_srights
== 0 &&
1661 port
->ip_nsrequest
!= IP_NULL
) {
1662 nsrequest
= port
->ip_nsrequest
;
1663 port
->ip_nsrequest
= IP_NULL
;
1664 mscount
= port
->ip_mscount
;
1667 ipc_notify_no_senders(nsrequest
, mscount
);
1675 * Routine: ipc_port_make_sonce_locked
1677 * Make a naked send-once right from a receive right.
1679 * The port is locked and active.
1683 ipc_port_make_sonce_locked(
1686 assert(ip_active(port
));
1687 port
->ip_sorights
++;
1693 * Routine: ipc_port_make_sonce
1695 * Make a naked send-once right from a receive right.
1697 * The port is not locked.
1701 ipc_port_make_sonce(
1704 if (!IP_VALID(port
))
1708 if (ip_active(port
)) {
1709 port
->ip_sorights
++;
1719 * Routine: ipc_port_release_sonce
1721 * Release a naked send-once right.
1722 * Consumes a ref for the port.
1724 * In normal situations, this is never used.
1725 * Send-once rights are only consumed when
1726 * a message (possibly a send-once notification)
1729 * Nothing locked except possibly a space.
1733 ipc_port_release_sonce(
1736 if (!IP_VALID(port
))
1741 assert(port
->ip_sorights
> 0);
1743 port
->ip_sorights
--;
1750 * Routine: ipc_port_release_receive
1752 * Release a naked (in limbo or in transit) receive right.
1753 * Consumes a ref for the port; destroys the port.
1759 ipc_port_release_receive(
1764 if (!IP_VALID(port
))
1768 assert(ip_active(port
));
1769 assert(port
->ip_receiver_name
== MACH_PORT_NULL
);
1770 dest
= port
->ip_destination
;
1772 ipc_port_destroy(port
); /* consumes ref, unlocks */
1774 if (dest
!= IP_NULL
)
1779 * Routine: ipc_port_alloc_special
1781 * Allocate a port in a special space.
1782 * The new port is returned with one ref.
1783 * If unsuccessful, IP_NULL is returned.
1789 ipc_port_alloc_special(
1794 port
= (ipc_port_t
) io_alloc(IOT_PORT
);
1795 if (port
== IP_NULL
)
1799 uintptr_t buf
[IP_CALLSTACK_MAX
];
1800 ipc_port_callstack_init_debug(&buf
[0], IP_CALLSTACK_MAX
);
1801 #endif /* MACH_ASSERT */
1803 bzero((char *)port
, sizeof(*port
));
1804 io_lock_init(&port
->ip_object
);
1805 port
->ip_references
= 1;
1806 port
->ip_object
.io_bits
= io_makebits(TRUE
, IOT_PORT
, 0);
1808 ipc_port_init(port
, space
, 1);
1811 ipc_port_init_debug(port
, &buf
[0], IP_CALLSTACK_MAX
);
1812 #endif /* MACH_ASSERT */
1818 * Routine: ipc_port_dealloc_special
1820 * Deallocate a port in a special space.
1821 * Consumes one ref for the port.
1827 ipc_port_dealloc_special(
1829 __assert_only ipc_space_t space
)
1832 assert(ip_active(port
));
1833 // assert(port->ip_receiver_name != MACH_PORT_NULL);
1834 assert(port
->ip_receiver
== space
);
1837 * We clear ip_receiver_name and ip_receiver to simplify
1838 * the ipc_space_kernel check in ipc_mqueue_send.
1841 port
->ip_receiver_name
= MACH_PORT_NULL
;
1842 port
->ip_receiver
= IS_NULL
;
1844 /* relevant part of ipc_port_clear_receiver */
1845 ipc_port_set_mscount(port
, 0);
1846 port
->ip_messages
.imq_seqno
= 0;
1848 ipc_port_destroy(port
);
1852 * Routine: ipc_port_finalize
1854 * Called on last reference deallocate to
1855 * free any remaining data associated with the
1864 ipc_port_request_t requests
= port
->ip_requests
;
1866 assert(!ip_active(port
));
1867 if (requests
!= IPR_NULL
) {
1868 ipc_table_size_t its
= requests
->ipr_size
;
1869 it_requests_free(its
, requests
);
1870 port
->ip_requests
= IPR_NULL
;
1874 ipc_port_track_dealloc(port
);
1875 #endif /* MACH_ASSERT */
1879 #include <kern/machine.h>
1882 * Keep a list of all allocated ports.
1883 * Allocation is intercepted via ipc_port_init;
1884 * deallocation is intercepted via io_free.
1886 queue_head_t port_alloc_queue
;
1887 lck_spin_t port_alloc_queue_lock
;
1889 unsigned long port_count
= 0;
1890 unsigned long port_count_warning
= 20000;
1891 unsigned long port_timestamp
= 0;
1893 void db_port_stack_trace(
1898 unsigned int verbose
,
1899 unsigned int display
,
1900 unsigned int ref_search
,
1901 unsigned int ref_target
);
1904 * Initialize global state needed for run-time
1908 ipc_port_debug_init(void)
1910 queue_init(&port_alloc_queue
);
1912 lck_spin_init(&port_alloc_queue_lock
, &ipc_lck_grp
, &ipc_lck_attr
);
1914 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt
, sizeof (ipc_portbt
)))
1919 extern int proc_pid(struct proc
*);
1920 #endif /* MACH_BSD */
1923 * Initialize all of the debugging state in a port.
1924 * Insert the port into a global list of all allocated ports.
1927 ipc_port_init_debug(
1929 uintptr_t *callstack
,
1930 unsigned int callstack_max
)
1934 port
->ip_thread
= current_thread();
1935 port
->ip_timetrack
= port_timestamp
++;
1936 for (i
= 0; i
< callstack_max
; ++i
)
1937 port
->ip_callstack
[i
] = callstack
[i
];
1938 for (i
= 0; i
< IP_NSPARES
; ++i
)
1939 port
->ip_spares
[i
] = 0;
1942 task_t task
= current_task();
1943 if (task
!= TASK_NULL
) {
1944 struct proc
* proc
= (struct proc
*) get_bsdtask_info(task
);
1946 port
->ip_spares
[0] = proc_pid(proc
);
1948 #endif /* MACH_BSD */
1951 lck_spin_lock(&port_alloc_queue_lock
);
1953 if (port_count_warning
> 0 && port_count
>= port_count_warning
)
1954 assert(port_count
< port_count_warning
);
1955 queue_enter(&port_alloc_queue
, port
, ipc_port_t
, ip_port_links
);
1956 lck_spin_unlock(&port_alloc_queue_lock
);
1961 * Routine: ipc_port_callstack_init_debug
1963 * Calls the machine-dependent routine to
1964 * fill in an array with up to IP_CALLSTACK_MAX
1965 * levels of return pc information
1967 * May block (via copyin)
1970 ipc_port_callstack_init_debug(
1971 uintptr_t *callstack
,
1972 unsigned int callstack_max
)
1976 /* guarantee the callstack is initialized */
1977 for (i
=0; i
< callstack_max
; i
++)
1981 machine_callstack(callstack
, callstack_max
);
1985 * Remove a port from the queue of allocated ports.
1986 * This routine should be invoked JUST prior to
1987 * deallocating the actual memory occupied by the port.
1991 ipc_port_track_dealloc(
1992 __unused ipc_port_t port
)
1997 ipc_port_track_dealloc(
2000 lck_spin_lock(&port_alloc_queue_lock
);
2001 assert(port_count
> 0);
2003 queue_remove(&port_alloc_queue
, port
, ipc_port_t
, ip_port_links
);
2004 lck_spin_unlock(&port_alloc_queue_lock
);
2009 #endif /* MACH_ASSERT */