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