FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_port.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_port.c,v $
29 * Revision 2.18 93/11/17 17:00:18 dbg
30 * Added ANSI function prototypes.
31 * [93/03/30 dbg]
32 *
33 * Include kern/sched_prim.h instead of kern/ipc_sched.h.
34 * [93/01/26 dbg]
35 *
36 * Revision 2.17 92/08/03 17:35:07 jfriedl
37 * removed silly prototypes
38 * [92/08/02 jfriedl]
39 *
40 * Revision 2.16 92/05/21 17:11:11 jfriedl
41 * Added a few things to shut up gcc warnings.
42 * [92/05/16 jfriedl]
43 *
44 * Revision 2.15 92/04/06 01:16:19 rpd
45 * Fixed ipc_port_dealloc_special for ipc_space_reply.
46 * Fixed ipc_port_set_seqno with ipc_port_lock_mqueue.
47 * [92/04/05 rpd]
48 *
49 * Revision 2.14 92/03/10 16:26:13 jsb
50 * Merged in norma branch changes as of NORMA_MK7:
51 * Removed token-related fields. Added fields for receive-right migration
52 * and xmm support. Updated ipc_port_{init,print} accordingly.
53 * [92/03/09 13:20:23 jsb]
54 *
55 * Revision 2.13 91/12/14 14:27:37 jsb
56 * Removed ipc_fields.h hack.
57 *
58 * Revision 2.12 91/11/14 16:56:14 rpd
59 * Added ipc_fields.h support to ipc_port_{init,print}.
60 * Call norma_ipc_port_destroy instead of norma_ipc_destroy.
61 * [91/11/00 jsb]
62 *
63 * Revision 2.11 91/10/09 16:09:42 af
64 * Removed unused variable.
65 * [91/09/16 09:42:52 rpd]
66 *
67 * Revision 2.10 91/08/28 11:13:44 jsb
68 * Added ip_seqno and ipc_port_set_seqno.
69 * Changed ipc_port_init to initialize ip_seqno.
70 * Changed ipc_port_clear_receiver to zero ip_seqno.
71 * [91/08/09 rpd]
72 * Renamed clport fields in struct ipc_port to ip_norma fields.
73 * [91/08/15 08:20:08 jsb]
74 *
75 * Revision 2.9 91/08/03 18:18:30 jsb
76 * Call norma_ipc_destroy when destroying port.
77 * Added clport fields to ipc_port_print.
78 * [91/07/24 22:14:01 jsb]
79 *
80 * Fixed include. Changed clport field initialization.
81 * [91/07/17 14:05:38 jsb]
82 *
83 * Revision 2.8 91/06/17 15:46:21 jsb
84 * Renamed NORMA conditionals.
85 * [91/06/17 10:44:21 jsb]
86 *
87 * Revision 2.7 91/05/14 16:35:22 mrt
88 * Correcting copyright
89 *
90 * Revision 2.6 91/03/16 14:48:27 rpd
91 * Renamed ipc_thread_go to thread_go.
92 * [91/02/17 rpd]
93 *
94 * Revision 2.5 91/02/05 17:23:02 mrt
95 * Changed to new Mach copyright
96 * [91/02/01 15:49:46 mrt]
97 *
98 * Revision 2.4 90/11/05 14:29:30 rpd
99 * Changed ip_release to ipc_port_release.
100 * Use new ip_reference and ip_release.
101 * [90/10/29 rpd]
102 *
103 * Revision 2.3 90/09/28 16:55:10 jsb
104 * Added NORMA_IPC support.
105 * [90/09/28 14:03:45 jsb]
106 *
107 * Revision 2.2 90/06/02 14:51:08 rpd
108 * Created for new IPC.
109 * [90/03/26 21:01:02 rpd]
110 *
111 */
112 /*
113 * File: ipc/ipc_port.c
114 * Author: Rich Draves
115 * Date: 1989
116 *
117 * Functions to manipulate IPC ports.
118 */
119
120 #include <mach_ipc_compat.h>
121
122 #include <mach/port.h>
123 #include <mach/kern_return.h>
124 #include <kern/lock.h>
125 #include <kern/sched_prim.h>
126 #include <kern/ipc_kobject.h>
127 #include <kern/memory.h>
128 #include <ipc/ipc_entry.h>
129 #include <ipc/ipc_space.h>
130 #include <ipc/ipc_object.h>
131 #include <ipc/ipc_port.h>
132 #include <ipc/ipc_pset.h>
133 #include <ipc/ipc_right.h>
134 #include <ipc/ipc_thread.h>
135 #include <ipc/ipc_mqueue.h>
136 #include <ipc/ipc_notify.h>
137 #if NORMA_IPC
138 #include <norma/ipc_node.h>
139 #endif /* NORMA_IPC */
140
141
142
143 decl_simple_lock_data(, ipc_port_multiple_lock_data)
144
145 decl_simple_lock_data(, ipc_port_timestamp_lock_data)
146 ipc_port_timestamp_t ipc_port_timestamp_data;
147
148 /*
149 * Routine: ipc_port_timestamp
150 * Purpose:
151 * Retrieve a timestamp value.
152 */
153
154 ipc_port_timestamp_t
155 ipc_port_timestamp(void)
156 {
157 ipc_port_timestamp_t timestamp;
158
159 ipc_port_timestamp_lock();
160 timestamp = ipc_port_timestamp_data++;
161 ipc_port_timestamp_unlock();
162
163 return timestamp;
164 }
165
166 /*
167 * Routine: ipc_port_dnrequest
168 * Purpose:
169 * Try to allocate a dead-name request slot.
170 * If successful, returns the request index.
171 * Otherwise returns zero.
172 * Conditions:
173 * The port is locked and active.
174 * Returns:
175 * KERN_SUCCESS A request index was found.
176 * KERN_NO_SPACE No index allocated.
177 */
178
179 kern_return_t
180 ipc_port_dnrequest(
181 ipc_port_t port,
182 mach_port_t name,
183 ipc_port_t soright,
184 ipc_port_request_index_t *indexp)
185 {
186 ipc_port_request_t ipr, table;
187 ipc_port_request_index_t index;
188
189 assert(ip_active(port));
190 assert(name != MACH_PORT_NULL);
191 assert(soright != IP_NULL);
192
193 table = port->ip_dnrequests;
194 if (table == IPR_NULL)
195 return KERN_NO_SPACE;
196
197 index = table->ipr_next;
198 if (index == 0)
199 return KERN_NO_SPACE;
200
201 ipr = &table[index];
202 assert(ipr->ipr_name == MACH_PORT_NULL);
203
204 table->ipr_next = ipr->ipr_next;
205 ipr->ipr_name = name;
206 ipr->ipr_soright = soright;
207
208 *indexp = index;
209 return KERN_SUCCESS;
210 }
211
212 /*
213 * Routine: ipc_port_dngrow
214 * Purpose:
215 * Grow a port's table of dead-name requests.
216 * Conditions:
217 * The port must be locked and active.
218 * Nothing else locked; will allocate memory.
219 * Upon return the port is unlocked.
220 * Returns:
221 * KERN_SUCCESS Grew the table.
222 * KERN_SUCCESS Somebody else grew the table.
223 * KERN_SUCCESS The port died.
224 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
225 */
226
227 kern_return_t
228 ipc_port_dngrow(
229 ipc_port_t port)
230 {
231 ipc_table_size_t its;
232 ipc_port_request_t otable, ntable;
233
234 assert(ip_active(port));
235
236 otable = port->ip_dnrequests;
237 if (otable == IPR_NULL)
238 its = &ipc_table_dnrequests[0];
239 else
240 its = otable->ipr_size + 1;
241
242 ip_reference(port);
243 ip_unlock(port);
244
245 if ((its->its_size == 0) ||
246 ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
247 ipc_port_release(port);
248 return KERN_RESOURCE_SHORTAGE;
249 }
250
251 ip_lock(port);
252 ip_release(port);
253
254 /*
255 * Check that port is still active and that nobody else
256 * has slipped in and grown the table on us. Note that
257 * just checking port->ip_dnrequests == otable isn't
258 * sufficient; must check ipr_size.
259 */
260
261 if (ip_active(port) &&
262 (port->ip_dnrequests == otable) &&
263 ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
264 ipc_table_size_t oits = 0; /* '=0' to shut up lint */
265 ipc_table_elems_t osize, nsize;
266 ipc_port_request_index_t free, i;
267
268 /* copy old table to new table */
269
270 if (otable != IPR_NULL) {
271 oits = otable->ipr_size;
272 osize = oits->its_size;
273 free = otable->ipr_next;
274
275 bcopy((char *)(otable + 1), (char *)(ntable + 1),
276 (osize - 1) * sizeof(struct ipc_port_request));
277 } else {
278 osize = 1;
279 free = 0;
280 }
281
282 nsize = its->its_size;
283 assert(nsize > osize);
284
285 /* add new elements to the new table's free list */
286
287 for (i = osize; i < nsize; i++) {
288 ipc_port_request_t ipr = &ntable[i];
289
290 ipr->ipr_name = MACH_PORT_NULL;
291 ipr->ipr_next = free;
292 free = i;
293 }
294
295 ntable->ipr_next = free;
296 ntable->ipr_size = its;
297 port->ip_dnrequests = ntable;
298 ip_unlock(port);
299
300 if (otable != IPR_NULL)
301 it_dnrequests_free(oits, otable);
302 } else {
303 ip_check_unlock(port);
304 it_dnrequests_free(its, ntable);
305 }
306
307 return KERN_SUCCESS;
308 }
309
310 /*
311 * Routine: ipc_port_dncancel
312 * Purpose:
313 * Cancel a dead-name request and return the send-once right.
314 * Conditions:
315 * The port must be locked and active.
316 */
317
318 ipc_port_t
319 ipc_port_dncancel(
320 ipc_port_t port,
321 mach_port_t name,
322 ipc_port_request_index_t index)
323 {
324 ipc_port_request_t ipr, table;
325 ipc_port_t dnrequest;
326
327 assert(ip_active(port));
328 assert(name != MACH_PORT_NULL);
329 assert(index != 0);
330
331 table = port->ip_dnrequests;
332 assert(table != IPR_NULL);
333
334 ipr = &table[index];
335 dnrequest = ipr->ipr_soright;
336 assert(ipr->ipr_name == name);
337
338 /* return ipr to the free list inside the table */
339
340 ipr->ipr_name = MACH_PORT_NULL;
341 ipr->ipr_next = table->ipr_next;
342 table->ipr_next = index;
343
344 return dnrequest;
345 }
346
347 /*
348 * Routine: ipc_port_pdrequest
349 * Purpose:
350 * Make a port-deleted request, returning the
351 * previously registered send-once right.
352 * Just cancels the previous request if notify is IP_NULL.
353 * Conditions:
354 * The port is locked and active. It is unlocked.
355 * Consumes a ref for notify (if non-null), and
356 * returns previous with a ref (if non-null).
357 */
358
359 void
360 ipc_port_pdrequest(
361 ipc_port_t port,
362 ipc_port_t notify,
363 ipc_port_t *previousp)
364 {
365 ipc_port_t previous;
366
367 assert(ip_active(port));
368
369 previous = port->ip_pdrequest;
370 port->ip_pdrequest = notify;
371 ip_unlock(port);
372
373 *previousp = previous;
374 }
375
376 /*
377 * Routine: ipc_port_nsrequest
378 * Purpose:
379 * Make a no-senders request, returning the
380 * previously registered send-once right.
381 * Just cancels the previous request if notify is IP_NULL.
382 * Conditions:
383 * The port is locked and active. It is unlocked.
384 * Consumes a ref for notify (if non-null), and
385 * returns previous with a ref (if non-null).
386 */
387
388 void
389 ipc_port_nsrequest(
390 ipc_port_t port,
391 mach_port_mscount_t sync,
392 ipc_port_t notify,
393 ipc_port_t *previousp)
394 {
395 ipc_port_t previous;
396 mach_port_mscount_t mscount;
397
398 assert(ip_active(port));
399
400 previous = port->ip_nsrequest;
401 mscount = port->ip_mscount;
402
403 if ((port->ip_srights == 0) &&
404 (sync <= mscount) &&
405 (notify != IP_NULL)) {
406 port->ip_nsrequest = IP_NULL;
407 ip_unlock(port);
408 ipc_notify_no_senders(notify, mscount);
409 } else {
410 port->ip_nsrequest = notify;
411 ip_unlock(port);
412 }
413
414 *previousp = previous;
415 }
416
417 /*
418 * Routine: ipc_port_set_qlimit
419 * Purpose:
420 * Changes a port's queue limit; the maximum number
421 * of messages which may be queued to the port.
422 * Conditions:
423 * The port is locked and active.
424 */
425
426 void
427 ipc_port_set_qlimit(
428 ipc_port_t port,
429 mach_port_msgcount_t qlimit)
430 {
431 assert(ip_active(port));
432 assert(qlimit <= MACH_PORT_QLIMIT_MAX);
433
434 /* wake up senders allowed by the new qlimit */
435
436 if (qlimit > port->ip_qlimit) {
437 mach_port_msgcount_t i, wakeup;
438
439 /* caution: wakeup, qlimit are unsigned */
440
441 wakeup = qlimit - port->ip_qlimit;
442
443 for (i = 0; i < wakeup; i++) {
444 ipc_thread_t th;
445
446 th = ipc_thread_dequeue(&port->ip_blocked);
447 if (th == ITH_NULL)
448 break;
449
450 th->ith_state = MACH_MSG_SUCCESS;
451 thread_go(th);
452 }
453 }
454
455 port->ip_qlimit = qlimit;
456 }
457
458 /*
459 * Routine: ipc_port_lock_mqueue
460 * Purpose:
461 * Locks and returns the message queue that the port is using.
462 * The message queue may be in the port or in its port set.
463 * Conditions:
464 * The port is locked and active.
465 * Port set, message queue locks may be taken.
466 */
467
468 ipc_mqueue_t
469 ipc_port_lock_mqueue(
470 ipc_port_t port)
471 {
472 if (port->ip_pset != IPS_NULL) {
473 ipc_pset_t pset = port->ip_pset;
474
475 ips_lock(pset);
476 if (ips_active(pset)) {
477 imq_lock(&pset->ips_messages);
478 ips_unlock(pset);
479 return &pset->ips_messages;
480 }
481
482 ipc_pset_remove(pset, port);
483 ips_check_unlock(pset);
484 }
485
486 imq_lock(&port->ip_messages);
487 return &port->ip_messages;
488 }
489
490 /*
491 * Routine: ipc_port_set_seqno
492 * Purpose:
493 * Changes a port's sequence number.
494 * Conditions:
495 * The port is locked and active.
496 * Port set, message queue locks may be taken.
497 */
498
499 void
500 ipc_port_set_seqno(
501 ipc_port_t port,
502 mach_port_seqno_t seqno)
503 {
504 ipc_mqueue_t mqueue;
505
506 mqueue = ipc_port_lock_mqueue(port);
507 port->ip_seqno = seqno;
508 imq_unlock(mqueue);
509 }
510
511 /*
512 * Routine: ipc_port_clear_receiver
513 * Purpose:
514 * Prepares a receive right for transmission/destruction.
515 * Conditions:
516 * The port is locked and active.
517 */
518
519 void
520 ipc_port_clear_receiver(
521 ipc_port_t port)
522 {
523 ipc_pset_t pset;
524
525 assert(ip_active(port));
526
527 pset = port->ip_pset;
528 if (pset != IPS_NULL) {
529 /* No threads receiving from port, but must remove from set. */
530
531 ips_lock(pset);
532 ipc_pset_remove(pset, port);
533 ips_check_unlock(pset);
534 } else {
535 /* Else, wake up all receivers, indicating why. */
536
537 imq_lock(&port->ip_messages);
538 ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_DIED);
539 imq_unlock(&port->ip_messages);
540 }
541
542 ipc_port_set_mscount(port, 0);
543 imq_lock(&port->ip_messages);
544 port->ip_seqno = 0;
545 imq_unlock(&port->ip_messages);
546 }
547
548 /*
549 * Routine: ipc_port_init
550 * Purpose:
551 * Initializes a newly-allocated port.
552 * Doesn't touch the ip_object fields.
553 */
554
555 void
556 ipc_port_init(
557 ipc_port_t port,
558 ipc_space_t space,
559 mach_port_t name)
560 {
561 /* port->ip_kobject doesn't have to be initialized */
562
563 port->ip_receiver = space;
564 port->ip_receiver_name = name;
565
566 port->ip_mscount = 0;
567 port->ip_srights = 0;
568 port->ip_sorights = 0;
569
570 port->ip_nsrequest = IP_NULL;
571 port->ip_pdrequest = IP_NULL;
572 port->ip_dnrequests = IPR_NULL;
573
574 port->ip_pset = IPS_NULL;
575 port->ip_seqno = 0;
576 port->ip_msgcount = 0;
577 port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
578
579 #if NORMA_IPC
580 port->ip_norma_uid = 0;
581 port->ip_norma_dest_node = 0;
582 port->ip_norma_stransit = 0;
583 port->ip_norma_sotransit = 0;
584 port->ip_norma_xmm_object_refs = 0;
585 port->ip_norma_is_proxy = FALSE;
586 port->ip_norma_is_special = FALSE;
587 port->ip_norma_atrium = IP_NULL;
588 port->ip_norma_queue_next = port;
589 port->ip_norma_xmm_object = IP_NULL;
590 port->ip_norma_next = port;
591 port->ip_norma_spare1 = 0L;
592 port->ip_norma_spare2 = 0L;
593 port->ip_norma_spare3 = 0L;
594 port->ip_norma_spare4 = 0L;
595 #endif /* NORMA_IPC */
596
597 ipc_mqueue_init(&port->ip_messages);
598 ipc_thread_queue_init(&port->ip_blocked);
599 }
600
601 /*
602 * Routine: ipc_port_alloc
603 * Purpose:
604 * Allocate a port.
605 * Conditions:
606 * Nothing locked. If successful, the port is returned
607 * locked. (The caller doesn't have a reference.)
608 * Returns:
609 * KERN_SUCCESS The port is allocated.
610 * KERN_INVALID_TASK The space is dead.
611 * KERN_NO_SPACE No room for an entry in the space.
612 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
613 */
614
615 kern_return_t
616 ipc_port_alloc(
617 ipc_space_t space,
618 mach_port_t *namep,
619 ipc_port_t *portp)
620 {
621 ipc_port_t port;
622 mach_port_t name;
623 kern_return_t kr;
624
625 kr = ipc_object_alloc(space, IOT_PORT,
626 MACH_PORT_TYPE_RECEIVE, 0,
627 &name, (ipc_object_t *) &port);
628 if (kr != KERN_SUCCESS)
629 return kr;
630 /* port is locked */
631
632 ipc_port_init(port, space, name);
633
634 *namep = name;
635 *portp = port;
636 return KERN_SUCCESS;
637 }
638
639 /*
640 * Routine: ipc_port_alloc_name
641 * Purpose:
642 * Allocate a port, with a specific name.
643 * Conditions:
644 * Nothing locked. If successful, the port is returned
645 * locked. (The caller doesn't have a reference.)
646 * Returns:
647 * KERN_SUCCESS The port is allocated.
648 * KERN_INVALID_TASK The space is dead.
649 * KERN_NAME_EXISTS The name already denotes a right.
650 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
651 */
652
653 kern_return_t
654 ipc_port_alloc_name(
655 ipc_space_t space,
656 mach_port_t name,
657 ipc_port_t *portp)
658 {
659 ipc_port_t port;
660 kern_return_t kr;
661
662 kr = ipc_object_alloc_name(space, IOT_PORT,
663 MACH_PORT_TYPE_RECEIVE, 0,
664 name, (ipc_object_t *) &port);
665 if (kr != KERN_SUCCESS)
666 return kr;
667 /* port is locked */
668
669 ipc_port_init(port, space, name);
670
671 *portp = port;
672 return KERN_SUCCESS;
673 }
674
675 #if MACH_IPC_COMPAT
676 /*
677 * Routine: ipc_port_delete_compat
678 * Purpose:
679 * Find and destroy a compat entry for a dead port.
680 * If successful, generate a port-deleted notification.
681 * Conditions:
682 * Nothing locked; the port is dead.
683 * Frees a ref for the space.
684 */
685
686 void
687 ipc_port_delete_compat(
688 ipc_port_t port,
689 ipc_space_t space,
690 mach_port_t name)
691 {
692 ipc_entry_t entry;
693 kern_return_t kr;
694
695 assert(!ip_active(port));
696
697 kr = ipc_right_lookup_write(space, name, &entry);
698 if (kr == KERN_SUCCESS) {
699 ipc_port_t sright;
700
701 /* space is write-locked and active */
702
703 if ((ipc_port_t) entry->ie_object == port) {
704 assert(entry->ie_bits & IE_BITS_COMPAT);
705
706 sright = ipc_space_make_notify(space);
707
708 kr = ipc_right_destroy(space, name, entry);
709 /* space is unlocked */
710 assert(kr == KERN_INVALID_NAME);
711 } else {
712 is_write_unlock(space);
713 sright = IP_NULL;
714 }
715
716 if (IP_VALID(sright))
717 ipc_notify_port_deleted_compat(sright, name);
718 }
719
720 is_release(space);
721 }
722 #endif /* MACH_IPC_COMPAT */
723
724 /*
725 * Routine: ipc_port_destroy
726 * Purpose:
727 * Destroys a port. Cleans up queued messages.
728 *
729 * If the port has a backup, it doesn't get destroyed,
730 * but is sent in a port-destroyed notification to the backup.
731 * Conditions:
732 * The port is locked and alive; nothing else locked.
733 * The caller has a reference, which is consumed.
734 * Afterwards, the port is unlocked and dead.
735 */
736
737 void
738 ipc_port_destroy(
739 ipc_port_t port)
740 {
741 ipc_port_t pdrequest, nsrequest;
742 ipc_mqueue_t mqueue;
743 ipc_kmsg_queue_t kmqueue;
744 ipc_kmsg_t kmsg;
745 ipc_thread_t sender;
746 ipc_port_request_t dnrequests;
747
748 assert(ip_active(port));
749 /* port->ip_receiver_name is garbage */
750 /* port->ip_receiver/port->ip_destination is garbage */
751 assert(port->ip_pset == IPS_NULL);
752 assert(port->ip_mscount == 0);
753 assert(port->ip_seqno == 0);
754
755 /* first check for a backup port */
756
757 pdrequest = port->ip_pdrequest;
758 if (pdrequest != IP_NULL) {
759 /* we assume the ref for pdrequest */
760 port->ip_pdrequest = IP_NULL;
761
762 /* make port be in limbo */
763 port->ip_receiver_name = MACH_PORT_NULL;
764 port->ip_destination = IP_NULL;
765 ip_unlock(port);
766
767 #if MACH_IPC_COMPAT
768 /*
769 * pdrequest might actually be a send right instead
770 * of a send-once right, indicated by the low bit
771 * of the pointer value. If this is the case,
772 * we must use ipc_notify_port_destroyed_compat.
773 */
774
775 if (ip_pdsendp(pdrequest)) {
776 ipc_port_t sright = ip_pdsend(pdrequest);
777
778 if (!ipc_port_check_circularity(port, sright)) {
779 /* consumes our refs for port and sright */
780 ipc_notify_port_destroyed_compat(sright, port);
781 return;
782 } else {
783 /* consume sright and destroy port */
784 ipc_port_release_send(sright);
785 }
786 } else
787 #endif /* MACH_IPC_COMPAT */
788
789 if (!ipc_port_check_circularity(port, pdrequest)) {
790 /* consumes our refs for port and pdrequest */
791 ipc_notify_port_destroyed(pdrequest, port);
792 return;
793 } else {
794 /* consume pdrequest and destroy port */
795 ipc_port_release_sonce(pdrequest);
796 }
797
798 ip_lock(port);
799 assert(ip_active(port));
800 assert(port->ip_pset == IPS_NULL);
801 assert(port->ip_mscount == 0);
802 assert(port->ip_seqno == 0);
803 assert(port->ip_pdrequest == IP_NULL);
804 assert(port->ip_receiver_name == MACH_PORT_NULL);
805 assert(port->ip_destination == IP_NULL);
806
807 /* fall through and destroy the port */
808 }
809
810 #if NORMA_IPC
811 /*
812 * destroy any NORMA_IPC state associated with port
813 */
814 norma_ipc_port_destroy(port);
815 #endif /* NORMA_IPC */
816
817 /*
818 * rouse all blocked senders
819 *
820 * This must be done with the port locked, because
821 * ipc_mqueue_send can play with the ip_blocked queue
822 * of a dead port.
823 */
824
825 while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) {
826 sender->ith_state = MACH_MSG_SUCCESS;
827 thread_go(sender);
828 }
829
830 /* once port is dead, we don't need to keep it locked */
831
832 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
833 port->ip_timestamp = ipc_port_timestamp();
834 ip_unlock(port);
835
836 /* throw away no-senders request */
837
838 nsrequest = port->ip_nsrequest;
839 if (nsrequest != IP_NULL)
840 ipc_notify_send_once(nsrequest); /* consumes ref */
841
842 /* destroy any queued messages */
843
844 mqueue = &port->ip_messages;
845 imq_lock(mqueue);
846 assert(ipc_thread_queue_empty(&mqueue->imq_threads));
847 kmqueue = &mqueue->imq_messages;
848
849 while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) {
850 imq_unlock(mqueue);
851
852 assert(kmsg->ikm_header.msgh_remote_port ==
853 (mach_port_t) port);
854
855 ipc_port_release(port);
856 kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
857 ipc_kmsg_destroy(kmsg);
858
859 imq_lock(mqueue);
860 }
861
862 imq_unlock(mqueue);
863
864 /* generate dead-name notifications */
865
866 dnrequests = port->ip_dnrequests;
867 if (dnrequests != IPR_NULL) {
868 ipc_table_size_t its = dnrequests->ipr_size;
869 ipc_table_elems_t size = its->its_size;
870 ipc_port_request_index_t index;
871
872 for (index = 1; index < size; index++) {
873 ipc_port_request_t ipr = &dnrequests[index];
874 mach_port_t name = ipr->ipr_name;
875 ipc_port_t soright;
876
877 if (name == MACH_PORT_NULL)
878 continue;
879
880 soright = ipr->ipr_soright;
881 assert(soright != IP_NULL);
882
883 #if MACH_IPC_COMPAT
884 if (ipr_spacep(soright)) {
885 ipc_port_delete_compat(port,
886 ipr_space(soright), name);
887 continue;
888 }
889 #endif /* MACH_IPC_COMPAT */
890
891 ipc_notify_dead_name(soright, name);
892 }
893
894 it_dnrequests_free(its, dnrequests);
895 }
896
897 if (ip_kotype(port) != IKOT_NONE)
898 ipc_kobject_destroy(port);
899
900 ipc_port_release(port); /* consume caller's ref */
901 }
902
903 /*
904 * Routine: ipc_port_check_circularity
905 * Purpose:
906 * Check if queueing "port" in a message for "dest"
907 * would create a circular group of ports and messages.
908 *
909 * If no circularity (FALSE returned), then "port"
910 * is changed from "in limbo" to "in transit".
911 *
912 * That is, we want to set port->ip_destination == dest,
913 * but guaranteeing that this doesn't create a circle
914 * port->ip_destination->ip_destination->... == port
915 * Conditions:
916 * No ports locked. References held for "port" and "dest".
917 */
918
919 boolean_t
920 ipc_port_check_circularity(
921 ipc_port_t port,
922 ipc_port_t dest)
923 {
924 ipc_port_t base;
925
926 assert(port != IP_NULL);
927 assert(dest != IP_NULL);
928
929 if (port == dest)
930 return TRUE;
931 base = dest;
932
933 /*
934 * First try a quick check that can run in parallel.
935 * No circularity if dest is not in transit.
936 */
937
938 ip_lock(port);
939 if (ip_lock_try(dest)) {
940 if (!ip_active(dest) ||
941 (dest->ip_receiver_name != MACH_PORT_NULL) ||
942 (dest->ip_destination == IP_NULL))
943 goto not_circular;
944
945 /* dest is in transit; further checking necessary */
946
947 ip_unlock(dest);
948 }
949 ip_unlock(port);
950
951 ipc_port_multiple_lock(); /* massive serialization */
952
953 /*
954 * Search for the end of the chain (a port not in transit),
955 * acquiring locks along the way.
956 */
957
958 for (;;) {
959 ip_lock(base);
960
961 if (!ip_active(base) ||
962 (base->ip_receiver_name != MACH_PORT_NULL) ||
963 (base->ip_destination == IP_NULL))
964 break;
965
966 base = base->ip_destination;
967 }
968
969 /* all ports in chain from dest to base, inclusive, are locked */
970
971 if (port == base) {
972 /* circularity detected! */
973
974 ipc_port_multiple_unlock();
975
976 /* port (== base) is in limbo */
977
978 assert(ip_active(port));
979 assert(port->ip_receiver_name == MACH_PORT_NULL);
980 assert(port->ip_destination == IP_NULL);
981
982 while (dest != IP_NULL) {
983 ipc_port_t next;
984
985 /* dest is in transit or in limbo */
986
987 assert(ip_active(dest));
988 assert(dest->ip_receiver_name == MACH_PORT_NULL);
989
990 next = dest->ip_destination;
991 ip_unlock(dest);
992 dest = next;
993 }
994
995 return TRUE;
996 }
997
998 /*
999 * The guarantee: lock port while the entire chain is locked.
1000 * Once port is locked, we can take a reference to dest,
1001 * add port to the chain, and unlock everything.
1002 */
1003
1004 ip_lock(port);
1005 ipc_port_multiple_unlock();
1006
1007 not_circular:
1008
1009 /* port is in limbo */
1010
1011 assert(ip_active(port));
1012 assert(port->ip_receiver_name == MACH_PORT_NULL);
1013 assert(port->ip_destination == IP_NULL);
1014
1015 ip_reference(dest);
1016 port->ip_destination = dest;
1017
1018 /* now unlock chain */
1019
1020 while (port != base) {
1021 ipc_port_t next;
1022
1023 /* port is in transit */
1024
1025 assert(ip_active(port));
1026 assert(port->ip_receiver_name == MACH_PORT_NULL);
1027 assert(port->ip_destination != IP_NULL);
1028
1029 next = port->ip_destination;
1030 ip_unlock(port);
1031 port = next;
1032 }
1033
1034 /* base is not in transit */
1035
1036 assert(!ip_active(base) ||
1037 (base->ip_receiver_name != MACH_PORT_NULL) ||
1038 (base->ip_destination == IP_NULL));
1039 ip_unlock(base);
1040
1041 return FALSE;
1042 }
1043
1044 /*
1045 * Routine: ipc_port_lookup_notify
1046 * Purpose:
1047 * Make a send-once notify port from a receive right.
1048 * Returns IP_NULL if name doesn't denote a receive right.
1049 * Conditions:
1050 * The space must be locked (read or write) and active.
1051 */
1052
1053 ipc_port_t
1054 ipc_port_lookup_notify(
1055 ipc_space_t space,
1056 mach_port_t name)
1057 {
1058 ipc_port_t port;
1059 ipc_entry_t entry;
1060
1061 assert(space->is_active);
1062
1063 entry = ipc_entry_lookup(space, name);
1064 if (entry == IE_NULL)
1065 return IP_NULL;
1066
1067 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
1068 return IP_NULL;
1069
1070 port = (ipc_port_t) entry->ie_object;
1071 assert(port != IP_NULL);
1072
1073 ip_lock(port);
1074 assert(ip_active(port));
1075 assert(port->ip_receiver_name == name);
1076 assert(port->ip_receiver == space);
1077
1078 ip_reference(port);
1079 port->ip_sorights++;
1080 ip_unlock(port);
1081
1082 return port;
1083 }
1084
1085 /*
1086 * Routine: ipc_port_make_send
1087 * Purpose:
1088 * Make a naked send right from a receive right.
1089 * Conditions:
1090 * The port is not locked but it is active.
1091 */
1092
1093 ipc_port_t
1094 ipc_port_make_send(
1095 ipc_port_t port)
1096 {
1097 assert(IP_VALID(port));
1098
1099 ip_lock(port);
1100 assert(ip_active(port));
1101 port->ip_mscount++;
1102 port->ip_srights++;
1103 ip_reference(port);
1104 ip_unlock(port);
1105
1106 return port;
1107 }
1108
1109 /*
1110 * Routine: ipc_port_copy_send
1111 * Purpose:
1112 * Make a naked send right from another naked send right.
1113 * IP_NULL -> IP_NULL
1114 * IP_DEAD -> IP_DEAD
1115 * dead port -> IP_DEAD
1116 * live port -> port + ref
1117 * Conditions:
1118 * Nothing locked except possibly a space.
1119 */
1120
1121 ipc_port_t
1122 ipc_port_copy_send(
1123 ipc_port_t port)
1124 {
1125 ipc_port_t sright;
1126
1127 if (!IP_VALID(port))
1128 return port;
1129
1130 ip_lock(port);
1131 if (ip_active(port)) {
1132 assert(port->ip_srights > 0);
1133
1134 ip_reference(port);
1135 port->ip_srights++;
1136 sright = port;
1137 } else
1138 sright = IP_DEAD;
1139 ip_unlock(port);
1140
1141 return sright;
1142 }
1143
1144 /*
1145 * Routine: ipc_port_copyout_send
1146 * Purpose:
1147 * Copyout a naked send right (possibly null/dead),
1148 * or if that fails, destroy the right.
1149 * Conditions:
1150 * Nothing locked.
1151 */
1152
1153 mach_port_t
1154 ipc_port_copyout_send(
1155 ipc_port_t sright,
1156 ipc_space_t space)
1157 {
1158 mach_port_t name;
1159
1160 if (IP_VALID(sright)) {
1161 kern_return_t kr;
1162
1163 kr = ipc_object_copyout(space, (ipc_object_t) sright,
1164 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
1165 if (kr != KERN_SUCCESS) {
1166 ipc_port_release_send(sright);
1167
1168 if (kr == KERN_INVALID_CAPABILITY)
1169 name = MACH_PORT_DEAD;
1170 else
1171 name = MACH_PORT_NULL;
1172 }
1173 } else
1174 name = (mach_port_t) sright;
1175
1176 return name;
1177 }
1178
1179 /*
1180 * Routine: ipc_port_release_send
1181 * Purpose:
1182 * Release a (valid) naked send right.
1183 * Consumes a ref for the port.
1184 * Conditions:
1185 * Nothing locked.
1186 */
1187
1188 void
1189 ipc_port_release_send(
1190 ipc_port_t port)
1191 {
1192 ipc_port_t nsrequest;
1193
1194 assert(IP_VALID(port));
1195
1196 ip_lock(port);
1197 ip_release(port);
1198
1199 if (!ip_active(port)) {
1200 ip_check_unlock(port);
1201 return;
1202 }
1203
1204 assert(port->ip_srights > 0);
1205
1206 if ((--port->ip_srights == 0) &&
1207 ((nsrequest = port->ip_nsrequest) != IP_NULL)) {
1208
1209 /* handle no-more-senders notification */
1210
1211 mach_port_mscount_t mscount;
1212
1213 port->ip_nsrequest = IP_NULL;
1214 mscount = port->ip_mscount;
1215
1216 ip_unlock(port);
1217 ipc_notify_no_senders(nsrequest, mscount);
1218 }
1219 else {
1220 ip_unlock(port);
1221 }
1222 }
1223
1224 /*
1225 * Routine: ipc_port_make_sonce
1226 * Purpose:
1227 * Make a naked send-once right from a receive right.
1228 * Conditions:
1229 * The port is not locked but it is active.
1230 */
1231
1232 ipc_port_t
1233 ipc_port_make_sonce(
1234 ipc_port_t port)
1235 {
1236 assert(IP_VALID(port));
1237
1238 ip_lock(port);
1239 assert(ip_active(port));
1240 port->ip_sorights++;
1241 ip_reference(port);
1242 ip_unlock(port);
1243
1244 return port;
1245 }
1246
1247 /*
1248 * Routine: ipc_port_release_sonce
1249 * Purpose:
1250 * Release a naked send-once right.
1251 * Consumes a ref for the port.
1252 *
1253 * In normal situations, this is never used.
1254 * Send-once rights are only consumed when
1255 * a message (possibly a send-once notification)
1256 * is sent to them.
1257 * Conditions:
1258 * Nothing locked except possibly a space.
1259 */
1260
1261 void
1262 ipc_port_release_sonce(
1263 ipc_port_t port)
1264 {
1265 assert(IP_VALID(port));
1266
1267 ip_lock(port);
1268 ip_release(port);
1269
1270 if (!ip_active(port)) {
1271 ip_check_unlock(port);
1272 return;
1273 }
1274
1275 assert(port->ip_sorights > 0);
1276
1277 port->ip_sorights--;
1278 ip_unlock(port);
1279 }
1280
1281 /*
1282 * Routine: ipc_port_release_receive
1283 * Purpose:
1284 * Release a naked (in limbo or in transit) receive right.
1285 * Consumes a ref for the port; destroys the port.
1286 * Conditions:
1287 * Nothing locked.
1288 */
1289
1290 void
1291 ipc_port_release_receive(
1292 ipc_port_t port)
1293 {
1294 ipc_port_t dest;
1295
1296 assert(IP_VALID(port));
1297
1298 ip_lock(port);
1299 assert(ip_active(port));
1300 assert(port->ip_receiver_name == MACH_PORT_NULL);
1301 dest = port->ip_destination;
1302
1303 ipc_port_destroy(port); /* consumes ref, unlocks */
1304
1305 if (dest != IP_NULL)
1306 ipc_port_release(dest);
1307 }
1308
1309 /*
1310 * Routine: ipc_port_alloc_special
1311 * Purpose:
1312 * Allocate a port in a special space.
1313 * The new port is returned with one ref.
1314 * If unsuccessful, IP_NULL is returned.
1315 * Conditions:
1316 * Nothing locked.
1317 */
1318
1319 ipc_port_t
1320 ipc_port_alloc_special(
1321 ipc_space_t space)
1322 {
1323 #if NORMA_IPC
1324 #if i386
1325 int ret = (&ret)[2]; /* where we were called from */
1326 #else
1327 int ret = (int) ipc_port_alloc_special;
1328 #endif
1329 extern int input_msgh_id;
1330 #endif /* NORMA_IPC */
1331 ipc_port_t port;
1332
1333 port = (ipc_port_t) io_alloc(IOT_PORT);
1334 if (port == IP_NULL)
1335 return IP_NULL;
1336
1337 io_lock_init(&port->ip_object);
1338 port->ip_references = 1;
1339 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1340
1341 /*
1342 * The actual values of ip_receiver_name aren't important,
1343 * as long as they are valid (not null/dead).
1344 */
1345
1346 ipc_port_init(port, space, 1);
1347
1348 #if NORMA_IPC
1349 port->ip_norma_spare1 = ret;
1350 port->ip_norma_spare2 = input_msgh_id;
1351 #endif /* NORMA_IPC */
1352 return port;
1353 }
1354
1355 /*
1356 * Routine: ipc_port_dealloc_special
1357 * Purpose:
1358 * Deallocate a port in a special space.
1359 * Consumes one ref for the port.
1360 * Conditions:
1361 * Nothing locked.
1362 */
1363
1364 void
1365 ipc_port_dealloc_special(
1366 ipc_port_t port,
1367 ipc_space_t space)
1368 {
1369 ip_lock(port);
1370 assert(ip_active(port));
1371 assert(port->ip_receiver_name != MACH_PORT_NULL);
1372 assert(port->ip_receiver == space);
1373
1374 /*
1375 * We clear ip_receiver_name and ip_receiver to simplify
1376 * the ipc_space_kernel check in ipc_mqueue_send.
1377 */
1378
1379 port->ip_receiver_name = MACH_PORT_NULL;
1380 port->ip_receiver = IS_NULL;
1381
1382 /*
1383 * For ipc_space_kernel, all ipc_port_clear_receiver does
1384 * is clean things up for the assertions in ipc_port_destroy.
1385 * For ipc_space_reply, there might be a waiting receiver.
1386 */
1387
1388 ipc_port_clear_receiver(port);
1389 ipc_port_destroy(port);
1390 }
1391
1392 #if MACH_IPC_COMPAT
1393
1394 /*
1395 * Routine: ipc_port_alloc_compat
1396 * Purpose:
1397 * Allocate a port.
1398 * Conditions:
1399 * Nothing locked. If successful, the port is returned
1400 * locked. (The caller doesn't have a reference.)
1401 *
1402 * Like ipc_port_alloc, except that the new entry
1403 * is IE_BITS_COMPAT.
1404 * Returns:
1405 * KERN_SUCCESS The port is allocated.
1406 * KERN_INVALID_TASK The space is dead.
1407 * KERN_NO_SPACE No room for an entry in the space.
1408 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1409 */
1410
1411 kern_return_t
1412 ipc_port_alloc_compat(
1413 ipc_space_t space,
1414 mach_port_t *namep,
1415 ipc_port_t *portp)
1416 {
1417 ipc_port_t port;
1418 ipc_entry_t entry;
1419 mach_port_t name;
1420 ipc_table_size_t its;
1421 ipc_port_request_t table;
1422 ipc_table_elems_t size;
1423 ipc_port_request_index_t free, i;
1424 kern_return_t kr;
1425
1426 port = ip_alloc();
1427 if (port == IP_NULL)
1428 return KERN_RESOURCE_SHORTAGE;
1429
1430 its = &ipc_table_dnrequests[0];
1431 table = it_dnrequests_alloc(its);
1432 if (table == IPR_NULL) {
1433 ip_free(port);
1434 return KERN_RESOURCE_SHORTAGE;
1435 }
1436
1437 kr = ipc_entry_alloc(space, &name, &entry);
1438 if (kr != KERN_SUCCESS) {
1439 ip_free(port);
1440 it_dnrequests_free(its, table);
1441 return kr;
1442 }
1443 /* space is write-locked */
1444
1445 entry->ie_object = (ipc_object_t) port;
1446 entry->ie_request = 1;
1447 entry->ie_bits |= IE_BITS_COMPAT|MACH_PORT_TYPE_RECEIVE;
1448
1449 ip_lock_init(port);
1450 ip_lock(port);
1451 is_write_unlock(space);
1452
1453 port->ip_references = 1; /* for entry, not caller */
1454 port->ip_bits = io_makebits(TRUE, IOT_PORT, 0);
1455
1456 ipc_port_init(port, space, name);
1457
1458 size = its->its_size;
1459 assert(size > 1);
1460 free = 0;
1461
1462 for (i = 2; i < size; i++) {
1463 ipc_port_request_t ipr = &table[i];
1464
1465 ipr->ipr_name = MACH_PORT_NULL;
1466 ipr->ipr_next = free;
1467 free = i;
1468 }
1469
1470 table->ipr_next = free;
1471 table->ipr_size = its;
1472 port->ip_dnrequests = table;
1473
1474 table[1].ipr_name = name;
1475 table[1].ipr_soright = ipr_spacem(space);
1476 is_reference(space);
1477
1478 *namep = name;
1479 *portp = port;
1480 return KERN_SUCCESS;
1481 }
1482
1483 /*
1484 * Routine: ipc_port_copyout_send_compat
1485 * Purpose:
1486 * Copyout a naked send right (possibly null/dead),
1487 * or if that fails, destroy the right.
1488 * Like ipc_port_copyout_send, except that if a
1489 * new translation is created it has the compat bit.
1490 * Conditions:
1491 * Nothing locked.
1492 */
1493
1494 mach_port_t
1495 ipc_port_copyout_send_compat(
1496 ipc_port_t sright,
1497 ipc_space_t space)
1498 {
1499 mach_port_t name;
1500
1501 if (IP_VALID(sright)) {
1502 kern_return_t kr;
1503
1504 kr = ipc_object_copyout_compat(space, (ipc_object_t) sright,
1505 MACH_MSG_TYPE_PORT_SEND, &name);
1506 if (kr != KERN_SUCCESS) {
1507 ipc_port_release_send(sright);
1508 name = MACH_PORT_NULL;
1509 }
1510 } else
1511 name = (mach_port_t) sright;
1512
1513 return name;
1514 }
1515
1516 /*
1517 * Routine: ipc_port_copyout_receiver
1518 * Purpose:
1519 * Copyout a port reference (possibly null)
1520 * by giving the caller his name for the port,
1521 * if he is the receiver.
1522 * Conditions:
1523 * Nothing locked. Consumes a ref for the port.
1524 */
1525
1526 mach_port_t
1527 ipc_port_copyout_receiver(
1528 ipc_port_t port,
1529 ipc_space_t space)
1530 {
1531 mach_port_t name;
1532
1533 if (!IP_VALID(port))
1534 return MACH_PORT_NULL;
1535
1536 ip_lock(port);
1537 if (port->ip_receiver == space) {
1538 name = port->ip_receiver_name;
1539 assert(MACH_PORT_VALID(name));
1540 } else
1541 name = MACH_PORT_NULL;
1542
1543 ip_release(port);
1544 ip_check_unlock(port);
1545
1546 return name;
1547 }
1548
1549 #endif /* MACH_IPC_COMPAT */
1550
1551 #include <mach_kdb.h>
1552
1553
1554 #if MACH_KDB
1555 #include <ddb/db_output.h>
1556
1557 /*
1558 * Routine: ipc_port_print
1559 * Purpose:
1560 * Pretty-print a port for kdb.
1561 */
1562
1563 void
1564 ipc_port_print(
1565 ipc_port_t port)
1566 {
1567 db_printf("port 0x%x\n", port);
1568
1569 db_indent += 2;
1570
1571 ipc_object_print(&port->ip_object);
1572 db_iprintf("receiver=0x%x", port->ip_receiver);
1573 db_printf(", receiver_name=0x%x\n", port->ip_receiver_name);
1574
1575 db_iprintf("mscount=%d", port->ip_mscount);
1576 db_printf(", srights=%d", port->ip_srights);
1577 db_printf(", sorights=%d\n", port->ip_sorights);
1578
1579 db_iprintf("nsrequest=0x%x", port->ip_nsrequest);
1580 db_printf(", pdrequest=0x%x", port->ip_pdrequest);
1581 db_printf(", dnrequests=0x%x\n", port->ip_dnrequests);
1582
1583 db_iprintf("pset=0x%x", port->ip_pset);
1584 db_printf(", seqno=%d", port->ip_seqno);
1585 db_printf(", msgcount=%d", port->ip_msgcount);
1586 db_printf(", qlimit=%d\n", port->ip_qlimit);
1587
1588 db_iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
1589 db_printf(", rcvrs=0x%x", port->ip_messages.imq_threads.ithq_base);
1590 db_printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
1591 db_printf(", kobj=0x%x\n", port->ip_kobject);
1592
1593 #if NORMA_IPC
1594 db_iprintf("norma_uid=%x", port->ip_norma_uid);
1595 db_printf(", dest_node=%d", port->ip_norma_dest_node);
1596 db_printf(", stransit=%d", port->ip_norma_stransit);
1597 db_printf(", xorefs=%d", port->ip_norma_xmm_object_refs);
1598 db_printf(", sotransit=%d\n", port->ip_norma_sotransit);
1599
1600 db_iprintf("norma_is_proxy=%d", port->ip_norma_is_proxy);
1601 db_printf(", is_special=%d\n", port->ip_norma_is_special);
1602
1603 db_iprintf("norma_atrium=0x%x", port->ip_norma_atrium);
1604 db_printf(", queue_next=0x%x", port->ip_norma_queue_next);
1605 db_printf(", xmm_object=0x%x", port->ip_norma_xmm_object);
1606 db_printf(", next=0x%x\n", port->ip_norma_next);
1607
1608 db_iprintf("norma_spare1=0x%x", port->ip_norma_spare1);
1609 db_printf(", norma_spare2=0x%x", port->ip_norma_spare2);
1610 db_printf(", norma_spare3=0x%x", port->ip_norma_spare3);
1611 db_printf(", norma_spare4=0x%x\n", port->ip_norma_spare4);
1612 #endif /* NORMA_IPC */
1613
1614 db_indent -=2;
1615 }
1616
1617 #endif /* MACH_KDB */
Cache object: c91cff1764dac337743005409bd781d6
|