]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_port.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_port.c
1 /*
2 * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * 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>
69 #include <kern/thread.h>
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
91 decl_mutex_data(, ipc_port_multiple_lock_data)
92 decl_mutex_data(, ipc_port_timestamp_lock_data)
93 ipc_port_timestamp_t ipc_port_timestamp_data;
94
95 #if MACH_ASSERT
96 void ipc_port_init_debug(
97 ipc_port_t port);
98 #endif /* MACH_ASSERT */
99
100 #if MACH_KDB && ZONE_DEBUG
101 /* Forwards */
102 void print_type_ports(unsigned, unsigned);
103 void 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
112 ipc_port_timestamp_t
113 ipc_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
137 kern_return_t
138 ipc_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
186 kern_return_t
187 ipc_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
295 ipc_port_t
296 ipc_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
336 void
337 ipc_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
365 void
366 ipc_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
402 void
403 ipc_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) {
414 ipc_pset_remove_from_all(port);
415 assert(port->ip_pset_count == 0);
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
438 void
439 ipc_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
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
481 kern_return_t
482 ipc_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 if (task_is_classic(current_task())) {
502 IP_SET_CLASSIC(port);
503 }
504
505 *namep = name;
506 *portp = port;
507
508 return KERN_SUCCESS;
509 }
510
511 /*
512 * Routine: ipc_port_alloc_name
513 * Purpose:
514 * Allocate a port, with a specific name.
515 * Conditions:
516 * Nothing locked. If successful, the port is returned
517 * locked. (The caller doesn't have a reference.)
518 * Returns:
519 * KERN_SUCCESS The port is allocated.
520 * KERN_INVALID_TASK The space is dead.
521 * KERN_NAME_EXISTS The name already denotes a right.
522 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
523 */
524
525 kern_return_t
526 ipc_port_alloc_name(
527 ipc_space_t space,
528 mach_port_name_t name,
529 ipc_port_t *portp)
530 {
531 ipc_port_t port;
532 kern_return_t kr;
533
534 kr = ipc_object_alloc_name(space, IOT_PORT,
535 MACH_PORT_TYPE_RECEIVE, 0,
536 name, (ipc_object_t *) &port);
537 if (kr != KERN_SUCCESS)
538 return kr;
539
540 /* port is locked */
541
542 ipc_port_init(port, space, name);
543
544 if (task_is_classic(current_task())) {
545 IP_SET_CLASSIC(port);
546 }
547
548 *portp = port;
549
550 return KERN_SUCCESS;
551 }
552
553 /*
554 * Generate dead name notifications. Called from ipc_port_destroy.
555 * Port is unlocked but still has reference(s);
556 * dnrequests was taken from port while the port
557 * was locked but the port now has port->ip_dnrequests set to IPR_NULL.
558 */
559 void
560 ipc_port_dnnotify(
561 ipc_port_t port,
562 ipc_port_request_t dnrequests)
563 {
564 ipc_table_size_t its = dnrequests->ipr_size;
565 ipc_table_elems_t size = its->its_size;
566 ipc_port_request_index_t index;
567
568 for (index = 1; index < size; index++) {
569 ipc_port_request_t ipr = &dnrequests[index];
570 mach_port_name_t name = ipr->ipr_name;
571 ipc_port_t soright;
572
573 if (name == MACH_PORT_NULL)
574 continue;
575
576 soright = ipr->ipr_soright;
577 assert(soright != IP_NULL);
578
579 ipc_notify_dead_name(soright, name);
580 }
581
582 it_dnrequests_free(its, dnrequests);
583 }
584
585 /*
586 * Routine: ipc_port_destroy
587 * Purpose:
588 * Destroys a port. Cleans up queued messages.
589 *
590 * If the port has a backup, it doesn't get destroyed,
591 * but is sent in a port-destroyed notification to the backup.
592 * Conditions:
593 * The port is locked and alive; nothing else locked.
594 * The caller has a reference, which is consumed.
595 * Afterwards, the port is unlocked and dead.
596 */
597
598 void
599 ipc_port_destroy(
600 ipc_port_t port)
601 {
602 ipc_port_t pdrequest, nsrequest;
603 ipc_mqueue_t mqueue;
604 ipc_kmsg_queue_t kmqueue;
605 ipc_kmsg_t kmsg;
606 ipc_port_request_t dnrequests;
607
608 assert(ip_active(port));
609 /* port->ip_receiver_name is garbage */
610 /* port->ip_receiver/port->ip_destination is garbage */
611 assert(port->ip_pset_count == 0);
612 assert(port->ip_mscount == 0);
613
614 /* first check for a backup port */
615
616 pdrequest = port->ip_pdrequest;
617 if (pdrequest != IP_NULL) {
618 /* we assume the ref for pdrequest */
619 port->ip_pdrequest = IP_NULL;
620
621 /* make port be in limbo */
622 port->ip_receiver_name = MACH_PORT_NULL;
623 port->ip_destination = IP_NULL;
624 ip_unlock(port);
625
626 /* consumes our refs for port and pdrequest */
627 ipc_notify_port_destroyed(pdrequest, port);
628 return;
629 }
630
631 /* once port is dead, we don't need to keep it locked */
632
633 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
634 port->ip_timestamp = ipc_port_timestamp();
635
636 /* save for later */
637 dnrequests = port->ip_dnrequests;
638 port->ip_dnrequests = IPR_NULL;
639
640 /*
641 * If the port has a preallocated message buffer and that buffer
642 * is not inuse, free it. If it has an inuse one, then the kmsg
643 * free will detect that we freed the association and it can free it
644 * like a normal buffer.
645 */
646 if (IP_PREALLOC(port)) {
647 kmsg = port->ip_premsg;
648 assert(kmsg != IKM_NULL);
649 IP_CLEAR_PREALLOC(port, kmsg);
650 if (!ikm_prealloc_inuse(kmsg))
651 ipc_kmsg_free(kmsg);
652 }
653 ip_unlock(port);
654
655 /* throw away no-senders request */
656
657 nsrequest = port->ip_nsrequest;
658 if (nsrequest != IP_NULL)
659 ipc_notify_send_once(nsrequest); /* consumes ref */
660
661 /* destroy any queued messages */
662 mqueue = &port->ip_messages;
663 ipc_mqueue_destroy(mqueue);
664
665 /* generate dead-name notifications */
666 if (dnrequests != IPR_NULL) {
667 ipc_port_dnnotify(port, dnrequests);
668 }
669
670 ipc_kobject_destroy(port);
671
672 ipc_port_release(port); /* consume caller's ref */
673 }
674
675 /*
676 * Routine: ipc_port_check_circularity
677 * Purpose:
678 * Check if queueing "port" in a message for "dest"
679 * would create a circular group of ports and messages.
680 *
681 * If no circularity (FALSE returned), then "port"
682 * is changed from "in limbo" to "in transit".
683 *
684 * That is, we want to set port->ip_destination == dest,
685 * but guaranteeing that this doesn't create a circle
686 * port->ip_destination->ip_destination->... == port
687 * Conditions:
688 * No ports locked. References held for "port" and "dest".
689 */
690
691 boolean_t
692 ipc_port_check_circularity(
693 ipc_port_t port,
694 ipc_port_t dest)
695 {
696 ipc_port_t base;
697
698 assert(port != IP_NULL);
699 assert(dest != IP_NULL);
700
701 if (port == dest)
702 return TRUE;
703 base = dest;
704
705 /*
706 * First try a quick check that can run in parallel.
707 * No circularity if dest is not in transit.
708 */
709
710 ip_lock(port);
711 if (ip_lock_try(dest)) {
712 if (!ip_active(dest) ||
713 (dest->ip_receiver_name != MACH_PORT_NULL) ||
714 (dest->ip_destination == IP_NULL))
715 goto not_circular;
716
717 /* dest is in transit; further checking necessary */
718
719 ip_unlock(dest);
720 }
721 ip_unlock(port);
722
723 ipc_port_multiple_lock(); /* massive serialization */
724
725 /*
726 * Search for the end of the chain (a port not in transit),
727 * acquiring locks along the way.
728 */
729
730 for (;;) {
731 ip_lock(base);
732
733 if (!ip_active(base) ||
734 (base->ip_receiver_name != MACH_PORT_NULL) ||
735 (base->ip_destination == IP_NULL))
736 break;
737
738 base = base->ip_destination;
739 }
740
741 /* all ports in chain from dest to base, inclusive, are locked */
742
743 if (port == base) {
744 /* circularity detected! */
745
746 ipc_port_multiple_unlock();
747
748 /* port (== base) is in limbo */
749
750 assert(ip_active(port));
751 assert(port->ip_receiver_name == MACH_PORT_NULL);
752 assert(port->ip_destination == IP_NULL);
753
754 while (dest != IP_NULL) {
755 ipc_port_t next;
756
757 /* dest is in transit or in limbo */
758
759 assert(ip_active(dest));
760 assert(dest->ip_receiver_name == MACH_PORT_NULL);
761
762 next = dest->ip_destination;
763 ip_unlock(dest);
764 dest = next;
765 }
766
767 return TRUE;
768 }
769
770 /*
771 * The guarantee: lock port while the entire chain is locked.
772 * Once port is locked, we can take a reference to dest,
773 * add port to the chain, and unlock everything.
774 */
775
776 ip_lock(port);
777 ipc_port_multiple_unlock();
778
779 not_circular:
780
781 /* port is in limbo */
782
783 assert(ip_active(port));
784 assert(port->ip_receiver_name == MACH_PORT_NULL);
785 assert(port->ip_destination == IP_NULL);
786
787 ip_reference(dest);
788 port->ip_destination = dest;
789
790 /* now unlock chain */
791
792 while (port != base) {
793 ipc_port_t next;
794
795 /* port is in transit */
796
797 assert(ip_active(port));
798 assert(port->ip_receiver_name == MACH_PORT_NULL);
799 assert(port->ip_destination != IP_NULL);
800
801 next = port->ip_destination;
802 ip_unlock(port);
803 port = next;
804 }
805
806 /* base is not in transit */
807
808 assert(!ip_active(base) ||
809 (base->ip_receiver_name != MACH_PORT_NULL) ||
810 (base->ip_destination == IP_NULL));
811 ip_unlock(base);
812
813 return FALSE;
814 }
815
816 /*
817 * Routine: ipc_port_lookup_notify
818 * Purpose:
819 * Make a send-once notify port from a receive right.
820 * Returns IP_NULL if name doesn't denote a receive right.
821 * Conditions:
822 * The space must be locked (read or write) and active.
823 * Being the active space, we can rely on thread server_id
824 * context to give us the proper server level sub-order
825 * within the space.
826 */
827
828 ipc_port_t
829 ipc_port_lookup_notify(
830 ipc_space_t space,
831 mach_port_name_t name)
832 {
833 ipc_port_t port;
834 ipc_entry_t entry;
835
836 assert(space->is_active);
837
838 entry = ipc_entry_lookup(space, name);
839 if (entry == IE_NULL)
840 return IP_NULL;
841 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
842 return IP_NULL;
843
844 port = (ipc_port_t) entry->ie_object;
845 assert(port != IP_NULL);
846
847 ip_lock(port);
848 assert(ip_active(port));
849 assert(port->ip_receiver_name == name);
850 assert(port->ip_receiver == space);
851
852 ip_reference(port);
853 port->ip_sorights++;
854 ip_unlock(port);
855
856 return port;
857 }
858
859 /*
860 * Routine: ipc_port_make_send_locked
861 * Purpose:
862 * Make a naked send right from a receive right.
863 *
864 * Conditions:
865 * port locked and active.
866 */
867 ipc_port_t
868 ipc_port_make_send_locked(
869 ipc_port_t port)
870 {
871 assert(ip_active(port));
872 port->ip_mscount++;
873 port->ip_srights++;
874 ip_reference(port);
875 ip_unlock(port);
876 return port;
877 }
878
879 /*
880 * Routine: ipc_port_make_send
881 * Purpose:
882 * Make a naked send right from a receive right.
883 */
884
885 ipc_port_t
886 ipc_port_make_send(
887 ipc_port_t port)
888 {
889
890 if (!IP_VALID(port))
891 return port;
892
893 ip_lock(port);
894 if (ip_active(port)) {
895 port->ip_mscount++;
896 port->ip_srights++;
897 ip_reference(port);
898 ip_unlock(port);
899 return port;
900 }
901 ip_unlock(port);
902 return IP_DEAD;
903 }
904
905 /*
906 * Routine: ipc_port_copy_send
907 * Purpose:
908 * Make a naked send right from another naked send right.
909 * IP_NULL -> IP_NULL
910 * IP_DEAD -> IP_DEAD
911 * dead port -> IP_DEAD
912 * live port -> port + ref
913 * Conditions:
914 * Nothing locked except possibly a space.
915 */
916
917 ipc_port_t
918 ipc_port_copy_send(
919 ipc_port_t port)
920 {
921 ipc_port_t sright;
922
923 if (!IP_VALID(port))
924 return port;
925
926 ip_lock(port);
927 if (ip_active(port)) {
928 assert(port->ip_srights > 0);
929
930 ip_reference(port);
931 port->ip_srights++;
932 sright = port;
933 } else
934 sright = IP_DEAD;
935 ip_unlock(port);
936
937 return sright;
938 }
939
940 /*
941 * Routine: ipc_port_copyout_send
942 * Purpose:
943 * Copyout a naked send right (possibly null/dead),
944 * or if that fails, destroy the right.
945 * Conditions:
946 * Nothing locked.
947 */
948
949 mach_port_name_t
950 ipc_port_copyout_send(
951 ipc_port_t sright,
952 ipc_space_t space)
953 {
954 mach_port_name_t name;
955
956 if (IP_VALID(sright)) {
957 kern_return_t kr;
958
959 kr = ipc_object_copyout(space, (ipc_object_t) sright,
960 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
961 if (kr != KERN_SUCCESS) {
962 ipc_port_release_send(sright);
963
964 if (kr == KERN_INVALID_CAPABILITY)
965 name = MACH_PORT_DEAD;
966 else
967 name = MACH_PORT_NULL;
968 }
969 } else
970 name = (mach_port_name_t) sright;
971
972 return name;
973 }
974
975 /*
976 * Routine: ipc_port_release_send
977 * Purpose:
978 * Release a (valid) naked send right.
979 * Consumes a ref for the port.
980 * Conditions:
981 * Nothing locked.
982 */
983
984 void
985 ipc_port_release_send(
986 ipc_port_t port)
987 {
988 ipc_port_t nsrequest = IP_NULL;
989 mach_port_mscount_t mscount;
990
991 assert(IP_VALID(port));
992
993 ip_lock(port);
994 ip_release(port);
995
996 if (!ip_active(port)) {
997 ip_check_unlock(port);
998 return;
999 }
1000
1001 assert(port->ip_srights > 0);
1002
1003 if (--port->ip_srights == 0 &&
1004 port->ip_nsrequest != IP_NULL) {
1005 nsrequest = port->ip_nsrequest;
1006 port->ip_nsrequest = IP_NULL;
1007 mscount = port->ip_mscount;
1008 ip_unlock(port);
1009 ipc_notify_no_senders(nsrequest, mscount);
1010 /*
1011 * Check that there are no other locks taken, because
1012 * [norma_]ipc_notify_no_senders routines may block.
1013 */
1014 check_simple_locks();
1015 } else
1016 ip_unlock(port);
1017 }
1018
1019 /*
1020 * Routine: ipc_port_make_sonce
1021 * Purpose:
1022 * Make a naked send-once right from a receive right.
1023 * Conditions:
1024 * The port is not locked but it is active.
1025 */
1026
1027 ipc_port_t
1028 ipc_port_make_sonce(
1029 ipc_port_t port)
1030 {
1031 assert(IP_VALID(port));
1032
1033 ip_lock(port);
1034 assert(ip_active(port));
1035 port->ip_sorights++;
1036 ip_reference(port);
1037 ip_unlock(port);
1038
1039 return port;
1040 }
1041
1042 /*
1043 * Routine: ipc_port_release_sonce
1044 * Purpose:
1045 * Release a naked send-once right.
1046 * Consumes a ref for the port.
1047 *
1048 * In normal situations, this is never used.
1049 * Send-once rights are only consumed when
1050 * a message (possibly a send-once notification)
1051 * is sent to them.
1052 * Conditions:
1053 * Nothing locked except possibly a space.
1054 */
1055
1056 void
1057 ipc_port_release_sonce(
1058 ipc_port_t port)
1059 {
1060 assert(IP_VALID(port));
1061
1062 ip_lock(port);
1063
1064 assert(port->ip_sorights > 0);
1065
1066 port->ip_sorights--;
1067
1068 ip_release(port);
1069
1070 if (!ip_active(port)) {
1071 ip_check_unlock(port);
1072 return;
1073 }
1074
1075 ip_unlock(port);
1076 }
1077
1078 /*
1079 * Routine: ipc_port_release_receive
1080 * Purpose:
1081 * Release a naked (in limbo or in transit) receive right.
1082 * Consumes a ref for the port; destroys the port.
1083 * Conditions:
1084 * Nothing locked.
1085 */
1086
1087 void
1088 ipc_port_release_receive(
1089 ipc_port_t port)
1090 {
1091 ipc_port_t dest;
1092
1093 assert(IP_VALID(port));
1094
1095 ip_lock(port);
1096 assert(ip_active(port));
1097 assert(port->ip_receiver_name == MACH_PORT_NULL);
1098 dest = port->ip_destination;
1099
1100 ipc_port_destroy(port); /* consumes ref, unlocks */
1101
1102 if (dest != IP_NULL)
1103 ipc_port_release(dest);
1104 }
1105
1106 /*
1107 * Routine: ipc_port_alloc_special
1108 * Purpose:
1109 * Allocate a port in a special space.
1110 * The new port is returned with one ref.
1111 * If unsuccessful, IP_NULL is returned.
1112 * Conditions:
1113 * Nothing locked.
1114 */
1115
1116 ipc_port_t
1117 ipc_port_alloc_special(
1118 ipc_space_t space)
1119 {
1120 ipc_port_t port;
1121
1122 port = (ipc_port_t) io_alloc(IOT_PORT);
1123 if (port == IP_NULL)
1124 return IP_NULL;
1125
1126 bzero((char *)port, sizeof(*port));
1127 io_lock_init(&port->ip_object);
1128 port->ip_references = 1;
1129 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1130
1131 ipc_port_init(port, space, 1);
1132
1133 return port;
1134 }
1135
1136 /*
1137 * Routine: ipc_port_dealloc_special
1138 * Purpose:
1139 * Deallocate a port in a special space.
1140 * Consumes one ref for the port.
1141 * Conditions:
1142 * Nothing locked.
1143 */
1144
1145 void
1146 ipc_port_dealloc_special(
1147 ipc_port_t port,
1148 ipc_space_t space)
1149 {
1150 ip_lock(port);
1151 assert(ip_active(port));
1152 // assert(port->ip_receiver_name != MACH_PORT_NULL);
1153 assert(port->ip_receiver == space);
1154
1155 /*
1156 * We clear ip_receiver_name and ip_receiver to simplify
1157 * the ipc_space_kernel check in ipc_mqueue_send.
1158 */
1159
1160 port->ip_receiver_name = MACH_PORT_NULL;
1161 port->ip_receiver = IS_NULL;
1162
1163 /* relevant part of ipc_port_clear_receiver */
1164 ipc_port_set_mscount(port, 0);
1165 port->ip_messages.imq_seqno = 0;
1166
1167 ipc_port_destroy(port);
1168 }
1169
1170
1171 #if MACH_ASSERT
1172 /*
1173 * Keep a list of all allocated ports.
1174 * Allocation is intercepted via ipc_port_init;
1175 * deallocation is intercepted via io_free.
1176 */
1177 queue_head_t port_alloc_queue;
1178 decl_mutex_data(,port_alloc_queue_lock)
1179
1180 unsigned long port_count = 0;
1181 unsigned long port_count_warning = 20000;
1182 unsigned long port_timestamp = 0;
1183
1184 void db_port_stack_trace(
1185 ipc_port_t port);
1186 void db_ref(
1187 int refs);
1188 int db_port_walk(
1189 unsigned int verbose,
1190 unsigned int display,
1191 unsigned int ref_search,
1192 unsigned int ref_target);
1193
1194 /*
1195 * Initialize global state needed for run-time
1196 * port debugging.
1197 */
1198 void
1199 ipc_port_debug_init(void)
1200 {
1201 queue_init(&port_alloc_queue);
1202 mutex_init(&port_alloc_queue_lock, ETAP_IPC_PORT_ALLOCQ);
1203 }
1204
1205
1206 /*
1207 * Initialize all of the debugging state in a port.
1208 * Insert the port into a global list of all allocated ports.
1209 */
1210 void
1211 ipc_port_init_debug(
1212 ipc_port_t port)
1213 {
1214 unsigned int i;
1215
1216 port->ip_thread = (unsigned long) current_thread();
1217 port->ip_timetrack = port_timestamp++;
1218 for (i = 0; i < IP_CALLSTACK_MAX; ++i)
1219 port->ip_callstack[i] = 0;
1220 for (i = 0; i < IP_NSPARES; ++i)
1221 port->ip_spares[i] = 0;
1222
1223 /*
1224 * Machine-dependent routine to fill in an
1225 * array with up to IP_CALLSTACK_MAX levels
1226 * of return pc information.
1227 */
1228 machine_callstack(&port->ip_callstack[0], IP_CALLSTACK_MAX);
1229
1230 #if 0
1231 mutex_lock(&port_alloc_queue_lock);
1232 ++port_count;
1233 if (port_count_warning > 0 && port_count >= port_count_warning)
1234 assert(port_count < port_count_warning);
1235 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1236 mutex_unlock(&port_alloc_queue_lock);
1237 #endif
1238 }
1239
1240
1241 /*
1242 * Remove a port from the queue of allocated ports.
1243 * This routine should be invoked JUST prior to
1244 * deallocating the actual memory occupied by the port.
1245 */
1246 void
1247 ipc_port_track_dealloc(
1248 ipc_port_t port)
1249 {
1250 #if 0
1251 mutex_lock(&port_alloc_queue_lock);
1252 assert(port_count > 0);
1253 --port_count;
1254 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1255 mutex_unlock(&port_alloc_queue_lock);
1256 #endif
1257 }
1258
1259 #endif /* MACH_ASSERT */
1260
1261
1262 #if MACH_KDB
1263
1264 #include <ddb/db_output.h>
1265 #include <ddb/db_print.h>
1266
1267 #define printf kdbprintf
1268 extern int db_indent;
1269
1270 int
1271 db_port_queue_print(
1272 ipc_port_t port);
1273
1274 /*
1275 * ipc_entry_print - pretty-print an ipc_entry
1276 */
1277 static void ipc_entry_print(struct ipc_entry *, char *); /* forward */
1278
1279 static void ipc_entry_print(struct ipc_entry *iep, char *tag)
1280 {
1281 ipc_entry_bits_t bits = iep->ie_bits;
1282
1283 iprintf("%s @", tag);
1284 printf(" 0x%x, bits=%x object=%x\n", iep, bits, iep->ie_object);
1285 db_indent += 2;
1286 iprintf("urefs=%x ", IE_BITS_UREFS(bits));
1287 printf("type=%x gen=%x\n", IE_BITS_TYPE(bits), IE_BITS_GEN(bits));
1288 db_indent -= 2;
1289 }
1290
1291 /*
1292 * Routine: ipc_port_print
1293 * Purpose:
1294 * Pretty-print a port for kdb.
1295 */
1296 int ipc_port_print_long = 0; /* set for more detail */
1297
1298 void
1299 ipc_port_print(
1300 ipc_port_t port,
1301 boolean_t have_addr,
1302 db_expr_t count,
1303 char *modif)
1304 {
1305 extern int db_indent;
1306 db_addr_t task;
1307 int task_id;
1308 int nmsgs;
1309 int verbose = 0;
1310 #if MACH_ASSERT
1311 int i, needs_db_indent, items_printed;
1312 #endif /* MACH_ASSERT */
1313
1314 if (db_option(modif, 'l') || db_option(modif, 'v'))
1315 ++verbose;
1316
1317 printf("port 0x%x\n", port);
1318
1319 db_indent += 2;
1320
1321 ipc_object_print(&port->ip_object);
1322
1323 if (ipc_port_print_long) {
1324 printf("\n");
1325 }
1326
1327 if (!ip_active(port)) {
1328 iprintf("timestamp=0x%x", port->ip_timestamp);
1329 } else if (port->ip_receiver_name == MACH_PORT_NULL) {
1330 iprintf("destination=0x%x (", port->ip_destination);
1331 if (port->ip_destination != MACH_PORT_NULL &&
1332 (task = db_task_from_space(port->ip_destination->
1333 ip_receiver, &task_id)))
1334 printf("task%d at 0x%x", task_id, task);
1335 else
1336 printf("unknown");
1337 printf(")");
1338 } else {
1339 iprintf("receiver=0x%x (", port->ip_receiver);
1340 if (port->ip_receiver == ipc_space_kernel)
1341 printf("kernel");
1342 else if (port->ip_receiver == ipc_space_reply)
1343 printf("reply");
1344 else if (port->ip_receiver == default_pager_space)
1345 printf("default_pager");
1346 else if (task = db_task_from_space(port->ip_receiver, &task_id))
1347 printf("task%d at 0x%x", task_id, task);
1348 else
1349 printf("unknown");
1350 printf(")");
1351 }
1352 printf(", receiver_name=0x%x\n", port->ip_receiver_name);
1353
1354 iprintf("mscount=%d", port->ip_mscount);
1355 printf(", srights=%d", port->ip_srights);
1356 printf(", sorights=%d\n", port->ip_sorights);
1357
1358 iprintf("nsrequest=0x%x", port->ip_nsrequest);
1359 printf(", pdrequest=0x%x", port->ip_pdrequest);
1360 printf(", dnrequests=0x%x\n", port->ip_dnrequests);
1361
1362 iprintf("pset_count=0x%x", port->ip_pset_count);
1363 printf(", seqno=%d", port->ip_messages.imq_seqno);
1364 printf(", msgcount=%d", port->ip_messages.imq_msgcount);
1365 printf(", qlimit=%d\n", port->ip_messages.imq_qlimit);
1366
1367 iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
1368 printf(", rcvrs queue=0x%x", port->ip_messages.imq_wait_queue);
1369 printf(", kobj=0x%x\n", port->ip_kobject);
1370
1371 iprintf("premsg=0x%x", port->ip_premsg);
1372
1373 #if MACH_ASSERT
1374 /* don't bother printing callstack or queue links */
1375 iprintf("ip_thread=0x%x, ip_timetrack=0x%x\n",
1376 port->ip_thread, port->ip_timetrack);
1377 items_printed = 0;
1378 needs_db_indent = 1;
1379 for (i = 0; i < IP_NSPARES; ++i) {
1380 if (port->ip_spares[i] != 0) {
1381 if (needs_db_indent) {
1382 iprintf("");
1383 needs_db_indent = 0;
1384 }
1385 printf("%sip_spares[%d] = %d",
1386 items_printed ? ", " : "", i,
1387 port->ip_spares[i]);
1388 if (++items_printed >= 4) {
1389 needs_db_indent = 1;
1390 printf("\n");
1391 items_printed = 0;
1392 }
1393 }
1394 }
1395 #endif /* MACH_ASSERT */
1396
1397 if (verbose) {
1398 iprintf("kmsg queue contents:\n");
1399 db_indent += 2;
1400 nmsgs = db_port_queue_print(port);
1401 db_indent -= 2;
1402 iprintf("...total kmsgs: %d\n", nmsgs);
1403 }
1404
1405 db_indent -=2;
1406 }
1407
1408 ipc_port_t
1409 ipc_name_to_data(
1410 task_t task,
1411 mach_port_name_t name)
1412 {
1413 ipc_space_t space;
1414 ipc_entry_t entry;
1415
1416 if (task == TASK_NULL) {
1417 db_printf("port_name_to_data: task is null\n");
1418 return (0);
1419 }
1420 if ((space = task->itk_space) == 0) {
1421 db_printf("port_name_to_data: task->itk_space is null\n");
1422 return (0);
1423 }
1424 if (!space->is_active) {
1425 db_printf("port_name_to_data: task->itk_space not active\n");
1426 return (0);
1427 }
1428 if ((entry = ipc_entry_lookup(space, name)) == 0) {
1429 db_printf("port_name_to_data: lookup yields zero\n");
1430 return (0);
1431 }
1432 return ((ipc_port_t)entry->ie_object);
1433 }
1434
1435 #if ZONE_DEBUG
1436 void
1437 print_type_ports(type, dead)
1438 unsigned type;
1439 unsigned dead;
1440 {
1441 ipc_port_t port;
1442 int n;
1443
1444 n = 0;
1445 for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
1446 port;
1447 port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT],
1448 (vm_offset_t)port))
1449 if (ip_kotype(port) == type &&
1450 (!dead || !ip_active(port))) {
1451 if (++n % 5)
1452 printf("0x%x\t", port);
1453 else
1454 printf("0x%x\n", port);
1455 }
1456 if (n % 5)
1457 printf("\n");
1458 }
1459
1460 void
1461 print_ports(void)
1462 {
1463 ipc_port_t port;
1464 int total_port_count;
1465 int space_null_count;
1466 int space_kernel_count;
1467 int space_reply_count;
1468 int space_pager_count;
1469 int space_other_count;
1470
1471 struct {
1472 int total_count;
1473 int dead_count;
1474 } port_types[IKOT_MAX_TYPE];
1475
1476 total_port_count = 0;
1477
1478 bzero((char *)&port_types[0], sizeof(port_types));
1479 space_null_count = 0;
1480 space_kernel_count = 0;
1481 space_reply_count = 0;
1482 space_pager_count = 0;
1483 space_other_count = 0;
1484
1485 for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
1486 port;
1487 port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT],
1488 (vm_offset_t)port)) {
1489 total_port_count++;
1490 if (ip_kotype(port) >= IKOT_MAX_TYPE) {
1491 port_types[IKOT_UNKNOWN].total_count++;
1492 if (!io_active(&port->ip_object))
1493 port_types[IKOT_UNKNOWN].dead_count++;
1494 } else {
1495 port_types[ip_kotype(port)].total_count++;
1496 if (!io_active(&port->ip_object))
1497 port_types[ip_kotype(port)].dead_count++;
1498 }
1499
1500 if (!port->ip_receiver)
1501 space_null_count++;
1502 else if (port->ip_receiver == ipc_space_kernel)
1503 space_kernel_count++;
1504 else if (port->ip_receiver == ipc_space_reply)
1505 space_reply_count++;
1506 else if (port->ip_receiver == default_pager_space)
1507 space_pager_count++;
1508 else
1509 space_other_count++;
1510 }
1511 printf("\n%7d total ports\n\n", total_port_count);
1512
1513 #define PRINT_ONE_PORT_TYPE(name) \
1514 printf("%7d %s", port_types[IKOT_##name].total_count, # name); \
1515 if (port_types[IKOT_##name].dead_count) \
1516 printf(" (%d dead ports)", port_types[IKOT_##name].dead_count);\
1517 printf("\n");
1518
1519 PRINT_ONE_PORT_TYPE(NONE);
1520 PRINT_ONE_PORT_TYPE(THREAD);
1521 PRINT_ONE_PORT_TYPE(TASK);
1522 PRINT_ONE_PORT_TYPE(HOST);
1523 PRINT_ONE_PORT_TYPE(HOST_PRIV);
1524 PRINT_ONE_PORT_TYPE(PROCESSOR);
1525 PRINT_ONE_PORT_TYPE(PSET);
1526 PRINT_ONE_PORT_TYPE(PSET_NAME);
1527 PRINT_ONE_PORT_TYPE(PAGING_REQUEST);
1528 PRINT_ONE_PORT_TYPE(MEMORY_OBJECT);
1529 PRINT_ONE_PORT_TYPE(MIG);
1530 PRINT_ONE_PORT_TYPE(XMM_PAGER);
1531 PRINT_ONE_PORT_TYPE(XMM_KERNEL);
1532 PRINT_ONE_PORT_TYPE(XMM_REPLY);
1533 PRINT_ONE_PORT_TYPE(CLOCK);
1534 PRINT_ONE_PORT_TYPE(CLOCK_CTRL);
1535 PRINT_ONE_PORT_TYPE(MASTER_DEVICE);
1536 PRINT_ONE_PORT_TYPE(UNKNOWN);
1537 printf("\nipc_space:\n\n");
1538 printf("NULL KERNEL REPLY PAGER OTHER\n");
1539 printf("%d %d %d %d %d\n",
1540 space_null_count,
1541 space_kernel_count,
1542 space_reply_count,
1543 space_pager_count,
1544 space_other_count
1545 );
1546 }
1547
1548 #endif /* ZONE_DEBUG */
1549
1550
1551 /*
1552 * Print out all the kmsgs in a queue. Aggregate kmsgs with
1553 * identical message ids into a single entry. Count up the
1554 * amount of inline and out-of-line data consumed by each
1555 * and every kmsg.
1556 *
1557 */
1558
1559 #define KMSG_MATCH_FIELD(kmsg) ((unsigned int) kmsg->ikm_header.msgh_id)
1560 #define DKQP_LONG(kmsg) FALSE
1561 char *dkqp_long_format = "(%3d) <%10d> 0x%x %10d %10d\n";
1562 char *dkqp_format = "(%3d) <%10d> 0x%x %10d %10d\n";
1563
1564 int
1565 db_kmsg_queue_print(
1566 ipc_kmsg_t kmsg);
1567 int
1568 db_kmsg_queue_print(
1569 ipc_kmsg_t kmsg)
1570 {
1571 ipc_kmsg_t ikmsg, first_kmsg;
1572 register int icount;
1573 mach_msg_id_t cur_id;
1574 unsigned int inline_total, ool_total;
1575 int nmsgs;
1576
1577 iprintf("Count msgh_id kmsg addr inline bytes ool bytes\n");
1578 inline_total = ool_total = (vm_size_t) 0;
1579 cur_id = KMSG_MATCH_FIELD(kmsg);
1580 for (icount = 0, nmsgs = 0, first_kmsg = ikmsg = kmsg;
1581 kmsg != IKM_NULL && (kmsg != first_kmsg || nmsgs == 0);
1582 kmsg = kmsg->ikm_next) {
1583 ++nmsgs;
1584 if (!(KMSG_MATCH_FIELD(kmsg) == cur_id)) {
1585 iprintf(DKQP_LONG(kmsg) ? dkqp_long_format:dkqp_format,
1586 icount, cur_id, ikmsg, inline_total,ool_total);
1587 cur_id = KMSG_MATCH_FIELD(kmsg);
1588 icount = 1;
1589 ikmsg = kmsg;
1590 inline_total = ool_total = 0;
1591 } else {
1592 icount++;
1593 }
1594 if (DKQP_LONG(kmsg))
1595 inline_total += kmsg->ikm_size;
1596 else
1597 inline_total += kmsg->ikm_header.msgh_size;
1598 }
1599 iprintf(DKQP_LONG(kmsg) ? dkqp_long_format : dkqp_format,
1600 icount, cur_id, ikmsg, inline_total, ool_total);
1601 return nmsgs;
1602 }
1603
1604
1605 /*
1606 * Process all of the messages on a port - prints out the
1607 * number of occurences of each message type, and the first
1608 * kmsg with a particular msgh_id.
1609 */
1610 int
1611 db_port_queue_print(
1612 ipc_port_t port)
1613 {
1614 ipc_kmsg_t kmsg;
1615
1616 if (ipc_kmsg_queue_empty(&port->ip_messages.imq_messages))
1617 return 0;
1618 kmsg = ipc_kmsg_queue_first(&port->ip_messages.imq_messages);
1619 return db_kmsg_queue_print(kmsg);
1620 }
1621
1622
1623 #if MACH_ASSERT
1624 #include <ddb/db_sym.h>
1625 #include <ddb/db_access.h>
1626
1627 #define FUNC_NULL ((void (*)) 0)
1628 #define MAX_REFS 5 /* bins for tracking ref counts */
1629
1630 /*
1631 * Translate port's cache of call stack pointers
1632 * into symbolic names.
1633 */
1634 void
1635 db_port_stack_trace(
1636 ipc_port_t port)
1637 {
1638 unsigned int i;
1639
1640 for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
1641 iprintf("[%d] 0x%x\t", i, port->ip_callstack[i]);
1642 if (port->ip_callstack[i] != 0 &&
1643 DB_VALID_KERN_ADDR(port->ip_callstack[i]))
1644 db_printsym(port->ip_callstack[i], DB_STGY_PROC);
1645 printf("\n");
1646 }
1647 }
1648
1649
1650 typedef struct port_item {
1651 unsigned long item;
1652 unsigned long count;
1653 } port_item;
1654
1655
1656 #define ITEM_MAX 400
1657 typedef struct port_track {
1658 char *name;
1659 unsigned long max;
1660 unsigned long warning;
1661 port_item items[ITEM_MAX];
1662 } port_track;
1663
1664 port_track port_callers; /* match against calling addresses */
1665 port_track port_threads; /* match against allocating threads */
1666 port_track port_spaces; /* match against ipc spaces */
1667
1668 void port_track_init(
1669 port_track *trackp,
1670 char *name);
1671 void port_item_add(
1672 port_track *trackp,
1673 unsigned long item);
1674 void port_track_sort(
1675 port_track *trackp);
1676 void port_track_print(
1677 port_track *trackp,
1678 void (*func)(port_item *));
1679 void port_callers_print(
1680 port_item *p);
1681
1682 void
1683 port_track_init(
1684 port_track *trackp,
1685 char *name)
1686 {
1687 port_item *i;
1688
1689 trackp->max = trackp->warning = 0;
1690 trackp->name = name;
1691 for (i = trackp->items; i < trackp->items + ITEM_MAX; ++i)
1692 i->item = i->count = 0;
1693 }
1694
1695
1696 void
1697 port_item_add(
1698 port_track *trackp,
1699 unsigned long item)
1700 {
1701 port_item *limit, *i;
1702
1703 limit = trackp->items + trackp->max;
1704 for (i = trackp->items; i < limit; ++i)
1705 if (i->item == item) {
1706 i->count++;
1707 return;
1708 }
1709 if (trackp->max >= ITEM_MAX) {
1710 if (trackp->warning++ == 0)
1711 iprintf("%s: no room\n", trackp->name);
1712 return;
1713 }
1714 i->item = item;
1715 i->count = 1;
1716 trackp->max++;
1717 }
1718
1719
1720 /*
1721 * Simple (and slow) bubble sort.
1722 */
1723 void
1724 port_track_sort(
1725 port_track *trackp)
1726 {
1727 port_item *limit, *p;
1728 port_item temp;
1729 boolean_t unsorted;
1730
1731 limit = trackp->items + trackp->max - 1;
1732 do {
1733 unsorted = FALSE;
1734 for (p = trackp->items; p < limit - 1; ++p) {
1735 if (p->count < (p+1)->count) {
1736 temp = *p;
1737 *p = *(p+1);
1738 *(p+1) = temp;
1739 unsorted = TRUE;
1740 }
1741 }
1742 } while (unsorted == TRUE);
1743 }
1744
1745
1746 void
1747 port_track_print(
1748 port_track *trackp,
1749 void (*func)(port_item *))
1750 {
1751 port_item *limit, *p;
1752
1753 limit = trackp->items + trackp->max;
1754 iprintf("%s:\n", trackp->name);
1755 for (p = trackp->items; p < limit; ++p) {
1756 if (func != FUNC_NULL)
1757 (*func)(p);
1758 else
1759 iprintf("0x%x\t%8d\n", p->item, p->count);
1760 }
1761 }
1762
1763
1764 void
1765 port_callers_print(
1766 port_item *p)
1767 {
1768 iprintf("0x%x\t%8d\t", p->item, p->count);
1769 db_printsym(p->item, DB_STGY_PROC);
1770 printf("\n");
1771 }
1772
1773
1774 /*
1775 * Show all ports with a given reference count.
1776 */
1777 void
1778 db_ref(
1779 int refs)
1780 {
1781 db_port_walk(1, 1, 1, refs);
1782 }
1783
1784
1785 /*
1786 * Examine all currently allocated ports.
1787 * Options:
1788 * verbose display suspicious ports
1789 * display print out each port encountered
1790 * ref_search restrict examination to ports with
1791 * a specified reference count
1792 * ref_target reference count for ref_search
1793 */
1794 int
1795 db_port_walk(
1796 unsigned int verbose,
1797 unsigned int display,
1798 unsigned int ref_search,
1799 unsigned int ref_target)
1800 {
1801 ipc_port_t port;
1802 unsigned int ref_overflow, refs, i, ref_inactive_overflow;
1803 unsigned int no_receiver, no_match;
1804 unsigned int ref_counts[MAX_REFS];
1805 unsigned int inactive[MAX_REFS];
1806 unsigned int ipc_ports = 0;
1807 unsigned int proxies = 0, principals = 0;
1808
1809 iprintf("Allocated port count is %d\n", port_count);
1810 no_receiver = no_match = ref_overflow = 0;
1811 ref_inactive_overflow = 0;
1812 for (i = 0; i < MAX_REFS; ++i) {
1813 ref_counts[i] = 0;
1814 inactive[i] = 0;
1815 }
1816 port_track_init(&port_callers, "port callers");
1817 port_track_init(&port_threads, "port threads");
1818 port_track_init(&port_spaces, "port spaces");
1819 if (ref_search)
1820 iprintf("Walking ports of ref_count=%d.\n", ref_target);
1821 else
1822 iprintf("Walking all ports.\n");
1823
1824 queue_iterate(&port_alloc_queue, port, ipc_port_t, ip_port_links) {
1825 char *port_type;
1826
1827 port_type = " IPC port";
1828 if (ip_active(port))
1829 ipc_ports++;
1830
1831 refs = port->ip_references;
1832 if (ref_search && refs != ref_target)
1833 continue;
1834
1835 if (refs >= MAX_REFS) {
1836 if (ip_active(port))
1837 ++ref_overflow;
1838 else
1839 ++ref_inactive_overflow;
1840 } else {
1841 if (refs == 0 && verbose)
1842 iprintf("%s 0x%x has ref count of zero!\n",
1843 port_type, port);
1844 if (ip_active(port))
1845 ref_counts[refs]++;
1846 else
1847 inactive[refs]++;
1848 }
1849 port_item_add(&port_threads, (unsigned long) port->ip_thread);
1850 for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
1851 if (port->ip_callstack[i] != 0 &&
1852 DB_VALID_KERN_ADDR(port->ip_callstack[i]))
1853 port_item_add(&port_callers,
1854 port->ip_callstack[i]);
1855 }
1856 if (!ip_active(port)) {
1857 if (verbose)
1858 iprintf("%s 0x%x, inactive, refcnt %d\n",
1859 port_type, port, refs);
1860 continue;
1861 }
1862
1863 if (port->ip_receiver_name == MACH_PORT_NULL) {
1864 iprintf("%s 0x%x, no receiver, refcnt %d\n",
1865 port, refs);
1866 ++no_receiver;
1867 continue;
1868 }
1869 if (port->ip_receiver == ipc_space_kernel ||
1870 port->ip_receiver == ipc_space_reply ||
1871 ipc_entry_lookup(port->ip_receiver,
1872 port->ip_receiver_name)
1873 != IE_NULL) {
1874 port_item_add(&port_spaces,
1875 (unsigned long)port->ip_receiver);
1876 if (display) {
1877 iprintf( "%s 0x%x time 0x%x ref_cnt %d\n",
1878 port_type, port,
1879 port->ip_timetrack, refs);
1880 }
1881 continue;
1882 }
1883 iprintf("%s 0x%x, rcvr 0x%x, name 0x%x, ref %d, no match\n",
1884 port_type, port, port->ip_receiver,
1885 port->ip_receiver_name, refs);
1886 ++no_match;
1887 }
1888 iprintf("Active port type summary:\n");
1889 iprintf("\tlocal IPC %6d\n", ipc_ports);
1890 iprintf("summary:\tcallers %d threads %d spaces %d\n",
1891 port_callers.max, port_threads.max, port_spaces.max);
1892
1893 iprintf("\tref_counts:\n");
1894 for (i = 0; i < MAX_REFS; ++i)
1895 iprintf("\t ref_counts[%d] = %d\n", i, ref_counts[i]);
1896
1897 iprintf("\t%d ports w/o receivers, %d w/o matches\n",
1898 no_receiver, no_match);
1899
1900 iprintf("\tinactives:");
1901 if ( ref_inactive_overflow || inactive[0] || inactive[1] ||
1902 inactive[2] || inactive[3] || inactive[4] )
1903 printf(" [0]=%d [1]=%d [2]=%d [3]=%d [4]=%d [5+]=%d\n",
1904 inactive[0], inactive[1], inactive[2],
1905 inactive[3], inactive[4], ref_inactive_overflow);
1906 else
1907 printf(" No inactive ports.\n");
1908
1909 port_track_sort(&port_spaces);
1910 port_track_print(&port_spaces, FUNC_NULL);
1911 port_track_sort(&port_threads);
1912 port_track_print(&port_threads, FUNC_NULL);
1913 port_track_sort(&port_callers);
1914 port_track_print(&port_callers, port_callers_print);
1915 return 0;
1916 }
1917
1918
1919 #endif /* MACH_ASSERT */
1920
1921 #endif /* MACH_KDB */