|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * File: ipc/ipc_port.c
31: * Author: Rich Draves
32: * Date: 1989
33: *
34: * Functions to manipulate IPC ports.
35: */
36:
1.1.1.3 ! root 37: #include <kern/printf.h>
! 38: #include <string.h>
1.1 root 39:
40: #include <mach/port.h>
41: #include <mach/kern_return.h>
42: #include <kern/lock.h>
43: #include <kern/ipc_sched.h>
44: #include <kern/ipc_kobject.h>
45: #include <ipc/ipc_entry.h>
46: #include <ipc/ipc_space.h>
47: #include <ipc/ipc_object.h>
48: #include <ipc/ipc_port.h>
49: #include <ipc/ipc_pset.h>
50: #include <ipc/ipc_thread.h>
51: #include <ipc/ipc_mqueue.h>
52: #include <ipc/ipc_notify.h>
53:
1.1.1.3 ! root 54: #if MACH_KDB
! 55: #include <ddb/db_output.h>
! 56: #include <ipc/ipc_print.h>
! 57: #endif /* MACH_KDB */
1.1 root 58:
59:
60: decl_simple_lock_data(, ipc_port_multiple_lock_data)
61:
62: decl_simple_lock_data(, ipc_port_timestamp_lock_data)
63: ipc_port_timestamp_t ipc_port_timestamp_data;
64:
65: /*
66: * Routine: ipc_port_timestamp
67: * Purpose:
68: * Retrieve a timestamp value.
69: */
70:
71: ipc_port_timestamp_t
72: ipc_port_timestamp(void)
73: {
74: ipc_port_timestamp_t timestamp;
75:
76: ipc_port_timestamp_lock();
77: timestamp = ipc_port_timestamp_data++;
78: ipc_port_timestamp_unlock();
79:
80: return timestamp;
81: }
82:
83: /*
84: * Routine: ipc_port_dnrequest
85: * Purpose:
86: * Try to allocate a dead-name request slot.
87: * If successful, returns the request index.
88: * Otherwise returns zero.
89: * Conditions:
90: * The port is locked and active.
91: * Returns:
92: * KERN_SUCCESS A request index was found.
93: * KERN_NO_SPACE No index allocated.
94: */
95:
96: kern_return_t
97: ipc_port_dnrequest(port, name, soright, indexp)
98: ipc_port_t port;
99: mach_port_t name;
100: ipc_port_t soright;
101: ipc_port_request_index_t *indexp;
102: {
103: ipc_port_request_t ipr, table;
104: ipc_port_request_index_t index;
105:
106: assert(ip_active(port));
107: assert(name != MACH_PORT_NULL);
108: assert(soright != IP_NULL);
109:
110: table = port->ip_dnrequests;
111: if (table == IPR_NULL)
112: return KERN_NO_SPACE;
113:
114: index = table->ipr_next;
115: if (index == 0)
116: return KERN_NO_SPACE;
117:
118: ipr = &table[index];
119: assert(ipr->ipr_name == MACH_PORT_NULL);
120:
121: table->ipr_next = ipr->ipr_next;
122: ipr->ipr_name = name;
123: ipr->ipr_soright = soright;
124:
125: *indexp = index;
126: return KERN_SUCCESS;
127: }
128:
129: /*
130: * Routine: ipc_port_dngrow
131: * Purpose:
132: * Grow a port's table of dead-name requests.
133: * Conditions:
134: * The port must be locked and active.
135: * Nothing else locked; will allocate memory.
136: * Upon return the port is unlocked.
137: * Returns:
138: * KERN_SUCCESS Grew the table.
139: * KERN_SUCCESS Somebody else grew the table.
140: * KERN_SUCCESS The port died.
141: * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
142: */
143:
144: kern_return_t
145: ipc_port_dngrow(port)
146: ipc_port_t port;
147: {
148: ipc_table_size_t its;
149: ipc_port_request_t otable, ntable;
150:
151: assert(ip_active(port));
152:
153: otable = port->ip_dnrequests;
154: if (otable == IPR_NULL)
155: its = &ipc_table_dnrequests[0];
156: else
157: its = otable->ipr_size + 1;
158:
159: ip_reference(port);
160: ip_unlock(port);
161:
162: if ((its->its_size == 0) ||
163: ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
164: ipc_port_release(port);
165: return KERN_RESOURCE_SHORTAGE;
166: }
167:
168: ip_lock(port);
169: ip_release(port);
170:
171: /*
172: * Check that port is still active and that nobody else
173: * has slipped in and grown the table on us. Note that
174: * just checking port->ip_dnrequests == otable isn't
175: * sufficient; must check ipr_size.
176: */
177:
178: if (ip_active(port) &&
179: (port->ip_dnrequests == otable) &&
180: ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
181: ipc_table_size_t oits = 0; /* '=0' to shut up lint */
182: ipc_table_elems_t osize, nsize;
183: ipc_port_request_index_t free, i;
184:
185: /* copy old table to new table */
186:
187: if (otable != IPR_NULL) {
188: oits = otable->ipr_size;
189: osize = oits->its_size;
190: free = otable->ipr_next;
191:
1.1.1.3 ! root 192: memcpy((ntable + 1), (otable + 1),
1.1 root 193: (osize - 1) * sizeof(struct ipc_port_request));
194: } else {
195: osize = 1;
196: free = 0;
197: }
198:
199: nsize = its->its_size;
200: assert(nsize > osize);
201:
202: /* add new elements to the new table's free list */
203:
204: for (i = osize; i < nsize; i++) {
205: ipc_port_request_t ipr = &ntable[i];
206:
207: ipr->ipr_name = MACH_PORT_NULL;
208: ipr->ipr_next = free;
209: free = i;
210: }
211:
212: ntable->ipr_next = free;
213: ntable->ipr_size = its;
214: port->ip_dnrequests = ntable;
215: ip_unlock(port);
216:
217: if (otable != IPR_NULL)
218: it_dnrequests_free(oits, otable);
219: } else {
220: ip_check_unlock(port);
221: it_dnrequests_free(its, ntable);
222: }
223:
224: return KERN_SUCCESS;
225: }
1.1.1.2 root 226:
1.1 root 227: /*
228: * Routine: ipc_port_dncancel
229: * Purpose:
230: * Cancel a dead-name request and return the send-once right.
231: * Conditions:
232: * The port must locked and active.
233: */
234:
235: ipc_port_t
236: ipc_port_dncancel(
237: ipc_port_t port,
238: mach_port_t name,
239: ipc_port_request_index_t index)
240: {
241: ipc_port_request_t ipr, table;
242: ipc_port_t dnrequest;
243:
244: assert(ip_active(port));
245: assert(name != MACH_PORT_NULL);
246: assert(index != 0);
247:
248: table = port->ip_dnrequests;
249: assert(table != IPR_NULL);
250:
251: ipr = &table[index];
252: dnrequest = ipr->ipr_soright;
253: assert(ipr->ipr_name == name);
254:
255: /* return ipr to the free list inside the table */
256:
257: ipr->ipr_name = MACH_PORT_NULL;
258: ipr->ipr_next = table->ipr_next;
259: table->ipr_next = index;
260:
261: return dnrequest;
262: }
263:
264: /*
265: * Routine: ipc_port_pdrequest
266: * Purpose:
267: * Make a port-deleted request, returning the
268: * previously registered send-once right.
269: * Just cancels the previous request if notify is IP_NULL.
270: * Conditions:
271: * The port is locked and active. It is unlocked.
272: * Consumes a ref for notify (if non-null), and
273: * returns previous with a ref (if non-null).
274: */
275:
276: void
277: ipc_port_pdrequest(
278: ipc_port_t port,
279: ipc_port_t notify,
280: ipc_port_t *previousp)
281: {
282: ipc_port_t previous;
283:
284: assert(ip_active(port));
285:
286: previous = port->ip_pdrequest;
287: port->ip_pdrequest = notify;
288: ip_unlock(port);
289:
290: *previousp = previous;
291: }
292:
293: /*
294: * Routine: ipc_port_nsrequest
295: * Purpose:
296: * Make a no-senders request, returning the
297: * previously registered send-once right.
298: * Just cancels the previous request if notify is IP_NULL.
299: * Conditions:
300: * The port is locked and active. It is unlocked.
301: * Consumes a ref for notify (if non-null), and
302: * returns previous with a ref (if non-null).
303: */
304:
305: void
306: ipc_port_nsrequest(
307: ipc_port_t port,
308: mach_port_mscount_t sync,
309: ipc_port_t notify,
310: ipc_port_t *previousp)
311: {
312: ipc_port_t previous;
313: mach_port_mscount_t mscount;
314:
315: assert(ip_active(port));
316:
317: previous = port->ip_nsrequest;
318: mscount = port->ip_mscount;
319:
320: if ((port->ip_srights == 0) &&
321: (sync <= mscount) &&
322: (notify != IP_NULL)) {
323: port->ip_nsrequest = IP_NULL;
324: ip_unlock(port);
325: ipc_notify_no_senders(notify, mscount);
326: } else {
327: port->ip_nsrequest = notify;
328: ip_unlock(port);
329: }
330:
331: *previousp = previous;
332: }
333:
334: /*
335: * Routine: ipc_port_set_qlimit
336: * Purpose:
337: * Changes a port's queue limit; the maximum number
338: * of messages which may be queued to the port.
339: * Conditions:
340: * The port is locked and active.
341: */
342:
343: void
344: ipc_port_set_qlimit(
345: ipc_port_t port,
346: mach_port_msgcount_t qlimit)
347: {
348: assert(ip_active(port));
349:
350: /* wake up senders allowed by the new qlimit */
351:
352: if (qlimit > port->ip_qlimit) {
353: mach_port_msgcount_t i, wakeup;
354:
355: /* caution: wakeup, qlimit are unsigned */
356:
357: wakeup = qlimit - port->ip_qlimit;
358:
359: for (i = 0; i < wakeup; i++) {
360: ipc_thread_t th;
361:
362: th = ipc_thread_dequeue(&port->ip_blocked);
363: if (th == ITH_NULL)
364: break;
365:
366: th->ith_state = MACH_MSG_SUCCESS;
367: thread_go(th);
368: }
369: }
370:
371: port->ip_qlimit = qlimit;
372: }
373:
374: /*
375: * Routine: ipc_port_lock_mqueue
376: * Purpose:
377: * Locks and returns the message queue that the port is using.
378: * The message queue may be in the port or in its port set.
379: * Conditions:
380: * The port is locked and active.
381: * Port set, message queue locks may be taken.
382: */
383:
384: ipc_mqueue_t
385: ipc_port_lock_mqueue(port)
386: ipc_port_t port;
387: {
388: if (port->ip_pset != IPS_NULL) {
389: ipc_pset_t pset = port->ip_pset;
390:
391: ips_lock(pset);
392: if (ips_active(pset)) {
393: imq_lock(&pset->ips_messages);
394: ips_unlock(pset);
395: return &pset->ips_messages;
396: }
397:
398: ipc_pset_remove(pset, port);
399: ips_check_unlock(pset);
400: }
401:
402: imq_lock(&port->ip_messages);
403: return &port->ip_messages;
404: }
405:
406: /*
407: * Routine: ipc_port_set_seqno
408: * Purpose:
409: * Changes a port's sequence number.
410: * Conditions:
411: * The port is locked and active.
412: * Port set, message queue locks may be taken.
413: */
414:
415: void
416: ipc_port_set_seqno(port, seqno)
417: ipc_port_t port;
418: mach_port_seqno_t seqno;
419: {
420: ipc_mqueue_t mqueue;
421:
422: mqueue = ipc_port_lock_mqueue(port);
423: port->ip_seqno = seqno;
424: imq_unlock(mqueue);
425: }
426:
427: /*
428: * Routine: ipc_port_clear_receiver
429: * Purpose:
430: * Prepares a receive right for transmission/destruction.
431: * Conditions:
432: * The port is locked and active.
433: */
434:
435: void
436: ipc_port_clear_receiver(
437: ipc_port_t port)
438: {
439: ipc_pset_t pset;
440:
441: assert(ip_active(port));
442:
443: pset = port->ip_pset;
444: if (pset != IPS_NULL) {
445: /* No threads receiving from port, but must remove from set. */
446:
447: ips_lock(pset);
448: ipc_pset_remove(pset, port);
449: ips_check_unlock(pset);
450: } else {
451: /* Else, wake up all receivers, indicating why. */
452:
453: imq_lock(&port->ip_messages);
454: ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_DIED);
455: imq_unlock(&port->ip_messages);
456: }
457:
458: ipc_port_set_mscount(port, 0);
459: imq_lock(&port->ip_messages);
460: port->ip_seqno = 0;
461: imq_unlock(&port->ip_messages);
462: }
463:
464: /*
465: * Routine: ipc_port_init
466: * Purpose:
467: * Initializes a newly-allocated port.
468: * Doesn't touch the ip_object fields.
469: */
470:
471: void
472: ipc_port_init(
473: ipc_port_t port,
474: ipc_space_t space,
475: mach_port_t name)
476: {
477: /* port->ip_kobject doesn't have to be initialized */
478:
479: ipc_target_init(&port->ip_target, name);
480:
481: port->ip_receiver = space;
482:
483: port->ip_mscount = 0;
484: port->ip_srights = 0;
485: port->ip_sorights = 0;
486:
487: port->ip_nsrequest = IP_NULL;
488: port->ip_pdrequest = IP_NULL;
489: port->ip_dnrequests = IPR_NULL;
490:
491: port->ip_pset = IPS_NULL;
492: port->ip_cur_target = &port->ip_target;
493: port->ip_seqno = 0;
494: port->ip_msgcount = 0;
495: port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
496:
497: ipc_mqueue_init(&port->ip_messages);
498: ipc_thread_queue_init(&port->ip_blocked);
499: }
500:
501: /*
502: * Routine: ipc_port_alloc
503: * Purpose:
504: * Allocate a port.
505: * Conditions:
506: * Nothing locked. If successful, the port is returned
507: * locked. (The caller doesn't have a reference.)
508: * Returns:
509: * KERN_SUCCESS The port is allocated.
510: * KERN_INVALID_TASK The space is dead.
511: * KERN_NO_SPACE No room for an entry in the space.
512: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
513: */
514:
515: kern_return_t
516: ipc_port_alloc(
517: ipc_space_t space,
518: mach_port_t *namep,
519: ipc_port_t *portp)
520: {
521: ipc_port_t port;
522: mach_port_t name;
523: kern_return_t kr;
524:
525: kr = ipc_object_alloc(space, IOT_PORT,
526: MACH_PORT_TYPE_RECEIVE, 0,
527: &name, (ipc_object_t *) &port);
528: if (kr != KERN_SUCCESS)
529: return kr;
530:
531: /* port is locked */
532:
533: ipc_port_init(port, space, name);
534:
535: *namep = name;
536: *portp = port;
537:
538: return KERN_SUCCESS;
539: }
540:
541: /*
542: * Routine: ipc_port_alloc_name
543: * Purpose:
544: * Allocate a port, with a specific name.
545: * Conditions:
546: * Nothing locked. If successful, the port is returned
547: * locked. (The caller doesn't have a reference.)
548: * Returns:
549: * KERN_SUCCESS The port is allocated.
550: * KERN_INVALID_TASK The space is dead.
551: * KERN_NAME_EXISTS The name already denotes a right.
552: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
553: */
554:
555: kern_return_t
556: ipc_port_alloc_name(
557: ipc_space_t space,
558: mach_port_t name,
559: ipc_port_t *portp)
560: {
561: ipc_port_t port;
562: kern_return_t kr;
563:
564: kr = ipc_object_alloc_name(space, IOT_PORT,
565: MACH_PORT_TYPE_RECEIVE, 0,
566: name, (ipc_object_t *) &port);
567: if (kr != KERN_SUCCESS)
568: return kr;
569: /* port is locked */
570:
571: ipc_port_init(port, space, name);
572:
573: *portp = port;
574: return KERN_SUCCESS;
575: }
576:
577: /*
578: * Routine: ipc_port_destroy
579: * Purpose:
580: * Destroys a port. Cleans up queued messages.
581: *
582: * If the port has a backup, it doesn't get destroyed,
583: * but is sent in a port-destroyed notification to the backup.
584: * Conditions:
585: * The port is locked and alive; nothing else locked.
586: * The caller has a reference, which is consumed.
587: * Afterwards, the port is unlocked and dead.
588: */
589:
590: void
591: ipc_port_destroy(
592: ipc_port_t port)
593: {
594: ipc_port_t pdrequest, nsrequest;
595: ipc_mqueue_t mqueue;
596: ipc_kmsg_queue_t kmqueue;
597: ipc_kmsg_t kmsg;
598: ipc_thread_t sender;
599: ipc_port_request_t dnrequests;
600:
601: assert(ip_active(port));
602: /* port->ip_receiver_name is garbage */
603: /* port->ip_receiver/port->ip_destination is garbage */
604: assert(port->ip_pset == IPS_NULL);
605: assert(port->ip_mscount == 0);
606: assert(port->ip_seqno == 0);
607:
608: /* first check for a backup port */
609:
610: pdrequest = port->ip_pdrequest;
611: if (pdrequest != IP_NULL) {
612: /* we assume the ref for pdrequest */
613: port->ip_pdrequest = IP_NULL;
614:
615: /* make port be in limbo */
616: port->ip_receiver_name = MACH_PORT_NULL;
617: port->ip_destination = IP_NULL;
618: ip_unlock(port);
619:
620: if (!ipc_port_check_circularity(port, pdrequest)) {
621: /* consumes our refs for port and pdrequest */
622: ipc_notify_port_destroyed(pdrequest, port);
623: return;
624: } else {
625: /* consume pdrequest and destroy port */
626: ipc_port_release_sonce(pdrequest);
627: }
628:
629: ip_lock(port);
630: assert(ip_active(port));
631: assert(port->ip_pset == IPS_NULL);
632: assert(port->ip_mscount == 0);
633: assert(port->ip_seqno == 0);
634: assert(port->ip_pdrequest == IP_NULL);
635: assert(port->ip_receiver_name == MACH_PORT_NULL);
636: assert(port->ip_destination == IP_NULL);
637:
638: /* fall through and destroy the port */
639: }
640:
641: /*
642: * rouse all blocked senders
643: *
644: * This must be done with the port locked, because
645: * ipc_mqueue_send can play with the ip_blocked queue
646: * of a dead port.
647: */
648:
649: while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) {
650: sender->ith_state = MACH_MSG_SUCCESS;
651: thread_go(sender);
652: }
653:
654: /* once port is dead, we don't need to keep it locked */
655:
656: port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
657: port->ip_timestamp = ipc_port_timestamp();
658: ip_unlock(port);
659:
660: /* throw away no-senders request */
661:
662: nsrequest = port->ip_nsrequest;
663: if (nsrequest != IP_NULL)
664: ipc_notify_send_once(nsrequest); /* consumes ref */
665:
666: /* destroy any queued messages */
667:
668: mqueue = &port->ip_messages;
669: imq_lock(mqueue);
670: assert(ipc_thread_queue_empty(&mqueue->imq_threads));
671: kmqueue = &mqueue->imq_messages;
672:
673: while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) {
674: imq_unlock(mqueue);
675:
676: assert(kmsg->ikm_header.msgh_remote_port ==
677: (mach_port_t) port);
678:
679: ipc_port_release(port);
680: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
681: ipc_kmsg_destroy(kmsg);
682:
683: imq_lock(mqueue);
684: }
685:
686: imq_unlock(mqueue);
687:
688: /* generate dead-name notifications */
689:
690: dnrequests = port->ip_dnrequests;
691: if (dnrequests != IPR_NULL) {
692: ipc_table_size_t its = dnrequests->ipr_size;
693: ipc_table_elems_t size = its->its_size;
694: ipc_port_request_index_t index;
695:
696: for (index = 1; index < size; index++) {
697: ipc_port_request_t ipr = &dnrequests[index];
698: mach_port_t name = ipr->ipr_name;
699: ipc_port_t soright;
700:
701: if (name == MACH_PORT_NULL)
702: continue;
703:
704: soright = ipr->ipr_soright;
705: assert(soright != IP_NULL);
706:
707: ipc_notify_dead_name(soright, name);
708: }
709:
710: it_dnrequests_free(its, dnrequests);
711: }
712:
713: if (ip_kotype(port) != IKOT_NONE)
714: ipc_kobject_destroy(port);
715:
716: /* Common destruction for the IPC target. */
717: ipc_target_terminate(&port->ip_target);
718:
719: ipc_port_release(port); /* consume caller's ref */
720: }
721:
722: /*
723: * Routine: ipc_port_check_circularity
724: * Purpose:
725: * Check if queueing "port" in a message for "dest"
726: * would create a circular group of ports and messages.
727: *
728: * If no circularity (FALSE returned), then "port"
729: * is changed from "in limbo" to "in transit".
730: *
731: * That is, we want to set port->ip_destination == dest,
732: * but guaranteeing that this doesn't create a circle
733: * port->ip_destination->ip_destination->... == port
734: * Conditions:
735: * No ports locked. References held for "port" and "dest".
736: */
737:
738: boolean_t
739: ipc_port_check_circularity(
740: ipc_port_t port,
741: ipc_port_t dest)
742: {
743: ipc_port_t base;
744:
745: assert(port != IP_NULL);
746: assert(dest != IP_NULL);
747:
748: if (port == dest)
749: return TRUE;
750: base = dest;
751:
752: /*
753: * First try a quick check that can run in parallel.
754: * No circularity if dest is not in transit.
755: */
756:
757: ip_lock(port);
758: if (ip_lock_try(dest)) {
759: if (!ip_active(dest) ||
760: (dest->ip_receiver_name != MACH_PORT_NULL) ||
761: (dest->ip_destination == IP_NULL))
762: goto not_circular;
763:
764: /* dest is in transit; further checking necessary */
765:
766: ip_unlock(dest);
767: }
768: ip_unlock(port);
769:
770: ipc_port_multiple_lock(); /* massive serialization */
771:
772: /*
773: * Search for the end of the chain (a port not in transit),
774: * acquiring locks along the way.
775: */
776:
777: for (;;) {
778: ip_lock(base);
779:
780: if (!ip_active(base) ||
781: (base->ip_receiver_name != MACH_PORT_NULL) ||
782: (base->ip_destination == IP_NULL))
783: break;
784:
785: base = base->ip_destination;
786: }
787:
788: /* all ports in chain from dest to base, inclusive, are locked */
789:
790: if (port == base) {
791: /* circularity detected! */
792:
793: ipc_port_multiple_unlock();
794:
795: /* port (== base) is in limbo */
796:
797: assert(ip_active(port));
798: assert(port->ip_receiver_name == MACH_PORT_NULL);
799: assert(port->ip_destination == IP_NULL);
800:
801: while (dest != IP_NULL) {
802: ipc_port_t next;
803:
804: /* dest is in transit or in limbo */
805:
806: assert(ip_active(dest));
807: assert(dest->ip_receiver_name == MACH_PORT_NULL);
808:
809: next = dest->ip_destination;
810: ip_unlock(dest);
811: dest = next;
812: }
813:
814: return TRUE;
815: }
816:
817: /*
818: * The guarantee: lock port while the entire chain is locked.
819: * Once port is locked, we can take a reference to dest,
820: * add port to the chain, and unlock everything.
821: */
822:
823: ip_lock(port);
824: ipc_port_multiple_unlock();
825:
826: not_circular:
827:
828: /* port is in limbo */
829:
830: assert(ip_active(port));
831: assert(port->ip_receiver_name == MACH_PORT_NULL);
832: assert(port->ip_destination == IP_NULL);
833:
834: ip_reference(dest);
835: port->ip_destination = dest;
836:
837: /* now unlock chain */
838:
839: while (port != base) {
840: ipc_port_t next;
841:
842: /* port is in transit */
843:
844: assert(ip_active(port));
845: assert(port->ip_receiver_name == MACH_PORT_NULL);
846: assert(port->ip_destination != IP_NULL);
847:
848: next = port->ip_destination;
849: ip_unlock(port);
850: port = next;
851: }
852:
853: /* base is not in transit */
854:
855: assert(!ip_active(base) ||
856: (base->ip_receiver_name != MACH_PORT_NULL) ||
857: (base->ip_destination == IP_NULL));
858: ip_unlock(base);
859:
860: return FALSE;
861: }
862:
863: /*
864: * Routine: ipc_port_lookup_notify
865: * Purpose:
866: * Make a send-once notify port from a receive right.
867: * Returns IP_NULL if name doesn't denote a receive right.
868: * Conditions:
869: * The space must be locked (read or write) and active.
870: */
871:
872: ipc_port_t
873: ipc_port_lookup_notify(
874: ipc_space_t space,
875: mach_port_t name)
876: {
877: ipc_port_t port;
878: ipc_entry_t entry;
879:
880: assert(space->is_active);
881:
882: entry = ipc_entry_lookup(space, name);
883: if (entry == IE_NULL)
884: return IP_NULL;
885:
886: if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
887: return IP_NULL;
888:
889: port = (ipc_port_t) entry->ie_object;
890: assert(port != IP_NULL);
891:
892: ip_lock(port);
893: assert(ip_active(port));
894: assert(port->ip_receiver_name == name);
895: assert(port->ip_receiver == space);
896:
897: ip_reference(port);
898: port->ip_sorights++;
899: ip_unlock(port);
900:
901: return port;
902: }
903:
904: /*
905: * Routine: ipc_port_make_send
906: * Purpose:
907: * Make a naked send right from a receive right.
908: * Conditions:
909: * The port is not locked but it is active.
910: */
911:
912: ipc_port_t
913: ipc_port_make_send(
914: ipc_port_t port)
915: {
916: assert(IP_VALID(port));
917:
918: ip_lock(port);
919: assert(ip_active(port));
920: port->ip_mscount++;
921: port->ip_srights++;
922: ip_reference(port);
923: ip_unlock(port);
924:
925: return port;
926: }
927:
928: /*
929: * Routine: ipc_port_copy_send
930: * Purpose:
931: * Make a naked send right from another naked send right.
932: * IP_NULL -> IP_NULL
933: * IP_DEAD -> IP_DEAD
934: * dead port -> IP_DEAD
935: * live port -> port + ref
936: * Conditions:
937: * Nothing locked except possibly a space.
938: */
939:
940: ipc_port_t
941: ipc_port_copy_send(
942: ipc_port_t port)
943: {
944: ipc_port_t sright;
945:
946: if (!IP_VALID(port))
947: return port;
948:
949: ip_lock(port);
950: if (ip_active(port)) {
951: assert(port->ip_srights > 0);
952:
953: ip_reference(port);
954: port->ip_srights++;
955: sright = port;
956: } else
957: sright = IP_DEAD;
958: ip_unlock(port);
959:
960: return sright;
961: }
962:
963: /*
964: * Routine: ipc_port_copyout_send
965: * Purpose:
966: * Copyout a naked send right (possibly null/dead),
967: * or if that fails, destroy the right.
968: * Conditions:
969: * Nothing locked.
970: */
971:
972: mach_port_t
973: ipc_port_copyout_send(
974: ipc_port_t sright,
975: ipc_space_t space)
976: {
977: mach_port_t name;
978:
979: if (IP_VALID(sright)) {
980: kern_return_t kr;
981:
982: kr = ipc_object_copyout(space, (ipc_object_t) sright,
983: MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
984: if (kr != KERN_SUCCESS) {
985: ipc_port_release_send(sright);
986:
987: if (kr == KERN_INVALID_CAPABILITY)
988: name = MACH_PORT_DEAD;
989: else
990: name = MACH_PORT_NULL;
991: }
992: } else
993: name = (mach_port_t) sright;
994:
995: return name;
996: }
997:
998: /*
999: * Routine: ipc_port_release_send
1000: * Purpose:
1001: * Release a (valid) naked send right.
1002: * Consumes a ref for the port.
1003: * Conditions:
1004: * Nothing locked.
1005: */
1006:
1007: void
1008: ipc_port_release_send(
1009: ipc_port_t port)
1010: {
1011: ipc_port_t nsrequest = IP_NULL;
1012: mach_port_mscount_t mscount;
1013:
1014: assert(IP_VALID(port));
1015:
1016: ip_lock(port);
1017: ip_release(port);
1018:
1019: if (!ip_active(port)) {
1020: ip_check_unlock(port);
1021: return;
1022: }
1023:
1024: assert(port->ip_srights > 0);
1025:
1026: if (--port->ip_srights == 0) {
1027: nsrequest = port->ip_nsrequest;
1028: if (nsrequest != IP_NULL) {
1029: port->ip_nsrequest = IP_NULL;
1030: mscount = port->ip_mscount;
1031: }
1032: }
1033:
1034: ip_unlock(port);
1035:
1036: if (nsrequest != IP_NULL)
1037: ipc_notify_no_senders(nsrequest, mscount);
1038: }
1039:
1040: /*
1041: * Routine: ipc_port_make_sonce
1042: * Purpose:
1043: * Make a naked send-once right from a receive right.
1044: * Conditions:
1045: * The port is not locked but it is active.
1046: */
1047:
1048: ipc_port_t
1049: ipc_port_make_sonce(
1050: ipc_port_t port)
1051: {
1052: assert(IP_VALID(port));
1053:
1054: ip_lock(port);
1055: assert(ip_active(port));
1056: port->ip_sorights++;
1057: ip_reference(port);
1058: ip_unlock(port);
1059:
1060: return port;
1061: }
1062:
1063: /*
1064: * Routine: ipc_port_release_sonce
1065: * Purpose:
1066: * Release a naked send-once right.
1067: * Consumes a ref for the port.
1068: *
1069: * In normal situations, this is never used.
1070: * Send-once rights are only consumed when
1071: * a message (possibly a send-once notification)
1072: * is sent to them.
1073: * Conditions:
1074: * Nothing locked except possibly a space.
1075: */
1076:
1077: void
1078: ipc_port_release_sonce(
1079: ipc_port_t port)
1080: {
1081: assert(IP_VALID(port));
1082:
1083: ip_lock(port);
1084:
1085: assert(port->ip_sorights > 0);
1086:
1087: port->ip_sorights--;
1088:
1089: ip_release(port);
1090:
1091: if (!ip_active(port)) {
1092: ip_check_unlock(port);
1093: return;
1094: }
1095:
1096: ip_unlock(port);
1097: }
1098:
1099: /*
1100: * Routine: ipc_port_release_receive
1101: * Purpose:
1102: * Release a naked (in limbo or in transit) receive right.
1103: * Consumes a ref for the port; destroys the port.
1104: * Conditions:
1105: * Nothing locked.
1106: */
1107:
1108: void
1109: ipc_port_release_receive(
1110: ipc_port_t port)
1111: {
1112: ipc_port_t dest;
1113:
1114: assert(IP_VALID(port));
1115:
1116: ip_lock(port);
1117: assert(ip_active(port));
1118: assert(port->ip_receiver_name == MACH_PORT_NULL);
1119: dest = port->ip_destination;
1120:
1121: ipc_port_destroy(port); /* consumes ref, unlocks */
1122:
1123: if (dest != IP_NULL)
1124: ipc_port_release(dest);
1125: }
1126:
1127: /*
1128: * Routine: ipc_port_alloc_special
1129: * Purpose:
1130: * Allocate a port in a special space.
1131: * The new port is returned with one ref.
1132: * If unsuccessful, IP_NULL is returned.
1133: * Conditions:
1134: * Nothing locked.
1135: */
1136:
1137: ipc_port_t
1138: ipc_port_alloc_special(space)
1139: ipc_space_t space;
1140: {
1141: ipc_port_t port;
1142:
1143: port = (ipc_port_t) io_alloc(IOT_PORT);
1144: if (port == IP_NULL)
1145: return IP_NULL;
1146:
1147: io_lock_init(&port->ip_object);
1148: port->ip_references = 1;
1149: port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1150:
1151: /*
1152: * The actual values of ip_receiver_name aren't important,
1153: * as long as they are valid (not null/dead).
1154: *
1155: * Mach4: we set it to the internal port structure address
1156: * so we can always just pass on ip_receiver_name during
1157: * an rpc regardless of whether the destination is user or
1158: * kernel (i.e. no special-casing code for the kernel along
1159: * the fast rpc path).
1160: */
1161:
1162: ipc_port_init(port, space, (mach_port_t)port);
1163:
1164: return port;
1165: }
1166:
1167: /*
1168: * Routine: ipc_port_dealloc_special
1169: * Purpose:
1170: * Deallocate a port in a special space.
1171: * Consumes one ref for the port.
1172: * Conditions:
1173: * Nothing locked.
1174: */
1175:
1176: void
1177: ipc_port_dealloc_special(
1178: ipc_port_t port,
1179: ipc_space_t space)
1180: {
1181: ip_lock(port);
1182: assert(ip_active(port));
1183: assert(port->ip_receiver_name != MACH_PORT_NULL);
1184: assert(port->ip_receiver == space);
1185:
1186: /*
1187: * We clear ip_receiver_name and ip_receiver to simplify
1188: * the ipc_space_kernel check in ipc_mqueue_send.
1189: */
1190:
1191: port->ip_receiver_name = MACH_PORT_NULL;
1192: port->ip_receiver = IS_NULL;
1193:
1194: /*
1195: * For ipc_space_kernel, all ipc_port_clear_receiver does
1196: * is clean things up for the assertions in ipc_port_destroy.
1197: * For ipc_space_reply, there might be a waiting receiver.
1198: */
1199:
1200: ipc_port_clear_receiver(port);
1201: ipc_port_destroy(port);
1202: }
1203:
1204: #if MACH_KDB
1205: #define printf kdbprintf
1206:
1207: /*
1208: * Routine: ipc_port_print
1209: * Purpose:
1210: * Pretty-print a port for kdb.
1211: */
1212:
1213: void
1214: ipc_port_print(port)
1215: ipc_port_t port;
1216: {
1217: printf("port 0x%x\n", port);
1218:
1219: indent += 2;
1220:
1221: ipc_object_print(&port->ip_object);
1222: iprintf("receiver=0x%x", port->ip_receiver);
1223: printf(", receiver_name=0x%x\n", port->ip_receiver_name);
1224:
1225: iprintf("mscount=%d", port->ip_mscount);
1226: printf(", srights=%d", port->ip_srights);
1227: printf(", sorights=%d\n", port->ip_sorights);
1228:
1229: iprintf("nsrequest=0x%x", port->ip_nsrequest);
1230: printf(", pdrequest=0x%x", port->ip_pdrequest);
1231: printf(", dnrequests=0x%x\n", port->ip_dnrequests);
1232:
1233: iprintf("pset=0x%x", port->ip_pset);
1234: printf(", seqno=%d", port->ip_seqno);
1235: printf(", msgcount=%d", port->ip_msgcount);
1236: printf(", qlimit=%d\n", port->ip_qlimit);
1237:
1238: iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
1239: printf(", rcvrs=0x%x", port->ip_messages.imq_threads.ithq_base);
1240: printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
1241: printf(", kobj=0x%x\n", port->ip_kobject);
1242:
1243: indent -=2;
1244: }
1245:
1.1.1.2 root 1246: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.