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