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