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