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