]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_port.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_port.c
1 /*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_FREE_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
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.
41 *
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.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
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,
60 * Version 2.0.
61 */
62 /*
63 */
64 /*
65 * File: ipc/ipc_port.c
66 * Author: Rich Draves
67 * Date: 1989
68 *
69 * Functions to manipulate IPC ports.
70 */
71
72 #include <norma_vm.h>
73 #include <mach_kdb.h>
74 #include <zone_debug.h>
75 #include <mach_assert.h>
76
77 #include <mach/port.h>
78 #include <mach/kern_return.h>
79 #include <kern/lock.h>
80 #include <kern/ipc_kobject.h>
81 #include <kern/thread.h>
82 #include <kern/misc_protos.h>
83 #include <kern/wait_queue.h>
84 #include <ipc/ipc_entry.h>
85 #include <ipc/ipc_space.h>
86 #include <ipc/ipc_object.h>
87 #include <ipc/ipc_port.h>
88 #include <ipc/ipc_pset.h>
89 #include <ipc/ipc_kmsg.h>
90 #include <ipc/ipc_mqueue.h>
91 #include <ipc/ipc_notify.h>
92 #include <ipc/ipc_print.h>
93 #include <ipc/ipc_table.h>
94
95 #include <security/mac_mach_internal.h>
96
97 #if MACH_KDB
98 #include <machine/db_machdep.h>
99 #include <ddb/db_command.h>
100 #include <ddb/db_expr.h>
101 #endif /* MACH_KDB */
102
103 #include <string.h>
104
105 decl_lck_mtx_data(, ipc_port_multiple_lock_data)
106 decl_lck_mtx_data(, ipc_port_timestamp_lock_data)
107 lck_mtx_ext_t ipc_port_multiple_lock_data_ext;
108 lck_mtx_ext_t ipc_port_timestamp_lock_data_ext;
109 ipc_port_timestamp_t ipc_port_timestamp_data;
110 int ipc_portbt;
111
112 #if MACH_ASSERT
113 void ipc_port_init_debug(
114 ipc_port_t port);
115 #endif /* MACH_ASSERT */
116
117 #if MACH_KDB && ZONE_DEBUG
118 /* Forwards */
119 void print_type_ports(unsigned, unsigned);
120 void print_ports(void);
121 #endif /* MACH_KDB && ZONE_DEBUG */
122
123 /*
124 * Routine: ipc_port_timestamp
125 * Purpose:
126 * Retrieve a timestamp value.
127 */
128
129 ipc_port_timestamp_t
130 ipc_port_timestamp(void)
131 {
132 ipc_port_timestamp_t timestamp;
133
134 ipc_port_timestamp_lock();
135 timestamp = ipc_port_timestamp_data++;
136 ipc_port_timestamp_unlock();
137
138 return timestamp;
139 }
140
141 /*
142 * Routine: ipc_port_dnrequest
143 * Purpose:
144 * Try to allocate a dead-name request slot.
145 * If successful, returns the request index.
146 * Otherwise returns zero.
147 * Conditions:
148 * The port is locked and active.
149 * Returns:
150 * KERN_SUCCESS A request index was found.
151 * KERN_NO_SPACE No index allocated.
152 */
153
154 kern_return_t
155 ipc_port_dnrequest(
156 ipc_port_t port,
157 mach_port_name_t name,
158 ipc_port_t soright,
159 ipc_port_request_index_t *indexp)
160 {
161 ipc_port_request_t ipr, table;
162 ipc_port_request_index_t index;
163
164 assert(ip_active(port));
165 assert(name != MACH_PORT_NULL);
166 assert(soright != IP_NULL);
167
168 table = port->ip_dnrequests;
169 if (table == IPR_NULL)
170 return KERN_NO_SPACE;
171
172 index = table->ipr_next;
173 if (index == 0)
174 return KERN_NO_SPACE;
175
176 ipr = &table[index];
177 assert(ipr->ipr_name == MACH_PORT_NULL);
178
179 table->ipr_next = ipr->ipr_next;
180 ipr->ipr_name = name;
181 ipr->ipr_soright = soright;
182
183 *indexp = index;
184 return KERN_SUCCESS;
185 }
186
187 /*
188 * Routine: ipc_port_dngrow
189 * Purpose:
190 * Grow a port's table of dead-name requests.
191 * Conditions:
192 * The port must be locked and active.
193 * Nothing else locked; will allocate memory.
194 * Upon return the port is unlocked.
195 * Returns:
196 * KERN_SUCCESS Grew the table.
197 * KERN_SUCCESS Somebody else grew the table.
198 * KERN_SUCCESS The port died.
199 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
200 * KERN_NO_SPACE Couldn't grow to desired size
201 */
202
203 kern_return_t
204 ipc_port_dngrow(
205 ipc_port_t port,
206 ipc_table_elems_t target_size)
207 {
208 ipc_table_size_t its;
209 ipc_port_request_t otable, ntable;
210
211 assert(ip_active(port));
212
213 otable = port->ip_dnrequests;
214 if (otable == IPR_NULL)
215 its = &ipc_table_dnrequests[0];
216 else
217 its = otable->ipr_size + 1;
218
219 if (target_size != ITS_SIZE_NONE) {
220 if ((otable != IPR_NULL) &&
221 (target_size <= otable->ipr_size->its_size)) {
222 ip_unlock(port);
223 return KERN_SUCCESS;
224 }
225 while ((its->its_size) && (its->its_size < target_size)) {
226 its++;
227 }
228 if (its->its_size == 0) {
229 ip_unlock(port);
230 return KERN_NO_SPACE;
231 }
232 }
233
234 ip_reference(port);
235 ip_unlock(port);
236
237 if ((its->its_size == 0) ||
238 ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
239 ipc_port_release(port);
240 return KERN_RESOURCE_SHORTAGE;
241 }
242
243 ip_lock(port);
244 ip_release(port);
245
246 /*
247 * Check that port is still active and that nobody else
248 * has slipped in and grown the table on us. Note that
249 * just checking port->ip_dnrequests == otable isn't
250 * sufficient; must check ipr_size.
251 */
252
253 if (ip_active(port) &&
254 (port->ip_dnrequests == otable) &&
255 ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
256 ipc_table_size_t oits;
257 ipc_table_elems_t osize, nsize;
258 ipc_port_request_index_t free, i;
259
260 /* copy old table to new table */
261
262 if (otable != IPR_NULL) {
263 oits = otable->ipr_size;
264 osize = oits->its_size;
265 free = otable->ipr_next;
266
267 (void) memcpy((void *)(ntable + 1),
268 (const void *)(otable + 1),
269 (osize - 1) * sizeof(struct ipc_port_request));
270 } else {
271 osize = 1;
272 oits = 0;
273 free = 0;
274 }
275
276 nsize = its->its_size;
277 assert(nsize > osize);
278
279 /* add new elements to the new table's free list */
280
281 for (i = osize; i < nsize; i++) {
282 ipc_port_request_t ipr = &ntable[i];
283
284 ipr->ipr_name = MACH_PORT_NULL;
285 ipr->ipr_next = free;
286 free = i;
287 }
288
289 ntable->ipr_next = free;
290 ntable->ipr_size = its;
291 port->ip_dnrequests = ntable;
292 ip_unlock(port);
293
294 if (otable != IPR_NULL) {
295 it_dnrequests_free(oits, otable);
296 }
297 } else {
298 ip_check_unlock(port);
299 it_dnrequests_free(its, ntable);
300 }
301
302 return KERN_SUCCESS;
303 }
304
305 /*
306 * Routine: ipc_port_dncancel
307 * Purpose:
308 * Cancel a dead-name request and return the send-once right.
309 * Conditions:
310 * The port must locked and active.
311 */
312
313 ipc_port_t
314 ipc_port_dncancel(
315 ipc_port_t port,
316 __assert_only mach_port_name_t name,
317 ipc_port_request_index_t index)
318 {
319 ipc_port_request_t ipr, table;
320 ipc_port_t dnrequest;
321
322 assert(ip_active(port));
323 assert(name != MACH_PORT_NULL);
324 assert(index != 0);
325
326 table = port->ip_dnrequests;
327 assert(table != IPR_NULL);
328
329 ipr = &table[index];
330 dnrequest = ipr->ipr_soright;
331 assert(ipr->ipr_name == name);
332
333 /* return ipr to the free list inside the table */
334
335 ipr->ipr_name = MACH_PORT_NULL;
336 ipr->ipr_next = table->ipr_next;
337 table->ipr_next = index;
338
339 return dnrequest;
340 }
341
342 /*
343 * Routine: ipc_port_pdrequest
344 * Purpose:
345 * Make a port-deleted request, returning the
346 * previously registered send-once right.
347 * Just cancels the previous request if notify is IP_NULL.
348 * Conditions:
349 * The port is locked and active. It is unlocked.
350 * Consumes a ref for notify (if non-null), and
351 * returns previous with a ref (if non-null).
352 */
353
354 void
355 ipc_port_pdrequest(
356 ipc_port_t port,
357 ipc_port_t notify,
358 ipc_port_t *previousp)
359 {
360 ipc_port_t previous;
361
362 assert(ip_active(port));
363
364 previous = port->ip_pdrequest;
365 port->ip_pdrequest = notify;
366 ip_unlock(port);
367
368 *previousp = previous;
369 }
370
371 /*
372 * Routine: ipc_port_nsrequest
373 * Purpose:
374 * Make a no-senders request, returning the
375 * previously registered send-once right.
376 * Just cancels the previous request if notify is IP_NULL.
377 * Conditions:
378 * The port is locked and active. It is unlocked.
379 * Consumes a ref for notify (if non-null), and
380 * returns previous with a ref (if non-null).
381 */
382
383 void
384 ipc_port_nsrequest(
385 ipc_port_t port,
386 mach_port_mscount_t sync,
387 ipc_port_t notify,
388 ipc_port_t *previousp)
389 {
390 ipc_port_t previous;
391 mach_port_mscount_t mscount;
392
393 assert(ip_active(port));
394
395 previous = port->ip_nsrequest;
396 mscount = port->ip_mscount;
397
398 if ((port->ip_srights == 0) && (sync <= mscount) &&
399 (notify != IP_NULL)) {
400 port->ip_nsrequest = IP_NULL;
401 ip_unlock(port);
402 ipc_notify_no_senders(notify, mscount);
403 } else {
404 port->ip_nsrequest = notify;
405 ip_unlock(port);
406 }
407
408 *previousp = previous;
409 }
410
411
412 /*
413 * Routine: ipc_port_clear_receiver
414 * Purpose:
415 * Prepares a receive right for transmission/destruction.
416 * Conditions:
417 * The port is locked and active.
418 */
419
420 void
421 ipc_port_clear_receiver(
422 ipc_port_t port)
423 {
424 spl_t s;
425
426 assert(ip_active(port));
427
428 /*
429 * pull ourselves from any sets.
430 */
431 if (port->ip_pset_count != 0) {
432 ipc_pset_remove_from_all(port);
433 assert(port->ip_pset_count == 0);
434 }
435
436 /*
437 * Send anyone waiting on the port's queue directly away.
438 * Also clear the mscount and seqno.
439 */
440 s = splsched();
441 imq_lock(&port->ip_messages);
442 ipc_mqueue_changed(&port->ip_messages);
443 ipc_port_set_mscount(port, 0);
444 port->ip_messages.imq_seqno = 0;
445 imq_unlock(&port->ip_messages);
446 splx(s);
447 }
448
449 /*
450 * Routine: ipc_port_init
451 * Purpose:
452 * Initializes a newly-allocated port.
453 * Doesn't touch the ip_object fields.
454 */
455
456 void
457 ipc_port_init(
458 ipc_port_t port,
459 ipc_space_t space,
460 mach_port_name_t name)
461 {
462 /* port->ip_kobject doesn't have to be initialized */
463
464 port->ip_receiver = space;
465 port->ip_receiver_name = name;
466
467 port->ip_mscount = 0;
468 port->ip_srights = 0;
469 port->ip_sorights = 0;
470
471 port->ip_nsrequest = IP_NULL;
472 port->ip_pdrequest = IP_NULL;
473 port->ip_dnrequests = IPR_NULL;
474
475 port->ip_pset_count = 0;
476 port->ip_premsg = IKM_NULL;
477 port->ip_context = 0;
478
479 #if MACH_ASSERT
480 ipc_port_init_debug(port);
481 #endif /* MACH_ASSERT */
482
483 ipc_mqueue_init(&port->ip_messages, FALSE /* set */);
484 }
485
486 /*
487 * Routine: ipc_port_alloc
488 * Purpose:
489 * Allocate a port.
490 * Conditions:
491 * Nothing locked. If successful, the port is returned
492 * locked. (The caller doesn't have a reference.)
493 * Returns:
494 * KERN_SUCCESS The port is allocated.
495 * KERN_INVALID_TASK The space is dead.
496 * KERN_NO_SPACE No room for an entry in the space.
497 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
498 */
499
500 kern_return_t
501 ipc_port_alloc(
502 ipc_space_t space,
503 mach_port_name_t *namep,
504 ipc_port_t *portp)
505 {
506 ipc_port_t port;
507 mach_port_name_t name;
508 kern_return_t kr;
509
510 kr = ipc_object_alloc(space, IOT_PORT,
511 MACH_PORT_TYPE_RECEIVE, 0,
512 &name, (ipc_object_t *) &port);
513 if (kr != KERN_SUCCESS)
514 return kr;
515
516 /* port is locked */
517
518 ipc_port_init(port, space, name);
519
520 #if CONFIG_MACF_MACH
521 task_t issuer = current_task();
522 tasklabel_lock2 (issuer, space->is_task);
523 mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
524 &port->ip_label);
525 tasklabel_unlock2 (issuer, space->is_task);
526 #endif
527
528 *namep = name;
529 *portp = port;
530
531 return KERN_SUCCESS;
532 }
533
534 /*
535 * Routine: ipc_port_alloc_name
536 * Purpose:
537 * Allocate a port, with a specific name.
538 * Conditions:
539 * Nothing locked. If successful, the port is returned
540 * locked. (The caller doesn't have a reference.)
541 * Returns:
542 * KERN_SUCCESS The port is allocated.
543 * KERN_INVALID_TASK The space is dead.
544 * KERN_NAME_EXISTS The name already denotes a right.
545 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
546 */
547
548 kern_return_t
549 ipc_port_alloc_name(
550 ipc_space_t space,
551 mach_port_name_t name,
552 ipc_port_t *portp)
553 {
554 ipc_port_t port;
555 kern_return_t kr;
556
557 kr = ipc_object_alloc_name(space, IOT_PORT,
558 MACH_PORT_TYPE_RECEIVE, 0,
559 name, (ipc_object_t *) &port);
560 if (kr != KERN_SUCCESS)
561 return kr;
562
563 /* port is locked */
564
565 ipc_port_init(port, space, name);
566
567 #if CONFIG_MACF_MACH
568 task_t issuer = current_task();
569 tasklabel_lock2 (issuer, space->is_task);
570 mac_port_label_associate(&issuer->maclabel, &space->is_task->maclabel,
571 &port->ip_label);
572 tasklabel_unlock2 (issuer, space->is_task);
573 #endif
574
575 *portp = port;
576
577 return KERN_SUCCESS;
578 }
579
580 /*
581 * Generate dead name notifications. Called from ipc_port_destroy.
582 * Port is unlocked but still has reference(s);
583 * dnrequests was taken from port while the port
584 * was locked but the port now has port->ip_dnrequests set to IPR_NULL.
585 */
586 void
587 ipc_port_dnnotify(
588 __unused ipc_port_t port,
589 ipc_port_request_t dnrequests)
590 {
591 ipc_table_size_t its = dnrequests->ipr_size;
592 ipc_table_elems_t size = its->its_size;
593 ipc_port_request_index_t index;
594
595 for (index = 1; index < size; index++) {
596 ipc_port_request_t ipr = &dnrequests[index];
597 mach_port_name_t name = ipr->ipr_name;
598 ipc_port_t soright;
599
600 if (name == MACH_PORT_NULL)
601 continue;
602
603 soright = ipr->ipr_soright;
604 assert(soright != IP_NULL);
605
606 ipc_notify_dead_name(soright, name);
607 }
608
609 it_dnrequests_free(its, dnrequests);
610 }
611
612 /*
613 * Routine: ipc_port_destroy
614 * Purpose:
615 * Destroys a port. Cleans up queued messages.
616 *
617 * If the port has a backup, it doesn't get destroyed,
618 * but is sent in a port-destroyed notification to the backup.
619 * Conditions:
620 * The port is locked and alive; nothing else locked.
621 * The caller has a reference, which is consumed.
622 * Afterwards, the port is unlocked and dead.
623 */
624
625 void
626 ipc_port_destroy(
627 ipc_port_t port)
628 {
629 ipc_port_t pdrequest, nsrequest;
630 ipc_mqueue_t mqueue;
631 ipc_kmsg_t kmsg;
632 ipc_port_request_t dnrequests;
633
634 assert(ip_active(port));
635 /* port->ip_receiver_name is garbage */
636 /* port->ip_receiver/port->ip_destination is garbage */
637 assert(port->ip_pset_count == 0);
638 assert(port->ip_mscount == 0);
639
640 /* first check for a backup port */
641
642 pdrequest = port->ip_pdrequest;
643 if (pdrequest != IP_NULL) {
644 /* we assume the ref for pdrequest */
645 port->ip_pdrequest = IP_NULL;
646
647 /* make port be in limbo */
648 port->ip_receiver_name = MACH_PORT_NULL;
649 port->ip_destination = IP_NULL;
650 ip_unlock(port);
651
652 /* consumes our refs for port and pdrequest */
653 ipc_notify_port_destroyed(pdrequest, port);
654 return;
655 }
656
657 /* once port is dead, we don't need to keep it locked */
658
659 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
660 port->ip_timestamp = ipc_port_timestamp();
661
662 /* save for later */
663 dnrequests = port->ip_dnrequests;
664 port->ip_dnrequests = IPR_NULL;
665
666 /*
667 * If the port has a preallocated message buffer and that buffer
668 * is not inuse, free it. If it has an inuse one, then the kmsg
669 * free will detect that we freed the association and it can free it
670 * like a normal buffer.
671 */
672 if (IP_PREALLOC(port)) {
673 kmsg = port->ip_premsg;
674 assert(kmsg != IKM_NULL);
675 IP_CLEAR_PREALLOC(port, kmsg);
676 if (!ikm_prealloc_inuse(kmsg))
677 ipc_kmsg_free(kmsg);
678 }
679 ip_unlock(port);
680
681 /* throw away no-senders request */
682
683 nsrequest = port->ip_nsrequest;
684 if (nsrequest != IP_NULL)
685 ipc_notify_send_once(nsrequest); /* consumes ref */
686
687 /* destroy any queued messages */
688 mqueue = &port->ip_messages;
689 ipc_mqueue_destroy(mqueue);
690
691 /* generate dead-name notifications */
692 if (dnrequests != IPR_NULL) {
693 ipc_port_dnnotify(port, dnrequests);
694 }
695
696 ipc_kobject_destroy(port);
697
698 ipc_port_release(port); /* consume caller's ref */
699 }
700
701 /*
702 * Routine: ipc_port_check_circularity
703 * Purpose:
704 * Check if queueing "port" in a message for "dest"
705 * would create a circular group of ports and messages.
706 *
707 * If no circularity (FALSE returned), then "port"
708 * is changed from "in limbo" to "in transit".
709 *
710 * That is, we want to set port->ip_destination == dest,
711 * but guaranteeing that this doesn't create a circle
712 * port->ip_destination->ip_destination->... == port
713 * Conditions:
714 * No ports locked. References held for "port" and "dest".
715 */
716
717 boolean_t
718 ipc_port_check_circularity(
719 ipc_port_t port,
720 ipc_port_t dest)
721 {
722 ipc_port_t base;
723
724 assert(port != IP_NULL);
725 assert(dest != IP_NULL);
726
727 if (port == dest)
728 return TRUE;
729 base = dest;
730
731 /*
732 * First try a quick check that can run in parallel.
733 * No circularity if dest is not in transit.
734 */
735
736 ip_lock(port);
737 if (ip_lock_try(dest)) {
738 if (!ip_active(dest) ||
739 (dest->ip_receiver_name != MACH_PORT_NULL) ||
740 (dest->ip_destination == IP_NULL))
741 goto not_circular;
742
743 /* dest is in transit; further checking necessary */
744
745 ip_unlock(dest);
746 }
747 ip_unlock(port);
748
749 ipc_port_multiple_lock(); /* massive serialization */
750
751 /*
752 * Search for the end of the chain (a port not in transit),
753 * acquiring locks along the way.
754 */
755
756 for (;;) {
757 ip_lock(base);
758
759 if (!ip_active(base) ||
760 (base->ip_receiver_name != MACH_PORT_NULL) ||
761 (base->ip_destination == IP_NULL))
762 break;
763
764 base = base->ip_destination;
765 }
766
767 /* all ports in chain from dest to base, inclusive, are locked */
768
769 if (port == base) {
770 /* circularity detected! */
771
772 ipc_port_multiple_unlock();
773
774 /* port (== base) is in limbo */
775
776 assert(ip_active(port));
777 assert(port->ip_receiver_name == MACH_PORT_NULL);
778 assert(port->ip_destination == IP_NULL);
779
780 while (dest != IP_NULL) {
781 ipc_port_t next;
782
783 /* dest is in transit or in limbo */
784
785 assert(ip_active(dest));
786 assert(dest->ip_receiver_name == MACH_PORT_NULL);
787
788 next = dest->ip_destination;
789 ip_unlock(dest);
790 dest = next;
791 }
792
793 return TRUE;
794 }
795
796 /*
797 * The guarantee: lock port while the entire chain is locked.
798 * Once port is locked, we can take a reference to dest,
799 * add port to the chain, and unlock everything.
800 */
801
802 ip_lock(port);
803 ipc_port_multiple_unlock();
804
805 not_circular:
806
807 /* port is in limbo */
808
809 assert(ip_active(port));
810 assert(port->ip_receiver_name == MACH_PORT_NULL);
811 assert(port->ip_destination == IP_NULL);
812
813 ip_reference(dest);
814 port->ip_destination = dest;
815
816 /* now unlock chain */
817
818 while (port != base) {
819 ipc_port_t next;
820
821 /* port is in transit */
822
823 assert(ip_active(port));
824 assert(port->ip_receiver_name == MACH_PORT_NULL);
825 assert(port->ip_destination != IP_NULL);
826
827 next = port->ip_destination;
828 ip_unlock(port);
829 port = next;
830 }
831
832 /* base is not in transit */
833
834 assert(!ip_active(base) ||
835 (base->ip_receiver_name != MACH_PORT_NULL) ||
836 (base->ip_destination == IP_NULL));
837 ip_unlock(base);
838
839 return FALSE;
840 }
841
842 /*
843 * Routine: ipc_port_lookup_notify
844 * Purpose:
845 * Make a send-once notify port from a receive right.
846 * Returns IP_NULL if name doesn't denote a receive right.
847 * Conditions:
848 * The space must be locked (read or write) and active.
849 * Being the active space, we can rely on thread server_id
850 * context to give us the proper server level sub-order
851 * within the space.
852 */
853
854 ipc_port_t
855 ipc_port_lookup_notify(
856 ipc_space_t space,
857 mach_port_name_t name)
858 {
859 ipc_port_t port;
860 ipc_entry_t entry;
861
862 assert(space->is_active);
863
864 entry = ipc_entry_lookup(space, name);
865 if (entry == IE_NULL)
866 return IP_NULL;
867 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
868 return IP_NULL;
869
870 port = (ipc_port_t) entry->ie_object;
871 assert(port != IP_NULL);
872
873 ip_lock(port);
874 assert(ip_active(port));
875 assert(port->ip_receiver_name == name);
876 assert(port->ip_receiver == space);
877
878 ip_reference(port);
879 port->ip_sorights++;
880 ip_unlock(port);
881
882 return port;
883 }
884
885 /*
886 * Routine: ipc_port_make_send_locked
887 * Purpose:
888 * Make a naked send right from a receive right.
889 *
890 * Conditions:
891 * port locked and active.
892 */
893 ipc_port_t
894 ipc_port_make_send_locked(
895 ipc_port_t port)
896 {
897 assert(ip_active(port));
898 port->ip_mscount++;
899 port->ip_srights++;
900 ip_reference(port);
901 ip_unlock(port);
902 return port;
903 }
904
905 /*
906 * Routine: ipc_port_make_send
907 * Purpose:
908 * Make a naked send right from a receive right.
909 */
910
911 ipc_port_t
912 ipc_port_make_send(
913 ipc_port_t port)
914 {
915
916 if (!IP_VALID(port))
917 return port;
918
919 ip_lock(port);
920 if (ip_active(port)) {
921 port->ip_mscount++;
922 port->ip_srights++;
923 ip_reference(port);
924 ip_unlock(port);
925 return port;
926 }
927 ip_unlock(port);
928 return IP_DEAD;
929 }
930
931 /*
932 * Routine: ipc_port_copy_send
933 * Purpose:
934 * Make a naked send right from another naked send right.
935 * IP_NULL -> IP_NULL
936 * IP_DEAD -> IP_DEAD
937 * dead port -> IP_DEAD
938 * live port -> port + ref
939 * Conditions:
940 * Nothing locked except possibly a space.
941 */
942
943 ipc_port_t
944 ipc_port_copy_send(
945 ipc_port_t port)
946 {
947 ipc_port_t sright;
948
949 if (!IP_VALID(port))
950 return port;
951
952 ip_lock(port);
953 if (ip_active(port)) {
954 assert(port->ip_srights > 0);
955
956 ip_reference(port);
957 port->ip_srights++;
958 sright = port;
959 } else
960 sright = IP_DEAD;
961 ip_unlock(port);
962
963 return sright;
964 }
965
966 /*
967 * Routine: ipc_port_copyout_send
968 * Purpose:
969 * Copyout a naked send right (possibly null/dead),
970 * or if that fails, destroy the right.
971 * Conditions:
972 * Nothing locked.
973 */
974
975 mach_port_name_t
976 ipc_port_copyout_send(
977 ipc_port_t sright,
978 ipc_space_t space)
979 {
980 mach_port_name_t name;
981
982 if (IP_VALID(sright)) {
983 kern_return_t kr;
984
985 kr = ipc_object_copyout(space, (ipc_object_t) sright,
986 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
987 if (kr != KERN_SUCCESS) {
988 ipc_port_release_send(sright);
989
990 if (kr == KERN_INVALID_CAPABILITY)
991 name = MACH_PORT_DEAD;
992 else
993 name = MACH_PORT_NULL;
994 }
995 } else
996 name = CAST_MACH_PORT_TO_NAME(sright);
997
998 return name;
999 }
1000
1001 /*
1002 * Routine: ipc_port_release_send
1003 * Purpose:
1004 * Release a (valid) naked send right.
1005 * Consumes a ref for the port.
1006 * Conditions:
1007 * Nothing locked.
1008 */
1009
1010 void
1011 ipc_port_release_send(
1012 ipc_port_t port)
1013 {
1014 ipc_port_t nsrequest = IP_NULL;
1015 mach_port_mscount_t mscount;
1016
1017 assert(IP_VALID(port));
1018
1019 ip_lock(port);
1020 ip_release(port);
1021
1022 if (!ip_active(port)) {
1023 ip_check_unlock(port);
1024 return;
1025 }
1026
1027 assert(port->ip_srights > 0);
1028
1029 if (--port->ip_srights == 0 &&
1030 port->ip_nsrequest != IP_NULL) {
1031 nsrequest = port->ip_nsrequest;
1032 port->ip_nsrequest = IP_NULL;
1033 mscount = port->ip_mscount;
1034 ip_unlock(port);
1035 ipc_notify_no_senders(nsrequest, mscount);
1036 } else
1037 ip_unlock(port);
1038 }
1039
1040 /*
1041 * Routine: ipc_port_make_sonce
1042 * Purpose:
1043 * Make a naked send-once right from a receive right.
1044 * Conditions:
1045 * The port is not locked but it is active.
1046 */
1047
1048 ipc_port_t
1049 ipc_port_make_sonce(
1050 ipc_port_t port)
1051 {
1052 assert(IP_VALID(port));
1053
1054 ip_lock(port);
1055 assert(ip_active(port));
1056 port->ip_sorights++;
1057 ip_reference(port);
1058 ip_unlock(port);
1059
1060 return port;
1061 }
1062
1063 /*
1064 * Routine: ipc_port_release_sonce
1065 * Purpose:
1066 * Release a naked send-once right.
1067 * Consumes a ref for the port.
1068 *
1069 * In normal situations, this is never used.
1070 * Send-once rights are only consumed when
1071 * a message (possibly a send-once notification)
1072 * is sent to them.
1073 * Conditions:
1074 * Nothing locked except possibly a space.
1075 */
1076
1077 void
1078 ipc_port_release_sonce(
1079 ipc_port_t port)
1080 {
1081 assert(IP_VALID(port));
1082
1083 ip_lock(port);
1084
1085 assert(port->ip_sorights > 0);
1086
1087 port->ip_sorights--;
1088
1089 ip_release(port);
1090
1091 if (!ip_active(port)) {
1092 ip_check_unlock(port);
1093 return;
1094 }
1095
1096 ip_unlock(port);
1097 }
1098
1099 /*
1100 * Routine: ipc_port_release_receive
1101 * Purpose:
1102 * Release a naked (in limbo or in transit) receive right.
1103 * Consumes a ref for the port; destroys the port.
1104 * Conditions:
1105 * Nothing locked.
1106 */
1107
1108 void
1109 ipc_port_release_receive(
1110 ipc_port_t port)
1111 {
1112 ipc_port_t dest;
1113
1114 assert(IP_VALID(port));
1115
1116 ip_lock(port);
1117 assert(ip_active(port));
1118 assert(port->ip_receiver_name == MACH_PORT_NULL);
1119 dest = port->ip_destination;
1120
1121 ipc_port_destroy(port); /* consumes ref, unlocks */
1122
1123 if (dest != IP_NULL)
1124 ipc_port_release(dest);
1125 }
1126
1127 /*
1128 * Routine: ipc_port_alloc_special
1129 * Purpose:
1130 * Allocate a port in a special space.
1131 * The new port is returned with one ref.
1132 * If unsuccessful, IP_NULL is returned.
1133 * Conditions:
1134 * Nothing locked.
1135 */
1136
1137 ipc_port_t
1138 ipc_port_alloc_special(
1139 ipc_space_t space)
1140 {
1141 ipc_port_t port;
1142
1143 port = (ipc_port_t) io_alloc(IOT_PORT);
1144 if (port == IP_NULL)
1145 return IP_NULL;
1146
1147 bzero((char *)port, sizeof(*port));
1148 io_lock_init(&port->ip_object);
1149 port->ip_references = 1;
1150 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1151
1152 ipc_port_init(port, space, 1);
1153
1154 #if CONFIG_MACF_MACH
1155 /* Currently, ipc_port_alloc_special is used for two things:
1156 * - Reply ports for messages from the kernel
1157 * - Ports for communication with the kernel (e.g. task ports)
1158 * Since both of these would typically be labelled as kernel objects,
1159 * we will use a new entry point for this purpose, as current_task()
1160 * is often wrong (i.e. not kernel_task) or null.
1161 */
1162 mac_port_label_init(&port->ip_label);
1163 mac_port_label_associate_kernel(&port->ip_label, space == ipc_space_reply);
1164 #endif
1165
1166 return port;
1167 }
1168
1169 /*
1170 * Routine: ipc_port_dealloc_special
1171 * Purpose:
1172 * Deallocate a port in a special space.
1173 * Consumes one ref for the port.
1174 * Conditions:
1175 * Nothing locked.
1176 */
1177
1178 void
1179 ipc_port_dealloc_special(
1180 ipc_port_t port,
1181 __assert_only ipc_space_t space)
1182 {
1183 ip_lock(port);
1184 assert(ip_active(port));
1185 // assert(port->ip_receiver_name != MACH_PORT_NULL);
1186 assert(port->ip_receiver == space);
1187
1188 /*
1189 * We clear ip_receiver_name and ip_receiver to simplify
1190 * the ipc_space_kernel check in ipc_mqueue_send.
1191 */
1192
1193 port->ip_receiver_name = MACH_PORT_NULL;
1194 port->ip_receiver = IS_NULL;
1195
1196 /* relevant part of ipc_port_clear_receiver */
1197 ipc_port_set_mscount(port, 0);
1198 port->ip_messages.imq_seqno = 0;
1199
1200 ipc_port_destroy(port);
1201 }
1202
1203
1204 #if MACH_ASSERT
1205 #include <kern/machine.h>
1206
1207 /*
1208 * Keep a list of all allocated ports.
1209 * Allocation is intercepted via ipc_port_init;
1210 * deallocation is intercepted via io_free.
1211 */
1212 queue_head_t port_alloc_queue;
1213 decl_lck_mtx_data(,port_alloc_queue_lock)
1214 lck_mtx_ext_t port_alloc_queue_lock_ext;
1215
1216 unsigned long port_count = 0;
1217 unsigned long port_count_warning = 20000;
1218 unsigned long port_timestamp = 0;
1219
1220 void db_port_stack_trace(
1221 ipc_port_t port);
1222 void db_ref(
1223 int refs);
1224 int db_port_walk(
1225 unsigned int verbose,
1226 unsigned int display,
1227 unsigned int ref_search,
1228 unsigned int ref_target);
1229
1230 /*
1231 * Initialize global state needed for run-time
1232 * port debugging.
1233 */
1234 void
1235 ipc_port_debug_init(void)
1236 {
1237 queue_init(&port_alloc_queue);
1238 lck_mtx_init_ext(&port_alloc_queue_lock, &port_alloc_queue_lock_ext, &ipc_lck_grp, &ipc_lck_attr);
1239
1240 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt)))
1241 ipc_portbt = 0;
1242 }
1243
1244 #ifdef MACH_BSD
1245 extern int proc_pid(struct proc*);
1246 #endif /* MACH_BSD */
1247
1248 /*
1249 * Initialize all of the debugging state in a port.
1250 * Insert the port into a global list of all allocated ports.
1251 */
1252 void
1253 ipc_port_init_debug(
1254 ipc_port_t port)
1255 {
1256 unsigned int i;
1257
1258 port->ip_thread = current_thread();
1259 port->ip_timetrack = port_timestamp++;
1260 for (i = 0; i < IP_CALLSTACK_MAX; ++i)
1261 port->ip_callstack[i] = 0;
1262 for (i = 0; i < IP_NSPARES; ++i)
1263 port->ip_spares[i] = 0;
1264
1265 #ifdef MACH_BSD
1266 task_t task = current_task();
1267 if (task != TASK_NULL) {
1268 struct proc* proc = (struct proc*) get_bsdtask_info(task);
1269 if (proc)
1270 port->ip_spares[0] = proc_pid(proc);
1271 }
1272 #endif /* MACH_BSD */
1273
1274 /*
1275 * Machine-dependent routine to fill in an
1276 * array with up to IP_CALLSTACK_MAX levels
1277 * of return pc information.
1278 */
1279 if (ipc_portbt)
1280 machine_callstack(&port->ip_callstack[0], IP_CALLSTACK_MAX);
1281
1282 #if 0
1283 lck_mtx_lock(&port_alloc_queue_lock);
1284 ++port_count;
1285 if (port_count_warning > 0 && port_count >= port_count_warning)
1286 assert(port_count < port_count_warning);
1287 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1288 lck_mtx_unlock(&port_alloc_queue_lock);
1289 #endif
1290 }
1291
1292
1293 /*
1294 * Remove a port from the queue of allocated ports.
1295 * This routine should be invoked JUST prior to
1296 * deallocating the actual memory occupied by the port.
1297 */
1298 #if 1
1299 void
1300 ipc_port_track_dealloc(
1301 __unused ipc_port_t port)
1302 {
1303 }
1304 #else
1305 void
1306 ipc_port_track_dealloc(
1307 ipc_port_t port)
1308 {
1309 lck_mtx_lock(&port_alloc_queue_lock);
1310 assert(port_count > 0);
1311 --port_count;
1312 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1313 lck_mtx_unlock(&port_alloc_queue_lock);
1314 }
1315 #endif
1316
1317 #endif /* MACH_ASSERT */
1318
1319
1320 #if MACH_KDB
1321
1322 #include <ddb/db_output.h>
1323 #include <ddb/db_print.h>
1324
1325 #define printf kdbprintf
1326
1327 int
1328 db_port_queue_print(
1329 ipc_port_t port);
1330
1331 /*
1332 * Routine: ipc_port_print
1333 * Purpose:
1334 * Pretty-print a port for kdb.
1335 */
1336 int ipc_port_print_long = 0; /* set for more detail */
1337
1338 void
1339 ipc_port_print(
1340 ipc_port_t port,
1341 __unused boolean_t have_addr,
1342 __unused db_expr_t count,
1343 char *modif)
1344 {
1345 db_addr_t task;
1346 int task_id;
1347 int nmsgs;
1348 int verbose = 0;
1349 #if MACH_ASSERT
1350 int i, needs_db_indent, items_printed;
1351 #endif /* MACH_ASSERT */
1352
1353 if (db_option(modif, 'l') || db_option(modif, 'v'))
1354 ++verbose;
1355
1356 printf("port 0x%x\n", port);
1357
1358 db_indent += 2;
1359
1360 ipc_object_print(&port->ip_object);
1361
1362 if (ipc_port_print_long) {
1363 printf("\n");
1364 }
1365
1366 if (!ip_active(port)) {
1367 iprintf("timestamp=0x%x", port->ip_timestamp);
1368 } else if (port->ip_receiver_name == MACH_PORT_NULL) {
1369 iprintf("destination=0x%x (", port->ip_destination);
1370 if (port->ip_destination != MACH_PORT_NULL &&
1371 (task = db_task_from_space(port->ip_destination->
1372 ip_receiver, &task_id)))
1373 printf("task%d at 0x%x", task_id, task);
1374 else
1375 printf("unknown");
1376 printf(")");
1377 } else {
1378 iprintf("receiver=0x%x (", port->ip_receiver);
1379 if (port->ip_receiver == ipc_space_kernel)
1380 printf("kernel");
1381 else if (port->ip_receiver == ipc_space_reply)
1382 printf("reply");
1383 else if (port->ip_receiver == default_pager_space)
1384 printf("default_pager");
1385 else if ((task = db_task_from_space(port->ip_receiver, &task_id)) != (db_addr_t)0)
1386 printf("task%d at 0x%x", task_id, task);
1387 else
1388 printf("unknown");
1389 printf(")");
1390 }
1391 printf(", receiver_name=0x%x\n", port->ip_receiver_name);
1392
1393 iprintf("mscount=%d", port->ip_mscount);
1394 printf(", srights=%d", port->ip_srights);
1395 printf(", sorights=%d\n", port->ip_sorights);
1396
1397 iprintf("nsrequest=0x%x", port->ip_nsrequest);
1398 printf(", pdrequest=0x%x", port->ip_pdrequest);
1399 printf(", dnrequests=0x%x\n", port->ip_dnrequests);
1400
1401 iprintf("pset_count=0x%x", port->ip_pset_count);
1402 printf(", seqno=%d", port->ip_messages.imq_seqno);
1403 printf(", msgcount=%d", port->ip_messages.imq_msgcount);
1404 printf(", qlimit=%d\n", port->ip_messages.imq_qlimit);
1405
1406 iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
1407 printf(", rcvrs queue=0x%x", port->ip_messages.imq_wait_queue);
1408 printf(", kobj=0x%x\n", port->ip_kobject);
1409
1410 iprintf("premsg=0x%x", port->ip_premsg);
1411
1412 #if MACH_ASSERT
1413 /* don't bother printing callstack or queue links */
1414 iprintf("ip_thread=0x%x, ip_timetrack=0x%x\n",
1415 port->ip_thread, port->ip_timetrack);
1416 items_printed = 0;
1417 needs_db_indent = 1;
1418 for (i = 0; i < IP_NSPARES; ++i) {
1419 if (port->ip_spares[i] != 0) {
1420 if (needs_db_indent) {
1421 iprintf("");
1422 needs_db_indent = 0;
1423 }
1424 printf("%sip_spares[%d] = %d",
1425 items_printed ? ", " : "", i,
1426 port->ip_spares[i]);
1427 if (++items_printed >= 4) {
1428 needs_db_indent = 1;
1429 printf("\n");
1430 items_printed = 0;
1431 }
1432 }
1433 }
1434 #endif /* MACH_ASSERT */
1435
1436 if (verbose) {
1437 iprintf("kmsg queue contents:\n");
1438 db_indent += 2;
1439 nmsgs = db_port_queue_print(port);
1440 db_indent -= 2;
1441 iprintf("...total kmsgs: %d\n", nmsgs);
1442 }
1443
1444 db_indent -=2;
1445 }
1446
1447 ipc_port_t
1448 ipc_name_to_data(
1449 task_t task,
1450 mach_port_name_t name)
1451 {
1452 ipc_space_t space;
1453 ipc_entry_t entry;
1454
1455 if (task == TASK_NULL) {
1456 db_printf("port_name_to_data: task is null\n");
1457 return (0);
1458 }
1459 if ((space = task->itk_space) == 0) {
1460 db_printf("port_name_to_data: task->itk_space is null\n");
1461 return (0);
1462 }
1463 if (!space->is_active) {
1464 db_printf("port_name_to_data: task->itk_space not active\n");
1465 return (0);
1466 }
1467 if ((entry = ipc_entry_lookup(space, name)) == 0) {
1468 db_printf("port_name_to_data: lookup yields zero\n");
1469 return (0);
1470 }
1471 return ((ipc_port_t)entry->ie_object);
1472 }
1473
1474 #if ZONE_DEBUG
1475 void
1476 print_type_ports(type, dead)
1477 unsigned type;
1478 unsigned dead;
1479 {
1480 ipc_port_t port;
1481 int n;
1482
1483 n = 0;
1484 for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
1485 port;
1486 port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT],
1487 port))
1488 if (ip_kotype(port) == type &&
1489 (!dead || !ip_active(port))) {
1490 if (++n % 5)
1491 printf("0x%x\t", port);
1492 else
1493 printf("0x%x\n", port);
1494 }
1495 if (n % 5)
1496 printf("\n");
1497 }
1498
1499 void
1500 print_ports(void)
1501 {
1502 ipc_port_t port;
1503 int total_port_count;
1504 int space_null_count;
1505 int space_kernel_count;
1506 int space_reply_count;
1507 int space_pager_count;
1508 int space_other_count;
1509
1510 struct {
1511 int total_count;
1512 int dead_count;
1513 } port_types[IKOT_MAX_TYPE];
1514
1515 total_port_count = 0;
1516
1517 bzero((char *)&port_types[0], sizeof(port_types));
1518 space_null_count = 0;
1519 space_kernel_count = 0;
1520 space_reply_count = 0;
1521 space_pager_count = 0;
1522 space_other_count = 0;
1523
1524 for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
1525 port;
1526 port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT],
1527 port)) {
1528 total_port_count++;
1529 if (ip_kotype(port) >= IKOT_MAX_TYPE) {
1530 port_types[IKOT_UNKNOWN].total_count++;
1531 if (!io_active(&port->ip_object))
1532 port_types[IKOT_UNKNOWN].dead_count++;
1533 } else {
1534 port_types[ip_kotype(port)].total_count++;
1535 if (!io_active(&port->ip_object))
1536 port_types[ip_kotype(port)].dead_count++;
1537 }
1538
1539 if (!port->ip_receiver)
1540 space_null_count++;
1541 else if (port->ip_receiver == ipc_space_kernel)
1542 space_kernel_count++;
1543 else if (port->ip_receiver == ipc_space_reply)
1544 space_reply_count++;
1545 else if (port->ip_receiver == default_pager_space)
1546 space_pager_count++;
1547 else
1548 space_other_count++;
1549 }
1550 printf("\n%7d total ports\n\n", total_port_count);
1551
1552 #define PRINT_ONE_PORT_TYPE(name) \
1553 printf("%7d %s", port_types[IKOT_##name].total_count, # name); \
1554 if (port_types[IKOT_##name].dead_count) \
1555 printf(" (%d dead ports)", port_types[IKOT_##name].dead_count);\
1556 printf("\n");
1557
1558 PRINT_ONE_PORT_TYPE(NONE);
1559 PRINT_ONE_PORT_TYPE(THREAD);
1560 PRINT_ONE_PORT_TYPE(TASK);
1561 PRINT_ONE_PORT_TYPE(HOST);
1562 PRINT_ONE_PORT_TYPE(HOST_PRIV);
1563 PRINT_ONE_PORT_TYPE(PROCESSOR);
1564 PRINT_ONE_PORT_TYPE(PSET);
1565 PRINT_ONE_PORT_TYPE(PSET_NAME);
1566 PRINT_ONE_PORT_TYPE(TIMER);
1567 PRINT_ONE_PORT_TYPE(PAGING_REQUEST);
1568 PRINT_ONE_PORT_TYPE(MIG);
1569 PRINT_ONE_PORT_TYPE(MEMORY_OBJECT);
1570 PRINT_ONE_PORT_TYPE(XMM_PAGER);
1571 PRINT_ONE_PORT_TYPE(XMM_KERNEL);
1572 PRINT_ONE_PORT_TYPE(XMM_REPLY);
1573 PRINT_ONE_PORT_TYPE(UND_REPLY);
1574 PRINT_ONE_PORT_TYPE(HOST_NOTIFY);
1575 PRINT_ONE_PORT_TYPE(HOST_SECURITY);
1576 PRINT_ONE_PORT_TYPE(LEDGER);
1577 PRINT_ONE_PORT_TYPE(MASTER_DEVICE);
1578 PRINT_ONE_PORT_TYPE(TASK_NAME);
1579 PRINT_ONE_PORT_TYPE(SUBSYSTEM);
1580 PRINT_ONE_PORT_TYPE(IO_DONE_QUEUE);
1581 PRINT_ONE_PORT_TYPE(SEMAPHORE);
1582 PRINT_ONE_PORT_TYPE(LOCK_SET);
1583 PRINT_ONE_PORT_TYPE(CLOCK);
1584 PRINT_ONE_PORT_TYPE(CLOCK_CTRL);
1585 PRINT_ONE_PORT_TYPE(IOKIT_SPARE);
1586 PRINT_ONE_PORT_TYPE(NAMED_ENTRY);
1587 PRINT_ONE_PORT_TYPE(IOKIT_CONNECT);
1588 PRINT_ONE_PORT_TYPE(IOKIT_OBJECT);
1589 PRINT_ONE_PORT_TYPE(UPL);
1590 PRINT_ONE_PORT_TYPE(MEM_OBJ_CONTROL);
1591
1592 PRINT_ONE_PORT_TYPE(UNKNOWN);
1593 printf("\nipc_space:\n\n");
1594 printf("NULL KERNEL REPLY PAGER OTHER\n");
1595 printf("%d %d %d %d %d\n",
1596 space_null_count,
1597 space_kernel_count,
1598 space_reply_count,
1599 space_pager_count,
1600 space_other_count
1601 );
1602 }
1603
1604 #endif /* ZONE_DEBUG */
1605
1606
1607 /*
1608 * Print out all the kmsgs in a queue. Aggregate kmsgs with
1609 * identical message ids into a single entry. Count up the
1610 * amount of inline and out-of-line data consumed by each
1611 * and every kmsg.
1612 *
1613 */
1614
1615 #define KMSG_MATCH_FIELD(kmsg) (kmsg->ikm_header->msgh_id)
1616 #define DKQP_LONG(kmsg) FALSE
1617 const char *dkqp_long_format = "(%3d) <%10d> 0x%x %10d %10d\n";
1618 const char *dkqp_format = "(%3d) <%10d> 0x%x %10d %10d\n";
1619
1620 int
1621 db_kmsg_queue_print(
1622 ipc_kmsg_t kmsg);
1623 int
1624 db_kmsg_queue_print(
1625 ipc_kmsg_t kmsg)
1626 {
1627 ipc_kmsg_t ikmsg, first_kmsg;
1628 register int icount;
1629 mach_msg_id_t cur_id;
1630 unsigned int inline_total, ool_total;
1631 int nmsgs;
1632
1633 iprintf("Count msgh_id kmsg addr inline bytes ool bytes\n");
1634 inline_total = ool_total = (vm_size_t) 0;
1635 cur_id = KMSG_MATCH_FIELD(kmsg);
1636 for (icount = 0, nmsgs = 0, first_kmsg = ikmsg = kmsg;
1637 kmsg != IKM_NULL && (kmsg != first_kmsg || nmsgs == 0);
1638 kmsg = kmsg->ikm_next) {
1639 ++nmsgs;
1640 if (!(KMSG_MATCH_FIELD(kmsg) == cur_id)) {
1641 iprintf(DKQP_LONG(kmsg) ? dkqp_long_format:dkqp_format,
1642 icount, cur_id, ikmsg, inline_total,ool_total);
1643 cur_id = KMSG_MATCH_FIELD(kmsg);
1644 icount = 1;
1645 ikmsg = kmsg;
1646 inline_total = ool_total = 0;
1647 } else {
1648 icount++;
1649 }
1650 if (DKQP_LONG(kmsg))
1651 inline_total += kmsg->ikm_size;
1652 else
1653 inline_total += kmsg->ikm_header->msgh_size;
1654 }
1655 iprintf(DKQP_LONG(kmsg) ? dkqp_long_format : dkqp_format,
1656 icount, cur_id, ikmsg, inline_total, ool_total);
1657 return nmsgs;
1658 }
1659
1660
1661 /*
1662 * Process all of the messages on a port - prints out the
1663 * number of occurences of each message type, and the first
1664 * kmsg with a particular msgh_id.
1665 */
1666 int
1667 db_port_queue_print(
1668 ipc_port_t port)
1669 {
1670 ipc_kmsg_t kmsg;
1671
1672 if (ipc_kmsg_queue_empty(&port->ip_messages.imq_messages))
1673 return 0;
1674 kmsg = ipc_kmsg_queue_first(&port->ip_messages.imq_messages);
1675 return db_kmsg_queue_print(kmsg);
1676 }
1677
1678
1679 #if MACH_ASSERT
1680 #include <ddb/db_sym.h>
1681 #include <ddb/db_access.h>
1682
1683 #define FUNC_NULL ((void (*)) 0)
1684 #define MAX_REFS 5 /* bins for tracking ref counts */
1685
1686 /*
1687 * Translate port's cache of call stack pointers
1688 * into symbolic names.
1689 */
1690 void
1691 db_port_stack_trace(
1692 ipc_port_t port)
1693 {
1694 unsigned int i;
1695
1696 for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
1697 iprintf("[%d] 0x%x\t", i, port->ip_callstack[i]);
1698 if (port->ip_callstack[i] != 0 &&
1699 DB_VALID_KERN_ADDR(port->ip_callstack[i]))
1700 db_printsym(port->ip_callstack[i], DB_STGY_PROC);
1701 printf("\n");
1702 }
1703 }
1704
1705
1706 typedef struct port_item {
1707 unsigned long item;
1708 unsigned long count;
1709 } port_item;
1710
1711
1712 #define ITEM_MAX 400
1713 typedef struct port_track {
1714 const char *name;
1715 unsigned long max;
1716 unsigned long warning;
1717 port_item items[ITEM_MAX];
1718 } port_track;
1719
1720 port_track port_callers; /* match against calling addresses */
1721 port_track port_threads; /* match against allocating threads */
1722 port_track port_spaces; /* match against ipc spaces */
1723
1724 void port_track_init(
1725 port_track *trackp,
1726 const char *name);
1727 void port_item_add(
1728 port_track *trackp,
1729 unsigned long item);
1730 void port_track_sort(
1731 port_track *trackp);
1732 void port_track_print(
1733 port_track *trackp,
1734 void (*func)(port_item *));
1735 void port_callers_print(
1736 port_item *p);
1737
1738 void
1739 port_track_init(
1740 port_track *trackp,
1741 const char *name)
1742 {
1743 port_item *i;
1744
1745 trackp->max = trackp->warning = 0;
1746 trackp->name = name;
1747 for (i = trackp->items; i < trackp->items + ITEM_MAX; ++i)
1748 i->item = i->count = 0;
1749 }
1750
1751
1752 void
1753 port_item_add(
1754 port_track *trackp,
1755 unsigned long item)
1756 {
1757 port_item *limit, *i;
1758
1759 limit = trackp->items + trackp->max;
1760 for (i = trackp->items; i < limit; ++i)
1761 if (i->item == item) {
1762 i->count++;
1763 return;
1764 }
1765 if (trackp->max >= ITEM_MAX) {
1766 if (trackp->warning++ == 0)
1767 iprintf("%s: no room\n", trackp->name);
1768 return;
1769 }
1770 i->item = item;
1771 i->count = 1;
1772 trackp->max++;
1773 }
1774
1775
1776 /*
1777 * Simple (and slow) bubble sort.
1778 */
1779 void
1780 port_track_sort(
1781 port_track *trackp)
1782 {
1783 port_item *limit, *p;
1784 port_item temp;
1785 boolean_t unsorted;
1786
1787 limit = trackp->items + trackp->max - 1;
1788 do {
1789 unsorted = FALSE;
1790 for (p = trackp->items; p < limit - 1; ++p) {
1791 if (p->count < (p+1)->count) {
1792 temp = *p;
1793 *p = *(p+1);
1794 *(p+1) = temp;
1795 unsorted = TRUE;
1796 }
1797 }
1798 } while (unsorted == TRUE);
1799 }
1800
1801
1802 void
1803 port_track_print(
1804 port_track *trackp,
1805 void (*func)(port_item *))
1806 {
1807 port_item *limit, *p;
1808
1809 limit = trackp->items + trackp->max;
1810 iprintf("%s:\n", trackp->name);
1811 for (p = trackp->items; p < limit; ++p) {
1812 if (func != FUNC_NULL)
1813 (*func)(p);
1814 else
1815 iprintf("0x%x\t%8d\n", p->item, p->count);
1816 }
1817 }
1818
1819
1820 void
1821 port_callers_print(
1822 port_item *p)
1823 {
1824 iprintf("0x%x\t%8d\t", p->item, p->count);
1825 db_printsym(p->item, DB_STGY_PROC);
1826 printf("\n");
1827 }
1828
1829
1830 /*
1831 * Show all ports with a given reference count.
1832 */
1833 void
1834 db_ref(
1835 int refs)
1836 {
1837 db_port_walk(1, 1, 1, refs);
1838 }
1839
1840
1841 /*
1842 * Examine all currently allocated ports.
1843 * Options:
1844 * verbose display suspicious ports
1845 * display print out each port encountered
1846 * ref_search restrict examination to ports with
1847 * a specified reference count
1848 * ref_target reference count for ref_search
1849 */
1850 int
1851 db_port_walk(
1852 unsigned int verbose,
1853 unsigned int display,
1854 unsigned int ref_search,
1855 unsigned int ref_target)
1856 {
1857 ipc_port_t port;
1858 unsigned int ref_overflow, refs, i, ref_inactive_overflow;
1859 unsigned int no_receiver, no_match;
1860 unsigned int ref_counts[MAX_REFS];
1861 unsigned int inactive[MAX_REFS];
1862 unsigned int ipc_ports = 0;
1863
1864 iprintf("Allocated port count is %d\n", port_count);
1865 no_receiver = no_match = ref_overflow = 0;
1866 ref_inactive_overflow = 0;
1867 for (i = 0; i < MAX_REFS; ++i) {
1868 ref_counts[i] = 0;
1869 inactive[i] = 0;
1870 }
1871 port_track_init(&port_callers, "port callers");
1872 port_track_init(&port_threads, "port threads");
1873 port_track_init(&port_spaces, "port spaces");
1874 if (ref_search)
1875 iprintf("Walking ports of ref_count=%d.\n", ref_target);
1876 else
1877 iprintf("Walking all ports.\n");
1878
1879 queue_iterate(&port_alloc_queue, port, ipc_port_t, ip_port_links) {
1880 const char *port_type;
1881
1882 port_type = " IPC port";
1883 if (ip_active(port))
1884 ipc_ports++;
1885
1886 refs = port->ip_references;
1887 if (ref_search && refs != ref_target)
1888 continue;
1889
1890 if (refs >= MAX_REFS) {
1891 if (ip_active(port))
1892 ++ref_overflow;
1893 else
1894 ++ref_inactive_overflow;
1895 } else {
1896 if (refs == 0 && verbose)
1897 iprintf("%s 0x%x has ref count of zero!\n",
1898 port_type, port);
1899 if (ip_active(port))
1900 ref_counts[refs]++;
1901 else
1902 inactive[refs]++;
1903 }
1904 port_item_add(&port_threads, (unsigned long) port->ip_thread);
1905 for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
1906 if (port->ip_callstack[i] != 0 &&
1907 DB_VALID_KERN_ADDR(port->ip_callstack[i]))
1908 port_item_add(&port_callers,
1909 port->ip_callstack[i]);
1910 }
1911 if (!ip_active(port)) {
1912 if (verbose)
1913 iprintf("%s 0x%x, inactive, refcnt %d\n",
1914 port_type, port, refs);
1915 continue;
1916 }
1917
1918 if (port->ip_receiver_name == MACH_PORT_NULL) {
1919 iprintf("%s 0x%x, no receiver, refcnt %d\n",
1920 port, refs);
1921 ++no_receiver;
1922 continue;
1923 }
1924 if (port->ip_receiver == ipc_space_kernel ||
1925 port->ip_receiver == ipc_space_reply ||
1926 ipc_entry_lookup(port->ip_receiver,
1927 port->ip_receiver_name)
1928 != IE_NULL) {
1929 port_item_add(&port_spaces,
1930 (unsigned long)port->ip_receiver);
1931 if (display) {
1932 iprintf( "%s 0x%x time 0x%x ref_cnt %d\n",
1933 port_type, port,
1934 port->ip_timetrack, refs);
1935 }
1936 continue;
1937 }
1938 iprintf("%s 0x%x, rcvr 0x%x, name 0x%x, ref %d, no match\n",
1939 port_type, port, port->ip_receiver,
1940 port->ip_receiver_name, refs);
1941 ++no_match;
1942 }
1943 iprintf("Active port type summary:\n");
1944 iprintf("\tlocal IPC %6d\n", ipc_ports);
1945 iprintf("summary:\tcallers %d threads %d spaces %d\n",
1946 port_callers.max, port_threads.max, port_spaces.max);
1947
1948 iprintf("\tref_counts:\n");
1949 for (i = 0; i < MAX_REFS; ++i)
1950 iprintf("\t ref_counts[%d] = %d\n", i, ref_counts[i]);
1951
1952 iprintf("\t%d ports w/o receivers, %d w/o matches\n",
1953 no_receiver, no_match);
1954
1955 iprintf("\tinactives:");
1956 if ( ref_inactive_overflow || inactive[0] || inactive[1] ||
1957 inactive[2] || inactive[3] || inactive[4] )
1958 printf(" [0]=%d [1]=%d [2]=%d [3]=%d [4]=%d [5+]=%d\n",
1959 inactive[0], inactive[1], inactive[2],
1960 inactive[3], inactive[4], ref_inactive_overflow);
1961 else
1962 printf(" No inactive ports.\n");
1963
1964 port_track_sort(&port_spaces);
1965 port_track_print(&port_spaces, FUNC_NULL);
1966 port_track_sort(&port_threads);
1967 port_track_print(&port_threads, FUNC_NULL);
1968 port_track_sort(&port_callers);
1969 port_track_print(&port_callers, port_callers_print);
1970 return 0;
1971 }
1972
1973
1974 #endif /* MACH_ASSERT */
1975
1976 #endif /* MACH_KDB */