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