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