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