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