]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_port.c
xnu-2782.10.72.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
A
79#include <kern/misc_protos.h>
80#include <kern/wait_queue.h>
81#include <ipc/ipc_entry.h>
82#include <ipc/ipc_space.h>
83#include <ipc/ipc_object.h>
84#include <ipc/ipc_port.h>
85#include <ipc/ipc_pset.h>
86#include <ipc/ipc_kmsg.h>
87#include <ipc/ipc_mqueue.h>
88#include <ipc/ipc_notify.h>
1c79356b 89#include <ipc/ipc_table.h>
fe8ab488 90#include <ipc/ipc_importance.h>
1c79356b 91
2d21ac55
A
92#include <security/mac_mach_internal.h>
93
1c79356b
A
94#include <string.h>
95
fe8ab488 96decl_lck_spin_data(, ipc_port_multiple_lock_data)
1c79356b 97ipc_port_timestamp_t ipc_port_timestamp_data;
b7266188 98int ipc_portbt;
1c79356b
A
99
100#if MACH_ASSERT
101void ipc_port_init_debug(
316670eb 102 ipc_port_t port,
39236c6e 103 uintptr_t *callstack,
316670eb
A
104 unsigned int callstack_max);
105
106void ipc_port_callstack_init_debug(
39236c6e 107 uintptr_t *callstack,
316670eb
A
108 unsigned int callstack_max);
109
1c79356b
A
110#endif /* MACH_ASSERT */
111
316670eb
A
112void
113ipc_port_release(ipc_port_t port)
114{
115 ip_release(port);
116}
117
118void
119ipc_port_reference(ipc_port_t port)
120{
121 ip_reference(port);
122}
1c79356b
A
123
124/*
125 * Routine: ipc_port_timestamp
126 * Purpose:
127 * Retrieve a timestamp value.
128 */
129
130ipc_port_timestamp_t
131ipc_port_timestamp(void)
132{
316670eb 133 return OSIncrementAtomic(&ipc_port_timestamp_data);
1c79356b
A
134}
135
136/*
6d2010ae 137 * Routine: ipc_port_request_alloc
1c79356b 138 * Purpose:
6d2010ae 139 * Try to allocate a request slot.
1c79356b
A
140 * If successful, returns the request index.
141 * Otherwise returns zero.
142 * Conditions:
143 * The port is locked and active.
144 * Returns:
145 * KERN_SUCCESS A request index was found.
146 * KERN_NO_SPACE No index allocated.
147 */
148
39236c6e
A
149#if IMPORTANCE_INHERITANCE
150kern_return_t
151ipc_port_request_alloc(
152 ipc_port_t port,
153 mach_port_name_t name,
154 ipc_port_t soright,
155 boolean_t send_possible,
156 boolean_t immediate,
157 ipc_port_request_index_t *indexp,
158 boolean_t *importantp)
159#else
1c79356b 160kern_return_t
6d2010ae 161ipc_port_request_alloc(
1c79356b
A
162 ipc_port_t port,
163 mach_port_name_t name,
164 ipc_port_t soright,
6d2010ae
A
165 boolean_t send_possible,
166 boolean_t immediate,
1c79356b 167 ipc_port_request_index_t *indexp)
39236c6e 168#endif /* IMPORTANCE_INHERITANCE */
1c79356b
A
169{
170 ipc_port_request_t ipr, table;
171 ipc_port_request_index_t index;
6d2010ae 172 uintptr_t mask = 0;
1c79356b 173
39236c6e
A
174#if IMPORTANCE_INHERITANCE
175 *importantp = FALSE;
176#endif /* IMPORTANCE_INHERITANCE */
177
1c79356b
A
178 assert(ip_active(port));
179 assert(name != MACH_PORT_NULL);
180 assert(soright != IP_NULL);
181
6d2010ae
A
182 table = port->ip_requests;
183
1c79356b
A
184 if (table == IPR_NULL)
185 return KERN_NO_SPACE;
186
187 index = table->ipr_next;
188 if (index == 0)
189 return KERN_NO_SPACE;
190
191 ipr = &table[index];
192 assert(ipr->ipr_name == MACH_PORT_NULL);
193
194 table->ipr_next = ipr->ipr_next;
195 ipr->ipr_name = name;
6d2010ae
A
196
197 if (send_possible) {
198 mask |= IPR_SOR_SPREQ_MASK;
199 if (immediate) {
200 mask |= IPR_SOR_SPARM_MASK;
39236c6e
A
201 if (port->ip_sprequests == 0) {
202 port->ip_sprequests = 1;
203#if IMPORTANCE_INHERITANCE
fe8ab488 204 /* TODO: Live importance support in send-possible */
39236c6e
A
205 if (port->ip_impdonation != 0 &&
206 port->ip_spimportant == 0 &&
207 (task_is_importance_donor(current_task()))) {
208 port->ip_spimportant = 1;
209 *importantp = TRUE;
210 }
211#endif /* IMPORTANCE_INHERTANCE */
212 }
6d2010ae
A
213 }
214 }
215 ipr->ipr_soright = IPR_SOR_MAKE(soright, mask);
1c79356b
A
216
217 *indexp = index;
6d2010ae 218
1c79356b
A
219 return KERN_SUCCESS;
220}
221
222/*
6d2010ae 223 * Routine: ipc_port_request_grow
1c79356b 224 * Purpose:
6d2010ae 225 * Grow a port's table of requests.
1c79356b
A
226 * Conditions:
227 * The port must be locked and active.
228 * Nothing else locked; will allocate memory.
229 * Upon return the port is unlocked.
230 * Returns:
231 * KERN_SUCCESS Grew the table.
232 * KERN_SUCCESS Somebody else grew the table.
233 * KERN_SUCCESS The port died.
234 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
235 * KERN_NO_SPACE Couldn't grow to desired size
236 */
237
238kern_return_t
6d2010ae 239ipc_port_request_grow(
91447636
A
240 ipc_port_t port,
241 ipc_table_elems_t target_size)
1c79356b
A
242{
243 ipc_table_size_t its;
244 ipc_port_request_t otable, ntable;
245
246 assert(ip_active(port));
247
6d2010ae 248 otable = port->ip_requests;
1c79356b 249 if (otable == IPR_NULL)
6d2010ae 250 its = &ipc_table_requests[0];
1c79356b
A
251 else
252 its = otable->ipr_size + 1;
253
254 if (target_size != ITS_SIZE_NONE) {
255 if ((otable != IPR_NULL) &&
256 (target_size <= otable->ipr_size->its_size)) {
257 ip_unlock(port);
258 return KERN_SUCCESS;
259 }
260 while ((its->its_size) && (its->its_size < target_size)) {
261 its++;
262 }
263 if (its->its_size == 0) {
264 ip_unlock(port);
265 return KERN_NO_SPACE;
266 }
267 }
268
269 ip_reference(port);
270 ip_unlock(port);
271
272 if ((its->its_size == 0) ||
6d2010ae 273 ((ntable = it_requests_alloc(its)) == IPR_NULL)) {
316670eb 274 ip_release(port);
1c79356b
A
275 return KERN_RESOURCE_SHORTAGE;
276 }
277
278 ip_lock(port);
1c79356b
A
279
280 /*
281 * Check that port is still active and that nobody else
282 * has slipped in and grown the table on us. Note that
6d2010ae
A
283 * just checking if the current table pointer == otable
284 * isn't sufficient; must check ipr_size.
1c79356b
A
285 */
286
6d2010ae 287 if (ip_active(port) && (port->ip_requests == otable) &&
1c79356b
A
288 ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
289 ipc_table_size_t oits;
290 ipc_table_elems_t osize, nsize;
291 ipc_port_request_index_t free, i;
292
293 /* copy old table to new table */
294
295 if (otable != IPR_NULL) {
296 oits = otable->ipr_size;
297 osize = oits->its_size;
298 free = otable->ipr_next;
299
300 (void) memcpy((void *)(ntable + 1),
301 (const void *)(otable + 1),
302 (osize - 1) * sizeof(struct ipc_port_request));
303 } else {
304 osize = 1;
91447636 305 oits = 0;
1c79356b
A
306 free = 0;
307 }
308
309 nsize = its->its_size;
310 assert(nsize > osize);
311
312 /* add new elements to the new table's free list */
313
314 for (i = osize; i < nsize; i++) {
315 ipc_port_request_t ipr = &ntable[i];
316
317 ipr->ipr_name = MACH_PORT_NULL;
318 ipr->ipr_next = free;
319 free = i;
320 }
321
322 ntable->ipr_next = free;
323 ntable->ipr_size = its;
6d2010ae 324 port->ip_requests = ntable;
1c79356b 325 ip_unlock(port);
316670eb 326 ip_release(port);
1c79356b
A
327
328 if (otable != IPR_NULL) {
6d2010ae 329 it_requests_free(oits, otable);
1c79356b
A
330 }
331 } else {
316670eb
A
332 ip_unlock(port);
333 ip_release(port);
6d2010ae 334 it_requests_free(its, ntable);
1c79356b
A
335 }
336
337 return KERN_SUCCESS;
338}
339
340/*
6d2010ae 341 * Routine: ipc_port_request_sparm
1c79356b 342 * Purpose:
6d2010ae 343 * Arm delayed send-possible request.
1c79356b 344 * Conditions:
6d2010ae 345 * The port must be locked and active.
39236c6e
A
346 *
347 * Returns TRUE if the request was armed
348 * (or armed with importance in that version).
6d2010ae
A
349 */
350
39236c6e
A
351#if IMPORTANCE_INHERITANCE
352boolean_t
353ipc_port_request_sparm(
354 ipc_port_t port,
355 __assert_only mach_port_name_t name,
356 ipc_port_request_index_t index,
357 mach_msg_option_t option)
358#else
359boolean_t
6d2010ae
A
360ipc_port_request_sparm(
361 ipc_port_t port,
362 __assert_only mach_port_name_t name,
363 ipc_port_request_index_t index)
39236c6e 364#endif /* IMPORTANCE_INHERITANCE */
6d2010ae
A
365{
366 if (index != IE_REQ_NONE) {
367 ipc_port_request_t ipr, table;
368
369 assert(ip_active(port));
370
371 table = port->ip_requests;
372 assert(table != IPR_NULL);
373
374 ipr = &table[index];
375 assert(ipr->ipr_name == name);
376
377 if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
378 ipr->ipr_soright = IPR_SOR_MAKE(ipr->ipr_soright, IPR_SOR_SPARM_MASK);
39236c6e
A
379 port->ip_sprequests = 1;
380#if IMPORTANCE_INHERITANCE
381 if (((option & MACH_SEND_NOIMPORTANCE) == 0) &&
382 (port->ip_impdonation != 0) &&
383 (port->ip_spimportant == 0) &&
384 (((option & MACH_SEND_IMPORTANCE) != 0) ||
385 (task_is_importance_donor(current_task())))) {
386 port->ip_spimportant = 1;
387 return TRUE;
388 }
389#else
390 return TRUE;
391#endif /* IMPORTANCE_INHERITANCE */
392 }
6d2010ae 393 }
39236c6e 394 return FALSE;
6d2010ae
A
395}
396
397/*
398 * Routine: ipc_port_request_type
399 * Purpose:
400 * Determine the type(s) of port requests enabled for a name.
401 * Conditions:
402 * The port must be locked or inactive (to avoid table growth).
403 * The index must not be IE_REQ_NONE and for the name in question.
404 */
405mach_port_type_t
406ipc_port_request_type(
407 ipc_port_t port,
408 __assert_only mach_port_name_t name,
409 ipc_port_request_index_t index)
410{
411 ipc_port_request_t ipr, table;
412 mach_port_type_t type = 0;
413
414 table = port->ip_requests;
415 assert (table != IPR_NULL);
416
417 assert(index != IE_REQ_NONE);
418 ipr = &table[index];
419 assert(ipr->ipr_name == name);
420
421 if (IP_VALID(IPR_SOR_PORT(ipr->ipr_soright))) {
422 type |= MACH_PORT_TYPE_DNREQUEST;
423
424 if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
425 type |= MACH_PORT_TYPE_SPREQUEST;
426
427 if (!IPR_SOR_SPARMED(ipr->ipr_soright)) {
428 type |= MACH_PORT_TYPE_SPREQUEST_DELAYED;
6d2010ae
A
429 }
430 }
431 }
432 return type;
433}
434
435/*
436 * Routine: ipc_port_request_cancel
437 * Purpose:
438 * Cancel a dead-name/send-possible request and return the send-once right.
439 * Conditions:
440 * The port must be locked and active.
441 * The index must not be IPR_REQ_NONE and must correspond with name.
1c79356b
A
442 */
443
444ipc_port_t
6d2010ae
A
445ipc_port_request_cancel(
446 ipc_port_t port,
91447636 447 __assert_only mach_port_name_t name,
6d2010ae 448 ipc_port_request_index_t index)
1c79356b
A
449{
450 ipc_port_request_t ipr, table;
6d2010ae 451 ipc_port_t request = IP_NULL;
1c79356b
A
452
453 assert(ip_active(port));
6d2010ae 454 table = port->ip_requests;
1c79356b
A
455 assert(table != IPR_NULL);
456
6d2010ae 457 assert (index != IE_REQ_NONE);
1c79356b 458 ipr = &table[index];
1c79356b 459 assert(ipr->ipr_name == name);
6d2010ae 460 request = IPR_SOR_PORT(ipr->ipr_soright);
1c79356b
A
461
462 /* return ipr to the free list inside the table */
1c79356b
A
463 ipr->ipr_name = MACH_PORT_NULL;
464 ipr->ipr_next = table->ipr_next;
465 table->ipr_next = index;
466
6d2010ae 467 return request;
1c79356b
A
468}
469
470/*
471 * Routine: ipc_port_pdrequest
472 * Purpose:
473 * Make a port-deleted request, returning the
474 * previously registered send-once right.
475 * Just cancels the previous request if notify is IP_NULL.
476 * Conditions:
477 * The port is locked and active. It is unlocked.
478 * Consumes a ref for notify (if non-null), and
479 * returns previous with a ref (if non-null).
480 */
481
482void
483ipc_port_pdrequest(
484 ipc_port_t port,
485 ipc_port_t notify,
486 ipc_port_t *previousp)
487{
488 ipc_port_t previous;
489
490 assert(ip_active(port));
491
492 previous = port->ip_pdrequest;
493 port->ip_pdrequest = notify;
494 ip_unlock(port);
495
496 *previousp = previous;
497}
498
499/*
500 * Routine: ipc_port_nsrequest
501 * Purpose:
502 * Make a no-senders request, returning the
503 * previously registered send-once right.
504 * Just cancels the previous request if notify is IP_NULL.
505 * Conditions:
506 * The port is locked and active. It is unlocked.
507 * Consumes a ref for notify (if non-null), and
508 * returns previous with a ref (if non-null).
509 */
510
511void
512ipc_port_nsrequest(
513 ipc_port_t port,
514 mach_port_mscount_t sync,
515 ipc_port_t notify,
516 ipc_port_t *previousp)
517{
518 ipc_port_t previous;
519 mach_port_mscount_t mscount;
520
521 assert(ip_active(port));
522
523 previous = port->ip_nsrequest;
524 mscount = port->ip_mscount;
525
526 if ((port->ip_srights == 0) && (sync <= mscount) &&
527 (notify != IP_NULL)) {
528 port->ip_nsrequest = IP_NULL;
529 ip_unlock(port);
530 ipc_notify_no_senders(notify, mscount);
531 } else {
532 port->ip_nsrequest = notify;
533 ip_unlock(port);
534 }
535
536 *previousp = previous;
537}
538
539
540/*
541 * Routine: ipc_port_clear_receiver
542 * Purpose:
543 * Prepares a receive right for transmission/destruction.
544 * Conditions:
545 * The port is locked and active.
546 */
547
548void
549ipc_port_clear_receiver(
316670eb
A
550 ipc_port_t port,
551 queue_t links)
1c79356b
A
552{
553 spl_t s;
554
555 assert(ip_active(port));
556
557 /*
558 * pull ourselves from any sets.
559 */
560 if (port->ip_pset_count != 0) {
316670eb 561 ipc_pset_remove_from_all(port, links);
9bccf70c 562 assert(port->ip_pset_count == 0);
1c79356b
A
563 }
564
565 /*
566 * Send anyone waiting on the port's queue directly away.
567 * Also clear the mscount and seqno.
568 */
569 s = splsched();
570 imq_lock(&port->ip_messages);
571 ipc_mqueue_changed(&port->ip_messages);
572 ipc_port_set_mscount(port, 0);
573 port->ip_messages.imq_seqno = 0;
39236c6e 574 port->ip_context = port->ip_guarded = port->ip_strict_guard = 0;
1c79356b
A
575 imq_unlock(&port->ip_messages);
576 splx(s);
577}
578
579/*
580 * Routine: ipc_port_init
581 * Purpose:
582 * Initializes a newly-allocated port.
583 * Doesn't touch the ip_object fields.
584 */
585
586void
587ipc_port_init(
588 ipc_port_t port,
589 ipc_space_t space,
590 mach_port_name_t name)
591{
592 /* port->ip_kobject doesn't have to be initialized */
593
594 port->ip_receiver = space;
595 port->ip_receiver_name = name;
596
597 port->ip_mscount = 0;
598 port->ip_srights = 0;
599 port->ip_sorights = 0;
600
601 port->ip_nsrequest = IP_NULL;
602 port->ip_pdrequest = IP_NULL;
6d2010ae 603 port->ip_requests = IPR_NULL;
1c79356b
A
604
605 port->ip_pset_count = 0;
606 port->ip_premsg = IKM_NULL;
b0d623f7 607 port->ip_context = 0;
1c79356b 608
39236c6e
A
609 port->ip_sprequests = 0;
610 port->ip_spimportant = 0;
611 port->ip_impdonation = 0;
612 port->ip_tempowner = 0;
39236c6e
A
613
614 port->ip_guarded = 0;
615 port->ip_strict_guard = 0;
616 port->ip_impcount = 0;
617
618 port->ip_reserved = 0;
619
1c79356b
A
620 ipc_mqueue_init(&port->ip_messages, FALSE /* set */);
621}
622
623/*
624 * Routine: ipc_port_alloc
625 * Purpose:
626 * Allocate a port.
627 * Conditions:
628 * Nothing locked. If successful, the port is returned
629 * locked. (The caller doesn't have a reference.)
630 * Returns:
631 * KERN_SUCCESS The port is allocated.
632 * KERN_INVALID_TASK The space is dead.
633 * KERN_NO_SPACE No room for an entry in the space.
634 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
635 */
636
637kern_return_t
638ipc_port_alloc(
639 ipc_space_t space,
640 mach_port_name_t *namep,
641 ipc_port_t *portp)
642{
643 ipc_port_t port;
644 mach_port_name_t name;
645 kern_return_t kr;
646
316670eb 647#if MACH_ASSERT
39236c6e 648 uintptr_t buf[IP_CALLSTACK_MAX];
316670eb
A
649 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
650#endif /* MACH_ASSERT */
651
1c79356b
A
652 kr = ipc_object_alloc(space, IOT_PORT,
653 MACH_PORT_TYPE_RECEIVE, 0,
654 &name, (ipc_object_t *) &port);
655 if (kr != KERN_SUCCESS)
656 return kr;
657
99c3a104 658 /* port and space are locked */
1c79356b
A
659 ipc_port_init(port, space, name);
660
316670eb
A
661#if MACH_ASSERT
662 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
663#endif /* MACH_ASSERT */
664
99c3a104
A
665 /* unlock space after init */
666 is_write_unlock(space);
667
1c79356b
A
668 *namep = name;
669 *portp = port;
670
671 return KERN_SUCCESS;
672}
673
674/*
675 * Routine: ipc_port_alloc_name
676 * Purpose:
677 * Allocate a port, with a specific name.
678 * Conditions:
679 * Nothing locked. If successful, the port is returned
680 * locked. (The caller doesn't have a reference.)
681 * Returns:
682 * KERN_SUCCESS The port is allocated.
683 * KERN_INVALID_TASK The space is dead.
684 * KERN_NAME_EXISTS The name already denotes a right.
685 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
686 */
687
688kern_return_t
689ipc_port_alloc_name(
690 ipc_space_t space,
691 mach_port_name_t name,
692 ipc_port_t *portp)
693{
694 ipc_port_t port;
695 kern_return_t kr;
696
316670eb 697#if MACH_ASSERT
39236c6e 698 uintptr_t buf[IP_CALLSTACK_MAX];
316670eb
A
699 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
700#endif /* MACH_ASSERT */
701
1c79356b
A
702 kr = ipc_object_alloc_name(space, IOT_PORT,
703 MACH_PORT_TYPE_RECEIVE, 0,
704 name, (ipc_object_t *) &port);
705 if (kr != KERN_SUCCESS)
706 return kr;
707
708 /* port is locked */
709
710 ipc_port_init(port, space, name);
711
316670eb
A
712#if MACH_ASSERT
713 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
714#endif /* MACH_ASSERT */
715
1c79356b
A
716 *portp = port;
717
718 return KERN_SUCCESS;
719}
720
721/*
6d2010ae
A
722 * Routine: ipc_port_spnotify
723 * Purpose:
724 * Generate send-possible port notifications.
725 * Conditions:
726 * Nothing locked, reference held on port.
1c79356b
A
727 */
728void
6d2010ae
A
729ipc_port_spnotify(
730 ipc_port_t port)
1c79356b 731{
6d2010ae
A
732 ipc_port_request_index_t index = 0;
733 ipc_table_elems_t size = 0;
39236c6e
A
734#if IMPORTANCE_INHERITANCE
735 boolean_t dropassert = FALSE;
736#endif /* IMPORTANCE_INHERITANCE */
1c79356b 737
6d2010ae
A
738 /*
739 * If the port has no send-possible request
740 * armed, don't bother to lock the port.
741 */
39236c6e 742 if (port->ip_sprequests == 0)
6d2010ae 743 return;
1c79356b 744
6d2010ae 745 ip_lock(port);
39236c6e
A
746
747#if IMPORTANCE_INHERITANCE
748 if (port->ip_spimportant != 0) {
749 port->ip_spimportant = 0;
fe8ab488
A
750 if (ipc_port_impcount_delta(port, -1, IP_NULL) == -1) {
751 dropassert = TRUE;
752 }
39236c6e
A
753 }
754#endif /* IMPORTANCE_INHERITANCE */
755
756 if (port->ip_sprequests == 0) {
6d2010ae 757 ip_unlock(port);
39236c6e 758 goto out;
6d2010ae 759 }
39236c6e 760 port->ip_sprequests = 0;
1c79356b 761
39236c6e 762revalidate:
6d2010ae
A
763 if (ip_active(port)) {
764 ipc_port_request_t requests;
765
766 /* table may change each time port unlocked (reload) */
767 requests = port->ip_requests;
768 assert(requests != IPR_NULL);
769
770 /*
771 * no need to go beyond table size when first
772 * we entered - those are future notifications.
773 */
774 if (size == 0)
775 size = requests->ipr_size->its_size;
776
777 /* no need to backtrack either */
778 while (++index < size) {
779 ipc_port_request_t ipr = &requests[index];
780 mach_port_name_t name = ipr->ipr_name;
781 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
782 boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright);
783
784 if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) {
785 /* claim send-once right - slot still inuse */
786 ipr->ipr_soright = IP_NULL;
787 ip_unlock(port);
788
789 ipc_notify_send_possible(soright, name);
790
791 ip_lock(port);
792 goto revalidate;
793 }
794 }
1c79356b 795 }
6d2010ae 796 ip_unlock(port);
39236c6e
A
797out:
798#if IMPORTANCE_INHERITANCE
fe8ab488
A
799 if (dropassert == TRUE && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) {
800 /* drop internal assertion */
801 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, 1);
39236c6e
A
802 }
803#endif /* IMPORTANCE_INHERITANCE */
804 return;
6d2010ae 805}
1c79356b 806
6d2010ae
A
807/*
808 * Routine: ipc_port_dnnotify
809 * Purpose:
810 * Generate dead name notifications for
811 * all outstanding dead-name and send-
812 * possible requests.
813 * Conditions:
814 * Nothing locked.
815 * Port must be inactive.
816 * Reference held on port.
817 */
818void
819ipc_port_dnnotify(
820 ipc_port_t port)
821{
822 ipc_port_request_t requests = port->ip_requests;
823
824 assert(!ip_active(port));
825 if (requests != IPR_NULL) {
826 ipc_table_size_t its = requests->ipr_size;
827 ipc_table_elems_t size = its->its_size;
828 ipc_port_request_index_t index;
829 for (index = 1; index < size; index++) {
830 ipc_port_request_t ipr = &requests[index];
831 mach_port_name_t name = ipr->ipr_name;
832 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
833
834 if (MACH_PORT_VALID(name) && IP_VALID(soright)) {
835 ipc_notify_dead_name(soright, name);
836 }
837 }
838 }
1c79356b
A
839}
840
6d2010ae 841
1c79356b
A
842/*
843 * Routine: ipc_port_destroy
844 * Purpose:
845 * Destroys a port. Cleans up queued messages.
846 *
847 * If the port has a backup, it doesn't get destroyed,
848 * but is sent in a port-destroyed notification to the backup.
849 * Conditions:
850 * The port is locked and alive; nothing else locked.
851 * The caller has a reference, which is consumed.
852 * Afterwards, the port is unlocked and dead.
853 */
854
855void
856ipc_port_destroy(
857 ipc_port_t port)
858{
859 ipc_port_t pdrequest, nsrequest;
860 ipc_mqueue_t mqueue;
1c79356b 861 ipc_kmsg_t kmsg;
1c79356b 862
39236c6e 863#if IMPORTANCE_INHERITANCE
fe8ab488 864 ipc_importance_task_t release_imp_task = IIT_NULL;
39236c6e
A
865 thread_t self = current_thread();
866 boolean_t top = (self->ith_assertions == 0);
867 natural_t assertcnt = 0;
868#endif /* IMPORTANCE_INHERITANCE */
869
1c79356b
A
870 assert(ip_active(port));
871 /* port->ip_receiver_name is garbage */
872 /* port->ip_receiver/port->ip_destination is garbage */
873 assert(port->ip_pset_count == 0);
874 assert(port->ip_mscount == 0);
875
39236c6e 876 /* check for a backup port */
1c79356b 877 pdrequest = port->ip_pdrequest;
39236c6e
A
878
879#if IMPORTANCE_INHERITANCE
fe8ab488 880 /* determine how many assertions to drop and from whom */
39236c6e
A
881 if (port->ip_tempowner != 0) {
882 assert(top);
fe8ab488
A
883 release_imp_task = port->ip_imp_task;
884 if (IIT_NULL != release_imp_task) {
885 port->ip_imp_task = IIT_NULL;
39236c6e
A
886 assertcnt = port->ip_impcount;
887 }
888 /* Otherwise, nothing to drop */
889 } else {
39236c6e
A
890 assertcnt = port->ip_impcount;
891 if (pdrequest != IP_NULL)
892 /* mark in limbo for the journey */
893 port->ip_tempowner = 1;
894 }
895
896 if (top)
897 self->ith_assertions = assertcnt;
898#endif /* IMPORTANCE_INHERITANCE */
899
1c79356b
A
900 if (pdrequest != IP_NULL) {
901 /* we assume the ref for pdrequest */
902 port->ip_pdrequest = IP_NULL;
903
904 /* make port be in limbo */
905 port->ip_receiver_name = MACH_PORT_NULL;
906 port->ip_destination = IP_NULL;
907 ip_unlock(port);
908
55e303ae
A
909 /* consumes our refs for port and pdrequest */
910 ipc_notify_port_destroyed(pdrequest, port);
39236c6e
A
911
912 goto drop_assertions;
1c79356b
A
913 }
914
915 /* once port is dead, we don't need to keep it locked */
916
917 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
918 port->ip_timestamp = ipc_port_timestamp();
fe8ab488 919 nsrequest = port->ip_nsrequest;
1c79356b 920
1c79356b
A
921 /*
922 * If the port has a preallocated message buffer and that buffer
9bccf70c 923 * is not inuse, free it. If it has an inuse one, then the kmsg
1c79356b
A
924 * free will detect that we freed the association and it can free it
925 * like a normal buffer.
926 */
927 if (IP_PREALLOC(port)) {
316670eb
A
928 ipc_port_t inuse_port;
929
1c79356b
A
930 kmsg = port->ip_premsg;
931 assert(kmsg != IKM_NULL);
316670eb 932 inuse_port = ikm_prealloc_inuse_port(kmsg);
9bccf70c 933 IP_CLEAR_PREALLOC(port, kmsg);
316670eb
A
934 ip_unlock(port);
935 if (inuse_port != IP_NULL) {
936 assert(inuse_port == port);
937 } else {
1c79356b 938 ipc_kmsg_free(kmsg);
316670eb
A
939 }
940 } else {
941 ip_unlock(port);
1c79356b 942 }
1c79356b 943
1c79356b 944 /* throw away no-senders request */
1c79356b
A
945 if (nsrequest != IP_NULL)
946 ipc_notify_send_once(nsrequest); /* consumes ref */
947
948 /* destroy any queued messages */
949 mqueue = &port->ip_messages;
950 ipc_mqueue_destroy(mqueue);
951
952 /* generate dead-name notifications */
6d2010ae 953 ipc_port_dnnotify(port);
1c79356b
A
954
955 ipc_kobject_destroy(port);
956
316670eb 957 ip_release(port); /* consume caller's ref */
39236c6e
A
958
959 drop_assertions:
960#if IMPORTANCE_INHERITANCE
fe8ab488 961 if (release_imp_task != IIT_NULL) {
39236c6e
A
962 if (assertcnt > 0) {
963 assert(top);
964 self->ith_assertions = 0;
fe8ab488
A
965 assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
966 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
39236c6e 967 }
fe8ab488 968 ipc_importance_task_release(release_imp_task);
39236c6e
A
969
970 } else if (assertcnt > 0) {
971 if (top) {
972 self->ith_assertions = 0;
fe8ab488
A
973 release_imp_task = current_task()->task_imp_base;
974 if (ipc_importance_task_is_any_receiver_type(release_imp_task)) {
975 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
39236c6e 976 }
39236c6e
A
977 }
978 }
979#endif /* IMPORTANCE_INHERITANCE */
1c79356b
A
980}
981
982/*
983 * Routine: ipc_port_check_circularity
984 * Purpose:
985 * Check if queueing "port" in a message for "dest"
986 * would create a circular group of ports and messages.
987 *
988 * If no circularity (FALSE returned), then "port"
989 * is changed from "in limbo" to "in transit".
990 *
991 * That is, we want to set port->ip_destination == dest,
992 * but guaranteeing that this doesn't create a circle
993 * port->ip_destination->ip_destination->... == port
39236c6e
A
994 *
995 * Additionally, if port was successfully changed to "in transit",
996 * propagate boost assertions from the "in limbo" port to all
997 * the ports in the chain, and, if the destination task accepts
998 * boosts, to the destination task.
999 *
1c79356b
A
1000 * Conditions:
1001 * No ports locked. References held for "port" and "dest".
1002 */
1003
1004boolean_t
1005ipc_port_check_circularity(
1006 ipc_port_t port,
1007 ipc_port_t dest)
1008{
1009 ipc_port_t base;
1010
39236c6e 1011#if IMPORTANCE_INHERITANCE
fe8ab488
A
1012 ipc_importance_task_t imp_task = IIT_NULL;
1013 ipc_importance_task_t release_imp_task = IIT_NULL;
39236c6e
A
1014 int assertcnt = 0;
1015#endif /* IMPORTANCE_INHERITANCE */
1016
1c79356b
A
1017 assert(port != IP_NULL);
1018 assert(dest != IP_NULL);
1019
1020 if (port == dest)
1021 return TRUE;
1022 base = dest;
1023
1024 /*
1025 * First try a quick check that can run in parallel.
1026 * No circularity if dest is not in transit.
1027 */
1028
1029 ip_lock(port);
1030 if (ip_lock_try(dest)) {
1031 if (!ip_active(dest) ||
1032 (dest->ip_receiver_name != MACH_PORT_NULL) ||
1033 (dest->ip_destination == IP_NULL))
1034 goto not_circular;
1035
1036 /* dest is in transit; further checking necessary */
1037
1038 ip_unlock(dest);
1039 }
1040 ip_unlock(port);
1041
1042 ipc_port_multiple_lock(); /* massive serialization */
1043
1044 /*
1045 * Search for the end of the chain (a port not in transit),
1046 * acquiring locks along the way.
1047 */
1048
1049 for (;;) {
1050 ip_lock(base);
1051
1052 if (!ip_active(base) ||
1053 (base->ip_receiver_name != MACH_PORT_NULL) ||
1054 (base->ip_destination == IP_NULL))
1055 break;
1056
1057 base = base->ip_destination;
1058 }
1059
1060 /* all ports in chain from dest to base, inclusive, are locked */
1061
1062 if (port == base) {
1063 /* circularity detected! */
1064
1065 ipc_port_multiple_unlock();
1066
1067 /* port (== base) is in limbo */
1068
1069 assert(ip_active(port));
1070 assert(port->ip_receiver_name == MACH_PORT_NULL);
1071 assert(port->ip_destination == IP_NULL);
1072
1073 while (dest != IP_NULL) {
1074 ipc_port_t next;
1075
1076 /* dest is in transit or in limbo */
1077
1078 assert(ip_active(dest));
1079 assert(dest->ip_receiver_name == MACH_PORT_NULL);
1080
1081 next = dest->ip_destination;
1082 ip_unlock(dest);
1083 dest = next;
1084 }
1085
1086 return TRUE;
1087 }
1088
1089 /*
1090 * The guarantee: lock port while the entire chain is locked.
1091 * Once port is locked, we can take a reference to dest,
1092 * add port to the chain, and unlock everything.
1093 */
1094
1095 ip_lock(port);
1096 ipc_port_multiple_unlock();
1097
1098 not_circular:
1099
1100 /* port is in limbo */
1101
1102 assert(ip_active(port));
1103 assert(port->ip_receiver_name == MACH_PORT_NULL);
1104 assert(port->ip_destination == IP_NULL);
1105
1106 ip_reference(dest);
1107 port->ip_destination = dest;
1108
39236c6e
A
1109#if IMPORTANCE_INHERITANCE
1110 /* must have been in limbo or still bound to a task */
1111 assert(port->ip_tempowner != 0);
1112
fe8ab488
A
1113 /*
1114 * We delayed dropping assertions from a specific task.
1115 * Cache that info now (we'll drop assertions and the
1116 * task reference below).
1117 */
1118 release_imp_task = port->ip_imp_task;
1119 if (IIT_NULL != release_imp_task) {
1120 port->ip_imp_task = IIT_NULL;
39236c6e
A
1121 }
1122 assertcnt = port->ip_impcount;
1123
1124 /* take the port out of limbo w.r.t. assertions */
1125 port->ip_tempowner = 0;
1126
1127#endif /* IMPORTANCE_INHERITANCE */
1128
1c79356b
A
1129 /* now unlock chain */
1130
39236c6e
A
1131 ip_unlock(port);
1132
1133 for (;;) {
1134
1135#if IMPORTANCE_INHERITANCE
1136 /* every port along chain track assertions behind it */
1137 dest->ip_impcount += assertcnt;
1138#endif /* IMPORTANCE_INHERITANCE */
1139
1140 if (dest == base)
1141 break;
1c79356b
A
1142
1143 /* port is in transit */
1144
39236c6e
A
1145 assert(ip_active(dest));
1146 assert(dest->ip_receiver_name == MACH_PORT_NULL);
1147 assert(dest->ip_destination != IP_NULL);
1c79356b 1148
39236c6e
A
1149#if IMPORTANCE_INHERITANCE
1150 assert(dest->ip_tempowner == 0);
1151#endif /* IMPORTANCE_INHERITANCE */
1152
1153 port = dest->ip_destination;
1154 ip_unlock(dest);
1155 dest = port;
1c79356b
A
1156 }
1157
1158 /* base is not in transit */
1c79356b
A
1159 assert(!ip_active(base) ||
1160 (base->ip_receiver_name != MACH_PORT_NULL) ||
1161 (base->ip_destination == IP_NULL));
39236c6e
A
1162
1163#if IMPORTANCE_INHERITANCE
1164 /*
1165 * Find the task to boost (if any).
1166 * We will boost "through" ports that don't know
1167 * about inheritance to deliver receive rights that
1168 * do.
1169 */
1170 if (ip_active(base) && (assertcnt > 0)) {
1171 if (base->ip_tempowner != 0) {
fe8ab488 1172 if (IIT_NULL != base->ip_imp_task) {
39236c6e 1173 /* specified tempowner task */
fe8ab488
A
1174 imp_task = base->ip_imp_task;
1175 assert(ipc_importance_task_is_any_receiver_type(imp_task));
1176 }
39236c6e
A
1177 /* otherwise don't boost current task */
1178
1179 } else if (base->ip_receiver_name != MACH_PORT_NULL) {
1180 ipc_space_t space = base->ip_receiver;
1181
1182 /* only spaces with boost-accepting tasks */
1183 if (space->is_task != TASK_NULL &&
fe8ab488
A
1184 ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base))
1185 imp_task = space->is_task->task_imp_base;
39236c6e
A
1186 }
1187
1188 /* take reference before unlocking base */
fe8ab488
A
1189 if (imp_task != IIT_NULL) {
1190 ipc_importance_task_reference(imp_task);
39236c6e
A
1191 }
1192 }
1193#endif /* IMPORTANCE_INHERITANCE */
1194
1c79356b
A
1195 ip_unlock(base);
1196
39236c6e
A
1197#if IMPORTANCE_INHERITANCE
1198 /*
1199 * Transfer assertions now that the ports are unlocked.
1200 * Avoid extra overhead if transferring to/from the same task.
1201 */
fe8ab488 1202 boolean_t transfer_assertions = (imp_task != release_imp_task) ? TRUE : FALSE;
39236c6e 1203
fe8ab488 1204 if (imp_task != IIT_NULL) {
39236c6e 1205 if (transfer_assertions)
fe8ab488
A
1206 ipc_importance_task_hold_internal_assertion(imp_task, assertcnt);
1207 ipc_importance_task_release(imp_task);
1208 imp_task = IIT_NULL;
39236c6e
A
1209 }
1210
fe8ab488 1211 if (release_imp_task != IIT_NULL) {
39236c6e 1212 if (transfer_assertions)
fe8ab488
A
1213 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1214 ipc_importance_task_release(release_imp_task);
1215 release_imp_task = IIT_NULL;
39236c6e
A
1216 }
1217#endif /* IMPORTANCE_INHERITANCE */
1218
1c79356b
A
1219 return FALSE;
1220}
1221
39236c6e 1222/*
fe8ab488
A
1223 * Routine: ipc_port_impcount_delta
1224 * Purpose:
1225 * Adjust only the importance count associated with a port.
1226 * If there are any adjustments to be made to receiver task,
1227 * those are handled elsewhere.
1228 *
1229 * For now, be defensive during deductions to make sure the
1230 * impcount for the port doesn't underflow zero. This will
1231 * go away when the port boost addition is made atomic (see
1232 * note in ipc_port_importance_delta()).
1233 * Conditions:
1234 * The port is referenced and locked.
1235 * Nothing else is locked.
1236 */
1237mach_port_delta_t
1238ipc_port_impcount_delta(
1239 ipc_port_t port,
1240 mach_port_delta_t delta,
1241 ipc_port_t __unused base)
1242{
1243 mach_port_delta_t absdelta;
1244
1245 if (!ip_active(port)) {
1246 return 0;
1247 }
1248
1249 /* adding/doing nothing is easy */
1250 if (delta >= 0) {
1251 port->ip_impcount += delta;
1252 return delta;
1253 }
1254
1255 absdelta = 0 - delta;
1256 //assert(port->ip_impcount >= absdelta);
1257 /* if we have enough to deduct, we're done */
1258 if (port->ip_impcount >= absdelta) {
1259 port->ip_impcount -= absdelta;
1260 return delta;
1261 }
1262
1263#if DEVELOPMENT || DEBUG
1264 if (port->ip_receiver_name != MACH_PORT_NULL) {
1265 task_t target_task = port->ip_receiver->is_task;
1266 ipc_importance_task_t target_imp = target_task->task_imp_base;
1267 const char *target_procname;
1268 int target_pid;
1269
1270 if (target_imp != IIT_NULL) {
1271 target_procname = target_imp->iit_procname;
1272 target_pid = target_imp->iit_bsd_pid;
1273 } else {
1274 target_procname = "unknown";
1275 target_pid = -1;
1276 }
1277 printf("Over-release of importance assertions for port 0x%x receiver pid %d (%s), "
1278 "dropping %d assertion(s) but port only has %d remaining.\n",
1279 port->ip_receiver_name,
1280 target_imp->iit_bsd_pid, target_imp->iit_procname,
1281 absdelta, port->ip_impcount);
1282
1283 } else if (base != IP_NULL) {
1284 task_t target_task = base->ip_receiver->is_task;
1285 ipc_importance_task_t target_imp = target_task->task_imp_base;
1286 const char *target_procname;
1287 int target_pid;
1288
1289 if (target_imp != IIT_NULL) {
1290 target_procname = target_imp->iit_procname;
1291 target_pid = target_imp->iit_bsd_pid;
1292 } else {
1293 target_procname = "unknown";
1294 target_pid = -1;
1295 }
1296 printf("Over-release of importance assertions for port %p "
1297 "enqueued on port 0x%x with receiver pid %d (%s), "
1298 "dropping %d assertion(s) but port only has %d remaining.\n",
1299 port, base->ip_receiver_name,
1300 target_imp->iit_bsd_pid, target_imp->iit_procname,
1301 absdelta, port->ip_impcount);
1302 }
1303#endif
1304 delta = 0 - port->ip_impcount;
1305 port->ip_impcount = 0;
1306 return delta;
1307}
1308
1309/*
1310 * Routine: ipc_port_importance_delta_internal
39236c6e
A
1311 * Purpose:
1312 * Adjust the importance count through the given port.
1313 * If the port is in transit, apply the delta throughout
1314 * the chain. Determine if the there is a task at the
1315 * base of the chain that wants/needs to be adjusted,
1316 * and if so, apply the delta.
1317 * Conditions:
1318 * The port is referenced and locked on entry.
1319 * Nothing else is locked.
1320 * The lock may be dropped on exit.
1321 * Returns TRUE if lock was dropped.
1322 */
1323#if IMPORTANCE_INHERITANCE
1324
1325boolean_t
fe8ab488 1326ipc_port_importance_delta_internal(
39236c6e 1327 ipc_port_t port,
fe8ab488
A
1328 mach_port_delta_t *deltap,
1329 ipc_importance_task_t *imp_task)
39236c6e
A
1330{
1331 ipc_port_t next, base;
39236c6e
A
1332 boolean_t dropped = FALSE;
1333
fe8ab488
A
1334 *imp_task = IIT_NULL;
1335
1336 if (*deltap == 0)
39236c6e
A
1337 return FALSE;
1338
1339 base = port;
1340
1341 /* if port is in transit, have to search for end of chain */
1342 if (ip_active(port) &&
1343 port->ip_destination != IP_NULL &&
1344 port->ip_receiver_name == MACH_PORT_NULL) {
1345
1346 dropped = TRUE;
1347
1348 ip_unlock(port);
1349 ipc_port_multiple_lock(); /* massive serialization */
1350 ip_lock(base);
1351
1352 while(ip_active(base) &&
1353 base->ip_destination != IP_NULL &&
1354 base->ip_receiver_name == MACH_PORT_NULL) {
1355
1356 base = base->ip_destination;
1357 ip_lock(base);
1358 }
1359 ipc_port_multiple_unlock();
1360 }
1361
1362 /* unlock down to the base, adding a boost at each level */
1363 for (;;) {
fe8ab488
A
1364 /*
1365 * JMM TODO - because of the port unlock to grab the multiple lock
1366 * above, a subsequent drop of importance could race and beat
1367 * the "previous" increase - causing the port impcount to go
1368 * negative briefly. The defensive deduction performed by
1369 * ipc_port_impcount_delta() defeats that, and therefore can
1370 * cause an importance leak once the increase finally arrives.
1371 *
1372 * Need to rework the importance delta logic to be more like
1373 * ipc_importance_inherit_from() where it locks all it needs in
1374 * one pass to avoid any lock drops - to keep that race from
1375 * ever occuring.
1376 */
1377 *deltap = ipc_port_impcount_delta(port, *deltap, base);
39236c6e 1378
fe8ab488 1379 if (port == base) {
39236c6e 1380 break;
fe8ab488 1381 }
39236c6e
A
1382
1383 /* port is in transit */
1384 assert(port->ip_tempowner == 0);
1385 next = port->ip_destination;
1386 ip_unlock(port);
1387 port = next;
1388 }
1389
1390 /* find the task (if any) to boost according to the base */
1391 if (ip_active(base)) {
1392 if (base->ip_tempowner != 0) {
fe8ab488
A
1393 if (IIT_NULL != base->ip_imp_task)
1394 *imp_task = base->ip_imp_task;
39236c6e
A
1395 /* otherwise don't boost */
1396
1397 } else if (base->ip_receiver_name != MACH_PORT_NULL) {
1398 ipc_space_t space = base->ip_receiver;
1399
1400 /* only spaces with boost-accepting tasks */
1401 if (space->is_task != TASK_NULL &&
fe8ab488
A
1402 ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base)) {
1403 *imp_task = space->is_task->task_imp_base;
1404 }
39236c6e
A
1405 }
1406 }
1407
1408 /*
1409 * Only the base is locked. If we have to hold or drop task
1410 * importance assertions, we'll have to drop that lock as well.
1411 */
fe8ab488 1412 if (*imp_task != IIT_NULL) {
39236c6e 1413 /* take a reference before unlocking base */
fe8ab488
A
1414 ipc_importance_task_reference(*imp_task);
1415 }
39236c6e 1416
fe8ab488 1417 if (dropped == TRUE) {
39236c6e 1418 ip_unlock(base);
fe8ab488 1419 }
39236c6e 1420
fe8ab488
A
1421 return dropped;
1422}
1423#endif /* IMPORTANCE_INHERITANCE */
39236c6e 1424
fe8ab488
A
1425/*
1426 * Routine: ipc_port_importance_delta
1427 * Purpose:
1428 * Adjust the importance count through the given port.
1429 * If the port is in transit, apply the delta throughout
1430 * the chain.
1431 *
1432 * If there is a task at the base of the chain that wants/needs
1433 * to be adjusted, apply the delta.
1434 * Conditions:
1435 * The port is referenced and locked on entry.
1436 * Nothing else is locked.
1437 * The lock may be dropped on exit.
1438 * Returns TRUE if lock was dropped.
1439 */
1440#if IMPORTANCE_INHERITANCE
1441
1442boolean_t
1443ipc_port_importance_delta(
1444 ipc_port_t port,
1445 mach_port_delta_t delta)
1446{
1447 ipc_importance_task_t imp_task = IIT_NULL;
1448 boolean_t dropped;
1449
1450 dropped = ipc_port_importance_delta_internal(port, &delta, &imp_task);
1451
1452 if (IIT_NULL == imp_task)
1453 return dropped;
1454
1455 if (!dropped) {
1456 dropped = TRUE;
1457 ip_unlock(port);
39236c6e
A
1458 }
1459
fe8ab488
A
1460 assert(ipc_importance_task_is_any_receiver_type(imp_task));
1461
1462 if (delta > 0)
1463 ipc_importance_task_hold_internal_assertion(imp_task, delta);
1464 else
1465 ipc_importance_task_drop_internal_assertion(imp_task, -delta);
1466
1467 ipc_importance_task_release(imp_task);
39236c6e
A
1468 return dropped;
1469}
1470#endif /* IMPORTANCE_INHERITANCE */
1471
1c79356b
A
1472/*
1473 * Routine: ipc_port_lookup_notify
1474 * Purpose:
1475 * Make a send-once notify port from a receive right.
1476 * Returns IP_NULL if name doesn't denote a receive right.
1477 * Conditions:
1478 * The space must be locked (read or write) and active.
1479 * Being the active space, we can rely on thread server_id
1480 * context to give us the proper server level sub-order
1481 * within the space.
1482 */
1483
1484ipc_port_t
1485ipc_port_lookup_notify(
1486 ipc_space_t space,
1487 mach_port_name_t name)
1488{
1489 ipc_port_t port;
1490 ipc_entry_t entry;
1491
316670eb 1492 assert(is_active(space));
1c79356b
A
1493
1494 entry = ipc_entry_lookup(space, name);
1495 if (entry == IE_NULL)
1496 return IP_NULL;
1497 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
1498 return IP_NULL;
1499
1500 port = (ipc_port_t) entry->ie_object;
1501 assert(port != IP_NULL);
1502
1503 ip_lock(port);
1504 assert(ip_active(port));
1505 assert(port->ip_receiver_name == name);
1506 assert(port->ip_receiver == space);
1507
1508 ip_reference(port);
1509 port->ip_sorights++;
1510 ip_unlock(port);
1511
1512 return port;
1513}
1514
1515/*
0b4e3aa0 1516 * Routine: ipc_port_make_send_locked
1c79356b
A
1517 * Purpose:
1518 * Make a naked send right from a receive right.
0b4e3aa0 1519 *
1c79356b 1520 * Conditions:
0b4e3aa0 1521 * port locked and active.
1c79356b 1522 */
1c79356b 1523ipc_port_t
0b4e3aa0 1524ipc_port_make_send_locked(
1c79356b
A
1525 ipc_port_t port)
1526{
1c79356b
A
1527 assert(ip_active(port));
1528 port->ip_mscount++;
1529 port->ip_srights++;
1530 ip_reference(port);
1c79356b
A
1531 return port;
1532}
1533
0b4e3aa0
A
1534/*
1535 * Routine: ipc_port_make_send
1536 * Purpose:
1537 * Make a naked send right from a receive right.
1538 */
1539
1540ipc_port_t
1541ipc_port_make_send(
1542 ipc_port_t port)
1543{
1544
1545 if (!IP_VALID(port))
1546 return port;
1547
1548 ip_lock(port);
1549 if (ip_active(port)) {
1550 port->ip_mscount++;
1551 port->ip_srights++;
1552 ip_reference(port);
1553 ip_unlock(port);
1554 return port;
1555 }
1556 ip_unlock(port);
1557 return IP_DEAD;
1558}
1559
1c79356b
A
1560/*
1561 * Routine: ipc_port_copy_send
1562 * Purpose:
1563 * Make a naked send right from another naked send right.
1564 * IP_NULL -> IP_NULL
1565 * IP_DEAD -> IP_DEAD
1566 * dead port -> IP_DEAD
1567 * live port -> port + ref
1568 * Conditions:
1569 * Nothing locked except possibly a space.
1570 */
1571
1572ipc_port_t
1573ipc_port_copy_send(
1574 ipc_port_t port)
1575{
1576 ipc_port_t sright;
1577
1578 if (!IP_VALID(port))
1579 return port;
1580
1581 ip_lock(port);
1582 if (ip_active(port)) {
1583 assert(port->ip_srights > 0);
1584
1585 ip_reference(port);
1586 port->ip_srights++;
1587 sright = port;
1588 } else
1589 sright = IP_DEAD;
1590 ip_unlock(port);
1591
1592 return sright;
1593}
1594
1595/*
1596 * Routine: ipc_port_copyout_send
1597 * Purpose:
1598 * Copyout a naked send right (possibly null/dead),
1599 * or if that fails, destroy the right.
1600 * Conditions:
1601 * Nothing locked.
1602 */
1603
1604mach_port_name_t
1605ipc_port_copyout_send(
1606 ipc_port_t sright,
1607 ipc_space_t space)
1608{
1609 mach_port_name_t name;
1610
1611 if (IP_VALID(sright)) {
1612 kern_return_t kr;
1613
1614 kr = ipc_object_copyout(space, (ipc_object_t) sright,
1615 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
1616 if (kr != KERN_SUCCESS) {
1617 ipc_port_release_send(sright);
1618
1619 if (kr == KERN_INVALID_CAPABILITY)
1620 name = MACH_PORT_DEAD;
1621 else
1622 name = MACH_PORT_NULL;
1623 }
1624 } else
b0d623f7 1625 name = CAST_MACH_PORT_TO_NAME(sright);
1c79356b
A
1626
1627 return name;
1628}
1629
1630/*
1631 * Routine: ipc_port_release_send
1632 * Purpose:
6d2010ae 1633 * Release a naked send right.
1c79356b
A
1634 * Consumes a ref for the port.
1635 * Conditions:
1636 * Nothing locked.
1637 */
1638
1639void
1640ipc_port_release_send(
1641 ipc_port_t port)
1642{
1643 ipc_port_t nsrequest = IP_NULL;
1644 mach_port_mscount_t mscount;
1645
6d2010ae
A
1646 if (!IP_VALID(port))
1647 return;
1c79356b
A
1648
1649 ip_lock(port);
1c79356b 1650
fe8ab488
A
1651 assert(port->ip_srights > 0);
1652 port->ip_srights--;
1653
1c79356b 1654 if (!ip_active(port)) {
316670eb
A
1655 ip_unlock(port);
1656 ip_release(port);
1c79356b
A
1657 return;
1658 }
1659
fe8ab488 1660 if (port->ip_srights == 0 &&
1c79356b
A
1661 port->ip_nsrequest != IP_NULL) {
1662 nsrequest = port->ip_nsrequest;
1663 port->ip_nsrequest = IP_NULL;
1664 mscount = port->ip_mscount;
1665 ip_unlock(port);
316670eb 1666 ip_release(port);
1c79356b 1667 ipc_notify_no_senders(nsrequest, mscount);
316670eb 1668 } else {
1c79356b 1669 ip_unlock(port);
316670eb
A
1670 ip_release(port);
1671 }
1672}
1673
1674/*
1675 * Routine: ipc_port_make_sonce_locked
1676 * Purpose:
1677 * Make a naked send-once right from a receive right.
1678 * Conditions:
1679 * The port is locked and active.
1680 */
1681
1682ipc_port_t
1683ipc_port_make_sonce_locked(
1684 ipc_port_t port)
1685{
1686 assert(ip_active(port));
1687 port->ip_sorights++;
1688 ip_reference(port);
1689 return port;
1c79356b
A
1690}
1691
1692/*
1693 * Routine: ipc_port_make_sonce
1694 * Purpose:
1695 * Make a naked send-once right from a receive right.
1696 * Conditions:
316670eb 1697 * The port is not locked.
1c79356b
A
1698 */
1699
1700ipc_port_t
1701ipc_port_make_sonce(
1702 ipc_port_t port)
1703{
6d2010ae
A
1704 if (!IP_VALID(port))
1705 return port;
1c79356b
A
1706
1707 ip_lock(port);
316670eb
A
1708 if (ip_active(port)) {
1709 port->ip_sorights++;
1710 ip_reference(port);
1711 ip_unlock(port);
1712 return port;
1713 }
1c79356b 1714 ip_unlock(port);
316670eb 1715 return IP_DEAD;
1c79356b
A
1716}
1717
1718/*
1719 * Routine: ipc_port_release_sonce
1720 * Purpose:
1721 * Release a naked send-once right.
1722 * Consumes a ref for the port.
1723 *
1724 * In normal situations, this is never used.
1725 * Send-once rights are only consumed when
1726 * a message (possibly a send-once notification)
1727 * is sent to them.
1728 * Conditions:
1729 * Nothing locked except possibly a space.
1730 */
1731
1732void
1733ipc_port_release_sonce(
1734 ipc_port_t port)
1735{
6d2010ae
A
1736 if (!IP_VALID(port))
1737 return;
1c79356b
A
1738
1739 ip_lock(port);
1740
1741 assert(port->ip_sorights > 0);
1742
1743 port->ip_sorights--;
1744
1c79356b 1745 ip_unlock(port);
316670eb 1746 ip_release(port);
1c79356b
A
1747}
1748
1749/*
1750 * Routine: ipc_port_release_receive
1751 * Purpose:
1752 * Release a naked (in limbo or in transit) receive right.
1753 * Consumes a ref for the port; destroys the port.
1754 * Conditions:
1755 * Nothing locked.
1756 */
1757
1758void
1759ipc_port_release_receive(
1760 ipc_port_t port)
1761{
1762 ipc_port_t dest;
1763
6d2010ae
A
1764 if (!IP_VALID(port))
1765 return;
1c79356b
A
1766
1767 ip_lock(port);
1768 assert(ip_active(port));
1769 assert(port->ip_receiver_name == MACH_PORT_NULL);
1770 dest = port->ip_destination;
1771
1772 ipc_port_destroy(port); /* consumes ref, unlocks */
1773
1774 if (dest != IP_NULL)
316670eb 1775 ip_release(dest);
1c79356b
A
1776}
1777
1778/*
1779 * Routine: ipc_port_alloc_special
1780 * Purpose:
1781 * Allocate a port in a special space.
1782 * The new port is returned with one ref.
1783 * If unsuccessful, IP_NULL is returned.
1784 * Conditions:
1785 * Nothing locked.
1786 */
1787
1788ipc_port_t
1789ipc_port_alloc_special(
1790 ipc_space_t space)
1791{
1792 ipc_port_t port;
1793
1794 port = (ipc_port_t) io_alloc(IOT_PORT);
1795 if (port == IP_NULL)
1796 return IP_NULL;
1797
316670eb 1798#if MACH_ASSERT
39236c6e 1799 uintptr_t buf[IP_CALLSTACK_MAX];
316670eb
A
1800 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
1801#endif /* MACH_ASSERT */
1802
1c79356b
A
1803 bzero((char *)port, sizeof(*port));
1804 io_lock_init(&port->ip_object);
1805 port->ip_references = 1;
1806 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1807
1808 ipc_port_init(port, space, 1);
1809
316670eb
A
1810#if MACH_ASSERT
1811 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX);
1812#endif /* MACH_ASSERT */
1813
1c79356b
A
1814 return port;
1815}
1816
1817/*
1818 * Routine: ipc_port_dealloc_special
1819 * Purpose:
1820 * Deallocate a port in a special space.
1821 * Consumes one ref for the port.
1822 * Conditions:
1823 * Nothing locked.
1824 */
1825
1826void
1827ipc_port_dealloc_special(
91447636
A
1828 ipc_port_t port,
1829 __assert_only ipc_space_t space)
1c79356b
A
1830{
1831 ip_lock(port);
1832 assert(ip_active(port));
55e303ae 1833// assert(port->ip_receiver_name != MACH_PORT_NULL);
1c79356b
A
1834 assert(port->ip_receiver == space);
1835
1836 /*
1837 * We clear ip_receiver_name and ip_receiver to simplify
1838 * the ipc_space_kernel check in ipc_mqueue_send.
1839 */
1840
1841 port->ip_receiver_name = MACH_PORT_NULL;
1842 port->ip_receiver = IS_NULL;
1843
1844 /* relevant part of ipc_port_clear_receiver */
1845 ipc_port_set_mscount(port, 0);
1846 port->ip_messages.imq_seqno = 0;
1847
1848 ipc_port_destroy(port);
1849}
1850
6d2010ae
A
1851/*
1852 * Routine: ipc_port_finalize
1853 * Purpose:
1854 * Called on last reference deallocate to
1855 * free any remaining data associated with the
1856 * port.
1857 * Conditions:
1858 * Nothing locked.
1859 */
1860void
1861ipc_port_finalize(
1862 ipc_port_t port)
1863{
1864 ipc_port_request_t requests = port->ip_requests;
1865
1866 assert(!ip_active(port));
1867 if (requests != IPR_NULL) {
1868 ipc_table_size_t its = requests->ipr_size;
1869 it_requests_free(its, requests);
1870 port->ip_requests = IPR_NULL;
1871 }
1872
1873#if MACH_ASSERT
1874 ipc_port_track_dealloc(port);
1875#endif /* MACH_ASSERT */
6d2010ae 1876}
1c79356b
A
1877
1878#if MACH_ASSERT
91447636
A
1879#include <kern/machine.h>
1880
1c79356b
A
1881/*
1882 * Keep a list of all allocated ports.
1883 * Allocation is intercepted via ipc_port_init;
1884 * deallocation is intercepted via io_free.
1885 */
1886queue_head_t port_alloc_queue;
316670eb 1887lck_spin_t port_alloc_queue_lock;
1c79356b
A
1888
1889unsigned long port_count = 0;
1890unsigned long port_count_warning = 20000;
1891unsigned long port_timestamp = 0;
1892
1893void db_port_stack_trace(
1894 ipc_port_t port);
1895void db_ref(
1896 int refs);
1897int db_port_walk(
1898 unsigned int verbose,
1899 unsigned int display,
1900 unsigned int ref_search,
1901 unsigned int ref_target);
1902
1903/*
1904 * Initialize global state needed for run-time
1905 * port debugging.
1906 */
1907void
1908ipc_port_debug_init(void)
1909{
1910 queue_init(&port_alloc_queue);
316670eb
A
1911
1912 lck_spin_init(&port_alloc_queue_lock, &ipc_lck_grp, &ipc_lck_attr);
b7266188
A
1913
1914 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt)))
1915 ipc_portbt = 0;
1c79356b
A
1916}
1917
b7266188
A
1918#ifdef MACH_BSD
1919extern int proc_pid(struct proc*);
1920#endif /* MACH_BSD */
1c79356b
A
1921
1922/*
1923 * Initialize all of the debugging state in a port.
1924 * Insert the port into a global list of all allocated ports.
1925 */
1926void
1927ipc_port_init_debug(
316670eb 1928 ipc_port_t port,
39236c6e 1929 uintptr_t *callstack,
316670eb 1930 unsigned int callstack_max)
1c79356b
A
1931{
1932 unsigned int i;
1933
91447636 1934 port->ip_thread = current_thread();
1c79356b 1935 port->ip_timetrack = port_timestamp++;
316670eb
A
1936 for (i = 0; i < callstack_max; ++i)
1937 port->ip_callstack[i] = callstack[i];
1c79356b 1938 for (i = 0; i < IP_NSPARES; ++i)
316670eb 1939 port->ip_spares[i] = 0;
1c79356b 1940
b7266188
A
1941#ifdef MACH_BSD
1942 task_t task = current_task();
1943 if (task != TASK_NULL) {
1944 struct proc* proc = (struct proc*) get_bsdtask_info(task);
1945 if (proc)
1946 port->ip_spares[0] = proc_pid(proc);
1947 }
1948#endif /* MACH_BSD */
1949
1c79356b 1950#if 0
316670eb 1951 lck_spin_lock(&port_alloc_queue_lock);
1c79356b
A
1952 ++port_count;
1953 if (port_count_warning > 0 && port_count >= port_count_warning)
1954 assert(port_count < port_count_warning);
1955 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
316670eb 1956 lck_spin_unlock(&port_alloc_queue_lock);
1c79356b
A
1957#endif
1958}
1959
316670eb
A
1960/*
1961 * Routine: ipc_port_callstack_init_debug
1962 * Purpose:
1963 * Calls the machine-dependent routine to
1964 * fill in an array with up to IP_CALLSTACK_MAX
1965 * levels of return pc information
1966 * Conditions:
1967 * May block (via copyin)
1968 */
1969void
1970ipc_port_callstack_init_debug(
39236c6e 1971 uintptr_t *callstack,
316670eb
A
1972 unsigned int callstack_max)
1973{
1974 unsigned int i;
1975
1976 /* guarantee the callstack is initialized */
1977 for (i=0; i < callstack_max; i++)
1978 callstack[i] = 0;
1979
1980 if (ipc_portbt)
1981 machine_callstack(callstack, callstack_max);
1982}
1c79356b
A
1983
1984/*
1985 * Remove a port from the queue of allocated ports.
1986 * This routine should be invoked JUST prior to
1987 * deallocating the actual memory occupied by the port.
1988 */
91447636 1989#if 1
1c79356b
A
1990void
1991ipc_port_track_dealloc(
91447636
A
1992 __unused ipc_port_t port)
1993{
1994}
1995#else
1996void
1997ipc_port_track_dealloc(
1998 ipc_port_t port)
1c79356b 1999{
316670eb 2000 lck_spin_lock(&port_alloc_queue_lock);
1c79356b
A
2001 assert(port_count > 0);
2002 --port_count;
2003 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
316670eb 2004 lck_spin_unlock(&port_alloc_queue_lock);
1c79356b 2005}
91447636 2006#endif
1c79356b 2007
6d2010ae 2008
1c79356b 2009#endif /* MACH_ASSERT */