xref: /NextBSD/sys/compat/mach/ipc/ipc_port.c (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
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