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