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