|
|
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/mach_msg.c
75: * Author: Rich Draves
76: * Date: 1989
77: *
78: * Exported message traps. See mach/message.h.
79: */
80:
81: #import <mach/features.h>
82:
83: #include <mach/kern_return.h>
84: #include <mach/port.h>
85: #include <mach/message.h>
86: #include <kern/assert.h>
87: #include <kern/counters.h>
88: #include <kern/lock.h>
89: #include <kern/sched_prim.h>
90: #include <kern/ipc_sched.h>
91: #include <vm/vm_map.h>
92: #include <ipc/ipc_kmsg.h>
93: #include <ipc/ipc_marequest.h>
94: #include <ipc/ipc_mqueue.h>
95: #include <ipc/ipc_object.h>
96: #include <ipc/ipc_notify.h>
97: #include <ipc/ipc_port.h>
98: #include <ipc/ipc_pset.h>
99: #include <ipc/ipc_space.h>
100: #include <ipc/ipc_thread.h>
101: #include <ipc/ipc_entry.h>
102: #include <ipc/mach_msg.h>
103:
104: /*
105: * Forward declarations
106: */
107:
108: mach_msg_return_t mach_msg_send(
109: mach_msg_header_t *msg,
110: mach_msg_option_t option,
111: mach_msg_size_t send_size,
112: mach_msg_timeout_t timeout,
113: mach_port_t notify);
114:
115: mach_msg_return_t mach_msg_receive(
116: mach_msg_header_t *msg,
117: mach_msg_option_t option,
118: mach_msg_size_t rcv_size,
119: mach_port_t rcv_name,
120: mach_msg_timeout_t timeout,
121: mach_port_t notify,
122: mach_msg_size_t list_size);
123:
124: mach_msg_return_t mach_msg_receive_error(
125: ipc_kmsg_t kmsg,
126: mach_msg_header_t *msg,
127: mach_msg_option_t option,
128: mach_port_seqno_t seqno,
129: ipc_space_t space);
130:
131: /* the size of each trailer has to be listed here for copyout purposes */
132: vm_size_t trailer_size[] = {
133: sizeof (mach_msg_trailer_t),
134: sizeof (mach_msg_seqno_trailer_t),
135: sizeof (mach_msg_security_trailer_t)
136: };
137:
138: /*
139: * Routine: mach_msg_send
140: * Purpose:
141: * Send a message.
142: * Conditions:
143: * Nothing locked.
144: * Returns:
145: * MACH_MSG_SUCCESS Sent the message.
146: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
147: * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
148: * MACH_SEND_INVALID_DATA Couldn't copy message data.
149: * MACH_SEND_INVALID_HEADER
150: * Illegal value in the message header bits.
151: * MACH_SEND_INVALID_DEST The space is dead.
152: * MACH_SEND_INVALID_NOTIFY Bad notify port.
153: * MACH_SEND_INVALID_DEST Can't copyin destination port.
154: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
155: * MACH_SEND_TIMED_OUT Timeout expired without delivery.
156: * MACH_SEND_INTERRUPTED Delivery interrupted.
157: * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
158: * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
159: * MACH_SEND_NOTIFY_IN_PROGRESS
160: * This space has already forced a message to this port.
161: */
162:
163: mach_msg_return_t
164: mach_msg_send(
165: mach_msg_header_t *msg,
166: mach_msg_option_t option,
167: mach_msg_size_t send_size,
168: mach_msg_timeout_t timeout,
169: mach_port_t notify)
170: {
171: ipc_space_t space = current_space();
172: vm_map_t map = current_map();
173: ipc_kmsg_t kmsg;
174: mach_msg_return_t mr;
175:
176: mr = ipc_kmsg_get(msg, option, send_size, MAX_TRAILER_SIZE, &kmsg);
177: if (mr != MACH_MSG_SUCCESS)
178: return mr;
179:
180: if (option & MACH_SEND_CANCEL) {
181: if (notify == MACH_PORT_NULL)
182: mr = MACH_SEND_INVALID_NOTIFY;
183: else
184: mr = ipc_kmsg_copyin(kmsg, space, map, notify);
185: } else
186: mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
187: if (mr != MACH_MSG_SUCCESS) {
188: ikm_free(kmsg);
189: return mr;
190: }
191:
192: mr = ipc_mqueue_send(kmsg, option & MACH_SEND_TIMEOUT,
193: timeout, IMQ_NULL_CONTINUE);
194: if (mr != MACH_MSG_SUCCESS) {
195: mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, IKM_NULL);
196:
197: assert(kmsg->ikm_marequest == IMAR_NULL);
198: (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
199: }
200:
201: return mr;
202: }
203:
204: #define FREE_SCATTER_LIST(l) \
205: MACRO_BEGIN \
206: if((l) != IKM_NULL) { \
207: ikm_free((l)); \
208: } \
209: MACRO_END
210:
211: /*
212: * Routine: mach_msg_receive
213: * Purpose:
214: * Receive a message.
215: * Conditions:
216: * Nothing locked.
217: * Returns:
218: * MACH_MSG_SUCCESS Received a message.
219: * MACH_RCV_INVALID_NAME The name doesn't denote a right,
220: * or the denoted right is not receive or port set.
221: * MACH_RCV_IN_SET Receive right is a member of a set.
222: * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
223: * MACH_RCV_TIMED_OUT Timeout expired without a message.
224: * MACH_RCV_INTERRUPTED Reception interrupted.
225: * MACH_RCV_PORT_DIED Port/set died while receiving.
226: * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
227: * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
228: * MACH_RCV_INVALID_NOTIFY Bad notify port.
229: * MACH_RCV_HEADER_ERROR
230: */
231:
232: mach_msg_return_t
233: mach_msg_receive(
234: mach_msg_header_t *msg,
235: mach_msg_option_t option,
236: mach_msg_size_t rcv_size,
237: mach_port_t rcv_name,
238: mach_msg_timeout_t timeout,
239: mach_port_t notify,
240: mach_msg_size_t list_size)
241: {
242: ipc_thread_t self = current_thread();
243: ipc_space_t space = current_space();
244: vm_map_t map = current_map();
245: ipc_object_t object;
246: ipc_mqueue_t mqueue;
247: ipc_kmsg_t kmsg;
248: mach_port_seqno_t seqno;
249: ipc_kmsg_t list;
250: mach_msg_return_t mr;
251: mach_msg_trailer_t *trailer;
252:
253: /*
254: * If MACH_RCV_OVERWRITE was specified, both receive_msg (msg)
255: * and receive_msg_size (list_size) need to be non NULL.
256: */
257: if (option & MACH_RCV_OVERWRITE) {
258: if (list_size < sizeof(mach_msg_base_t))
259: return MACH_RCV_SCATTER_SMALL;
260: else
261: if (ipc_kmsg_get(msg, MACH_MSG_OPTION_NONE,
262: list_size, 0, &list) != MACH_MSG_SUCCESS)
263: return MACH_RCV_INVALID_DATA;
264:
265: else
266: if ((((mach_msg_base_t *)
267: &kmsg->ikm_header)->body.msgh_descriptor_count *
268: sizeof (mach_msg_descriptor_t)) +
269: sizeof (mach_msg_base_t) > list_size) {
270: FREE_SCATTER_LIST(list);
271: return MACH_RCV_INVALID_TYPE;
272: }
273: }
274: else
275: list = IKM_NULL;
276:
277: mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
278: if (mr != MACH_MSG_SUCCESS) {
279: FREE_SCATTER_LIST(list);
280: return mr;
281: }
282: /* hold ref for object; mqueue is locked */
283:
284: /*
285: * ipc_mqueue_receive may not return, because if we block
286: * then our kernel stack may be discarded. So we save
287: * state here for mach_msg_receive_continue to pick up.
288: */
289:
290: self->ith_msg = msg;
291: self->ith_option = option;
292: self->ith_rcv_size = rcv_size;
293: self->ith_timeout = timeout;
294: self->ith_notify = notify;
295: self->ith_object = object;
296: self->ith_mqueue = mqueue;
297:
298: mr = ipc_mqueue_receive(mqueue,
299: option & (MACH_RCV_TRAILER_MASK|
300: MACH_RCV_TIMEOUT|
301: MACH_RCV_LARGE),
302: rcv_size, timeout,
303: FALSE, mach_msg_receive_continue,
304: &kmsg, &seqno, &list);
305: /* mqueue is unlocked */
306: ipc_object_release(object);
307:
308: if (mr != MACH_MSG_SUCCESS) {
309: if (mr == MACH_RCV_HEADER_ERROR) {
310: mach_msg_return_t pr;
311:
312: pr = mach_msg_receive_error(kmsg, msg,
313: option, seqno, space);
314: if (pr != MACH_MSG_SUCCESS)
315: mr = pr;
316: }
317: else
318: if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) {
319: if (option & MACH_RCV_LARGE) {
320: if (list != IKM_NULL) {
321: mach_msg_return_t pr;
322:
323: list_size = list->ikm_header.msgh_size;
324: list->ikm_header.msgh_size =
325: (mach_msg_size_t)kmsg;
326: pr = ipc_kmsg_put(
327: msg, list, list_size);
328: if (pr != MACH_MSG_SUCCESS)
329: mr = pr;
330: }
331: else
332: if (copyout((char *) &kmsg,
333: (char *) &msg->msgh_size,
334: sizeof(mach_msg_size_t)))
335: mr = MACH_RCV_INVALID_DATA;
336:
337: return mr;
338: }
339: else {
340: mach_msg_return_t pr;
341:
342: pr = mach_msg_receive_error(kmsg, msg,
343: option, seqno, space);
344: if (pr != MACH_MSG_SUCCESS)
345: mr = pr;
346: }
347: }
348:
349: FREE_SCATTER_LIST(list);
350: return mr;
351: }
352:
353: /*
354: * Generate requested trailer.
355: */
356: trailer = (mach_msg_trailer_t *)
357: ((vm_offset_t)&kmsg->ikm_header +
358: kmsg->ikm_header.msgh_size);
359:
360: if (option & MACH_RCV_NO_TRAILER) {
361: trailer->msgh_trailer_size =
362: trailer->msgh_trailer_type = 0;
363: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
364: }
365: else
366: if (kmsg->ikm_delta > 0) {
367: /* MACH_SEND_TRAILER */;
368: }
369: else {
370: int elements = GET_RCV_ELEMENTS(option);
371: #define trailer0 ((mach_msg_format_0_trailer_t *)trailer)
372:
373: if (elements == MACH_RCV_TRAILER_SENDER) {
374: trailer0->msgh_sender = kmsg->ikm_sender;
375: trailer0->msgh_seqno = seqno;
376: }
377: else
378: if (elements == MACH_RCV_TRAILER_SEQNO)
379: trailer0->msgh_seqno = seqno;
380:
381: trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
382: trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
383: #undef trailer0
384: }
385:
386: if (option & MACH_RCV_NOTIFY) {
387: if (notify == MACH_PORT_NULL)
388: mr = MACH_RCV_INVALID_NOTIFY;
389: else
390: mr = ipc_kmsg_copyout(kmsg, space, map, notify, list);
391: } else
392: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, list);
393: if (mr != MACH_MSG_SUCCESS) {
394: mach_msg_return_t pr;
395:
396: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
397: pr = ipc_kmsg_put(msg, kmsg,
398: kmsg->ikm_header.msgh_size +
399: trailer->msgh_trailer_size);
400: if (pr != MACH_MSG_SUCCESS)
401: mr = pr;
402:
403: } else {
404: pr = mach_msg_receive_error(kmsg, msg,
405: option, seqno, space);
406: if (pr != MACH_MSG_SUCCESS)
407: mr = pr;
408: }
409:
410: FREE_SCATTER_LIST(list);
411: return mr;
412: }
413:
414: FREE_SCATTER_LIST(list);
415: return ipc_kmsg_put(msg, kmsg,
416: kmsg->ikm_header.msgh_size +
417: trailer->msgh_trailer_size);
418: }
419:
420: /*
421: * Routine: mach_msg_receive_continue
422: * Purpose:
423: * Continue after blocking for a message.
424: * Conditions:
425: * Nothing locked. We are running on a new kernel stack,
426: * with the receive state saved in the thread. From here
427: * control goes back to user space.
428: */
429:
430: void
431: mach_msg_receive_continue(void)
432: {
433: ipc_thread_t self = current_thread();
434: ipc_space_t space = current_space();
435: vm_map_t map = current_map();
436: mach_msg_header_t *msg = self->ith_msg;
437: mach_msg_option_t option = self->ith_option;
438: mach_msg_trailer_t *trailer;
439: ipc_kmsg_t kmsg;
440: mach_port_seqno_t seqno;
441: ipc_kmsg_t list;
442: mach_msg_return_t mr;
443:
444: mr = ipc_mqueue_receive(self->ith_mqueue,
445: option & (MACH_RCV_TRAILER_MASK|
446: MACH_RCV_TIMEOUT|
447: MACH_RCV_LARGE),
448: self->ith_rcv_size, self->ith_timeout,
449: TRUE, mach_msg_receive_continue,
450: &kmsg, &seqno, &list);
451: /* mqueue is unlocked */
452: ipc_object_release(self->ith_object);
453:
454: if (mr != MACH_MSG_SUCCESS) {
455: if (mr == MACH_RCV_HEADER_ERROR) {
456: mach_msg_return_t pr;
457:
458: pr = mach_msg_receive_error(kmsg, msg,
459: option, seqno, space);
460: if (pr != MACH_MSG_SUCCESS)
461: mr = pr;
462: }
463: else
464: if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) {
465: if (option & MACH_RCV_LARGE) {
466: if (list != IKM_NULL) {
467: mach_msg_return_t pr;
468: mach_msg_size_t list_size;
469:
470: list_size = list->ikm_header.msgh_size;
471: list->ikm_header.msgh_size =
472: (mach_msg_size_t)kmsg;
473: pr = ipc_kmsg_put(
474: msg, list, list_size);
475: if (pr != MACH_MSG_SUCCESS)
476: mr = pr;
477: }
478: else
479: if (copyout((char *) &kmsg,
480: (char *) &msg->msgh_size,
481: sizeof(mach_msg_size_t)))
482: mr = MACH_RCV_INVALID_DATA;
483:
484: thread_syscall_return(mr);
485: /*NOTREACHED*/
486: }
487: else {
488: mach_msg_return_t pr;
489:
490: pr = mach_msg_receive_error(kmsg, msg,
491: option, seqno, space);
492: if (pr != MACH_MSG_SUCCESS)
493: mr = pr;
494: }
495: }
496:
497: FREE_SCATTER_LIST(list);
498: thread_syscall_return(mr);
499: /*NOTREACHED*/
500: }
501:
502: /*
503: * Generate requested trailer.
504: */
505: trailer = (mach_msg_trailer_t *)
506: ((vm_offset_t)&kmsg->ikm_header +
507: kmsg->ikm_header.msgh_size);
508:
509: if (option & MACH_RCV_NO_TRAILER) {
510: trailer->msgh_trailer_size =
511: trailer->msgh_trailer_type = 0;
512: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
513: }
514: else
515: if (kmsg->ikm_delta > 0) {
516: /* MACH_SEND_TRAILER */;
517: }
518: else {
519: int elements = GET_RCV_ELEMENTS(option);
520: #define trailer0 ((mach_msg_format_0_trailer_t *)trailer)
521:
522: if (elements == MACH_RCV_TRAILER_SENDER) {
523: trailer0->msgh_sender = kmsg->ikm_sender;
524: trailer0->msgh_seqno = seqno;
525: }
526: else
527: if (elements == MACH_RCV_TRAILER_SEQNO)
528: trailer0->msgh_seqno = seqno;
529:
530: trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
531: trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
532: #undef trailer0
533: }
534:
535: if (option & MACH_RCV_NOTIFY) {
536: if (self->ith_notify == MACH_PORT_NULL)
537: mr = MACH_RCV_INVALID_NOTIFY;
538: else
539: mr = ipc_kmsg_copyout(
540: kmsg, space, map,
541: self->ith_notify,
542: self->ith_list);
543: } else
544: mr = ipc_kmsg_copyout(
545: kmsg, space, map,
546: MACH_PORT_NULL,
547: self->ith_list);
548: if (mr != MACH_MSG_SUCCESS) {
549: mach_msg_return_t pr;
550:
551: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
552: pr = ipc_kmsg_put(msg, kmsg,
553: kmsg->ikm_header.msgh_size +
554: trailer->msgh_trailer_size);
555: if (pr != MACH_MSG_SUCCESS)
556: mr = pr;
557:
558: } else {
559: pr = mach_msg_receive_error(kmsg, msg,
560: option, seqno, space);
561: if (pr != MACH_MSG_SUCCESS)
562: mr = pr;
563: }
564:
565: FREE_SCATTER_LIST(list);
566: thread_syscall_return(mr);
567: /*NOTREACHED*/
568: }
569:
570: FREE_SCATTER_LIST(list);
571: mr = ipc_kmsg_put(msg, kmsg,
572: kmsg->ikm_header.msgh_size +
573: trailer->msgh_trailer_size);
574: thread_syscall_return(mr);
575: /*NOTREACHED*/
576: }
577:
578: /*
579: * Routine: mach_msg_receive_error [internal]
580: * Purpose:
581: * Builds a minimal header/trailer and copies it to
582: * the user message buffer. Invoked when in the case of a
583: * MACH_RCV_TOO_LARGE or MACH_RCV_HEADER_ERROR error.
584: * Conditions:
585: * Nothing locked.
586: * Returns:
587: * MACH_MSG_SUCCESS minimal headere/trailer copied
588: * MACH_RCV_INVALID_DATA copyout to user buffer failed
589: */
590:
591: mach_msg_return_t
592: mach_msg_receive_error(
593: ipc_kmsg_t kmsg,
594: mach_msg_header_t *msg,
595: mach_msg_option_t option,
596: mach_port_seqno_t seqno,
597: ipc_space_t space)
598: {
599: mach_msg_trailer_t *trailer;
600:
601: /*
602: * Copy out the destination port in the message.
603: * Destroy all other rights and memory in the message.
604: */
605: ipc_kmsg_copyout_dest(kmsg, space);
606:
607: /*
608: * Build a minimal message with a null trailer.
609: */
610: kmsg->ikm_header.msgh_size = sizeof(mach_msg_header_t);
611: trailer = (mach_msg_trailer_t *)
612: ((vm_offset_t)&kmsg->ikm_header +
613: kmsg->ikm_header.msgh_size);
614:
615: if (option & MACH_RCV_NO_TRAILER) {
616: trailer->msgh_trailer_size = trailer->msgh_trailer_type = 0;
617: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
618: }
619: else {
620: trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
621: trailer->msgh_trailer_size = sizeof (mach_msg_trailer_t);
622: }
623:
624: /*
625: * Copy the message to user space
626: */
627: return ipc_kmsg_put(msg, kmsg,
628: kmsg->ikm_header.msgh_size +
629: trailer->msgh_trailer_size);
630: }
631:
632: /*
633: * Routine: mach_msg_overwrite_trap [mach trap]
634: * Purpose:
635: * Possibly send a message; possibly receive a message.
636: * Conditions:
637: * Nothing locked.
638: * Returns:
639: * All of mach_msg_send and mach_msg_receive error codes.
640: */
641: static __inline__
642: mach_msg_return_t
643: _mach_msg_overwrite(
644: mach_msg_header_t *msg,
645: mach_msg_option_t option,
646: mach_msg_size_t send_size,
647: mach_msg_size_t rcv_size,
648: mach_port_t rcv_name,
649: mach_msg_timeout_t timeout,
650: mach_port_t notify,
651: mach_msg_header_t *rcv_msg,
652: mach_msg_size_t list_size)
653: {
654: mach_msg_return_t mr;
655:
656: if (option & MACH_SEND_MSG) {
657: mr = mach_msg_send(msg, option, send_size,
658: timeout, notify);
659: if (mr != MACH_MSG_SUCCESS)
660: return mr;
661: }
662:
663: if (option & MACH_RCV_MSG) {
664: mach_msg_header_t *rcv;
665:
666: /*
667: * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
668: * and receive buffer
669: * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
670: * alternate receive buffer (separate send and receive buffers).
671: */
672: if (option & MACH_RCV_OVERWRITE)
673: rcv = rcv_msg;
674: else if (rcv_msg != MACH_MSG_NULL)
675: rcv = rcv_msg;
676: else
677: rcv = msg;
678: mr = mach_msg_receive(rcv, option, rcv_size, rcv_name,
679: timeout, notify, list_size);
680: if (mr != MACH_MSG_SUCCESS)
681: return mr;
682: }
683:
684: return MACH_MSG_SUCCESS;
685: }
686:
687: mach_msg_return_t
688: mach_msg_overwrite_trap(
689: mach_msg_header_t *msg,
690: mach_msg_option_t option,
691: mach_msg_size_t sndsiz,
692: mach_msg_size_t rcvsiz,
693: mach_port_t rcvnam,
694: mach_msg_timeout_t tout,
695: mach_port_t notify,
696: mach_msg_header_t *rmsg,
697: mach_msg_size_t rmsgsiz)
698: {
699: return
700: (
701: _mach_msg_overwrite(
702: msg, option,
703: sndsiz,
704: rcvsiz, rcvnam,
705: tout, notify,
706: rmsg, rmsgsiz));
707: }
708:
709: mach_msg_return_t
710: mach_msg_trap(
711: mach_msg_header_t *msg,
712: mach_msg_option_t option,
713: mach_msg_size_t sndsiz,
714: mach_msg_size_t rcvsiz,
715: mach_port_t rcvnam,
716: mach_msg_timeout_t tout,
717: mach_port_t notify)
718: {
719: return
720: (
721: _mach_msg_overwrite(
722: msg, option,
723: sndsiz,
724: rcvsiz, rcvnam,
725: tout, notify,
726: MACH_MSG_NULL, (mach_msg_size_t) 0));
727: }
728:
729: mach_msg_return_t
730: mach_msg_simple_trap(
731: mach_msg_header_t *msg,
732: mach_msg_option_t option,
733: mach_msg_size_t sndsiz,
734: mach_msg_size_t rcvsiz,
735: mach_port_t rcvnam)
736: {
737: return
738: (
739: _mach_msg_overwrite(
740: msg, option,
741: sndsiz,
742: rcvsiz, rcvnam,
743: MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
744: MACH_MSG_NULL, (mach_msg_size_t) 0));
745: }
746:
747: /*
748: * Routine: mach_msg_interrupt
749: * Purpose:
750: * Attempts to force a thread waiting at mach_msg_continue or
751: * mach_msg_receive_continue into a clean point. Returns TRUE
752: * if this was possible.
753: * Conditions:
754: * Nothing locked. The thread must NOT be runnable.
755: */
756:
757: boolean_t
758: mach_msg_interrupt(
759: thread_t thread)
760: {
761: ipc_mqueue_t mqueue;
762:
763: assert((thread->swap_func == (void (*)()) mach_msg_continue) ||
764: (thread->swap_func == (void (*)()) mach_msg_receive_continue));
765:
766: mqueue = thread->ith_mqueue;
767: imq_lock(mqueue);
768: if (thread->ith_state != MACH_RCV_IN_PROGRESS) {
769: /*
770: * The thread is no longer waiting for a message.
771: * It may have a message sitting in ith_kmsg.
772: * We can't clean this up.
773: */
774:
775: imq_unlock(mqueue);
776: return FALSE;
777: }
778: ipc_thread_rmqueue(&mqueue->imq_threads, thread);
779: imq_unlock(mqueue);
780:
781: ipc_object_release(thread->ith_object);
782:
783: thread_set_syscall_return(thread, MACH_RCV_INTERRUPTED);
784: thread->swap_func = thread_exception_return;
785: return TRUE;
786: }
787:
788: #if MACH_IPC_COMPAT
789:
790: /*
791: * Routine: msg_return_translate
792: * Purpose:
793: * Translate from new error code to old error code.
794: */
795:
796: msg_return_t
797: msg_return_translate(
798: mach_msg_return_t mr)
799: {
800: switch (mr &~ MACH_MSG_MASK) {
801: case MACH_MSG_SUCCESS:
802: return 0; /* SEND_SUCCESS/RCV_SUCCESS/RPC_SUCCESS */
803:
804: case MACH_SEND_NO_BUFFER:
805: case MACH_SEND_NO_NOTIFY:
806: printf("msg_return_translate: %x -> interrupted\n", mr);
807: return SEND_INTERRUPTED;
808:
809: case MACH_SEND_MSG_TOO_SMALL:
810: return SEND_MSG_TOO_SMALL;
811: case MACH_SEND_INVALID_DATA:
812: case MACH_SEND_INVALID_MEMORY:
813: return SEND_INVALID_MEMORY;
814: case MACH_SEND_TIMED_OUT:
815: return SEND_TIMED_OUT;
816: case MACH_SEND_INTERRUPTED:
817: return SEND_INTERRUPTED;
818: case MACH_SEND_INVALID_DEST:
819: case MACH_SEND_INVALID_REPLY:
820: case MACH_SEND_INVALID_RIGHT:
821: case MACH_SEND_INVALID_TYPE:
822: return SEND_INVALID_PORT;
823: case MACH_SEND_WILL_NOTIFY:
824: return SEND_WILL_NOTIFY;
825: case MACH_SEND_NOTIFY_IN_PROGRESS:
826: return SEND_NOTIFY_IN_PROGRESS;
827:
828: case MACH_RCV_INVALID_NAME:
829: case MACH_RCV_IN_SET:
830: case MACH_RCV_PORT_DIED:
831: return RCV_INVALID_PORT;
832: case MACH_RCV_TOO_LARGE:
833: return RCV_TOO_LARGE;
834: case MACH_RCV_TIMED_OUT:
835: return RCV_TIMED_OUT;
836: case MACH_RCV_INTERRUPTED:
837: return RCV_INTERRUPTED;
838: case MACH_RCV_PORT_CHANGED:
839: return RCV_PORT_CHANGE;
840: case MACH_RCV_INVALID_DATA:
841: return RCV_INVALID_MEMORY;
842:
843: case MACH_SEND_IN_PROGRESS:
844: case MACH_SEND_INVALID_NOTIFY:
845: case MACH_SEND_INVALID_HEADER:
846: case MACH_RCV_IN_PROGRESS:
847: case MACH_RCV_INVALID_NOTIFY:
848: case MACH_RCV_HEADER_ERROR:
849: case MACH_RCV_BODY_ERROR:
850: default:
851: panic("msg_return_translate");
852: }
853: }
854:
855: /*
856: * Routine: msg_send_trap [mach trap]
857: * Purpose:
858: * Send a message.
859: * Conditions:
860: * Nothing locked.
861: * Returns:
862: */
863:
864: msg_return_t
865: msg_send_trap(
866: msg_header_t *msg,
867: msg_option_t option,
868: msg_size_t send_size,
869: msg_timeout_t timeout)
870: {
871: ipc_space_t space = current_space();
872: vm_map_t map = current_map();
873: ipc_kmsg_t kmsg;
874: integer_t send_delta = send_size;
875: mach_msg_return_t mr;
876:
877: send_size = (send_size + 3) & ~3; /* round up */
878: send_delta -= send_size;
879:
880: if (send_size > MSG_SIZE_MAX)
881: return SEND_MSG_TOO_LARGE;
882:
883: mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE,
884: (mach_msg_size_t) send_size, send_delta,
885: &kmsg);
886: if (mr != MACH_MSG_SUCCESS)
887: return msg_return_translate(mr);
888:
889: mr = ipc_kmsg_copyin_compat(kmsg, space, map);
890: if (mr != MACH_MSG_SUCCESS) {
891: ikm_free(kmsg);
892: return msg_return_translate(mr);
893: }
894:
895: if (option & SEND_NOTIFY) {
896: mr = ipc_mqueue_send(kmsg,
897: ((option & SEND_SWITCH) ?
898: MACH_SEND_SWITCH :
899: MACH_MSG_OPTION_NONE) |
900: MACH_SEND_TIMEOUT,
901: ((option & SEND_TIMEOUT) ?
902: (mach_msg_timeout_t) timeout :
903: MACH_MSG_TIMEOUT_NONE),
904: IMQ_NULL_CONTINUE);
905: if (mr == MACH_SEND_TIMED_OUT) {
906: ipc_port_t dest = (ipc_port_t)
907: kmsg->ikm_header.msgh_remote_port;
908:
909: mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
910: &kmsg->ikm_marequest);
911: if (mr == MACH_MSG_SUCCESS) {
912: ipc_mqueue_send_always(kmsg);
913: return SEND_WILL_NOTIFY;
914: }
915: }
916: }
917: else if (option & SEND_SWITCH)
918: mr = ipc_mqueue_send(kmsg,
919: ((option & SEND_TIMEOUT) ?
920: MACH_SEND_TIMEOUT :
921: MACH_MSG_OPTION_NONE) |
922: MACH_SEND_SWITCH,
923: (mach_msg_timeout_t) timeout,
924: msg_send_switch_continue);
925: else
926: mr = ipc_mqueue_send(kmsg,
927: ((option & SEND_TIMEOUT) ?
928: MACH_SEND_TIMEOUT :
929: MACH_MSG_OPTION_NONE),
930: (mach_msg_timeout_t) timeout,
931: IMQ_NULL_CONTINUE);
932:
933: if (mr != MACH_MSG_SUCCESS)
934: ipc_kmsg_destroy(kmsg);
935:
936: return msg_return_translate(mr);
937: }
938:
939: void
940: msg_send_switch_continue(void)
941: {
942: thread_syscall_return(SEND_SUCCESS);
943: /*NOTREACHED*/
944: }
945:
946: mach_msg_return_t
947: msg_receive_error(
948: ipc_kmsg_t kmsg,
949: msg_header_t *msg,
950: ipc_space_t space);
951:
952: /*
953: * Routine: msg_receive_trap [mach trap]
954: * Purpose:
955: * Receive a message.
956: * Conditions:
957: * Nothing locked.
958: * Returns:
959: */
960:
961: msg_return_t
962: msg_receive_trap(
963: msg_header_t *msg,
964: msg_option_t option,
965: msg_size_t rcv_size,
966: port_name_t rcv_name,
967: msg_timeout_t timeout)
968: {
969: ipc_thread_t self;
970: ipc_space_t space = current_space();
971: vm_map_t map = current_map();
972: ipc_object_t object;
973: ipc_mqueue_t mqueue;
974: ipc_kmsg_t kmsg;
975: mach_port_seqno_t seqno;
976: mach_msg_return_t mr;
977:
978: mr = ipc_mqueue_copyin(space, (mach_port_t) rcv_name,
979: &mqueue, &object);
980: if (mr != MACH_MSG_SUCCESS)
981: return msg_return_translate(mr);
982: /* hold ref for object; mqueue is locked */
983:
984: /*
985: * ipc_mqueue_receive may not return, because if we block
986: * then our kernel stack may be discarded. So we save
987: * state here for msg_receive_continue to pick up.
988: */
989:
990: self = current_thread();
991: self->ith_msg = (mach_msg_header_t *) msg;
992: self->ith_option = (mach_msg_option_t) option;
993: self->ith_rcv_size = (mach_msg_size_t) rcv_size;
994: self->ith_timeout = (mach_msg_timeout_t) timeout;
995: self->ith_object = object;
996: self->ith_mqueue = mqueue;
997:
998: mr = ipc_mqueue_receive(mqueue,
999: ((option & RCV_TIMEOUT) ?
1000: MACH_RCV_TIMEOUT :
1001: MACH_MSG_OPTION_NONE) |
1002: MACH_RCV_OLD_FORMAT,
1003: (option & RCV_LARGE) ?
1004: (mach_msg_size_t) rcv_size :
1005: MACH_MSG_SIZE_MAX,
1006: (mach_msg_timeout_t) timeout,
1007: FALSE, msg_receive_continue,
1008: &kmsg, &seqno, 0);
1009: /* mqueue is unlocked */
1010: ipc_object_release(object);
1011:
1012: if (mr != MACH_MSG_SUCCESS) {
1013: if (mr == MACH_RCV_HEADER_ERROR)
1014: mr = msg_receive_error(kmsg, msg, space);
1015: else
1016: if (mr == MACH_RCV_TOO_LARGE) {
1017: msg_size_t real_size =
1018: (msg_size_t) (mach_msg_size_t) kmsg;
1019:
1020: assert(real_size > rcv_size);
1021:
1022: (void) copyout((vm_offset_t) &real_size,
1023: (vm_offset_t) &msg->msg_size,
1024: sizeof(msg_size_t));
1025: }
1026:
1027: return msg_return_translate(mr);
1028: }
1029:
1030: if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
1031: assert(!(option & RCV_LARGE));
1032:
1033: ipc_kmsg_destroy(kmsg);
1034: return (RCV_TOO_LARGE);
1035: }
1036:
1037: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
1038:
1039: mr = ipc_kmsg_copyout_compat(kmsg, space, map);
1040: assert(mr == MACH_MSG_SUCCESS);
1041:
1042: kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
1043: mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
1044: kmsg->ikm_header.msgh_size);
1045: return msg_return_translate(mr);
1046: }
1047:
1048: /*
1049: * Routine: msg_rpc_trap [mach trap]
1050: * Purpose:
1051: * Send and receive a message.
1052: * Conditions:
1053: * Nothing locked.
1054: * Returns:
1055: */
1056:
1057: msg_return_t
1058: msg_rpc_trap(
1059: msg_header_t *msg,
1060: msg_option_t option,
1061: msg_size_t send_size,
1062: msg_size_t rcv_size,
1063: msg_timeout_t send_timeout,
1064: msg_timeout_t rcv_timeout)
1065: {
1066: ipc_thread_t self;
1067: ipc_space_t space = current_space();
1068: vm_map_t map = current_map();
1069: ipc_port_t reply;
1070: ipc_pset_t pset;
1071: ipc_mqueue_t mqueue;
1072: ipc_kmsg_t kmsg;
1073: integer_t send_delta = send_size;
1074: mach_port_seqno_t seqno;
1075: mach_msg_return_t mr;
1076:
1077: /*
1078: * Instead of using msg_send_trap and msg_receive_trap,
1079: * we implement msg_rpc_trap directly. The difference
1080: * is how the reply port is handled. Instead of using
1081: * ipc_mqueue_copyin, we save a reference for the reply
1082: * port carried in the sent message. For example,
1083: * consider a rename kernel call which changes the name
1084: * of the call's own reply port. This is the behaviour
1085: * of the Mach 2.5 msg_rpc_trap.
1086: */
1087:
1088: send_size = (send_size + 3) & ~3; /* round up */
1089: send_delta -= send_size;
1090:
1091: if (send_size > MSG_SIZE_MAX)
1092: return SEND_MSG_TOO_LARGE;
1093:
1094: mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE,
1095: (mach_msg_size_t) send_size, send_delta,
1096: &kmsg);
1097: if (mr != MACH_MSG_SUCCESS)
1098: return msg_return_translate(mr);
1099:
1100: mr = ipc_kmsg_copyin_compat(kmsg, space, map);
1101: if (mr != MACH_MSG_SUCCESS) {
1102: ikm_free(kmsg);
1103: return msg_return_translate(mr);
1104: }
1105:
1106: reply = (ipc_port_t) kmsg->ikm_header.msgh_local_port;
1107: if (IP_VALID(reply)) {
1108: ipc_port_t dest = (ipc_port_t)
1109: kmsg->ikm_header.msgh_remote_port;
1110:
1111: ipc_port_reference(reply);
1112: assert(IP_VALID(dest));
1113:
1114: ip_lock(dest);
1115:
1116: if (dest->ip_receiver == ipc_space_kernel) {
1117: ipc_mqueue_t mqueue;
1118:
1119: assert(ip_active(dest));
1120: ip_unlock(dest);
1121:
1122: kmsg = ipc_kobject_server(kmsg);
1123: if (kmsg == IKM_NULL)
1124: goto receive_reply;
1125:
1126: ip_lock(reply);
1127:
1128: if ((!ip_active(reply)) ||
1129: (reply->ip_receiver != space) ||
1130: (reply->ip_pset != IPS_NULL) ||
1131: (rcv_size < (kmsg->ikm_header.msgh_size +
1132: kmsg->ikm_delta)))
1133: {
1134: ip_unlock(reply);
1135: ipc_mqueue_send_always(kmsg);
1136: goto receive_reply;
1137: }
1138:
1139: mqueue = &reply->ip_messages;
1140: imq_lock(mqueue);
1141:
1142: if ((ipc_thread_queue_first(&mqueue->imq_threads)
1143: != ITH_NULL) ||
1144: (ipc_kmsg_queue_first(&mqueue->imq_messages)
1145: != IKM_NULL))
1146: {
1147: imq_unlock(mqueue);
1148: ip_unlock(reply);
1149: ipc_mqueue_send_always(kmsg);
1150: goto receive_reply;
1151: }
1152:
1153: assert(kmsg->ikm_marequest == IMAR_NULL);
1154: assert(ipc_thread_queue_first(&reply->ip_blocked)
1155: == ITH_NULL);
1156:
1157: reply->ip_seqno++;
1158: imq_unlock(mqueue);
1159:
1160: ip_release(reply);
1161: ip_unlock(reply);
1162:
1163: goto copyout_reply;
1164: }
1165:
1166: ip_unlock(dest);
1167: }
1168:
1169: if (option & SEND_NOTIFY) {
1170: mr = ipc_mqueue_send(kmsg,
1171: ((option & SEND_SWITCH) ?
1172: MACH_SEND_SWITCH :
1173: MACH_MSG_OPTION_NONE) |
1174: MACH_SEND_TIMEOUT,
1175: ((option & SEND_TIMEOUT) ?
1176: (mach_msg_timeout_t) send_timeout :
1177: MACH_MSG_TIMEOUT_NONE),
1178: IMQ_NULL_CONTINUE);
1179: if (mr == MACH_SEND_TIMED_OUT) {
1180: ipc_port_t dest = (ipc_port_t)
1181: kmsg->ikm_header.msgh_remote_port;
1182:
1183: mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
1184: &kmsg->ikm_marequest);
1185: if (mr == MACH_MSG_SUCCESS) {
1186: ipc_mqueue_send_always(kmsg);
1187: if (IP_VALID(reply))
1188: ipc_port_release(reply);
1189: return SEND_WILL_NOTIFY;
1190: }
1191: }
1192: }
1193: else if (option & SEND_SWITCH)
1194: mr = ipc_mqueue_send(kmsg,
1195: ((option & SEND_TIMEOUT) ?
1196: MACH_SEND_TIMEOUT :
1197: MACH_MSG_OPTION_NONE) |
1198: MACH_SEND_SWITCH,
1199: (mach_msg_timeout_t) send_timeout,
1200: IMQ_NULL_CONTINUE);
1201: else
1202: mr = ipc_mqueue_send(kmsg,
1203: ((option & SEND_TIMEOUT) ?
1204: MACH_SEND_TIMEOUT :
1205: MACH_MSG_OPTION_NONE),
1206: (mach_msg_timeout_t) send_timeout,
1207: IMQ_NULL_CONTINUE);
1208:
1209: if (mr != MACH_MSG_SUCCESS) {
1210: ipc_kmsg_destroy(kmsg);
1211: if (IP_VALID(reply))
1212: ipc_port_release(reply);
1213: return msg_return_translate(mr);
1214: }
1215:
1216: receive_reply:
1217: if (!IP_VALID(reply))
1218: return RCV_INVALID_PORT;
1219:
1220: ip_lock(reply);
1221: if (reply->ip_receiver != space) {
1222: ip_release(reply);
1223: ip_check_unlock(reply);
1224: return RCV_INVALID_PORT;
1225: }
1226:
1227: assert(ip_active(reply));
1228: pset = reply->ip_pset;
1229:
1230: if (pset != IPS_NULL) {
1231: ips_lock(pset);
1232: if (ips_active(pset)) {
1233: ips_unlock(pset);
1234: ip_release(reply);
1235: ip_unlock(reply);
1236: return RCV_INVALID_PORT;
1237: }
1238:
1239: ipc_pset_remove(pset, reply);
1240: ips_check_unlock(pset);
1241: assert(reply->ip_pset == IPS_NULL);
1242: }
1243:
1244: mqueue = &reply->ip_messages;
1245: imq_lock(mqueue);
1246: ip_unlock(reply);
1247:
1248: /*
1249: * ipc_mqueue_receive may not return, because if we block
1250: * then our kernel stack may be discarded. So we save
1251: * state here for msg_receive_continue to pick up.
1252: */
1253:
1254: self = current_thread();
1255: self->ith_msg = (mach_msg_header_t *) msg;
1256: self->ith_option = (mach_msg_option_t) option;
1257: self->ith_rcv_size = (mach_msg_size_t) rcv_size;
1258: self->ith_timeout = (mach_msg_timeout_t) rcv_timeout;
1259: self->ith_object = (ipc_object_t) reply;
1260: self->ith_mqueue = mqueue;
1261:
1262: mr = ipc_mqueue_receive(mqueue,
1263: ((option & RCV_TIMEOUT) ?
1264: MACH_RCV_TIMEOUT :
1265: MACH_MSG_OPTION_NONE) |
1266: MACH_RCV_OLD_FORMAT,
1267: (option & RCV_LARGE) ?
1268: (mach_msg_size_t) rcv_size :
1269: MACH_MSG_SIZE_MAX,
1270: (mach_msg_timeout_t) rcv_timeout,
1271: FALSE, msg_receive_continue,
1272: &kmsg, &seqno, 0);
1273: /* mqueue is unlocked */
1274: ipc_port_release(reply);
1275:
1276: if (mr != MACH_MSG_SUCCESS) {
1277: if (mr == MACH_RCV_HEADER_ERROR)
1278: mr = msg_receive_error(kmsg, msg, space);
1279: else
1280: if (mr == MACH_RCV_TOO_LARGE) {
1281: msg_size_t real_size =
1282: (msg_size_t) (mach_msg_size_t) kmsg;
1283:
1284: assert(real_size > rcv_size);
1285:
1286: (void) copyout((vm_offset_t) &real_size,
1287: (vm_offset_t) &msg->msg_size,
1288: sizeof(msg_size_t));
1289: }
1290:
1291: return msg_return_translate(mr);
1292: }
1293:
1294: if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
1295: assert(!(option & RCV_LARGE));
1296:
1297: ipc_kmsg_destroy(kmsg);
1298: return (RCV_TOO_LARGE);
1299: }
1300:
1301: copyout_reply:
1302: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
1303:
1304: mr = ipc_kmsg_copyout_compat(kmsg, space, map);
1305: assert(mr == MACH_MSG_SUCCESS);
1306:
1307: kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
1308: mr = ipc_kmsg_put((mach_msg_header_t *) msg,
1309: kmsg, kmsg->ikm_header.msgh_size);
1310: return msg_return_translate(mr);
1311: }
1312:
1313: /*
1314: * Routine: msg_receive_continue
1315: * Purpose:
1316: * Continue after blocking for a message.
1317: * Conditions:
1318: * Nothing locked. We are running on a new kernel stack,
1319: * with the receive state saved in the thread. From here
1320: * control goes back to user space.
1321: */
1322:
1323: void
1324: msg_receive_continue(void)
1325: {
1326: ipc_thread_t self = current_thread();
1327: msg_header_t *msg = (msg_header_t *) self->ith_msg;
1328: msg_option_t option = (msg_option_t) self->ith_option;
1329: ipc_kmsg_t kmsg;
1330: mach_port_seqno_t seqno;
1331: mach_msg_return_t mr;
1332:
1333: mr = ipc_mqueue_receive(self->ith_mqueue,
1334: ((option & RCV_TIMEOUT) ?
1335: MACH_RCV_TIMEOUT :
1336: MACH_MSG_OPTION_NONE) |
1337: MACH_RCV_OLD_FORMAT,
1338: (option & RCV_LARGE) ?
1339: self->ith_rcv_size :
1340: MACH_MSG_SIZE_MAX,
1341: self->ith_timeout,
1342: TRUE, msg_receive_continue,
1343: &kmsg, &seqno, 0);
1344: /* mqueue is unlocked */
1345: ipc_object_release(self->ith_object);
1346:
1347: if (mr != MACH_MSG_SUCCESS) {
1348: if (mr == MACH_RCV_HEADER_ERROR)
1349: mr = msg_receive_error(kmsg, msg, current_space());
1350: else
1351: if (mr == MACH_RCV_TOO_LARGE) {
1352: msg_size_t real_size =
1353: (msg_size_t) (mach_msg_size_t) kmsg;
1354:
1355: assert(real_size > rcv_size);
1356:
1357: (void) copyout((vm_offset_t) &real_size,
1358: (vm_offset_t) &msg->msg_size,
1359: sizeof(msg_size_t));
1360: }
1361:
1362: thread_syscall_return(msg_return_translate(mr));
1363: /*NOTREACHED*/
1364: }
1365:
1366: if (kmsg->ikm_header.msgh_size > self->ith_rcv_size) {
1367: assert(!(option & RCV_LARGE));
1368:
1369: ipc_kmsg_destroy(kmsg);
1370: thread_syscall_return(RCV_TOO_LARGE);
1371: /*NOTREACHED*/
1372: }
1373:
1374: assert(kmsg->ikm_header.msgh_size <= self->ith_rcv_size);
1375:
1376: mr = ipc_kmsg_copyout_compat(kmsg, current_space(), current_map());
1377: assert(mr == MACH_MSG_SUCCESS);
1378:
1379: kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
1380: mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
1381: kmsg->ikm_header.msgh_size);
1382: thread_syscall_return(msg_return_translate(mr));
1383: /*NOTREACHED*/
1384: }
1385:
1386: mach_msg_return_t
1387: msg_receive_error(
1388: ipc_kmsg_t kmsg,
1389: msg_header_t *msg,
1390: ipc_space_t space)
1391: {
1392: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
1393: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
1394: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
1395: mach_msg_return_t mr;
1396:
1397: if (IO_VALID(reply))
1398: ipc_object_destroy(reply, reply_type);
1399: (ipc_object_t)kmsg->ikm_header.msgh_local_port = IO_NULL;
1400:
1401: assert(!(mbits & MACH_MSGH_BITS_OLD_FORMAT));
1402: if (mbits & MACH_MSGH_BITS_COMPLEX) {
1403: mach_msg_body_t *body;
1404:
1405: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
1406: ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count);
1407: }
1408:
1409: kmsg->ikm_header.msgh_size = sizeof (mach_msg_header_t);
1410: kmsg->ikm_header.msgh_reserved = 0; /* copied to msg_type */
1411: mr = ipc_kmsg_copyout_compat(kmsg, space, VM_MAP_NULL);
1412: assert(mr == MACH_MSG_SUCCESS);
1413:
1414: return ipc_kmsg_put((mach_msg_header_t *)msg, kmsg,
1415: kmsg->ikm_header.msgh_size);
1416: }
1417:
1418: #endif MACH_IPC_COMPAT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.