|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990
27: * Open Software Foundation, Inc.
28: *
29: * Permission to use, copy, modify, and distribute this software and
30: * its documentation for any purpose and without fee is hereby granted,
31: * provided that the above copyright notice appears in all copies and
32: * that both the copyright notice and this permission notice appear in
33: * supporting documentation, and that the name of ("OSF") or Open Software
34: * Foundation not be used in advertising or publicity pertaining to
35: * distribution of the software without specific, written prior permission.
36: *
37: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
38: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
39: * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY
40: * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
41: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
42: * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING
43: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
44: */
45: /*
46: * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
47: */
48: /*
49: * Mach Operating System
50: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
51: * All Rights Reserved.
52: *
53: * Permission to use, copy, modify and distribute this software and its
54: * documentation is hereby granted, provided that both the copyright
55: * notice and this permission notice appear in all copies of the
56: * software, derivative works or modified versions, and any portions
57: * thereof, and that both notices appear in supporting documentation.
58: *
59: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
60: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
61: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
62: *
63: * Carnegie Mellon requests users of this software to return to
64: *
65: * Software Distribution Coordinator or [email protected]
66: * School of Computer Science
67: * Carnegie Mellon University
68: * Pittsburgh PA 15213-3890
69: *
70: * any improvements or extensions that they make and grant Carnegie Mellon
71: * the rights to redistribute these changes.
72: */
73: /*
74: * File: ipc/ipc_mqueue.c
75: * Author: Rich Draves
76: * Date: 1989
77: *
78: * Functions to manipulate IPC message queues.
79: */
80:
81: #include <mach/port.h>
82: #include <mach/message.h>
83: #include <kern/assert.h>
84: #include <kern/counters.h>
85: #include <kern/sched_prim.h>
86: #include <kern/ipc_sched.h>
87: #include <kern/ipc_kobject.h>
88: #include <ipc/ipc_mqueue.h>
89: #include <ipc/ipc_thread.h>
90: #include <ipc/ipc_kmsg.h>
91: #include <ipc/ipc_port.h>
92: #include <ipc/ipc_pset.h>
93: #include <ipc/ipc_space.h>
94: #include <ipc/ipc_marequest.h>
95:
96: /*
97: * Routine: ipc_mqueue_init
98: * Purpose:
99: * Initialize a newly-allocated message queue.
100: */
101:
102: void
103: ipc_mqueue_init(
104: ipc_mqueue_t mqueue)
105: {
106: imq_lock_init(mqueue);
107: ipc_kmsg_queue_init(&mqueue->imq_messages);
108: ipc_thread_queue_init(&mqueue->imq_threads);
109: }
110:
111: /*
112: * Routine: ipc_mqueue_move
113: * Purpose:
114: * Move messages from one queue (source) to another (dest).
115: * Only moves messages sent to the specified port.
116: * Conditions:
117: * Both queues must be locked.
118: * (This is sufficient to manipulate port->ip_seqno.)
119: */
120:
121: void
122: ipc_mqueue_move(
123: ipc_mqueue_t dest,
124: ipc_mqueue_t source,
125: ipc_port_t port)
126: {
127: ipc_kmsg_queue_t oldq, newq;
128: ipc_thread_queue_t blockedq;
129: ipc_kmsg_t kmsg, next;
130: ipc_thread_t th;
131:
132: oldq = &source->imq_messages;
133: newq = &dest->imq_messages;
134: blockedq = &dest->imq_threads;
135:
136: for (kmsg = ipc_kmsg_queue_first(oldq);
137: kmsg != IKM_NULL; kmsg = next) {
138: next = ipc_kmsg_queue_next(oldq, kmsg);
139:
140: /* only move messages sent to port */
141:
142: if (kmsg->ikm_header.msgh_remote_port != (mach_port_t) port)
143: continue;
144:
145: ipc_kmsg_rmqueue(oldq, kmsg);
146:
147: /* before adding kmsg to newq, check for a blocked receiver */
148:
149: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_OLD_FORMAT) {
150: while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) {
151: assert(ipc_kmsg_queue_empty(newq));
152:
153: /* check if the receiver can handle the message */
154:
155: if (!(th->ith_rcv_option & MACH_RCV_OLD_FORMAT)) {
156: th->ith_state = MACH_RCV_HEADER_ERROR;
157: th->ith_kmsg = kmsg;
158: th->ith_seqno = port->ip_seqno++;
159: thread_go(th);
160:
161: goto next_kmsg;
162: }
163: else
164: if (kmsg->ikm_header.msgh_size <= th->ith_msize) {
165: th->ith_state = MACH_MSG_SUCCESS;
166: th->ith_kmsg = kmsg;
167: th->ith_seqno = port->ip_seqno++;
168: thread_go(th);
169:
170: goto next_kmsg;
171: }
172: else {
173: th->ith_state = MACH_RCV_TOO_LARGE;
174: th->ith_msize = kmsg->ikm_header.msgh_size;
175: }
176:
177: thread_go(th);
178: }
179: }
180: else {
181: boolean_t msg_is_complex =
182: (kmsg->ikm_header.msgh_bits &
183: MACH_MSGH_BITS_COMPLEX) != 0;
184:
185: while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) {
186: assert(ipc_kmsg_queue_empty(newq));
187:
188: /*
189: * Check if the receiver can handle the message
190: */
191: if (th->ith_rcv_option & MACH_RCV_OLD_FORMAT) {
192: if (msg_is_complex ||
193: kmsg->ikm_header.msgh_size >
194: sizeof (mach_msg_header_t) ||
195: th->ith_msize <
196: sizeof (mach_msg_header_t)) {
197: th->ith_state = MACH_RCV_HEADER_ERROR;
198: th->ith_kmsg = kmsg;
199: th->ith_seqno = port->ip_seqno++;
200: thread_go(th);
201:
202: goto next_kmsg;
203: }
204:
205: /*
206: * As a special case, allow simple
207: * messages which consist of only a
208: * header to be received with the old
209: * messaging primatives.
210: */
211: th->ith_state = MACH_MSG_SUCCESS;
212: }
213: else
214: if (kmsg->ikm_header.msgh_size > (th->ith_msize -
215: REQUESTED_TRAILER_SIZE(th->ith_rcv_option))) {
216: /*
217: * The receive buffer isn't large enough
218: */
219: th->ith_state = MACH_RCV_TOO_LARGE;
220:
221: if (th->ith_rcv_option & MACH_RCV_LARGE) {
222: th->ith_msize = kmsg->ikm_header.msgh_size;
223: thread_go(th);
224: continue;
225: }
226: }
227: else
228: if (msg_is_complex && th->ith_list != IKM_NULL &&
229: (th->ith_state =
230: ipc_kmsg_check_scatter(
231: kmsg, th->ith_rcv_option,
232: &th->ith_list))
233: != MACH_MSG_SUCCESS) {
234: /*
235: * Check for type/VM errors.
236: */
237: if (th->ith_state == MACH_RCV_INVALID_TYPE ||
238: (th->ith_state & MACH_MSG_VM_KERNEL) != 0) {
239: thread_go(th);
240: continue;
241: }
242:
243: /*
244: * The scatter list isn't large enough.
245: */
246: if (th->ith_rcv_option & MACH_RCV_LARGE) {
247: th->ith_msize = kmsg->ikm_header.msgh_size;
248: thread_go(th);
249: continue;
250: }
251: }
252: else
253: th->ith_state = MACH_MSG_SUCCESS;
254:
255: /*
256: * Got a receiver. Possibly with a size error.
257: * Hand the receiver the message and process the
258: * next one.
259: */
260: th->ith_kmsg = kmsg;
261: th->ith_seqno = port->ip_seqno++;
262: thread_go(th);
263: goto next_kmsg;
264: }
265: }
266:
267: /* didn't find a receiver to handle the message */
268:
269: ipc_kmsg_enqueue(newq, kmsg);
270: next_kmsg:;
271: }
272: }
273:
274: /*
275: * Routine: ipc_mqueue_changed
276: * Purpose:
277: * Wake up receivers waiting in a message queue.
278: * Conditions:
279: * The message queue is locked.
280: */
281:
282: void
283: ipc_mqueue_changed(
284: ipc_mqueue_t mqueue,
285: mach_msg_return_t mr)
286: {
287: ipc_thread_t th;
288:
289: while ((th = ipc_thread_dequeue(&mqueue->imq_threads)) != ITH_NULL) {
290: th->ith_state = mr;
291: thread_go(th);
292: }
293: }
294:
295: /*
296: * Routine: ipc_mqueue_send
297: * Purpose:
298: * Send a message to a port. The message holds a reference
299: * for the destination port in the msgh_remote_port field.
300: *
301: * If unsuccessful, the caller still has possession of
302: * the message and must do something with it. If successful,
303: * the message is queued, given to a receiver, destroyed,
304: * or handled directly by the kernel via mach_msg.
305: * Conditions:
306: * Nothing locked.
307: * Returns:
308: * MACH_MSG_SUCCESS The message was accepted.
309: * MACH_SEND_TIMED_OUT Caller still has message.
310: * MACH_SEND_INTERRUPTED Caller still has message.
311: */
312:
313: mach_msg_return_t
314: ipc_mqueue_send(
315: ipc_kmsg_t kmsg,
316: mach_msg_option_t option,
317: mach_msg_timeout_t timeout,
318: void (*continuation)(void))
319: {
320: ipc_port_t port;
321:
322: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
323: assert(IP_VALID(port));
324:
325: ip_lock(port);
326:
327: if (port->ip_receiver == ipc_space_kernel) {
328: ipc_kmsg_t reply;
329:
330: /*
331: * We can check ip_receiver == ipc_space_kernel
332: * before checking that the port is active because
333: * ipc_port_dealloc_kernel clears ip_receiver
334: * before destroying a kernel port.
335: */
336:
337: assert(ip_active(port));
338: ip_unlock(port);
339:
340: reply = ipc_kobject_server(kmsg);
341: if (reply != IKM_NULL)
342: ipc_mqueue_send_always(reply);
343:
344: return MACH_MSG_SUCCESS;
345: }
346:
347: for (;;) {
348: ipc_thread_t self;
349:
350: /*
351: * Can't deliver to a dead port.
352: * However, we can pretend it got sent
353: * and was then immediately destroyed.
354: */
355:
356: if (!ip_active(port)) {
357: /*
358: * We can't let ipc_kmsg_destroy deallocate
359: * the port right, because we might end up
360: * in an infinite loop trying to deliver
361: * a send-once notification.
362: */
363:
364: ip_release(port);
365: ip_check_unlock(port);
366: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
367: ipc_kmsg_destroy(kmsg);
368: return MACH_MSG_SUCCESS;
369: }
370:
371: /*
372: * Don't block if:
373: * 1) We're under the queue limit.
374: * 2) Caller used the MACH_SEND_ALWAYS internal option.
375: * 3) Message is sent to a send-once right.
376: */
377:
378: if ((port->ip_msgcount < port->ip_qlimit) ||
379: (option & MACH_SEND_ALWAYS) ||
380: (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
381: MACH_MSG_TYPE_PORT_SEND_ONCE))
382: break;
383:
384: /* must block waiting for queue to clear */
385:
386: self = current_thread();
387:
388: if (option & MACH_SEND_TIMEOUT) {
389: if (timeout == 0) {
390: ip_unlock(port);
391: return MACH_SEND_TIMED_OUT;
392: }
393:
394: thread_will_wait_with_timeout(self, timeout);
395: } else
396: thread_will_wait(self);
397:
398: ipc_thread_enqueue(&port->ip_blocked, self);
399: self->ith_state = MACH_SEND_IN_PROGRESS;
400:
401: ip_unlock(port);
402: counter(c_ipc_mqueue_send_block++);
403: thread_block_with_continuation((void (*)(void)) 0);
404: ip_lock(port);
405:
406: /* why did we wake up? */
407:
408: if (self->ith_state == MACH_MSG_SUCCESS)
409: continue;
410: assert(self->ith_state == MACH_SEND_IN_PROGRESS);
411:
412: /* take ourselves off blocked queue */
413:
414: ipc_thread_rmqueue(&port->ip_blocked, self);
415:
416: /*
417: * Thread wakeup-reason field tells us why
418: * the wait was interrupted.
419: */
420:
421: switch (self->ith_wait_result) {
422: case THREAD_INTERRUPTED:
423: case THREAD_SHOULD_TERMINATE:
424: /* send was interrupted - give up */
425:
426: ip_unlock(port);
427: return MACH_SEND_INTERRUPTED;
428:
429: case THREAD_TIMED_OUT:
430: /* timeout expired */
431:
432: assert(option & MACH_SEND_TIMEOUT);
433: timeout = 0;
434: break;
435:
436: case THREAD_RESTART:
437: default:
438: panic("ipc_mqueue_send");
439: }
440: }
441:
442: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
443: ip_unlock(port);
444:
445: /* don't allow the creation of a circular loop */
446:
447: ipc_kmsg_destroy(kmsg);
448: return MACH_MSG_SUCCESS;
449: }
450:
451: {
452: ipc_mqueue_t mqueue;
453: ipc_pset_t pset;
454: ipc_thread_t receiver;
455: ipc_thread_queue_t receivers;
456:
457: port->ip_msgcount++;
458: assert(port->ip_msgcount > 0);
459:
460: pset = port->ip_pset;
461: if (pset == IPS_NULL)
462: mqueue = &port->ip_messages;
463: else
464: mqueue = &pset->ips_messages;
465:
466: imq_lock(mqueue);
467: receivers = &mqueue->imq_threads;
468:
469: /*
470: * Can unlock the port now that the msg queue is locked
471: * and we know the port is active. While the msg queue
472: * is locked, we have control of the kmsg, so the ref in
473: * it for the port is still good. If the msg queue is in
474: * a set (dead or alive), then we're OK because the port
475: * is still a member of the set and the set won't go away
476: * until the port is taken out, which tries to lock the
477: * set's msg queue to remove the port's msgs.
478: */
479:
480: ip_unlock(port);
481:
482: /* check for a receiver for the message */
483:
484: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_OLD_FORMAT) {
485: for (;;) {
486: receiver = ipc_thread_queue_first(receivers);
487: if (receiver == ITH_NULL) {
488: /* no receivers; queue kmsg */
489:
490: ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg);
491: imq_unlock(mqueue);
492: break;
493: }
494:
495: ipc_thread_rmqueue_first_macro(receivers, receiver);
496: assert(ipc_kmsg_queue_empty(&mqueue->imq_messages));
497:
498: if (!(receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT)) {
499: receiver->ith_state = MACH_RCV_HEADER_ERROR;
500: receiver->ith_kmsg = kmsg;
501: receiver->ith_seqno = port->ip_seqno++;
502: imq_unlock(mqueue);
503:
504: thread_go(receiver);
505: break;
506: }
507: else
508: if (kmsg->ikm_header.msgh_size <= receiver->ith_msize) {
509: /* got a successful receiver */
510:
511: receiver->ith_state = MACH_MSG_SUCCESS;
512: receiver->ith_kmsg = kmsg;
513: receiver->ith_seqno = port->ip_seqno++;
514: imq_unlock(mqueue);
515:
516: if (option & MACH_SEND_SWITCH)
517: thread_go_and_switch(continuation, receiver);
518: else
519: thread_go(receiver);
520: break;
521: }
522: else {
523: receiver->ith_state = MACH_RCV_TOO_LARGE;
524: receiver->ith_msize = kmsg->ikm_header.msgh_size;
525: }
526:
527: thread_go(receiver);
528: }
529: }
530: else {
531: boolean_t msg_is_complex =
532: (kmsg->ikm_header.msgh_bits &
533: MACH_MSGH_BITS_COMPLEX) != 0;
534:
535: for (;;) {
536: receiver = ipc_thread_queue_first(receivers);
537: if (receiver == ITH_NULL) {
538: /* no receivers; queue kmsg */
539:
540: ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg);
541: imq_unlock(mqueue);
542: break;
543: }
544:
545: ipc_thread_rmqueue_first_macro(receivers, receiver);
546: assert(ipc_kmsg_queue_empty(&mqueue->imq_messages));
547:
548: /*
549: * Got a potential receiver, verify sizes
550: */
551: if (receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT) {
552: if (msg_is_complex ||
553: kmsg->ikm_header.msgh_size >
554: sizeof (mach_msg_header_t) ||
555: receiver->ith_msize <
556: sizeof (mach_msg_header_t)) {
557: receiver->ith_state = MACH_RCV_HEADER_ERROR;
558: receiver->ith_kmsg = kmsg;
559: receiver->ith_seqno = port->ip_seqno++;
560: imq_unlock(mqueue);
561: thread_go(receiver);
562: break;
563: }
564:
565: receiver->ith_state = MACH_MSG_SUCCESS;
566: }
567: else
568: if (kmsg->ikm_header.msgh_size > (receiver->ith_msize -
569: REQUESTED_TRAILER_SIZE(receiver->ith_rcv_option))) {
570: /*
571: * The receive buffer isn't large enough
572: */
573: receiver->ith_state = MACH_RCV_TOO_LARGE;
574:
575: if (receiver->ith_rcv_option & MACH_RCV_LARGE) {
576: receiver->ith_msize = kmsg->ikm_header.msgh_size;
577: thread_go(receiver);
578: continue;
579: }
580: }
581: else
582: if (msg_is_complex && receiver->ith_list != IKM_NULL &&
583: (receiver->ith_state =
584: ipc_kmsg_check_scatter(
585: kmsg, receiver->ith_rcv_option,
586: &receiver->ith_list))
587: != MACH_MSG_SUCCESS) {
588: /*
589: * Check for type/VM errors.
590: */
591: if (receiver->ith_state == MACH_RCV_INVALID_TYPE ||
592: (receiver->ith_state & MACH_MSG_VM_KERNEL) != 0) {
593: thread_go(receiver);
594: continue;
595: }
596:
597: /*
598: * The scatter list isn't large enough.
599: */
600: if (receiver->ith_rcv_option & MACH_RCV_LARGE) {
601: receiver->ith_msize = kmsg->ikm_header.msgh_size;
602: thread_go(receiver);
603: continue;
604: }
605: }
606: else
607: receiver->ith_state = MACH_MSG_SUCCESS;
608:
609: /*
610: * Got a valid receiver. Possibly with an error.
611: * Hand the receiver the message.
612: */
613: receiver->ith_kmsg = kmsg;
614: receiver->ith_seqno = port->ip_seqno++;
615: imq_unlock(mqueue);
616: thread_go(receiver);
617: break;
618: }
619: }
620: }
621:
622: return MACH_MSG_SUCCESS;
623: }
624:
625: mach_msg_return_t
626: ipc_mqueue_send_interrupt(kmsg)
627: ipc_kmsg_t kmsg;
628: {
629: ipc_port_t port;
630:
631: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
632:
633: if (!ip_lock_try(port))
634: return MACH_MSG_IPC_KERNEL;
635:
636: if (!ip_active(port)) {
637: ip_unlock(port);
638: return MACH_SEND_INVALID_DEST;
639: }
640:
641: assert(!(kmsg->ikm_header.msgh_bits &
642: (MACH_MSGH_BITS_COMPLEX|MACH_MSGH_BITS_OLD_FORMAT)));
643:
644: {
645: ipc_mqueue_t mqueue;
646: ipc_pset_t pset;
647: ipc_thread_t receiver;
648: ipc_thread_queue_t receivers;
649:
650: pset = port->ip_pset;
651: if (pset == IPS_NULL)
652: mqueue = &port->ip_messages;
653: else
654: mqueue = &pset->ips_messages;
655:
656: if (!imq_lock_try(mqueue)) {
657: ip_unlock(port);
658: return MACH_MSG_IPC_KERNEL;
659: }
660: receivers = &mqueue->imq_threads;
661:
662: port->ip_msgcount++;
663:
664: /*
665: * Can unlock the port now that the msg queue is locked
666: * and we know the port is active. While the msg queue
667: * is locked, we have control of the kmsg, so the ref in
668: * it for the port is still good. If the msg queue is in
669: * a set (dead or alive), then we're OK because the port
670: * is still a member of the set and the set won't go away
671: * until the port is taken out, which tries to lock the
672: * set's msg queue to remove the port's msgs.
673: */
674:
675: ip_unlock(port);
676:
677: /* check for a receiver for the message */
678:
679: for (;;) {
680: receiver = ipc_thread_queue_first(receivers);
681: if (receiver == ITH_NULL) {
682: /* no receivers; queue kmsg */
683:
684: ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg);
685: imq_unlock(mqueue);
686: break;
687: }
688:
689: ipc_thread_rmqueue_first_macro(receivers, receiver);
690: assert(ipc_kmsg_queue_empty(&mqueue->imq_messages));
691:
692: /*
693: * Got a potential receiver, verify sizes
694: */
695: if (receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT) {
696: if ( kmsg->ikm_header.msgh_size >
697: sizeof (mach_msg_header_t) ||
698: receiver->ith_msize <
699: sizeof (mach_msg_header_t)) {
700: receiver->ith_state = MACH_RCV_HEADER_ERROR;
701: receiver->ith_kmsg = kmsg;
702: receiver->ith_seqno = port->ip_seqno++;
703: imq_unlock(mqueue);
704: thread_go(receiver);
705: break;
706: }
707:
708: receiver->ith_state = MACH_MSG_SUCCESS;
709: }
710: else
711: if (kmsg->ikm_header.msgh_size > (receiver->ith_msize -
712: REQUESTED_TRAILER_SIZE(receiver->ith_rcv_option))) {
713: /*
714: * The receive buffer isn't large enough
715: */
716: receiver->ith_state = MACH_RCV_TOO_LARGE;
717:
718: if (receiver->ith_rcv_option & MACH_RCV_LARGE) {
719: receiver->ith_msize = kmsg->ikm_header.msgh_size;
720: thread_go(receiver);
721: continue;
722: }
723: }
724: else
725: receiver->ith_state = MACH_MSG_SUCCESS;
726:
727: /*
728: * Got a valid receiver. Possibly with an error.
729: * Hand the receiver the message.
730: */
731: receiver->ith_kmsg = kmsg;
732: receiver->ith_seqno = port->ip_seqno++;
733: imq_unlock(mqueue);
734: thread_go(receiver);
735: break;
736: }
737: }
738:
739: return MACH_MSG_SUCCESS;
740: }
741:
742: /*
743: * Routine: ipc_mqueue_copyin
744: * Purpose:
745: * Convert a name in a space to a message queue.
746: * Conditions:
747: * Nothing locked. If successful, the message queue
748: * is returned locked and caller gets a ref for the object.
749: * This ref ensures the continued existence of the queue.
750: * Returns:
751: * MACH_MSG_SUCCESS Found a message queue.
752: * MACH_RCV_INVALID_NAME The space is dead.
753: * MACH_RCV_INVALID_NAME The name doesn't denote a right.
754: * MACH_RCV_INVALID_NAME
755: * The denoted right is not receive or port set.
756: * MACH_RCV_IN_SET Receive right is a member of a set.
757: */
758:
759: mach_msg_return_t
760: ipc_mqueue_copyin(
761: ipc_space_t space,
762: mach_port_t name,
763: ipc_mqueue_t *mqueuep,
764: ipc_object_t *objectp)
765: {
766: ipc_entry_t entry;
767: ipc_entry_bits_t bits;
768: ipc_object_t object;
769: ipc_mqueue_t mqueue;
770:
771: is_read_lock(space);
772: if (!space->is_active) {
773: is_read_unlock(space);
774: return MACH_RCV_INVALID_NAME;
775: }
776:
777: entry = ipc_entry_lookup(space, name);
778: if (entry == IE_NULL) {
779: is_read_unlock(space);
780: return MACH_RCV_INVALID_NAME;
781: }
782:
783: bits = entry->ie_bits;
784: object = entry->ie_object;
785:
786: if (bits & MACH_PORT_TYPE_RECEIVE) {
787: ipc_port_t port;
788: ipc_pset_t pset;
789:
790: port = (ipc_port_t) object;
791: assert(port != IP_NULL);
792:
793: ip_lock(port);
794: assert(ip_active(port));
795: assert(port->ip_receiver_name == name);
796: assert(port->ip_receiver == space);
797: is_read_unlock(space);
798:
799: pset = port->ip_pset;
800: if (pset != IPS_NULL) {
801: ips_lock(pset);
802: if (ips_active(pset)) {
803: ips_unlock(pset);
804: ip_unlock(port);
805: return MACH_RCV_IN_SET;
806: }
807:
808: ipc_pset_remove(pset, port);
809: ips_check_unlock(pset);
810: assert(port->ip_pset == IPS_NULL);
811: }
812:
813: mqueue = &port->ip_messages;
814: } else if (bits & MACH_PORT_TYPE_PORT_SET) {
815: ipc_pset_t pset;
816:
817: pset = (ipc_pset_t) object;
818: assert(pset != IPS_NULL);
819:
820: ips_lock(pset);
821: assert(ips_active(pset));
822: assert(pset->ips_local_name == name);
823: is_read_unlock(space);
824:
825: mqueue = &pset->ips_messages;
826: } else {
827: is_read_unlock(space);
828: return MACH_RCV_INVALID_NAME;
829: }
830:
831: /*
832: * At this point, the object is locked and active,
833: * the space is unlocked, and mqueue is initialized.
834: */
835:
836: io_reference(object);
837: imq_lock(mqueue);
838: io_unlock(object);
839:
840: *objectp = object;
841: *mqueuep = mqueue;
842: return MACH_MSG_SUCCESS;
843: }
844:
845: /*
846: * Routine: ipc_mqueue_receive
847: * Purpose:
848: * Receive a message from a message queue.
849: *
850: * If continuation is non-zero, then we might discard
851: * our kernel stack when we block. We will continue
852: * after unblocking by executing continuation.
853: *
854: * If resume is true, then we are resuming a receive
855: * operation after a blocked receive discarded our stack.
856: * Conditions:
857: * The message queue is locked; it is unlocked.
858: *
859: * Our caller must hold a reference for the port or port set
860: * to which this queue belongs, to keep the queue
861: * from being deallocated. Furthermore, the port or set
862: * must have been active when the queue was locked.
863: *
864: * The kmsg is returned with clean header fields
865: * and with the circular bit turned off.
866: * Returns:
867: * MACH_MSG_SUCCESS Message returned in kmsgp.
868: * MACH_RCV_TOO_LARGE Message size returned in kmsgp.
869: * MACH_RCV_TIMED_OUT No message obtained.
870: * MACH_RCV_INTERRUPTED No message obtained.
871: * MACH_RCV_PORT_DIED Port/set died; no message.
872: * MACH_RCV_PORT_CHANGED Port moved into set; no msg.
873: */
874:
875: mach_msg_return_t
876: ipc_mqueue_receive(
877: ipc_mqueue_t mqueue,
878: mach_msg_option_t option,
879: mach_msg_size_t max_size,
880: mach_msg_timeout_t timeout,
881: boolean_t resume,
882: void (*continuation)(void),
883: ipc_kmsg_t *kmsgp,
884: mach_port_seqno_t *seqnop,
885: ipc_kmsg_t *list)
886: {
887: ipc_port_t port;
888: ipc_kmsg_t kmsg;
889: mach_port_seqno_t seqno;
890: mach_msg_return_t mr;
891:
892: {
893: ipc_kmsg_queue_t kmsgs = &mqueue->imq_messages;
894: ipc_thread_t self = current_thread();
895:
896: if (resume)
897: goto after_thread_block;
898:
899: for (;;) {
900: kmsg = ipc_kmsg_queue_first(kmsgs);
901: if (kmsg != IKM_NULL) {
902: if (kmsg->ikm_header.msgh_bits &
903: MACH_MSGH_BITS_OLD_FORMAT) {
904: /*
905: * Old format message. (typed data) Verify
906: * that one of the old messaging primatives
907: * is being used for the receive operation.
908: */
909: if (!(option & MACH_RCV_OLD_FORMAT)) {
910: self->ith_state = MACH_RCV_HEADER_ERROR;
911: ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg);
912: port = (ipc_port_t)
913: kmsg->ikm_header.msgh_remote_port;
914: seqno = port->ip_seqno++;
915: break;
916: }
917:
918: /* check space requirements */
919:
920: if (kmsg->ikm_header.msgh_size > max_size) {
921: * (mach_msg_size_t *) kmsgp =
922: kmsg->ikm_header.msgh_size;
923: imq_unlock(mqueue);
924: return MACH_RCV_TOO_LARGE;
925: }
926:
927: self->ith_state = MACH_MSG_SUCCESS;
928: }
929: else {
930: /*
931: * New format message. (untyped data) Verify
932: * that one of the new messaging primatives
933: * is being used for the receive operation.
934: */
935: if (option & MACH_RCV_OLD_FORMAT) {
936: if ((kmsg->ikm_header.msgh_bits &
937: MACH_MSGH_BITS_COMPLEX) ||
938: kmsg->ikm_header.msgh_size >
939: sizeof (mach_msg_header_t) ||
940: max_size <
941: sizeof (mach_msg_header_t)) {
942: self->ith_state = MACH_RCV_HEADER_ERROR;
943: ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg);
944: port = (ipc_port_t)
945: kmsg->ikm_header.msgh_remote_port;
946: seqno = port->ip_seqno++;
947: break;
948: }
949:
950: self->ith_state = MACH_MSG_SUCCESS;
951: }
952: else
953: /*
954: * Verify sizes.
955: */
956: if (kmsg->ikm_header.msgh_size > (max_size -
957: REQUESTED_TRAILER_SIZE(option))) {
958: /*
959: * The receive buffer isn't large enough.
960: */
961: if (option & MACH_RCV_LARGE) {
962: *(mach_msg_size_t *)kmsgp =
963: kmsg->ikm_header.msgh_size;
964: imq_unlock(mqueue);
965: return MACH_RCV_TOO_LARGE;
966: }
967:
968: self->ith_state = MACH_RCV_TOO_LARGE;
969: }
970: else
971: if ((kmsg->ikm_header.msgh_bits &
972: MACH_MSGH_BITS_COMPLEX) &&
973: list && (*list) != IKM_NULL &&
974: (self->ith_state =
975: ipc_kmsg_check_scatter(
976: kmsg, option, list))
977: != MACH_MSG_SUCCESS) {
978: /*
979: * Check for type/VM errors.
980: */
981: if (self->ith_state == MACH_RCV_INVALID_TYPE ||
982: (self->ith_state & MACH_MSG_VM_KERNEL) != 0) {
983: imq_unlock(mqueue);
984: return self->ith_state;
985: }
986:
987: /*
988: * The scatter list isn't large enough.
989: */
990: if (option & MACH_RCV_LARGE) {
991: *(mach_msg_size_t *)kmsgp =
992: kmsg->ikm_header.msgh_size;
993: imq_unlock(mqueue);
994: return self->ith_state;
995: }
996: }
997: else
998: self->ith_state = MACH_MSG_SUCCESS;
999: }
1000:
1001: ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg);
1002: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
1003: seqno = port->ip_seqno++;
1004: break;
1005: }
1006:
1007: /* must block waiting for a message */
1008:
1009: if (option & MACH_RCV_TIMEOUT) {
1010: if (timeout == 0) {
1011: imq_unlock(mqueue);
1012: return MACH_RCV_TIMED_OUT;
1013: }
1014:
1015: thread_will_wait_with_timeout(self, timeout);
1016: } else
1017: thread_will_wait(self);
1018:
1019: ipc_thread_enqueue_macro(&mqueue->imq_threads, self);
1020: self->ith_state = MACH_RCV_IN_PROGRESS;
1021: self->ith_msize = max_size;
1022: self->ith_rcv_option = option;
1023: self->ith_list = list ? *list : IKM_NULL;
1024:
1025: imq_unlock(mqueue);
1026: if (continuation != (void (*)(void)) 0) {
1027: counter(c_ipc_mqueue_receive_block_user++);
1028: thread_block_with_continuation(continuation);
1029: } else {
1030: counter(c_ipc_mqueue_receive_block_kernel++);
1031: thread_block_with_continuation((void (*)(void)) 0);
1032: }
1033: after_thread_block:
1034: imq_lock(mqueue);
1035: if (list)
1036: (*list) = self->ith_list;
1037:
1038: /* why did we wake up? */
1039:
1040: if (self->ith_state == MACH_MSG_SUCCESS) {
1041: return_kmsg:
1042: /* pick up the message that was handed to us */
1043:
1044: kmsg = self->ith_kmsg;
1045: seqno = self->ith_seqno;
1046: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
1047: break;
1048: }
1049:
1050: switch (self->ith_state) {
1051: case MACH_RCV_INVALID_TYPE:
1052: /* bad invalid scatter list */
1053:
1054: imq_unlock(mqueue);
1055: return self->ith_state;
1056:
1057: case MACH_RCV_TOO_LARGE:
1058: case MACH_RCV_SCATTER_SMALL:
1059: /*
1060: * The receive buffer isn't large enough or
1061: * there is a scatter list and it doesn't match
1062: * the gather list.
1063: */
1064: if (!(self->ith_rcv_option &
1065: (MACH_RCV_LARGE|MACH_RCV_OLD_FORMAT)))
1066: goto return_kmsg;
1067:
1068: *(mach_msg_size_t *) kmsgp = self->ith_msize;
1069:
1070: /* fall-through */
1071:
1072: case MACH_RCV_PORT_DIED:
1073: case MACH_RCV_PORT_CHANGED:
1074: /* something bad happened to the port/set */
1075:
1076: imq_unlock(mqueue);
1077: return self->ith_state;
1078:
1079: case MACH_RCV_IN_PROGRESS:
1080: /*
1081: * Awakened for other than IPC completion.
1082: * Remove ourselves from the waiting queue,
1083: * then check the wakeup cause.
1084: */
1085:
1086: ipc_thread_rmqueue(&mqueue->imq_threads, self);
1087:
1088: switch (self->ith_wait_result) {
1089: case THREAD_INTERRUPTED:
1090: case THREAD_SHOULD_TERMINATE:
1091: /* receive was interrupted - give up */
1092:
1093: imq_unlock(mqueue);
1094: return MACH_RCV_INTERRUPTED;
1095:
1096: case THREAD_TIMED_OUT:
1097: /* timeout expired */
1098:
1099: assert(option & MACH_RCV_TIMEOUT);
1100: timeout = 0;
1101: break;
1102:
1103: case THREAD_RESTART:
1104: default:
1105: panic("ipc_mqueue_receive");
1106: }
1107: break;
1108:
1109: case MACH_RCV_HEADER_ERROR:
1110: /*
1111: * There was a message was queued on the
1112: * port, but its format was incompatible
1113: * with the receive operation we were
1114: * performing.
1115: */
1116: goto return_kmsg;
1117:
1118: default:
1119: panic("ipc_mqueue_receive: strange ith_state");
1120: }
1121: }
1122:
1123: mr = self->ith_state;
1124:
1125: /* we have a kmsg; unlock the msg queue */
1126:
1127: imq_unlock(mqueue);
1128: }
1129:
1130: {
1131: ipc_marequest_t marequest;
1132:
1133: marequest = kmsg->ikm_marequest;
1134: if (marequest != IMAR_NULL) {
1135: ipc_marequest_destroy(marequest);
1136: kmsg->ikm_marequest = IMAR_NULL;
1137: }
1138: assert((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0);
1139:
1140: assert(port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port);
1141: ip_lock(port);
1142:
1143: if (ip_active(port)) {
1144: ipc_thread_queue_t senders;
1145: ipc_thread_t sender;
1146:
1147: assert(port->ip_msgcount > 0);
1148: port->ip_msgcount--;
1149:
1150: senders = &port->ip_blocked;
1151: sender = ipc_thread_queue_first(senders);
1152:
1153: if ((sender != ITH_NULL) &&
1154: (port->ip_msgcount < port->ip_qlimit)) {
1155: ipc_thread_rmqueue(senders, sender);
1156: sender->ith_state = MACH_MSG_SUCCESS;
1157: thread_go(sender);
1158: }
1159: }
1160:
1161: ip_unlock(port);
1162: }
1163:
1164: *kmsgp = kmsg;
1165: *seqnop = seqno;
1166: return mr;
1167: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.