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