]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_port.c
xnu-4570.71.2.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
1c79356b
A
72#include <zone_debug.h>
73#include <mach_assert.h>
74
75#include <mach/port.h>
76#include <mach/kern_return.h>
1c79356b 77#include <kern/ipc_kobject.h>
1c79356b 78#include <kern/thread.h>
1c79356b 79#include <kern/misc_protos.h>
3e170ce0 80#include <kern/waitq.h>
39037602 81#include <kern/policy_internal.h>
813fb2f6
A
82#include <kern/debug.h>
83#include <kern/kcdata.h>
1c79356b
A
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>
1c79356b 92#include <ipc/ipc_table.h>
fe8ab488 93#include <ipc/ipc_importance.h>
5ba3f43e 94#include <machine/machlimits.h>
1c79356b 95
2d21ac55
A
96#include <security/mac_mach_internal.h>
97
1c79356b
A
98#include <string.h>
99
fe8ab488 100decl_lck_spin_data(, ipc_port_multiple_lock_data)
1c79356b 101ipc_port_timestamp_t ipc_port_timestamp_data;
b7266188 102int ipc_portbt;
1c79356b
A
103
104#if MACH_ASSERT
105void ipc_port_init_debug(
316670eb 106 ipc_port_t port,
39236c6e 107 uintptr_t *callstack,
316670eb
A
108 unsigned int callstack_max);
109
110void ipc_port_callstack_init_debug(
39236c6e 111 uintptr_t *callstack,
316670eb
A
112 unsigned int callstack_max);
113
1c79356b
A
114#endif /* MACH_ASSERT */
115
316670eb
A
116void
117ipc_port_release(ipc_port_t port)
118{
119 ip_release(port);
120}
121
122void
123ipc_port_reference(ipc_port_t port)
124{
125 ip_reference(port);
126}
1c79356b
A
127
128/*
129 * Routine: ipc_port_timestamp
130 * Purpose:
131 * Retrieve a timestamp value.
132 */
133
134ipc_port_timestamp_t
135ipc_port_timestamp(void)
136{
316670eb 137 return OSIncrementAtomic(&ipc_port_timestamp_data);
1c79356b
A
138}
139
140/*
6d2010ae 141 * Routine: ipc_port_request_alloc
1c79356b 142 * Purpose:
6d2010ae 143 * Try to allocate a request slot.
1c79356b
A
144 * If successful, returns the request index.
145 * Otherwise returns zero.
146 * Conditions:
147 * The port is locked and active.
148 * Returns:
149 * KERN_SUCCESS A request index was found.
150 * KERN_NO_SPACE No index allocated.
151 */
152
39236c6e
A
153#if IMPORTANCE_INHERITANCE
154kern_return_t
155ipc_port_request_alloc(
156 ipc_port_t port,
157 mach_port_name_t name,
158 ipc_port_t soright,
159 boolean_t send_possible,
160 boolean_t immediate,
161 ipc_port_request_index_t *indexp,
162 boolean_t *importantp)
163#else
1c79356b 164kern_return_t
6d2010ae 165ipc_port_request_alloc(
1c79356b
A
166 ipc_port_t port,
167 mach_port_name_t name,
168 ipc_port_t soright,
6d2010ae
A
169 boolean_t send_possible,
170 boolean_t immediate,
1c79356b 171 ipc_port_request_index_t *indexp)
39236c6e 172#endif /* IMPORTANCE_INHERITANCE */
1c79356b
A
173{
174 ipc_port_request_t ipr, table;
175 ipc_port_request_index_t index;
6d2010ae 176 uintptr_t mask = 0;
1c79356b 177
39236c6e
A
178#if IMPORTANCE_INHERITANCE
179 *importantp = FALSE;
180#endif /* IMPORTANCE_INHERITANCE */
181
1c79356b
A
182 assert(ip_active(port));
183 assert(name != MACH_PORT_NULL);
184 assert(soright != IP_NULL);
185
6d2010ae
A
186 table = port->ip_requests;
187
1c79356b
A
188 if (table == IPR_NULL)
189 return KERN_NO_SPACE;
190
191 index = table->ipr_next;
192 if (index == 0)
193 return KERN_NO_SPACE;
194
195 ipr = &table[index];
196 assert(ipr->ipr_name == MACH_PORT_NULL);
197
198 table->ipr_next = ipr->ipr_next;
199 ipr->ipr_name = name;
6d2010ae
A
200
201 if (send_possible) {
202 mask |= IPR_SOR_SPREQ_MASK;
203 if (immediate) {
204 mask |= IPR_SOR_SPARM_MASK;
39236c6e
A
205 if (port->ip_sprequests == 0) {
206 port->ip_sprequests = 1;
207#if IMPORTANCE_INHERITANCE
fe8ab488 208 /* TODO: Live importance support in send-possible */
39236c6e
A
209 if (port->ip_impdonation != 0 &&
210 port->ip_spimportant == 0 &&
211 (task_is_importance_donor(current_task()))) {
39236c6e
A
212 *importantp = TRUE;
213 }
214#endif /* IMPORTANCE_INHERTANCE */
215 }
6d2010ae
A
216 }
217 }
218 ipr->ipr_soright = IPR_SOR_MAKE(soright, mask);
1c79356b
A
219
220 *indexp = index;
6d2010ae 221
1c79356b
A
222 return KERN_SUCCESS;
223}
224
225/*
6d2010ae 226 * Routine: ipc_port_request_grow
1c79356b 227 * Purpose:
6d2010ae 228 * Grow a port's table of requests.
1c79356b
A
229 * Conditions:
230 * The port must be locked and active.
231 * Nothing else locked; will allocate memory.
232 * Upon return the port is unlocked.
233 * Returns:
234 * KERN_SUCCESS Grew the table.
235 * KERN_SUCCESS Somebody else grew the table.
236 * KERN_SUCCESS The port died.
237 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
238 * KERN_NO_SPACE Couldn't grow to desired size
239 */
240
241kern_return_t
6d2010ae 242ipc_port_request_grow(
91447636
A
243 ipc_port_t port,
244 ipc_table_elems_t target_size)
1c79356b
A
245{
246 ipc_table_size_t its;
247 ipc_port_request_t otable, ntable;
248
249 assert(ip_active(port));
250
6d2010ae 251 otable = port->ip_requests;
1c79356b 252 if (otable == IPR_NULL)
6d2010ae 253 its = &ipc_table_requests[0];
1c79356b
A
254 else
255 its = otable->ipr_size + 1;
256
257 if (target_size != ITS_SIZE_NONE) {
258 if ((otable != IPR_NULL) &&
259 (target_size <= otable->ipr_size->its_size)) {
260 ip_unlock(port);
261 return KERN_SUCCESS;
262 }
263 while ((its->its_size) && (its->its_size < target_size)) {
264 its++;
265 }
266 if (its->its_size == 0) {
267 ip_unlock(port);
268 return KERN_NO_SPACE;
269 }
270 }
271
272 ip_reference(port);
273 ip_unlock(port);
274
275 if ((its->its_size == 0) ||
6d2010ae 276 ((ntable = it_requests_alloc(its)) == IPR_NULL)) {
316670eb 277 ip_release(port);
1c79356b
A
278 return KERN_RESOURCE_SHORTAGE;
279 }
280
281 ip_lock(port);
1c79356b
A
282
283 /*
284 * Check that port is still active and that nobody else
285 * has slipped in and grown the table on us. Note that
6d2010ae
A
286 * just checking if the current table pointer == otable
287 * isn't sufficient; must check ipr_size.
1c79356b
A
288 */
289
6d2010ae 290 if (ip_active(port) && (port->ip_requests == otable) &&
1c79356b
A
291 ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
292 ipc_table_size_t oits;
293 ipc_table_elems_t osize, nsize;
294 ipc_port_request_index_t free, i;
295
296 /* copy old table to new table */
297
298 if (otable != IPR_NULL) {
299 oits = otable->ipr_size;
300 osize = oits->its_size;
301 free = otable->ipr_next;
302
303 (void) memcpy((void *)(ntable + 1),
304 (const void *)(otable + 1),
305 (osize - 1) * sizeof(struct ipc_port_request));
306 } else {
307 osize = 1;
91447636 308 oits = 0;
1c79356b
A
309 free = 0;
310 }
311
312 nsize = its->its_size;
313 assert(nsize > osize);
314
315 /* add new elements to the new table's free list */
316
317 for (i = osize; i < nsize; i++) {
318 ipc_port_request_t ipr = &ntable[i];
319
320 ipr->ipr_name = MACH_PORT_NULL;
321 ipr->ipr_next = free;
322 free = i;
323 }
324
325 ntable->ipr_next = free;
326 ntable->ipr_size = its;
6d2010ae 327 port->ip_requests = ntable;
1c79356b 328 ip_unlock(port);
316670eb 329 ip_release(port);
1c79356b
A
330
331 if (otable != IPR_NULL) {
6d2010ae 332 it_requests_free(oits, otable);
1c79356b
A
333 }
334 } else {
316670eb
A
335 ip_unlock(port);
336 ip_release(port);
6d2010ae 337 it_requests_free(its, ntable);
1c79356b
A
338 }
339
340 return KERN_SUCCESS;
341}
342
343/*
6d2010ae 344 * Routine: ipc_port_request_sparm
1c79356b 345 * Purpose:
6d2010ae 346 * Arm delayed send-possible request.
1c79356b 347 * Conditions:
6d2010ae 348 * The port must be locked and active.
39236c6e
A
349 *
350 * Returns TRUE if the request was armed
351 * (or armed with importance in that version).
6d2010ae
A
352 */
353
39236c6e
A
354boolean_t
355ipc_port_request_sparm(
356 ipc_port_t port,
357 __assert_only mach_port_name_t name,
358 ipc_port_request_index_t index,
39037602
A
359 mach_msg_option_t option,
360 mach_msg_priority_t override)
6d2010ae
A
361{
362 if (index != IE_REQ_NONE) {
363 ipc_port_request_t ipr, table;
364
365 assert(ip_active(port));
366
367 table = port->ip_requests;
368 assert(table != IPR_NULL);
369
370 ipr = &table[index];
371 assert(ipr->ipr_name == name);
372
39037602 373 /* Is there a valid destination? */
6d2010ae
A
374 if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
375 ipr->ipr_soright = IPR_SOR_MAKE(ipr->ipr_soright, IPR_SOR_SPARM_MASK);
39236c6e 376 port->ip_sprequests = 1;
39037602
A
377
378 if (option & MACH_SEND_OVERRIDE) {
379 /* apply override to message queue */
380 ipc_mqueue_override_send(&port->ip_messages, override);
381 }
382
39236c6e
A
383#if IMPORTANCE_INHERITANCE
384 if (((option & MACH_SEND_NOIMPORTANCE) == 0) &&
385 (port->ip_impdonation != 0) &&
386 (port->ip_spimportant == 0) &&
387 (((option & MACH_SEND_IMPORTANCE) != 0) ||
388 (task_is_importance_donor(current_task())))) {
39236c6e
A
389 return TRUE;
390 }
391#else
392 return TRUE;
393#endif /* IMPORTANCE_INHERITANCE */
394 }
6d2010ae 395 }
39236c6e 396 return FALSE;
6d2010ae
A
397}
398
399/*
400 * Routine: ipc_port_request_type
401 * Purpose:
402 * Determine the type(s) of port requests enabled for a name.
403 * Conditions:
404 * The port must be locked or inactive (to avoid table growth).
405 * The index must not be IE_REQ_NONE and for the name in question.
406 */
407mach_port_type_t
408ipc_port_request_type(
409 ipc_port_t port,
410 __assert_only mach_port_name_t name,
411 ipc_port_request_index_t index)
412{
413 ipc_port_request_t ipr, table;
414 mach_port_type_t type = 0;
415
416 table = port->ip_requests;
417 assert (table != IPR_NULL);
418
419 assert(index != IE_REQ_NONE);
420 ipr = &table[index];
421 assert(ipr->ipr_name == name);
422
423 if (IP_VALID(IPR_SOR_PORT(ipr->ipr_soright))) {
424 type |= MACH_PORT_TYPE_DNREQUEST;
425
426 if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
427 type |= MACH_PORT_TYPE_SPREQUEST;
428
429 if (!IPR_SOR_SPARMED(ipr->ipr_soright)) {
430 type |= MACH_PORT_TYPE_SPREQUEST_DELAYED;
6d2010ae
A
431 }
432 }
433 }
434 return type;
435}
436
437/*
438 * Routine: ipc_port_request_cancel
439 * Purpose:
440 * Cancel a dead-name/send-possible request and return the send-once right.
441 * Conditions:
442 * The port must be locked and active.
443 * The index must not be IPR_REQ_NONE and must correspond with name.
1c79356b
A
444 */
445
446ipc_port_t
6d2010ae
A
447ipc_port_request_cancel(
448 ipc_port_t port,
91447636 449 __assert_only mach_port_name_t name,
6d2010ae 450 ipc_port_request_index_t index)
1c79356b
A
451{
452 ipc_port_request_t ipr, table;
6d2010ae 453 ipc_port_t request = IP_NULL;
1c79356b
A
454
455 assert(ip_active(port));
6d2010ae 456 table = port->ip_requests;
1c79356b
A
457 assert(table != IPR_NULL);
458
6d2010ae 459 assert (index != IE_REQ_NONE);
1c79356b 460 ipr = &table[index];
1c79356b 461 assert(ipr->ipr_name == name);
6d2010ae 462 request = IPR_SOR_PORT(ipr->ipr_soright);
1c79356b
A
463
464 /* return ipr to the free list inside the table */
1c79356b
A
465 ipr->ipr_name = MACH_PORT_NULL;
466 ipr->ipr_next = table->ipr_next;
467 table->ipr_next = index;
468
6d2010ae 469 return request;
1c79356b
A
470}
471
472/*
473 * Routine: ipc_port_pdrequest
474 * Purpose:
475 * Make a port-deleted request, returning the
476 * previously registered send-once right.
477 * Just cancels the previous request if notify is IP_NULL.
478 * Conditions:
479 * The port is locked and active. It is unlocked.
480 * Consumes a ref for notify (if non-null), and
481 * returns previous with a ref (if non-null).
482 */
483
484void
485ipc_port_pdrequest(
486 ipc_port_t port,
487 ipc_port_t notify,
488 ipc_port_t *previousp)
489{
490 ipc_port_t previous;
491
492 assert(ip_active(port));
493
494 previous = port->ip_pdrequest;
495 port->ip_pdrequest = notify;
496 ip_unlock(port);
497
498 *previousp = previous;
499}
500
501/*
502 * Routine: ipc_port_nsrequest
503 * Purpose:
504 * Make a no-senders request, returning the
505 * previously registered send-once right.
506 * Just cancels the previous request if notify is IP_NULL.
507 * Conditions:
508 * The port is locked and active. It is unlocked.
509 * Consumes a ref for notify (if non-null), and
510 * returns previous with a ref (if non-null).
511 */
512
513void
514ipc_port_nsrequest(
515 ipc_port_t port,
516 mach_port_mscount_t sync,
517 ipc_port_t notify,
518 ipc_port_t *previousp)
519{
520 ipc_port_t previous;
521 mach_port_mscount_t mscount;
522
523 assert(ip_active(port));
524
525 previous = port->ip_nsrequest;
526 mscount = port->ip_mscount;
527
528 if ((port->ip_srights == 0) && (sync <= mscount) &&
529 (notify != IP_NULL)) {
530 port->ip_nsrequest = IP_NULL;
531 ip_unlock(port);
532 ipc_notify_no_senders(notify, mscount);
533 } else {
534 port->ip_nsrequest = notify;
535 ip_unlock(port);
536 }
537
538 *previousp = previous;
539}
540
541
542/*
543 * Routine: ipc_port_clear_receiver
544 * Purpose:
39037602
A
545 * Prepares a receive right for transmission/destruction,
546 * optionally performs mqueue destruction (with port lock held)
547 *
1c79356b
A
548 * Conditions:
549 * The port is locked and active.
39037602
A
550 * Returns:
551 * If should_destroy is TRUE, then the return value indicates
552 * whether the caller needs to reap kmsg structures that should
553 * be destroyed (by calling ipc_kmsg_reap_delayed)
554 *
555 * If should_destroy is FALSE, this always returns FALSE
1c79356b
A
556 */
557
39037602 558boolean_t
1c79356b 559ipc_port_clear_receiver(
39037602
A
560 ipc_port_t port,
561 boolean_t should_destroy)
1c79356b 562{
39037602
A
563 ipc_mqueue_t mqueue = &port->ip_messages;
564 boolean_t reap_messages = FALSE;
1c79356b
A
565
566 /*
39037602
A
567 * Pull ourselves out of any sets to which we belong.
568 * We hold the port locked, so even though this acquires and releases
569 * the mqueue lock, we know we won't be added to any other sets.
1c79356b 570 */
3e170ce0
A
571 if (port->ip_in_pset != 0) {
572 ipc_pset_remove_from_all(port);
573 assert(port->ip_in_pset == 0);
1c79356b
A
574 }
575
576 /*
577 * Send anyone waiting on the port's queue directly away.
578 * Also clear the mscount and seqno.
579 */
39037602
A
580 imq_lock(mqueue);
581 ipc_mqueue_changed(mqueue);
582 port->ip_mscount = 0;
583 mqueue->imq_seqno = 0;
39236c6e 584 port->ip_context = port->ip_guarded = port->ip_strict_guard = 0;
39037602
A
585
586 if (should_destroy) {
587 /*
588 * Mark the mqueue invalid, preventing further send/receive
589 * operations from succeeding. It's important for this to be
590 * done under the same lock hold as the ipc_mqueue_changed
591 * call to avoid additional threads blocking on an mqueue
592 * that's being destroyed.
593 */
594 reap_messages = ipc_mqueue_destroy_locked(mqueue);
595 }
596
1c79356b 597 imq_unlock(&port->ip_messages);
39037602
A
598
599 return reap_messages;
1c79356b
A
600}
601
602/*
603 * Routine: ipc_port_init
604 * Purpose:
605 * Initializes a newly-allocated port.
606 * Doesn't touch the ip_object fields.
607 */
608
609void
610ipc_port_init(
611 ipc_port_t port,
612 ipc_space_t space,
613 mach_port_name_t name)
614{
615 /* port->ip_kobject doesn't have to be initialized */
616
617 port->ip_receiver = space;
618 port->ip_receiver_name = name;
619
620 port->ip_mscount = 0;
621 port->ip_srights = 0;
622 port->ip_sorights = 0;
623
624 port->ip_nsrequest = IP_NULL;
625 port->ip_pdrequest = IP_NULL;
6d2010ae 626 port->ip_requests = IPR_NULL;
1c79356b 627
1c79356b 628 port->ip_premsg = IKM_NULL;
b0d623f7 629 port->ip_context = 0;
1c79356b 630
39236c6e
A
631 port->ip_sprequests = 0;
632 port->ip_spimportant = 0;
633 port->ip_impdonation = 0;
634 port->ip_tempowner = 0;
39236c6e
A
635
636 port->ip_guarded = 0;
637 port->ip_strict_guard = 0;
638 port->ip_impcount = 0;
639
5ba3f43e
A
640 port->ip_specialreply = 0;
641 port->ip_link_sync_qos = 0;
39236c6e 642
3e170ce0
A
643 ipc_mqueue_init(&port->ip_messages,
644 FALSE /* !set */, NULL /* no reserved link */);
1c79356b
A
645}
646
647/*
648 * Routine: ipc_port_alloc
649 * Purpose:
650 * Allocate a port.
651 * Conditions:
652 * Nothing locked. If successful, the port is returned
653 * locked. (The caller doesn't have a reference.)
654 * Returns:
655 * KERN_SUCCESS The port is allocated.
656 * KERN_INVALID_TASK The space is dead.
657 * KERN_NO_SPACE No room for an entry in the space.
658 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
659 */
660
661kern_return_t
662ipc_port_alloc(
663 ipc_space_t space,
664 mach_port_name_t *namep,
665 ipc_port_t *portp)
666{
667 ipc_port_t port;
668 mach_port_name_t name;
669 kern_return_t kr;
670
316670eb 671#if MACH_ASSERT
39236c6e 672 uintptr_t buf[IP_CALLSTACK_MAX];
316670eb
A
673 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
674#endif /* MACH_ASSERT */
675
1c79356b
A
676 kr = ipc_object_alloc(space, IOT_PORT,
677 MACH_PORT_TYPE_RECEIVE, 0,
678 &name, (ipc_object_t *) &port);
679 if (kr != KERN_SUCCESS)
680 return kr;
681
99c3a104 682 /* port and space are locked */
1c79356b
A
683 ipc_port_init(port, space, name);
684
316670eb
A
685#if MACH_ASSERT
686 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
687#endif /* MACH_ASSERT */
688
99c3a104
A
689 /* unlock space after init */
690 is_write_unlock(space);
691
1c79356b
A
692 *namep = name;
693 *portp = port;
694
695 return KERN_SUCCESS;
696}
697
698/*
699 * Routine: ipc_port_alloc_name
700 * Purpose:
701 * Allocate a port, with a specific name.
702 * Conditions:
703 * Nothing locked. If successful, the port is returned
704 * locked. (The caller doesn't have a reference.)
705 * Returns:
706 * KERN_SUCCESS The port is allocated.
707 * KERN_INVALID_TASK The space is dead.
708 * KERN_NAME_EXISTS The name already denotes a right.
709 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
710 */
711
712kern_return_t
713ipc_port_alloc_name(
714 ipc_space_t space,
715 mach_port_name_t name,
716 ipc_port_t *portp)
717{
718 ipc_port_t port;
719 kern_return_t kr;
720
316670eb 721#if MACH_ASSERT
39236c6e 722 uintptr_t buf[IP_CALLSTACK_MAX];
316670eb
A
723 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
724#endif /* MACH_ASSERT */
725
1c79356b
A
726 kr = ipc_object_alloc_name(space, IOT_PORT,
727 MACH_PORT_TYPE_RECEIVE, 0,
728 name, (ipc_object_t *) &port);
729 if (kr != KERN_SUCCESS)
730 return kr;
731
732 /* port is locked */
733
734 ipc_port_init(port, space, name);
735
316670eb
A
736#if MACH_ASSERT
737 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
738#endif /* MACH_ASSERT */
739
1c79356b
A
740 *portp = port;
741
742 return KERN_SUCCESS;
743}
744
745/*
6d2010ae
A
746 * Routine: ipc_port_spnotify
747 * Purpose:
748 * Generate send-possible port notifications.
749 * Conditions:
750 * Nothing locked, reference held on port.
1c79356b
A
751 */
752void
6d2010ae
A
753ipc_port_spnotify(
754 ipc_port_t port)
1c79356b 755{
6d2010ae
A
756 ipc_port_request_index_t index = 0;
757 ipc_table_elems_t size = 0;
1c79356b 758
6d2010ae
A
759 /*
760 * If the port has no send-possible request
761 * armed, don't bother to lock the port.
762 */
39236c6e 763 if (port->ip_sprequests == 0)
6d2010ae 764 return;
1c79356b 765
6d2010ae 766 ip_lock(port);
39236c6e
A
767
768#if IMPORTANCE_INHERITANCE
769 if (port->ip_spimportant != 0) {
770 port->ip_spimportant = 0;
39037602
A
771 if (ipc_port_importance_delta(port, IPID_OPTION_NORMAL, -1) == TRUE) {
772 ip_lock(port);
fe8ab488 773 }
39236c6e
A
774 }
775#endif /* IMPORTANCE_INHERITANCE */
776
777 if (port->ip_sprequests == 0) {
6d2010ae 778 ip_unlock(port);
39037602 779 return;
6d2010ae 780 }
39236c6e 781 port->ip_sprequests = 0;
1c79356b 782
39236c6e 783revalidate:
6d2010ae
A
784 if (ip_active(port)) {
785 ipc_port_request_t requests;
786
787 /* table may change each time port unlocked (reload) */
788 requests = port->ip_requests;
789 assert(requests != IPR_NULL);
790
791 /*
792 * no need to go beyond table size when first
793 * we entered - those are future notifications.
794 */
795 if (size == 0)
796 size = requests->ipr_size->its_size;
797
798 /* no need to backtrack either */
799 while (++index < size) {
800 ipc_port_request_t ipr = &requests[index];
801 mach_port_name_t name = ipr->ipr_name;
802 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
803 boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright);
804
805 if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) {
806 /* claim send-once right - slot still inuse */
807 ipr->ipr_soright = IP_NULL;
808 ip_unlock(port);
809
810 ipc_notify_send_possible(soright, name);
811
812 ip_lock(port);
813 goto revalidate;
814 }
815 }
1c79356b 816 }
6d2010ae 817 ip_unlock(port);
39236c6e 818 return;
6d2010ae 819}
1c79356b 820
6d2010ae
A
821/*
822 * Routine: ipc_port_dnnotify
823 * Purpose:
824 * Generate dead name notifications for
825 * all outstanding dead-name and send-
826 * possible requests.
827 * Conditions:
828 * Nothing locked.
829 * Port must be inactive.
830 * Reference held on port.
831 */
832void
833ipc_port_dnnotify(
834 ipc_port_t port)
835{
836 ipc_port_request_t requests = port->ip_requests;
837
838 assert(!ip_active(port));
839 if (requests != IPR_NULL) {
840 ipc_table_size_t its = requests->ipr_size;
841 ipc_table_elems_t size = its->its_size;
842 ipc_port_request_index_t index;
843 for (index = 1; index < size; index++) {
844 ipc_port_request_t ipr = &requests[index];
845 mach_port_name_t name = ipr->ipr_name;
846 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
847
848 if (MACH_PORT_VALID(name) && IP_VALID(soright)) {
849 ipc_notify_dead_name(soright, name);
850 }
851 }
852 }
1c79356b
A
853}
854
6d2010ae 855
1c79356b
A
856/*
857 * Routine: ipc_port_destroy
858 * Purpose:
859 * Destroys a port. Cleans up queued messages.
860 *
861 * If the port has a backup, it doesn't get destroyed,
862 * but is sent in a port-destroyed notification to the backup.
863 * Conditions:
864 * The port is locked and alive; nothing else locked.
865 * The caller has a reference, which is consumed.
866 * Afterwards, the port is unlocked and dead.
867 */
868
869void
39037602 870ipc_port_destroy(ipc_port_t port)
1c79356b
A
871{
872 ipc_port_t pdrequest, nsrequest;
873 ipc_mqueue_t mqueue;
1c79356b 874 ipc_kmsg_t kmsg;
5ba3f43e 875 boolean_t special_reply = port->ip_specialreply;
1c79356b 876
39236c6e 877#if IMPORTANCE_INHERITANCE
fe8ab488 878 ipc_importance_task_t release_imp_task = IIT_NULL;
39236c6e
A
879 thread_t self = current_thread();
880 boolean_t top = (self->ith_assertions == 0);
881 natural_t assertcnt = 0;
882#endif /* IMPORTANCE_INHERITANCE */
883
1c79356b
A
884 assert(ip_active(port));
885 /* port->ip_receiver_name is garbage */
886 /* port->ip_receiver/port->ip_destination is garbage */
1c79356b 887
39236c6e 888 /* check for a backup port */
1c79356b 889 pdrequest = port->ip_pdrequest;
39236c6e
A
890
891#if IMPORTANCE_INHERITANCE
fe8ab488 892 /* determine how many assertions to drop and from whom */
39236c6e
A
893 if (port->ip_tempowner != 0) {
894 assert(top);
fe8ab488
A
895 release_imp_task = port->ip_imp_task;
896 if (IIT_NULL != release_imp_task) {
897 port->ip_imp_task = IIT_NULL;
39236c6e
A
898 assertcnt = port->ip_impcount;
899 }
900 /* Otherwise, nothing to drop */
901 } else {
39236c6e
A
902 assertcnt = port->ip_impcount;
903 if (pdrequest != IP_NULL)
904 /* mark in limbo for the journey */
905 port->ip_tempowner = 1;
906 }
907
908 if (top)
909 self->ith_assertions = assertcnt;
910#endif /* IMPORTANCE_INHERITANCE */
911
1c79356b 912 if (pdrequest != IP_NULL) {
39037602
A
913 /* clear receiver, don't destroy the port */
914 (void)ipc_port_clear_receiver(port, FALSE);
915 assert(port->ip_in_pset == 0);
916 assert(port->ip_mscount == 0);
917
1c79356b
A
918 /* we assume the ref for pdrequest */
919 port->ip_pdrequest = IP_NULL;
920
921 /* make port be in limbo */
922 port->ip_receiver_name = MACH_PORT_NULL;
923 port->ip_destination = IP_NULL;
924 ip_unlock(port);
925
5ba3f43e
A
926 if (special_reply) {
927 ipc_port_unlink_special_reply_port(port,
928 IPC_PORT_UNLINK_SR_ALLOW_SYNC_QOS_LINKAGE);
929 }
55e303ae
A
930 /* consumes our refs for port and pdrequest */
931 ipc_notify_port_destroyed(pdrequest, port);
39236c6e
A
932
933 goto drop_assertions;
1c79356b
A
934 }
935
1c79356b
A
936 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
937 port->ip_timestamp = ipc_port_timestamp();
fe8ab488 938 nsrequest = port->ip_nsrequest;
1c79356b 939
39037602
A
940 /*
941 * The mach_msg_* paths don't hold a port lock, they only hold a
942 * reference to the port object. If a thread raced us and is now
943 * blocked waiting for message reception on this mqueue (or waiting
944 * for ipc_mqueue_full), it will never be woken up. We call
945 * ipc_port_clear_receiver() here, _after_ the port has been marked
946 * inactive, to wakeup any threads which may be blocked and ensure
947 * that no other thread can get lost waiting for a wake up on a
948 * port/mqueue that's been destroyed.
949 */
950 boolean_t reap_msgs = FALSE;
951 reap_msgs = ipc_port_clear_receiver(port, TRUE); /* marks mqueue inactive */
952 assert(port->ip_in_pset == 0);
953 assert(port->ip_mscount == 0);
954
1c79356b
A
955 /*
956 * If the port has a preallocated message buffer and that buffer
9bccf70c 957 * is not inuse, free it. If it has an inuse one, then the kmsg
1c79356b
A
958 * free will detect that we freed the association and it can free it
959 * like a normal buffer.
39037602
A
960 *
961 * Once the port is marked inactive we don't need to keep it locked.
1c79356b
A
962 */
963 if (IP_PREALLOC(port)) {
316670eb
A
964 ipc_port_t inuse_port;
965
1c79356b
A
966 kmsg = port->ip_premsg;
967 assert(kmsg != IKM_NULL);
316670eb 968 inuse_port = ikm_prealloc_inuse_port(kmsg);
9bccf70c 969 IP_CLEAR_PREALLOC(port, kmsg);
316670eb
A
970 ip_unlock(port);
971 if (inuse_port != IP_NULL) {
972 assert(inuse_port == port);
973 } else {
1c79356b 974 ipc_kmsg_free(kmsg);
316670eb
A
975 }
976 } else {
977 ip_unlock(port);
1c79356b 978 }
1c79356b 979
5ba3f43e
A
980 /* unlink the kmsg from special reply port */
981 if (special_reply) {
982 ipc_port_unlink_special_reply_port(port,
983 IPC_PORT_UNLINK_SR_ALLOW_SYNC_QOS_LINKAGE);
984 }
985
1c79356b 986 /* throw away no-senders request */
1c79356b
A
987 if (nsrequest != IP_NULL)
988 ipc_notify_send_once(nsrequest); /* consumes ref */
989
39037602
A
990 /*
991 * Reap any kmsg objects waiting to be destroyed.
992 * This must be done after we've released the port lock.
993 */
994 if (reap_msgs)
995 ipc_kmsg_reap_delayed();
996
1c79356b 997 mqueue = &port->ip_messages;
1c79356b 998
3e170ce0
A
999 /* cleanup waitq related resources */
1000 ipc_mqueue_deinit(mqueue);
1001
1c79356b 1002 /* generate dead-name notifications */
6d2010ae 1003 ipc_port_dnnotify(port);
1c79356b
A
1004
1005 ipc_kobject_destroy(port);
1006
316670eb 1007 ip_release(port); /* consume caller's ref */
39236c6e
A
1008
1009 drop_assertions:
1010#if IMPORTANCE_INHERITANCE
fe8ab488 1011 if (release_imp_task != IIT_NULL) {
39236c6e
A
1012 if (assertcnt > 0) {
1013 assert(top);
1014 self->ith_assertions = 0;
fe8ab488
A
1015 assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
1016 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
39236c6e 1017 }
fe8ab488 1018 ipc_importance_task_release(release_imp_task);
39236c6e
A
1019
1020 } else if (assertcnt > 0) {
1021 if (top) {
1022 self->ith_assertions = 0;
fe8ab488
A
1023 release_imp_task = current_task()->task_imp_base;
1024 if (ipc_importance_task_is_any_receiver_type(release_imp_task)) {
1025 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
39236c6e 1026 }
39236c6e
A
1027 }
1028 }
1029#endif /* IMPORTANCE_INHERITANCE */
1c79356b
A
1030}
1031
1032/*
1033 * Routine: ipc_port_check_circularity
1034 * Purpose:
1035 * Check if queueing "port" in a message for "dest"
1036 * would create a circular group of ports and messages.
1037 *
1038 * If no circularity (FALSE returned), then "port"
1039 * is changed from "in limbo" to "in transit".
1040 *
1041 * That is, we want to set port->ip_destination == dest,
1042 * but guaranteeing that this doesn't create a circle
1043 * port->ip_destination->ip_destination->... == port
39236c6e 1044 *
1c79356b
A
1045 * Conditions:
1046 * No ports locked. References held for "port" and "dest".
1047 */
1048
1049boolean_t
1050ipc_port_check_circularity(
1051 ipc_port_t port,
1052 ipc_port_t dest)
1053{
39236c6e 1054#if IMPORTANCE_INHERITANCE
4bd07ac2
A
1055 /* adjust importance counts at the same time */
1056 return ipc_importance_check_circularity(port, dest);
1057#else
1058 ipc_port_t base;
5ba3f43e
A
1059 sync_qos_count_t sync_qos_delta_add[THREAD_QOS_LAST] = {0};
1060 sync_qos_count_t sync_qos_delta_sub[THREAD_QOS_LAST] = {0};
1061 boolean_t update_knote = FALSE;
39236c6e 1062
1c79356b
A
1063 assert(port != IP_NULL);
1064 assert(dest != IP_NULL);
1065
1066 if (port == dest)
1067 return TRUE;
1068 base = dest;
1069
1070 /*
1071 * First try a quick check that can run in parallel.
1072 * No circularity if dest is not in transit.
1073 */
1c79356b
A
1074 ip_lock(port);
1075 if (ip_lock_try(dest)) {
1076 if (!ip_active(dest) ||
1077 (dest->ip_receiver_name != MACH_PORT_NULL) ||
1078 (dest->ip_destination == IP_NULL))
1079 goto not_circular;
1080
1081 /* dest is in transit; further checking necessary */
1082
1083 ip_unlock(dest);
1084 }
1085 ip_unlock(port);
1086
1087 ipc_port_multiple_lock(); /* massive serialization */
1088
1089 /*
1090 * Search for the end of the chain (a port not in transit),
1091 * acquiring locks along the way.
1092 */
1093
1094 for (;;) {
1095 ip_lock(base);
1096
1097 if (!ip_active(base) ||
1098 (base->ip_receiver_name != MACH_PORT_NULL) ||
1099 (base->ip_destination == IP_NULL))
1100 break;
1101
1102 base = base->ip_destination;
1103 }
1104
1105 /* all ports in chain from dest to base, inclusive, are locked */
1106
1107 if (port == base) {
1108 /* circularity detected! */
1109
1110 ipc_port_multiple_unlock();
1111
1112 /* port (== base) is in limbo */
1113
1114 assert(ip_active(port));
1115 assert(port->ip_receiver_name == MACH_PORT_NULL);
1116 assert(port->ip_destination == IP_NULL);
1117
1118 while (dest != IP_NULL) {
1119 ipc_port_t next;
1120
1121 /* dest is in transit or in limbo */
1122
1123 assert(ip_active(dest));
1124 assert(dest->ip_receiver_name == MACH_PORT_NULL);
1125
1126 next = dest->ip_destination;
1127 ip_unlock(dest);
1128 dest = next;
1129 }
1130
1131 return TRUE;
1132 }
1133
1134 /*
1135 * The guarantee: lock port while the entire chain is locked.
1136 * Once port is locked, we can take a reference to dest,
1137 * add port to the chain, and unlock everything.
1138 */
1139
1140 ip_lock(port);
1141 ipc_port_multiple_unlock();
1142
5ba3f43e
A
1143not_circular:
1144 imq_lock(&base->ip_messages);
1c79356b
A
1145
1146 /* port is in limbo */
1147
1148 assert(ip_active(port));
1149 assert(port->ip_receiver_name == MACH_PORT_NULL);
1150 assert(port->ip_destination == IP_NULL);
1151
1152 ip_reference(dest);
1153 port->ip_destination = dest;
1154
5ba3f43e
A
1155 /* Capture the sync qos count delta */
1156 for (int i = 0; i < THREAD_QOS_LAST; i++) {
1157 sync_qos_delta_add[i] = port_sync_qos(port, i);
1158 }
1159
1c79356b
A
1160 /* now unlock chain */
1161
39236c6e
A
1162 ip_unlock(port);
1163
1164 for (;;) {
5ba3f43e
A
1165 /* every port along chain tracks override behind it */
1166 update_knote = ipc_port_sync_qos_delta(dest, sync_qos_delta_add, sync_qos_delta_sub);
39236c6e
A
1167 if (dest == base)
1168 break;
1c79356b
A
1169
1170 /* port is in transit */
1171
39236c6e
A
1172 assert(ip_active(dest));
1173 assert(dest->ip_receiver_name == MACH_PORT_NULL);
1174 assert(dest->ip_destination != IP_NULL);
1c79356b 1175
39236c6e
A
1176 port = dest->ip_destination;
1177 ip_unlock(dest);
1178 dest = port;
1c79356b
A
1179 }
1180
1181 /* base is not in transit */
1c79356b
A
1182 assert(!ip_active(base) ||
1183 (base->ip_receiver_name != MACH_PORT_NULL) ||
1184 (base->ip_destination == IP_NULL));
39236c6e 1185
5ba3f43e
A
1186 if (update_knote) {
1187 KNOTE(&base->ip_messages.imq_klist, 0);
1188 }
1189 imq_unlock(&base->ip_messages);
1190
1c79356b
A
1191 ip_unlock(base);
1192
1193 return FALSE;
4bd07ac2 1194#endif /* !IMPORTANCE_INHERITANCE */
1c79356b
A
1195}
1196
5ba3f43e
A
1197/*
1198 * Routine: ipc_port_link_special_reply_port_with_qos
1199 * Purpose:
1200 * Link the special reply port with the destination port.
1201 * Update the sync qos count of special reply port,
1202 * destination port.
1203 *
1204 * Conditions:
1205 * Nothing is locked.
1206 */
1207kern_return_t
1208ipc_port_link_special_reply_port_with_qos(
1209 ipc_port_t special_reply_port,
1210 ipc_port_t dest_port,
1211 int qos)
1212{
1213 ipc_port_t next, base;
1214 sync_qos_count_t sync_qos_delta_add[THREAD_QOS_LAST] = {0};
1215 sync_qos_count_t sync_qos_delta_sub[THREAD_QOS_LAST] = {0};
1216 boolean_t update_knote = FALSE;
1217 boolean_t multiple_lock = FALSE;
1218
1219 ip_lock(dest_port);
1220
1221 /* Check if dest is active */
1222 if (!ip_active(dest_port)) {
1223 ip_unlock(dest_port);
1224 return KERN_FAILURE;
1225 }
1226
1227 if ((dest_port->ip_receiver_name == MACH_PORT_NULL) &&
1228 (dest_port->ip_destination != IP_NULL)) {
1229 /* dest_port is in transit; need to take the serialize lock */
1230 ip_unlock(dest_port);
1231 goto take_multiple_lock;
1232 }
1233
1234 /* Check if the port is a special reply port */
1235 if (ip_lock_try(special_reply_port)) {
1236 if (!special_reply_port->ip_specialreply ||
1237 !special_reply_port->ip_link_sync_qos ||
1238 (special_reply_port->ip_sync_qos_override_port != IP_NULL &&
1239 special_reply_port->ip_sync_qos_override_port != dest_port)) {
1240
1241 boolean_t link_sync_qos = special_reply_port->ip_link_sync_qos;
1242 ip_unlock(special_reply_port);
1243 ip_unlock(dest_port);
1244 /* return KERN_SUCCESS when link_sync_qos is not set */
1245 if (!link_sync_qos) {
1246 return KERN_SUCCESS;
1247 }
1248 return KERN_FAILURE;
1249 } else {
1250 goto both_ports_locked;
1251 }
1252 }
1253
1254 ip_unlock(dest_port);
1255
1256take_multiple_lock:
1257
1258 ipc_port_multiple_lock(); /* massive serialization */
1259 multiple_lock = TRUE;
1260
1261 ip_lock(special_reply_port);
1262
1263 /* Check if the special reply port is marked regular */
1264 if (!special_reply_port->ip_specialreply ||
1265 !special_reply_port->ip_link_sync_qos ||
1266 (special_reply_port->ip_sync_qos_override_port != IP_NULL &&
1267 special_reply_port->ip_sync_qos_override_port != dest_port)) {
1268
1269 boolean_t link_sync_qos = special_reply_port->ip_link_sync_qos;
1270 ip_unlock(special_reply_port);
1271 ipc_port_multiple_unlock();
1272 /* return KERN_SUCCESS when link_sync_qos is not set */
1273 if (!link_sync_qos) {
1274 return KERN_SUCCESS;
1275 }
1276 return KERN_FAILURE;
1277 }
1278
1279 ip_lock(dest_port);
1280
1281both_ports_locked:
1282 next = dest_port;
1283
1284 /* Apply the qos to special reply port, capture the old qos */
1285 if (special_reply_port->ip_sync_qos_override_port != IP_NULL) {
1286 /* Check if qos needs to be updated */
1287 if ((sync_qos_count_t)qos <= port_special_qos(special_reply_port)) {
1288 imq_lock(&dest_port->ip_messages);
1289 goto done_update;
1290 }
1291 sync_qos_delta_sub[port_special_qos(special_reply_port)]++;
1292 }
1293
1294 set_port_special_qos(special_reply_port, (sync_qos_count_t)qos);
1295 sync_qos_delta_add[qos]++;
1296
1297 /* Link the special reply port to dest port */
1298 if (special_reply_port->ip_sync_qos_override_port == IP_NULL) {
1299 /* take a reference on dest_port */
1300 ip_reference(dest_port);
1301 special_reply_port->ip_sync_qos_override_port = dest_port;
1302 }
1303
1304 /* Apply the sync qos delta to all in-transit ports */
1305 for (;;) {
1306 boolean_t port_not_in_transit = FALSE;
1307 if (!ip_active(next) ||
1308 (next->ip_receiver_name != MACH_PORT_NULL) ||
1309 (next->ip_destination == IP_NULL)) {
1310 /* Get the mqueue lock for destination port to update knotes */
1311 imq_lock(&next->ip_messages);
1312 port_not_in_transit = TRUE;
1313 }
1314 /* Apply the sync qos delta */
1315 update_knote = ipc_port_sync_qos_delta(next, sync_qos_delta_add, sync_qos_delta_sub);
1316
1317 if (port_not_in_transit)
1318 break;
1319
1320 next = next->ip_destination;
1321 ip_lock(next);
1322 }
1323done_update:
1324
1325 if (multiple_lock) {
1326 ipc_port_multiple_unlock();
1327 }
1328
1329 ip_unlock(special_reply_port);
1330 base = next;
1331 next = dest_port;
1332
1333 while (next != base) {
1334 ipc_port_t prev = next;
1335 next = next->ip_destination;
1336
1337 ip_unlock(prev);
1338 }
1339
1340 if (update_knote) {
1341 KNOTE(&base->ip_messages.imq_klist, 0);
1342 }
1343 imq_unlock(&base->ip_messages);
1344 ip_unlock(base);
1345 return KERN_SUCCESS;
1346}
1347
1348/*
1349 * Routine: ipc_port_unlink_special_reply_port_locked
1350 * Purpose:
1351 * If the special port is linked to a port, adjust it's sync qos override and unlink the port.
1352 * Condition:
1353 * Special reply port locked on entry.
1354 * Special reply port unlocked on return.
1355 * Returns:
1356 * None.
1357 */
1358void
1359ipc_port_unlink_special_reply_port_locked(
1360 ipc_port_t special_reply_port,
1361 struct knote *kn,
1362 uint8_t flags)
1363{
1364 ipc_port_t dest_port;
1365 sync_qos_count_t sync_qos;
1366 sync_qos_count_t sync_qos_delta_add[THREAD_QOS_LAST] = {0};
1367 sync_qos_count_t sync_qos_delta_sub[THREAD_QOS_LAST] = {0};
1368
1369 /* Return if called from copy out in pseudo receive */
1370 if (kn == ITH_KNOTE_PSEUDO) {
1371 ip_unlock(special_reply_port);
1372 return;
1373 }
1374
1375 /* check if special port has a port linked to it */
1376 if (special_reply_port->ip_specialreply == 0 ||
1377 special_reply_port->ip_sync_qos_override_port == IP_NULL) {
1378 set_port_special_qos(special_reply_port, 0);
1379 if (flags & IPC_PORT_UNLINK_SR_CLEAR_SPECIAL_REPLY) {
1380 special_reply_port->ip_specialreply = 0;
1381 }
1382 if (flags & IPC_PORT_UNLINK_SR_ALLOW_SYNC_QOS_LINKAGE) {
1383 special_reply_port->ip_link_sync_qos = 1;
1384 }
1385 ip_unlock(special_reply_port);
1386 return;
1387 }
1388
1389 /*
1390 * port->ip_sync_qos_override_port is not null and it is safe
1391 * to access it since ip_specialreply is set.
1392 */
1393 dest_port = special_reply_port->ip_sync_qos_override_port;
1394 sync_qos_delta_sub[port_special_qos(special_reply_port)]++;
1395 sync_qos = port_special_qos(special_reply_port);
1396
1397 /* Clear qos delta for special reply port */
1398 set_port_special_qos(special_reply_port, 0);
1399 special_reply_port->ip_sync_qos_override_port = IP_NULL;
1400 if (flags & IPC_PORT_UNLINK_SR_CLEAR_SPECIAL_REPLY) {
1401 special_reply_port->ip_specialreply = 0;
1402 }
1403
1404 if (flags & IPC_PORT_UNLINK_SR_ALLOW_SYNC_QOS_LINKAGE) {
1405 special_reply_port->ip_link_sync_qos = 1;
1406 } else {
1407 special_reply_port->ip_link_sync_qos = 0;
1408 }
1409
1410 ip_unlock(special_reply_port);
1411
1412 /* Add the sync qos on knote */
1413 if (ITH_KNOTE_VALID(kn)) {
1414 knote_adjust_sync_qos(kn, sync_qos, TRUE);
1415 }
1416
1417 /* Adjust the sync qos of destination */
1418 ipc_port_adjust_sync_qos(dest_port, sync_qos_delta_add, sync_qos_delta_sub);
1419 ip_release(dest_port);
1420}
1421
1422/*
1423 * Routine: ipc_port_unlink_special_reply_port
1424 * Purpose:
1425 * If the special port is linked to a port, adjust it's sync qos override and unlink the port.
1426 * Condition:
1427 * Nothing locked.
1428 * Returns:
1429 * None.
1430 */
1431void
1432ipc_port_unlink_special_reply_port(
1433 ipc_port_t special_reply_port,
1434 uint8_t flags)
1435{
1436 ip_lock(special_reply_port);
1437 ipc_port_unlink_special_reply_port_locked(special_reply_port, NULL, flags);
1438 /* special_reply_port unlocked */
1439}
1440
1441/*
1442 * Routine: ipc_port_sync_qos_delta
1443 * Purpose:
1444 * Adjust the sync qos count associated with a port.
1445 *
1446 * For now, be defensive during deductions to make sure the
1447 * sync_qos count for the port doesn't underflow zero.
1448 * Returns:
1449 * TRUE: if max sync qos of the port changes.
1450 * FALSE: otherwise.
1451 * Conditions:
1452 * The port is referenced and locked.
1453 * The mqueue is locked if port is not in-transit.
1454 */
1455boolean_t
1456ipc_port_sync_qos_delta(
1457 ipc_port_t port,
1458 sync_qos_count_t *sync_qos_delta_add,
1459 sync_qos_count_t *sync_qos_delta_sub)
1460{
1461 sync_qos_count_t max_sync_qos_index;
1462
1463 if (!ip_active(port)) {
1464 return FALSE;
1465 }
1466
1467 max_sync_qos_index = ipc_port_get_max_sync_qos_index(port);
1468
1469 for (int i = 0; i < THREAD_QOS_LAST; i++) {
1470 sync_qos_count_t port_sync_qos_count = port_sync_qos(port, i);
1471 /* Do not let the sync qos underflow */
1472 if (sync_qos_delta_sub[i] > port_sync_qos_count) {
1473 KDBG_FILTERED(IMPORTANCE_CODE(IMP_SYNC_IPC_QOS, IMP_SYNC_IPC_QOS_UNDERFLOW),
1474 i, VM_KERNEL_UNSLIDE_OR_PERM(port),
1475 port_sync_qos_count, sync_qos_delta_sub[i]);
1476
1477 set_port_sync_qos(port, i, 0);
1478 } else if (sync_qos_delta_sub[i] != 0) {
1479 KDBG_FILTERED(IMPORTANCE_CODE(IMP_SYNC_IPC_QOS, IMP_SYNC_IPC_QOS_REMOVED),
1480 i, VM_KERNEL_UNSLIDE_OR_PERM(port),
1481 port_sync_qos_count, sync_qos_delta_sub[i]);
1482
1483 set_port_sync_qos(port, i, (port_sync_qos_count - sync_qos_delta_sub[i]));
1484 }
1485
1486 port_sync_qos_count = port_sync_qos(port, i);
1487 /* Do not let the sync qos overflow */
1488 if (UCHAR_MAX - sync_qos_delta_add[i] < port_sync_qos_count) {
1489 KDBG_FILTERED(IMPORTANCE_CODE(IMP_SYNC_IPC_QOS, IMP_SYNC_IPC_QOS_OVERFLOW),
1490 i, VM_KERNEL_UNSLIDE_OR_PERM(port),
1491 port_sync_qos_count, sync_qos_delta_add[i]);
1492
1493 set_port_sync_qos(port, i, UCHAR_MAX);
1494 } else if (sync_qos_delta_add[i] != 0) {
1495 KDBG_FILTERED(IMPORTANCE_CODE(IMP_SYNC_IPC_QOS, IMP_SYNC_IPC_QOS_APPLIED),
1496 i, VM_KERNEL_UNSLIDE_OR_PERM(port),
1497 port_sync_qos_count, sync_qos_delta_add[i]);
1498
1499 set_port_sync_qos(port, i, (port_sync_qos_count + sync_qos_delta_add[i]));
1500 }
1501 }
1502 return (ipc_port_get_max_sync_qos_index(port) != max_sync_qos_index);
1503}
1504
1505/*
1506 * Routine: ipc_port_get_max_sync_qos_index
1507 * Purpose:
1508 * Return the max sync qos of the port.
1509 *
1510 * Conditions:
1511 */
1512sync_qos_count_t
1513ipc_port_get_max_sync_qos_index(
1514 ipc_port_t port)
1515{
1516 int i;
1517 for (i = THREAD_QOS_LAST - 1; i >= 0; i--) {
1518 if (port_sync_qos(port, i) != 0) {
1519 return i;
1520 }
1521 }
1522 return THREAD_QOS_UNSPECIFIED;
1523}
1524
1525/*
1526 * Routine: ipc_port_adjust_sync_qos
1527 * Purpose:
1528 * Adjust sync qos of the port and it's destination
1529 * port if the port is in transit.
1530 * Conditions:
1531 * Nothing locked.
1532 * Returns:
1533 * None.
1534 */
1535void
1536ipc_port_adjust_sync_qos(
1537 ipc_port_t port,
1538 sync_qos_count_t *sync_qos_delta_add,
1539 sync_qos_count_t *sync_qos_delta_sub)
1540{
1541 boolean_t update_knote;
1542 boolean_t multiple_lock = FALSE;
1543 ipc_port_t dest, base, next;
1544
1545 ip_lock(port);
1546
1547 /* Check if the port is in transit */
1548 if (!ip_active(port) ||
1549 (port->ip_receiver_name != MACH_PORT_NULL) ||
1550 (port->ip_destination == IP_NULL)) {
1551 /* lock the mqueue since port is not in-transit */
1552 imq_lock(&port->ip_messages);
1553 update_knote = ipc_port_sync_qos_delta(port, sync_qos_delta_add, sync_qos_delta_sub);
1554 if (update_knote) {
1555 KNOTE(&port->ip_messages.imq_klist, 0);
1556 }
1557 imq_unlock(&port->ip_messages);
1558 ip_unlock(port);
1559 return;
1560 }
1561
1562 dest = port->ip_destination;
1563 assert(dest != IP_NULL);
1564
1565 if (ip_lock_try(dest)) {
1566 if (!ip_active(dest) ||
1567 (dest->ip_receiver_name != MACH_PORT_NULL) ||
1568 (dest->ip_destination == IP_NULL)) {
1569 update_knote = ipc_port_sync_qos_delta(port, sync_qos_delta_add, sync_qos_delta_sub);
1570 ip_unlock(port);
1571
1572 /* lock the mqueue since dest is not in-transit */
1573 imq_lock(&dest->ip_messages);
1574 update_knote = ipc_port_sync_qos_delta(dest, sync_qos_delta_add, sync_qos_delta_sub);
1575 if (update_knote) {
1576 KNOTE(&dest->ip_messages.imq_klist, 0);
1577 }
1578 imq_unlock(&dest->ip_messages);
1579 ip_unlock(dest);
1580 return;
1581 }
1582
1583 /* dest is in transit; need to take the serialize lock */
1584 ip_unlock(dest);
1585 }
1586
1587 ip_unlock(port);
1588
1589 ipc_port_multiple_lock(); /* massive serialization */
1590 multiple_lock = TRUE;
1591
1592 ip_lock(port);
1593 next = port;
1594
1595 /* Apply the sync qos delta to all in-transit ports */
1596 for (;;) {
1597 boolean_t port_not_in_transit = FALSE;
1598
1599 if (!ip_active(next) ||
1600 (next->ip_receiver_name != MACH_PORT_NULL) ||
1601 (next->ip_destination == IP_NULL)) {
1602 /* Get the mqueue lock for destination port to update knotes */
1603 imq_lock(&next->ip_messages);
1604 port_not_in_transit = TRUE;
1605 }
1606
1607 /* Apply the sync qos delta */
1608 update_knote = ipc_port_sync_qos_delta(next, sync_qos_delta_add, sync_qos_delta_sub);
1609
1610 if (port_not_in_transit)
1611 break;
1612
1613 next = next->ip_destination;
1614 ip_lock(next);
1615 }
1616
1617 if (multiple_lock) {
1618 ipc_port_multiple_unlock();
1619 }
1620
1621 base = next;
1622 next = port;
1623
1624 while (next != base) {
1625 ipc_port_t prev = next;
1626 next = next->ip_destination;
1627
1628 ip_unlock(prev);
1629 }
1630
1631 if (update_knote) {
1632 KNOTE(&base->ip_messages.imq_klist, 0);
1633 }
1634 imq_unlock(&base->ip_messages);
1635 ip_unlock(base);
1636}
1637
39236c6e 1638/*
fe8ab488
A
1639 * Routine: ipc_port_impcount_delta
1640 * Purpose:
1641 * Adjust only the importance count associated with a port.
1642 * If there are any adjustments to be made to receiver task,
1643 * those are handled elsewhere.
1644 *
1645 * For now, be defensive during deductions to make sure the
1646 * impcount for the port doesn't underflow zero. This will
1647 * go away when the port boost addition is made atomic (see
1648 * note in ipc_port_importance_delta()).
1649 * Conditions:
1650 * The port is referenced and locked.
1651 * Nothing else is locked.
1652 */
1653mach_port_delta_t
1654ipc_port_impcount_delta(
1655 ipc_port_t port,
1656 mach_port_delta_t delta,
1657 ipc_port_t __unused base)
1658{
1659 mach_port_delta_t absdelta;
1660
1661 if (!ip_active(port)) {
1662 return 0;
1663 }
1664
1665 /* adding/doing nothing is easy */
1666 if (delta >= 0) {
1667 port->ip_impcount += delta;
1668 return delta;
1669 }
1670
1671 absdelta = 0 - delta;
fe8ab488
A
1672 if (port->ip_impcount >= absdelta) {
1673 port->ip_impcount -= absdelta;
1674 return delta;
1675 }
1676
4bd07ac2 1677#if (DEVELOPMENT || DEBUG)
fe8ab488
A
1678 if (port->ip_receiver_name != MACH_PORT_NULL) {
1679 task_t target_task = port->ip_receiver->is_task;
1680 ipc_importance_task_t target_imp = target_task->task_imp_base;
1681 const char *target_procname;
1682 int target_pid;
1683
1684 if (target_imp != IIT_NULL) {
1685 target_procname = target_imp->iit_procname;
1686 target_pid = target_imp->iit_bsd_pid;
1687 } else {
1688 target_procname = "unknown";
1689 target_pid = -1;
1690 }
1691 printf("Over-release of importance assertions for port 0x%x receiver pid %d (%s), "
1692 "dropping %d assertion(s) but port only has %d remaining.\n",
1693 port->ip_receiver_name,
4bd07ac2 1694 target_pid, target_procname,
fe8ab488
A
1695 absdelta, port->ip_impcount);
1696
1697 } else if (base != IP_NULL) {
1698 task_t target_task = base->ip_receiver->is_task;
1699 ipc_importance_task_t target_imp = target_task->task_imp_base;
1700 const char *target_procname;
1701 int target_pid;
1702
1703 if (target_imp != IIT_NULL) {
1704 target_procname = target_imp->iit_procname;
1705 target_pid = target_imp->iit_bsd_pid;
1706 } else {
1707 target_procname = "unknown";
1708 target_pid = -1;
1709 }
4bd07ac2 1710 printf("Over-release of importance assertions for port 0x%lx "
fe8ab488
A
1711 "enqueued on port 0x%x with receiver pid %d (%s), "
1712 "dropping %d assertion(s) but port only has %d remaining.\n",
4bd07ac2
A
1713 (unsigned long)VM_KERNEL_UNSLIDE_OR_PERM((uintptr_t)port),
1714 base->ip_receiver_name,
1715 target_pid, target_procname,
fe8ab488
A
1716 absdelta, port->ip_impcount);
1717 }
1718#endif
4bd07ac2 1719
fe8ab488
A
1720 delta = 0 - port->ip_impcount;
1721 port->ip_impcount = 0;
1722 return delta;
1723}
1724
1725/*
1726 * Routine: ipc_port_importance_delta_internal
39236c6e
A
1727 * Purpose:
1728 * Adjust the importance count through the given port.
1729 * If the port is in transit, apply the delta throughout
1730 * the chain. Determine if the there is a task at the
1731 * base of the chain that wants/needs to be adjusted,
1732 * and if so, apply the delta.
1733 * Conditions:
1734 * The port is referenced and locked on entry.
4bd07ac2 1735 * Importance may be locked.
39236c6e
A
1736 * Nothing else is locked.
1737 * The lock may be dropped on exit.
1738 * Returns TRUE if lock was dropped.
1739 */
1740#if IMPORTANCE_INHERITANCE
1741
1742boolean_t
fe8ab488 1743ipc_port_importance_delta_internal(
39236c6e 1744 ipc_port_t port,
4bd07ac2 1745 natural_t options,
fe8ab488
A
1746 mach_port_delta_t *deltap,
1747 ipc_importance_task_t *imp_task)
39236c6e
A
1748{
1749 ipc_port_t next, base;
39236c6e
A
1750 boolean_t dropped = FALSE;
1751
fe8ab488
A
1752 *imp_task = IIT_NULL;
1753
1754 if (*deltap == 0)
39236c6e
A
1755 return FALSE;
1756
4bd07ac2
A
1757 assert(options == IPID_OPTION_NORMAL || options == IPID_OPTION_SENDPOSSIBLE);
1758
39236c6e
A
1759 base = port;
1760
1761 /* if port is in transit, have to search for end of chain */
1762 if (ip_active(port) &&
1763 port->ip_destination != IP_NULL &&
1764 port->ip_receiver_name == MACH_PORT_NULL) {
1765
1766 dropped = TRUE;
1767
1768 ip_unlock(port);
1769 ipc_port_multiple_lock(); /* massive serialization */
1770 ip_lock(base);
1771
1772 while(ip_active(base) &&
1773 base->ip_destination != IP_NULL &&
1774 base->ip_receiver_name == MACH_PORT_NULL) {
1775
1776 base = base->ip_destination;
1777 ip_lock(base);
1778 }
1779 ipc_port_multiple_unlock();
1780 }
1781
4bd07ac2
A
1782 /*
1783 * If the port lock is dropped b/c the port is in transit, there is a
1784 * race window where another thread can drain messages and/or fire a
1785 * send possible notification before we get here.
1786 *
1787 * We solve this race by checking to see if our caller armed the send
1788 * possible notification, whether or not it's been fired yet, and
1789 * whether or not we've already set the port's ip_spimportant bit. If
1790 * we don't need a send-possible boost, then we'll just apply a
1791 * harmless 0-boost to the port.
1792 */
1793 if (options & IPID_OPTION_SENDPOSSIBLE) {
1794 assert(*deltap == 1);
1795 if (port->ip_sprequests && port->ip_spimportant == 0)
1796 port->ip_spimportant = 1;
1797 else
1798 *deltap = 0;
1799 }
1800
1801 /* unlock down to the base, adjusting boost(s) at each level */
39236c6e 1802 for (;;) {
fe8ab488 1803 *deltap = ipc_port_impcount_delta(port, *deltap, base);
39236c6e 1804
fe8ab488 1805 if (port == base) {
39236c6e 1806 break;
fe8ab488 1807 }
39236c6e
A
1808
1809 /* port is in transit */
1810 assert(port->ip_tempowner == 0);
1811 next = port->ip_destination;
1812 ip_unlock(port);
1813 port = next;
1814 }
1815
1816 /* find the task (if any) to boost according to the base */
1817 if (ip_active(base)) {
1818 if (base->ip_tempowner != 0) {
fe8ab488
A
1819 if (IIT_NULL != base->ip_imp_task)
1820 *imp_task = base->ip_imp_task;
39236c6e
A
1821 /* otherwise don't boost */
1822
1823 } else if (base->ip_receiver_name != MACH_PORT_NULL) {
1824 ipc_space_t space = base->ip_receiver;
1825
1826 /* only spaces with boost-accepting tasks */
1827 if (space->is_task != TASK_NULL &&
fe8ab488
A
1828 ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base)) {
1829 *imp_task = space->is_task->task_imp_base;
1830 }
39236c6e
A
1831 }
1832 }
1833
1834 /*
1835 * Only the base is locked. If we have to hold or drop task
1836 * importance assertions, we'll have to drop that lock as well.
1837 */
fe8ab488 1838 if (*imp_task != IIT_NULL) {
39236c6e 1839 /* take a reference before unlocking base */
fe8ab488
A
1840 ipc_importance_task_reference(*imp_task);
1841 }
39236c6e 1842
fe8ab488 1843 if (dropped == TRUE) {
39236c6e 1844 ip_unlock(base);
fe8ab488 1845 }
39236c6e 1846
fe8ab488
A
1847 return dropped;
1848}
1849#endif /* IMPORTANCE_INHERITANCE */
39236c6e 1850
fe8ab488
A
1851/*
1852 * Routine: ipc_port_importance_delta
1853 * Purpose:
1854 * Adjust the importance count through the given port.
1855 * If the port is in transit, apply the delta throughout
1856 * the chain.
1857 *
1858 * If there is a task at the base of the chain that wants/needs
1859 * to be adjusted, apply the delta.
1860 * Conditions:
1861 * The port is referenced and locked on entry.
1862 * Nothing else is locked.
1863 * The lock may be dropped on exit.
1864 * Returns TRUE if lock was dropped.
1865 */
1866#if IMPORTANCE_INHERITANCE
1867
1868boolean_t
1869ipc_port_importance_delta(
1870 ipc_port_t port,
4bd07ac2 1871 natural_t options,
fe8ab488
A
1872 mach_port_delta_t delta)
1873{
1874 ipc_importance_task_t imp_task = IIT_NULL;
1875 boolean_t dropped;
1876
4bd07ac2 1877 dropped = ipc_port_importance_delta_internal(port, options, &delta, &imp_task);
fe8ab488 1878
4bd07ac2 1879 if (IIT_NULL == imp_task || delta == 0)
fe8ab488
A
1880 return dropped;
1881
4bd07ac2 1882 if (!dropped)
fe8ab488 1883 ip_unlock(port);
39236c6e 1884
fe8ab488
A
1885 assert(ipc_importance_task_is_any_receiver_type(imp_task));
1886
1887 if (delta > 0)
1888 ipc_importance_task_hold_internal_assertion(imp_task, delta);
1889 else
1890 ipc_importance_task_drop_internal_assertion(imp_task, -delta);
1891
1892 ipc_importance_task_release(imp_task);
4bd07ac2 1893 return TRUE;
39236c6e
A
1894}
1895#endif /* IMPORTANCE_INHERITANCE */
1896
1c79356b
A
1897/*
1898 * Routine: ipc_port_lookup_notify
1899 * Purpose:
1900 * Make a send-once notify port from a receive right.
1901 * Returns IP_NULL if name doesn't denote a receive right.
1902 * Conditions:
1903 * The space must be locked (read or write) and active.
1904 * Being the active space, we can rely on thread server_id
1905 * context to give us the proper server level sub-order
1906 * within the space.
1907 */
1908
1909ipc_port_t
1910ipc_port_lookup_notify(
1911 ipc_space_t space,
1912 mach_port_name_t name)
1913{
1914 ipc_port_t port;
1915 ipc_entry_t entry;
1916
316670eb 1917 assert(is_active(space));
1c79356b
A
1918
1919 entry = ipc_entry_lookup(space, name);
1920 if (entry == IE_NULL)
1921 return IP_NULL;
1922 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
1923 return IP_NULL;
1924
3e170ce0 1925 __IGNORE_WCASTALIGN(port = (ipc_port_t) entry->ie_object);
1c79356b
A
1926 assert(port != IP_NULL);
1927
1928 ip_lock(port);
1929 assert(ip_active(port));
1930 assert(port->ip_receiver_name == name);
1931 assert(port->ip_receiver == space);
1932
1933 ip_reference(port);
1934 port->ip_sorights++;
1935 ip_unlock(port);
1936
1937 return port;
1938}
1939
1940/*
0b4e3aa0 1941 * Routine: ipc_port_make_send_locked
1c79356b
A
1942 * Purpose:
1943 * Make a naked send right from a receive right.
0b4e3aa0 1944 *
1c79356b 1945 * Conditions:
0b4e3aa0 1946 * port locked and active.
1c79356b 1947 */
1c79356b 1948ipc_port_t
0b4e3aa0 1949ipc_port_make_send_locked(
1c79356b
A
1950 ipc_port_t port)
1951{
1c79356b
A
1952 assert(ip_active(port));
1953 port->ip_mscount++;
1954 port->ip_srights++;
1955 ip_reference(port);
1c79356b
A
1956 return port;
1957}
1958
0b4e3aa0
A
1959/*
1960 * Routine: ipc_port_make_send
1961 * Purpose:
1962 * Make a naked send right from a receive right.
1963 */
1964
1965ipc_port_t
1966ipc_port_make_send(
1967 ipc_port_t port)
1968{
1969
1970 if (!IP_VALID(port))
1971 return port;
1972
1973 ip_lock(port);
1974 if (ip_active(port)) {
1975 port->ip_mscount++;
1976 port->ip_srights++;
1977 ip_reference(port);
1978 ip_unlock(port);
1979 return port;
1980 }
1981 ip_unlock(port);
1982 return IP_DEAD;
1983}
1984
1c79356b
A
1985/*
1986 * Routine: ipc_port_copy_send
1987 * Purpose:
1988 * Make a naked send right from another naked send right.
1989 * IP_NULL -> IP_NULL
1990 * IP_DEAD -> IP_DEAD
1991 * dead port -> IP_DEAD
1992 * live port -> port + ref
1993 * Conditions:
1994 * Nothing locked except possibly a space.
1995 */
1996
1997ipc_port_t
1998ipc_port_copy_send(
1999 ipc_port_t port)
2000{
2001 ipc_port_t sright;
2002
2003 if (!IP_VALID(port))
2004 return port;
2005
2006 ip_lock(port);
2007 if (ip_active(port)) {
2008 assert(port->ip_srights > 0);
2009
2010 ip_reference(port);
2011 port->ip_srights++;
2012 sright = port;
2013 } else
2014 sright = IP_DEAD;
2015 ip_unlock(port);
2016
2017 return sright;
2018}
2019
2020/*
2021 * Routine: ipc_port_copyout_send
2022 * Purpose:
2023 * Copyout a naked send right (possibly null/dead),
2024 * or if that fails, destroy the right.
2025 * Conditions:
2026 * Nothing locked.
2027 */
2028
2029mach_port_name_t
2030ipc_port_copyout_send(
2031 ipc_port_t sright,
2032 ipc_space_t space)
2033{
2034 mach_port_name_t name;
2035
2036 if (IP_VALID(sright)) {
2037 kern_return_t kr;
2038
2039 kr = ipc_object_copyout(space, (ipc_object_t) sright,
2040 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
2041 if (kr != KERN_SUCCESS) {
2042 ipc_port_release_send(sright);
2043
2044 if (kr == KERN_INVALID_CAPABILITY)
2045 name = MACH_PORT_DEAD;
2046 else
2047 name = MACH_PORT_NULL;
2048 }
2049 } else
b0d623f7 2050 name = CAST_MACH_PORT_TO_NAME(sright);
1c79356b
A
2051
2052 return name;
2053}
2054
2055/*
2056 * Routine: ipc_port_release_send
2057 * Purpose:
6d2010ae 2058 * Release a naked send right.
1c79356b
A
2059 * Consumes a ref for the port.
2060 * Conditions:
2061 * Nothing locked.
2062 */
2063
2064void
2065ipc_port_release_send(
2066 ipc_port_t port)
2067{
2068 ipc_port_t nsrequest = IP_NULL;
2069 mach_port_mscount_t mscount;
2070
6d2010ae
A
2071 if (!IP_VALID(port))
2072 return;
1c79356b
A
2073
2074 ip_lock(port);
1c79356b 2075
fe8ab488 2076 assert(port->ip_srights > 0);
5ba3f43e
A
2077 if (port->ip_srights == 0) {
2078 panic("Over-release of port %p send right!", port);
2079 }
2080
fe8ab488
A
2081 port->ip_srights--;
2082
1c79356b 2083 if (!ip_active(port)) {
316670eb
A
2084 ip_unlock(port);
2085 ip_release(port);
1c79356b
A
2086 return;
2087 }
2088
fe8ab488 2089 if (port->ip_srights == 0 &&
1c79356b
A
2090 port->ip_nsrequest != IP_NULL) {
2091 nsrequest = port->ip_nsrequest;
2092 port->ip_nsrequest = IP_NULL;
2093 mscount = port->ip_mscount;
2094 ip_unlock(port);
316670eb 2095 ip_release(port);
1c79356b 2096 ipc_notify_no_senders(nsrequest, mscount);
316670eb 2097 } else {
1c79356b 2098 ip_unlock(port);
316670eb
A
2099 ip_release(port);
2100 }
2101}
2102
2103/*
2104 * Routine: ipc_port_make_sonce_locked
2105 * Purpose:
2106 * Make a naked send-once right from a receive right.
2107 * Conditions:
2108 * The port is locked and active.
2109 */
2110
2111ipc_port_t
2112ipc_port_make_sonce_locked(
2113 ipc_port_t port)
2114{
2115 assert(ip_active(port));
2116 port->ip_sorights++;
2117 ip_reference(port);
2118 return port;
1c79356b
A
2119}
2120
2121/*
2122 * Routine: ipc_port_make_sonce
2123 * Purpose:
2124 * Make a naked send-once right from a receive right.
2125 * Conditions:
316670eb 2126 * The port is not locked.
1c79356b
A
2127 */
2128
2129ipc_port_t
2130ipc_port_make_sonce(
2131 ipc_port_t port)
2132{
6d2010ae
A
2133 if (!IP_VALID(port))
2134 return port;
1c79356b
A
2135
2136 ip_lock(port);
316670eb
A
2137 if (ip_active(port)) {
2138 port->ip_sorights++;
2139 ip_reference(port);
2140 ip_unlock(port);
2141 return port;
2142 }
1c79356b 2143 ip_unlock(port);
316670eb 2144 return IP_DEAD;
1c79356b
A
2145}
2146
2147/*
2148 * Routine: ipc_port_release_sonce
2149 * Purpose:
2150 * Release a naked send-once right.
2151 * Consumes a ref for the port.
2152 *
2153 * In normal situations, this is never used.
2154 * Send-once rights are only consumed when
2155 * a message (possibly a send-once notification)
2156 * is sent to them.
2157 * Conditions:
2158 * Nothing locked except possibly a space.
2159 */
2160
2161void
2162ipc_port_release_sonce(
2163 ipc_port_t port)
2164{
6d2010ae
A
2165 if (!IP_VALID(port))
2166 return;
1c79356b 2167
5ba3f43e
A
2168 ipc_port_unlink_special_reply_port(port, IPC_PORT_UNLINK_SR_NONE);
2169
1c79356b
A
2170 ip_lock(port);
2171
2172 assert(port->ip_sorights > 0);
5ba3f43e
A
2173 if (port->ip_sorights == 0) {
2174 panic("Over-release of port %p send-once right!", port);
2175 }
1c79356b
A
2176
2177 port->ip_sorights--;
2178
1c79356b 2179 ip_unlock(port);
316670eb 2180 ip_release(port);
1c79356b
A
2181}
2182
2183/*
2184 * Routine: ipc_port_release_receive
2185 * Purpose:
2186 * Release a naked (in limbo or in transit) receive right.
2187 * Consumes a ref for the port; destroys the port.
2188 * Conditions:
2189 * Nothing locked.
2190 */
2191
2192void
2193ipc_port_release_receive(
2194 ipc_port_t port)
2195{
2196 ipc_port_t dest;
2197
6d2010ae
A
2198 if (!IP_VALID(port))
2199 return;
1c79356b
A
2200
2201 ip_lock(port);
2202 assert(ip_active(port));
2203 assert(port->ip_receiver_name == MACH_PORT_NULL);
2204 dest = port->ip_destination;
2205
2206 ipc_port_destroy(port); /* consumes ref, unlocks */
2207
2208 if (dest != IP_NULL)
316670eb 2209 ip_release(dest);
1c79356b
A
2210}
2211
2212/*
2213 * Routine: ipc_port_alloc_special
2214 * Purpose:
2215 * Allocate a port in a special space.
2216 * The new port is returned with one ref.
2217 * If unsuccessful, IP_NULL is returned.
2218 * Conditions:
2219 * Nothing locked.
2220 */
2221
2222ipc_port_t
2223ipc_port_alloc_special(
2224 ipc_space_t space)
2225{
2226 ipc_port_t port;
2227
3e170ce0 2228 __IGNORE_WCASTALIGN(port = (ipc_port_t) io_alloc(IOT_PORT));
1c79356b
A
2229 if (port == IP_NULL)
2230 return IP_NULL;
2231
316670eb 2232#if MACH_ASSERT
39236c6e 2233 uintptr_t buf[IP_CALLSTACK_MAX];
316670eb
A
2234 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
2235#endif /* MACH_ASSERT */
2236
1c79356b
A
2237 bzero((char *)port, sizeof(*port));
2238 io_lock_init(&port->ip_object);
2239 port->ip_references = 1;
2240 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
2241
2242 ipc_port_init(port, space, 1);
2243
316670eb
A
2244#if MACH_ASSERT
2245 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
2246#endif /* MACH_ASSERT */
2247
1c79356b
A
2248 return port;
2249}
2250
2251/*
2252 * Routine: ipc_port_dealloc_special
2253 * Purpose:
2254 * Deallocate a port in a special space.
2255 * Consumes one ref for the port.
2256 * Conditions:
2257 * Nothing locked.
2258 */
2259
2260void
2261ipc_port_dealloc_special(
91447636
A
2262 ipc_port_t port,
2263 __assert_only ipc_space_t space)
1c79356b
A
2264{
2265 ip_lock(port);
2266 assert(ip_active(port));
55e303ae 2267// assert(port->ip_receiver_name != MACH_PORT_NULL);
1c79356b
A
2268 assert(port->ip_receiver == space);
2269
2270 /*
2271 * We clear ip_receiver_name and ip_receiver to simplify
2272 * the ipc_space_kernel check in ipc_mqueue_send.
2273 */
2274
2275 port->ip_receiver_name = MACH_PORT_NULL;
2276 port->ip_receiver = IS_NULL;
2277
2278 /* relevant part of ipc_port_clear_receiver */
2279 ipc_port_set_mscount(port, 0);
2280 port->ip_messages.imq_seqno = 0;
2281
2282 ipc_port_destroy(port);
2283}
2284
6d2010ae
A
2285/*
2286 * Routine: ipc_port_finalize
2287 * Purpose:
2288 * Called on last reference deallocate to
2289 * free any remaining data associated with the
2290 * port.
2291 * Conditions:
2292 * Nothing locked.
2293 */
2294void
2295ipc_port_finalize(
2296 ipc_port_t port)
2297{
2298 ipc_port_request_t requests = port->ip_requests;
2299
2300 assert(!ip_active(port));
2301 if (requests != IPR_NULL) {
2302 ipc_table_size_t its = requests->ipr_size;
2303 it_requests_free(its, requests);
2304 port->ip_requests = IPR_NULL;
2305 }
3e170ce0
A
2306
2307 ipc_mqueue_deinit(&port->ip_messages);
6d2010ae
A
2308
2309#if MACH_ASSERT
2310 ipc_port_track_dealloc(port);
2311#endif /* MACH_ASSERT */
6d2010ae 2312}
1c79356b 2313
813fb2f6
A
2314/*
2315 * Routine: kdp_mqueue_send_find_owner
2316 * Purpose:
2317 * Discover the owner of the ipc_mqueue that contains the input
2318 * waitq object. The thread blocked on the waitq should be
2319 * waiting for an IPC_MQUEUE_FULL event.
2320 * Conditions:
2321 * The 'waitinfo->wait_type' value should already be set to
2322 * kThreadWaitPortSend.
2323 * Note:
2324 * If we find out that the containing port is actually in
2325 * transit, we reset the wait_type field to reflect this.
2326 */
2327void
2328kdp_mqueue_send_find_owner(struct waitq * waitq, __assert_only event64_t event, thread_waitinfo_t * waitinfo)
2329{
2330 assert(waitinfo->wait_type == kThreadWaitPortSend);
2331 assert(event == IPC_MQUEUE_FULL);
2332
2333 ipc_mqueue_t mqueue = imq_from_waitq(waitq);
2334 ipc_port_t port = ip_from_mq(mqueue); /* we are blocking on send */
2335 assert(kdp_is_in_zone(port, "ipc ports"));
2336
2337 waitinfo->owner = 0;
2338 waitinfo->context = VM_KERNEL_UNSLIDE_OR_PERM(port);
2339 if (ip_lock_held_kdp(port)) {
2340 /*
2341 * someone has the port locked: it may be in an
2342 * inconsistent state: bail
2343 */
2344 waitinfo->owner = STACKSHOT_WAITOWNER_PORT_LOCKED;
2345 return;
2346 }
2347
2348 if (ip_active(port)) {
2349 if (port->ip_tempowner) {
5ba3f43e 2350 if (port->ip_imp_task != IIT_NULL && port->ip_imp_task->iit_task != NULL) {
813fb2f6
A
2351 /* port is held by a tempowner */
2352 waitinfo->owner = pid_from_task(port->ip_imp_task->iit_task);
2353 } else {
2354 waitinfo->owner = STACKSHOT_WAITOWNER_INTRANSIT;
2355 }
2356 } else if (port->ip_receiver_name) {
2357 /* port in a space */
2358 if (port->ip_receiver == ipc_space_kernel) {
2359 /*
2360 * The kernel pid is 0, make this
2361 * distinguishable from no-owner and
2362 * inconsistent port state.
2363 */
2364 waitinfo->owner = STACKSHOT_WAITOWNER_KERNEL;
2365 } else {
2366 waitinfo->owner = pid_from_task(port->ip_receiver->is_task);
2367 }
2368 } else if (port->ip_destination != IP_NULL) {
2369 /* port in transit */
2370 waitinfo->wait_type = kThreadWaitPortSendInTransit;
2371 waitinfo->owner = VM_KERNEL_UNSLIDE_OR_PERM(port->ip_destination);
2372 }
2373 }
2374}
2375
2376/*
2377 * Routine: kdp_mqueue_recv_find_owner
2378 * Purpose:
2379 * Discover the "owner" of the ipc_mqueue that contains the input
2380 * waitq object. The thread blocked on the waitq is trying to
2381 * receive on the mqueue.
2382 * Conditions:
2383 * The 'waitinfo->wait_type' value should already be set to
2384 * kThreadWaitPortReceive.
2385 * Note:
2386 * If we find that we are actualy waiting on a port set, we reset
2387 * the wait_type field to reflect this.
2388 */
2389void
2390kdp_mqueue_recv_find_owner(struct waitq * waitq, __assert_only event64_t event, thread_waitinfo_t * waitinfo)
2391{
2392 assert(waitinfo->wait_type == kThreadWaitPortReceive);
2393 assert(event == IPC_MQUEUE_RECEIVE);
2394
2395 ipc_mqueue_t mqueue = imq_from_waitq(waitq);
2396 waitinfo->owner = 0;
2397 if (imq_is_set(mqueue)) { /* we are waiting on a port set */
2398 ipc_pset_t set = ips_from_mq(mqueue);
2399 assert(kdp_is_in_zone(set, "ipc port sets"));
2400
2401 /* Reset wait type to specify waiting on port set receive */
2402 waitinfo->wait_type = kThreadWaitPortSetReceive;
2403 waitinfo->context = VM_KERNEL_UNSLIDE_OR_PERM(set);
2404 if (ips_lock_held_kdp(set)) {
2405 waitinfo->owner = STACKSHOT_WAITOWNER_PSET_LOCKED;
2406 }
2407 /* There is no specific owner "at the other end" of a port set, so leave unset. */
2408 } else {
2409 ipc_port_t port = ip_from_mq(mqueue);
2410 assert(kdp_is_in_zone(port, "ipc ports"));
2411
2412 waitinfo->context = VM_KERNEL_UNSLIDE_OR_PERM(port);
2413 if (ip_lock_held_kdp(port)) {
2414 waitinfo->owner = STACKSHOT_WAITOWNER_PORT_LOCKED;
2415 return;
2416 }
2417
2418 if (ip_active(port)) {
2419 if (port->ip_receiver_name != MACH_PORT_NULL) {
2420 waitinfo->owner = port->ip_receiver_name;
2421 } else {
2422 waitinfo->owner = STACKSHOT_WAITOWNER_INTRANSIT;
2423 }
2424 }
2425 }
2426}
2427
1c79356b 2428#if MACH_ASSERT
91447636
A
2429#include <kern/machine.h>
2430
1c79356b
A
2431/*
2432 * Keep a list of all allocated ports.
2433 * Allocation is intercepted via ipc_port_init;
2434 * deallocation is intercepted via io_free.
2435 */
3e170ce0 2436#if 0
1c79356b 2437queue_head_t port_alloc_queue;
316670eb 2438lck_spin_t port_alloc_queue_lock;
3e170ce0 2439#endif
1c79356b
A
2440
2441unsigned long port_count = 0;
2442unsigned long port_count_warning = 20000;
2443unsigned long port_timestamp = 0;
2444
2445void db_port_stack_trace(
2446 ipc_port_t port);
2447void db_ref(
2448 int refs);
2449int db_port_walk(
2450 unsigned int verbose,
2451 unsigned int display,
2452 unsigned int ref_search,
2453 unsigned int ref_target);
2454
2455/*
2456 * Initialize global state needed for run-time
2457 * port debugging.
2458 */
2459void
2460ipc_port_debug_init(void)
2461{
3e170ce0 2462#if 0
1c79356b 2463 queue_init(&port_alloc_queue);
316670eb 2464 lck_spin_init(&port_alloc_queue_lock, &ipc_lck_grp, &ipc_lck_attr);
3e170ce0 2465#endif
b7266188
A
2466
2467 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt)))
2468 ipc_portbt = 0;
1c79356b
A
2469}
2470
b7266188
A
2471#ifdef MACH_BSD
2472extern int proc_pid(struct proc*);
2473#endif /* MACH_BSD */
1c79356b
A
2474
2475/*
2476 * Initialize all of the debugging state in a port.
2477 * Insert the port into a global list of all allocated ports.
2478 */
2479void
2480ipc_port_init_debug(
316670eb 2481 ipc_port_t port,
39236c6e 2482 uintptr_t *callstack,
316670eb 2483 unsigned int callstack_max)
1c79356b
A
2484{
2485 unsigned int i;
2486
91447636 2487 port->ip_thread = current_thread();
1c79356b 2488 port->ip_timetrack = port_timestamp++;
316670eb
A
2489 for (i = 0; i < callstack_max; ++i)
2490 port->ip_callstack[i] = callstack[i];
1c79356b 2491 for (i = 0; i < IP_NSPARES; ++i)
316670eb 2492 port->ip_spares[i] = 0;
1c79356b 2493
b7266188
A
2494#ifdef MACH_BSD
2495 task_t task = current_task();
2496 if (task != TASK_NULL) {
2497 struct proc* proc = (struct proc*) get_bsdtask_info(task);
2498 if (proc)
2499 port->ip_spares[0] = proc_pid(proc);
2500 }
2501#endif /* MACH_BSD */
2502
1c79356b 2503#if 0
316670eb 2504 lck_spin_lock(&port_alloc_queue_lock);
1c79356b
A
2505 ++port_count;
2506 if (port_count_warning > 0 && port_count >= port_count_warning)
2507 assert(port_count < port_count_warning);
2508 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
316670eb 2509 lck_spin_unlock(&port_alloc_queue_lock);
1c79356b
A
2510#endif
2511}
2512
316670eb
A
2513/*
2514 * Routine: ipc_port_callstack_init_debug
2515 * Purpose:
2516 * Calls the machine-dependent routine to
2517 * fill in an array with up to IP_CALLSTACK_MAX
2518 * levels of return pc information
2519 * Conditions:
2520 * May block (via copyin)
2521 */
2522void
2523ipc_port_callstack_init_debug(
39236c6e 2524 uintptr_t *callstack,
316670eb
A
2525 unsigned int callstack_max)
2526{
2527 unsigned int i;
2528
2529 /* guarantee the callstack is initialized */
2530 for (i=0; i < callstack_max; i++)
2531 callstack[i] = 0;
2532
2533 if (ipc_portbt)
2534 machine_callstack(callstack, callstack_max);
2535}
1c79356b
A
2536
2537/*
2538 * Remove a port from the queue of allocated ports.
2539 * This routine should be invoked JUST prior to
2540 * deallocating the actual memory occupied by the port.
2541 */
91447636 2542#if 1
1c79356b
A
2543void
2544ipc_port_track_dealloc(
91447636
A
2545 __unused ipc_port_t port)
2546{
2547}
2548#else
2549void
2550ipc_port_track_dealloc(
2551 ipc_port_t port)
1c79356b 2552{
316670eb 2553 lck_spin_lock(&port_alloc_queue_lock);
1c79356b
A
2554 assert(port_count > 0);
2555 --port_count;
2556 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
316670eb 2557 lck_spin_unlock(&port_alloc_queue_lock);
1c79356b 2558}
91447636 2559#endif
1c79356b 2560
6d2010ae 2561
1c79356b 2562#endif /* MACH_ASSERT */