|
|
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: */
31: /*
32: * File: ipc/mach_msg.c
33: * Author: Rich Draves
34: * Date: 1989
35: *
36: * Exported message traps. See mach/message.h.
37: */
38:
39: #include <mach_ipc_compat.h>
40: #include <norma_ipc.h>
41:
42: #include <mach/kern_return.h>
43: #include <mach/port.h>
44: #include <mach/message.h>
45: #include <kern/assert.h>
46: #include <kern/counters.h>
47: #include <kern/lock.h>
48: #include <kern/sched_prim.h>
49: #include <kern/ipc_sched.h>
50: #include <vm/vm_map.h>
51: #include <ipc/ipc_kmsg.h>
52: #include <ipc/ipc_marequest.h>
53: #include <ipc/ipc_mqueue.h>
54: #include <ipc/ipc_object.h>
55: #include <ipc/ipc_notify.h>
56: #include <ipc/ipc_port.h>
57: #include <ipc/ipc_pset.h>
58: #include <ipc/ipc_space.h>
59: #include <ipc/ipc_thread.h>
60: #include <ipc/ipc_entry.h>
61: #include <ipc/mach_msg.h>
62:
63:
64:
65: extern void exception_raise_continue();
66: extern void exception_raise_continue_fast();
67: #ifndef CONTINUATIONS
68: #define mach_msg_receive_continue 0
69: #define msg_receive_continue 0
70: #endif
71:
72: /*
73: * Routine: mach_msg_send
74: * Purpose:
75: * Send a message.
76: * Conditions:
77: * Nothing locked.
78: * Returns:
79: * MACH_MSG_SUCCESS Sent the message.
80: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
81: * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
82: * MACH_SEND_INVALID_DATA Couldn't copy message data.
83: * MACH_SEND_INVALID_HEADER
84: * Illegal value in the message header bits.
85: * MACH_SEND_INVALID_DEST The space is dead.
86: * MACH_SEND_INVALID_NOTIFY Bad notify port.
87: * MACH_SEND_INVALID_DEST Can't copyin destination port.
88: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
89: * MACH_SEND_TIMED_OUT Timeout expired without delivery.
90: * MACH_SEND_INTERRUPTED Delivery interrupted.
91: * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
92: * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
93: * MACH_SEND_NOTIFY_IN_PROGRESS
94: * This space has already forced a message to this port.
95: */
96:
97: mach_msg_return_t
98: mach_msg_send(msg, option, send_size, time_out, notify)
99: mach_msg_header_t *msg;
100: mach_msg_option_t option;
101: mach_msg_size_t send_size;
102: mach_msg_timeout_t time_out;
103: mach_port_t notify;
104: {
105: ipc_space_t space = current_space();
106: vm_map_t map = current_map();
107: ipc_kmsg_t kmsg;
108: mach_msg_return_t mr;
109:
110: mr = ipc_kmsg_get(msg, send_size, &kmsg);
111: if (mr != MACH_MSG_SUCCESS)
112: return mr;
113:
114: if (option & MACH_SEND_CANCEL) {
115: if (notify == MACH_PORT_NULL)
116: mr = MACH_SEND_INVALID_NOTIFY;
117: else
118: mr = ipc_kmsg_copyin(kmsg, space, map, notify);
119: } else
120: mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
121: if (mr != MACH_MSG_SUCCESS) {
122: ikm_free(kmsg);
123: return mr;
124: }
125:
126: if (option & MACH_SEND_NOTIFY) {
127: mr = ipc_mqueue_send(kmsg, MACH_SEND_TIMEOUT,
128: ((option & MACH_SEND_TIMEOUT) ?
129: time_out : MACH_MSG_TIMEOUT_NONE));
130: if (mr == MACH_SEND_TIMED_OUT) {
131: ipc_port_t dest = (ipc_port_t)
132: kmsg->ikm_header.msgh_remote_port;
133:
134: if (notify == MACH_PORT_NULL)
135: mr = MACH_SEND_INVALID_NOTIFY;
136: else
137: mr = ipc_marequest_create(space, dest,
138: notify, &kmsg->ikm_marequest);
139: if (mr == MACH_MSG_SUCCESS) {
140: ipc_mqueue_send_always(kmsg);
141: return MACH_SEND_WILL_NOTIFY;
142: }
143: }
144: } else
145: mr = ipc_mqueue_send(kmsg, option & MACH_SEND_TIMEOUT,
146: time_out);
147:
148: if (mr != MACH_MSG_SUCCESS) {
149: mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map);
150:
151: assert(kmsg->ikm_marequest == IMAR_NULL);
152: (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
153: }
154:
155: return mr;
156: }
157:
158: /*
159: * Routine: mach_msg_receive
160: * Purpose:
161: * Receive a message.
162: * Conditions:
163: * Nothing locked.
164: * Returns:
165: * MACH_MSG_SUCCESS Received a message.
166: * MACH_RCV_INVALID_NAME The name doesn't denote a right,
167: * or the denoted right is not receive or port set.
168: * MACH_RCV_IN_SET Receive right is a member of a set.
169: * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
170: * MACH_RCV_TIMED_OUT Timeout expired without a message.
171: * MACH_RCV_INTERRUPTED Reception interrupted.
172: * MACH_RCV_PORT_DIED Port/set died while receiving.
173: * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
174: * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
175: * MACH_RCV_INVALID_NOTIFY Bad notify port.
176: * MACH_RCV_HEADER_ERROR
177: */
178:
179: mach_msg_return_t
180: mach_msg_receive(msg, option, rcv_size, rcv_name, time_out, notify)
181: mach_msg_header_t *msg;
182: mach_msg_option_t option;
183: mach_msg_size_t rcv_size;
184: mach_port_t rcv_name;
185: mach_msg_timeout_t time_out;
186: mach_port_t notify;
187: {
188: ipc_thread_t self = current_thread();
189: ipc_space_t space = current_space();
190: vm_map_t map = current_map();
191: ipc_object_t object;
192: ipc_mqueue_t mqueue;
193: ipc_kmsg_t kmsg;
194: mach_port_seqno_t seqno;
195: mach_msg_return_t mr;
196:
197: mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
198: if (mr != MACH_MSG_SUCCESS)
199: return mr;
200: /* hold ref for object; mqueue is locked */
201:
202: #ifdef CONTINUATIONS
203: /*
204: * ipc_mqueue_receive may not return, because if we block
205: * then our kernel stack may be discarded. So we save
206: * state here for mach_msg_receive_continue to pick up.
207: */
208:
209: self->ith_msg = msg;
210: self->ith_option = option;
211: self->ith_rcv_size = rcv_size;
212: self->ith_timeout = time_out;
213: self->ith_notify = notify;
214: self->ith_object = object;
215: self->ith_mqueue = mqueue;
216: #endif
217:
218: if (option & MACH_RCV_LARGE) {
219: mr = ipc_mqueue_receive(mqueue, option & MACH_RCV_TIMEOUT,
220: rcv_size, time_out,
221: FALSE, mach_msg_receive_continue,
222: &kmsg, &seqno);
223: /* mqueue is unlocked */
224: ipc_object_release(object);
225: if (mr != MACH_MSG_SUCCESS) {
226: if (mr == MACH_RCV_TOO_LARGE) {
227: mach_msg_size_t real_size =
228: (mach_msg_size_t) (natural_t) kmsg;
229:
230: assert(real_size > rcv_size);
231:
232: (void) copyout((vm_offset_t) &real_size,
233: (vm_offset_t) &msg->msgh_size,
234: sizeof(mach_msg_size_t));
235: }
236:
237: return mr;
238: }
239:
240: kmsg->ikm_header.msgh_seqno = seqno;
241: assert(kmsg->ikm_header.msgh_size <= rcv_size);
242: } else {
243: mr = ipc_mqueue_receive(mqueue, option & MACH_RCV_TIMEOUT,
244: MACH_MSG_SIZE_MAX, time_out,
245: FALSE, mach_msg_receive_continue,
246: &kmsg, &seqno);
247: /* mqueue is unlocked */
248: ipc_object_release(object);
249: if (mr != MACH_MSG_SUCCESS)
250: return mr;
251:
252: kmsg->ikm_header.msgh_seqno = seqno;
253: if (kmsg->ikm_header.msgh_size > rcv_size) {
254: ipc_kmsg_copyout_dest(kmsg, space);
255: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
256: return MACH_RCV_TOO_LARGE;
257: }
258: }
259:
260: if (option & MACH_RCV_NOTIFY) {
261: if (notify == MACH_PORT_NULL)
262: mr = MACH_RCV_INVALID_NOTIFY;
263: else
264: mr = ipc_kmsg_copyout(kmsg, space, map, notify);
265: } else
266: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
267: if (mr != MACH_MSG_SUCCESS) {
268: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
269: (void) ipc_kmsg_put(msg, kmsg,
270: kmsg->ikm_header.msgh_size);
271: } else {
272: ipc_kmsg_copyout_dest(kmsg, space);
273: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
274: }
275:
276: return mr;
277: }
278:
279: return ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
280: }
281:
282: #ifdef CONTINUATIONS
283: /*
284: * Routine: mach_msg_receive_continue
285: * Purpose:
286: * Continue after blocking for a message.
287: * Conditions:
288: * Nothing locked. We are running on a new kernel stack,
289: * with the receive state saved in the thread. From here
290: * control goes back to user space.
291: */
292:
293: void
294: mach_msg_receive_continue()
295: {
296: ipc_thread_t self = current_thread();
297: ipc_space_t space = current_space();
298: vm_map_t map = current_map();
299: mach_msg_header_t *msg = self->ith_msg;
300: mach_msg_option_t option = self->ith_option;
301: mach_msg_size_t rcv_size = self->ith_rcv_size;
302: mach_msg_timeout_t time_out = self->ith_timeout;
303: mach_port_t notify = self->ith_notify;
304: ipc_object_t object = self->ith_object;
305: ipc_mqueue_t mqueue = self->ith_mqueue;
306: ipc_kmsg_t kmsg;
307: mach_port_seqno_t seqno;
308: mach_msg_return_t mr;
309:
310: if (option & MACH_RCV_LARGE) {
311: mr = ipc_mqueue_receive(mqueue, option & MACH_RCV_TIMEOUT,
312: rcv_size, time_out,
313: TRUE, mach_msg_receive_continue,
314: &kmsg, &seqno);
315: /* mqueue is unlocked */
316: ipc_object_release(object);
317: if (mr != MACH_MSG_SUCCESS) {
318: if (mr == MACH_RCV_TOO_LARGE) {
319: mach_msg_size_t real_size =
320: (mach_msg_size_t) (natural_t) kmsg;
321:
322: assert(real_size > rcv_size);
323:
324: (void) copyout((vm_offset_t) &real_size,
325: (vm_offset_t) &msg->msgh_size,
326: sizeof(mach_msg_size_t));
327: }
328:
329: thread_syscall_return(mr);
330: /*NOTREACHED*/
331: }
332:
333: kmsg->ikm_header.msgh_seqno = seqno;
334: assert(kmsg->ikm_header.msgh_size <= rcv_size);
335: } else {
336: mr = ipc_mqueue_receive(mqueue, option & MACH_RCV_TIMEOUT,
337: MACH_MSG_SIZE_MAX, time_out,
338: TRUE, mach_msg_receive_continue,
339: &kmsg, &seqno);
340: /* mqueue is unlocked */
341: ipc_object_release(object);
342: if (mr != MACH_MSG_SUCCESS) {
343: thread_syscall_return(mr);
344: /*NOTREACHED*/
345: }
346:
347: kmsg->ikm_header.msgh_seqno = seqno;
348: if (kmsg->ikm_header.msgh_size > rcv_size) {
349: ipc_kmsg_copyout_dest(kmsg, space);
350: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
351: thread_syscall_return(MACH_RCV_TOO_LARGE);
352: /*NOTREACHED*/
353: }
354: }
355:
356: if (option & MACH_RCV_NOTIFY) {
357: if (notify == MACH_PORT_NULL)
358: mr = MACH_RCV_INVALID_NOTIFY;
359: else
360: mr = ipc_kmsg_copyout(kmsg, space, map, notify);
361: } else
362: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
363: if (mr != MACH_MSG_SUCCESS) {
364: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
365: (void) ipc_kmsg_put(msg, kmsg,
366: kmsg->ikm_header.msgh_size);
367: } else {
368: ipc_kmsg_copyout_dest(kmsg, space);
369: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
370: }
371:
372: thread_syscall_return(mr);
373: /*NOTREACHED*/
374: }
375:
376: mr = ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
377: thread_syscall_return(mr);
378: /*NOTREACHED*/
379: }
380: #endif /* CONTINUATIONS */
381:
382: /*
383: * Routine: mach_msg_trap [mach trap]
384: * Purpose:
385: * Possibly send a message; possibly receive a message.
386: * Conditions:
387: * Nothing locked.
388: * Returns:
389: * All of mach_msg_send and mach_msg_receive error codes.
390: */
391:
392: mach_msg_return_t
393: mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify)
394: mach_msg_header_t *msg;
395: mach_msg_option_t option;
396: mach_msg_size_t send_size;
397: mach_msg_size_t rcv_size;
398: mach_port_t rcv_name;
399: mach_msg_timeout_t time_out;
400: mach_port_t notify;
401: {
402: mach_msg_return_t mr;
403:
404: #ifdef CONTINUATIONS
405: /* first check for common cases */
406:
407: if (option == (MACH_SEND_MSG|MACH_RCV_MSG)) {
408: register ipc_thread_t self = current_thread();
409: ipc_space_t space = self->task->itk_space;
410: register ipc_kmsg_t kmsg;
411: register ipc_port_t dest_port;
412: ipc_object_t rcv_object;
413: register ipc_mqueue_t rcv_mqueue;
414: mach_msg_size_t reply_size;
415:
416: /*
417: * This case is divided into ten sections, each
418: * with a label. There are five optimized
419: * sections and six unoptimized sections, which
420: * do the same thing but handle all possible
421: * cases and are slower.
422: *
423: * The five sections for an RPC are
424: * 1) Get request message into a buffer.
425: * (fast_get or slow_get)
426: * 2) Copyin request message and rcv_name.
427: * (fast_copyin or slow_copyin)
428: * 3) Enqueue request and dequeue reply.
429: * (fast_send_receive or
430: * slow_send and slow_receive)
431: * 4) Copyout reply message.
432: * (fast_copyout or slow_copyout)
433: * 5) Put reply message to user's buffer.
434: * (fast_put or slow_put)
435: *
436: * Keep the locking hierarchy firmly in mind.
437: * (First spaces, then ports, then port sets,
438: * then message queues.) Only a non-blocking
439: * attempt can be made to acquire locks out of
440: * order, or acquire two locks on the same level.
441: * Acquiring two locks on the same level will
442: * fail if the objects are really the same,
443: * unless simple locking is disabled. This is OK,
444: * because then the extra unlock does nothing.
445: *
446: * There are two major reasons these RPCs can't use
447: * ipc_thread_switch, and use slow_send/slow_receive:
448: * 1) Kernel RPCs.
449: * 2) Servers fall behind clients, so
450: * client doesn't find a blocked server thread and
451: * server finds waiting messages and can't block.
452: */
453:
454: /*
455: fast_get:
456: */
457: /*
458: * optimized ipc_kmsg_get
459: *
460: * No locks, references, or messages held.
461: * We must clear ikm_cache before copyinmsg.
462: */
463:
464: if ((send_size > IKM_SAVED_MSG_SIZE) ||
465: (send_size < sizeof(mach_msg_header_t)) ||
466: (send_size & 3) ||
467: ((kmsg = ikm_cache()) == IKM_NULL))
468: goto slow_get;
469:
470: ikm_cache() = IKM_NULL;
471: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
472:
473: if (copyinmsg((vm_offset_t) msg, (vm_offset_t) &kmsg->ikm_header,
474: send_size)) {
475: ikm_free(kmsg);
476: goto slow_get;
477: }
478:
479: kmsg->ikm_header.msgh_size = send_size;
480:
481: fast_copyin:
482: /*
483: * optimized ipc_kmsg_copyin/ipc_mqueue_copyin
484: *
485: * We have the request message data in kmsg.
486: * Must still do copyin, send, receive, etc.
487: *
488: * If the message isn't simple, we can't combine
489: * ipc_kmsg_copyin_header and ipc_mqueue_copyin,
490: * because copyin of the message body might
491: * affect rcv_name.
492: */
493:
494: switch (kmsg->ikm_header.msgh_bits) {
495: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
496: MACH_MSG_TYPE_MAKE_SEND_ONCE): {
497: register ipc_entry_t table;
498: register ipc_entry_num_t size;
499: register ipc_port_t reply_port;
500:
501: /* sending a request message */
502:
503: {
504: register mach_port_index_t index;
505: register mach_port_gen_t gen;
506:
507: {
508: register mach_port_t reply_name =
509: kmsg->ikm_header.msgh_local_port;
510:
511: if (reply_name != rcv_name)
512: goto slow_copyin;
513:
514: /* optimized ipc_entry_lookup of reply_name */
515:
516: index = MACH_PORT_INDEX(reply_name);
517: gen = MACH_PORT_GEN(reply_name);
518: }
519:
520: is_read_lock(space);
521: assert(space->is_active);
522:
523: size = space->is_table_size;
524: table = space->is_table;
525:
526: if (index >= size)
527: goto abort_request_copyin;
528:
529: {
530: register ipc_entry_t entry;
531: register ipc_entry_bits_t bits;
532:
533: entry = &table[index];
534: bits = entry->ie_bits;
535:
536: /* check generation number and type bit */
537:
538: if ((bits & (IE_BITS_GEN_MASK|
539: MACH_PORT_TYPE_RECEIVE)) !=
540: (gen | MACH_PORT_TYPE_RECEIVE))
541: goto abort_request_copyin;
542:
543: reply_port = (ipc_port_t) entry->ie_object;
544: assert(reply_port != IP_NULL);
545: }
546: }
547:
548: /* optimized ipc_entry_lookup of dest_name */
549:
550: {
551: register mach_port_index_t index;
552: register mach_port_gen_t gen;
553:
554: {
555: register mach_port_t dest_name =
556: kmsg->ikm_header.msgh_remote_port;
557:
558: index = MACH_PORT_INDEX(dest_name);
559: gen = MACH_PORT_GEN(dest_name);
560: }
561:
562: if (index >= size)
563: goto abort_request_copyin;
564:
565: {
566: register ipc_entry_t entry;
567: register ipc_entry_bits_t bits;
568:
569: entry = &table[index];
570: bits = entry->ie_bits;
571:
572: /* check generation number and type bit */
573:
574: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
575: (gen | MACH_PORT_TYPE_SEND))
576: goto abort_request_copyin;
577:
578: assert(IE_BITS_UREFS(bits) > 0);
579:
580: dest_port = (ipc_port_t) entry->ie_object;
581: assert(dest_port != IP_NULL);
582: }
583: }
584:
585: /*
586: * To do an atomic copyin, need simultaneous
587: * locks on both ports and the space. If
588: * dest_port == reply_port, and simple locking is
589: * enabled, then we will abort. Otherwise it's
590: * OK to unlock twice.
591: */
592:
593: ip_lock(dest_port);
594: if (!ip_active(dest_port) ||
595: !ip_lock_try(reply_port)) {
596: ip_unlock(dest_port);
597: goto abort_request_copyin;
598: }
599: is_read_unlock(space);
600:
601: assert(dest_port->ip_srights > 0);
602: dest_port->ip_srights++;
603: ip_reference(dest_port);
604:
605: assert(ip_active(reply_port));
606: assert(reply_port->ip_receiver_name ==
607: kmsg->ikm_header.msgh_local_port);
608: assert(reply_port->ip_receiver == space);
609:
610: reply_port->ip_sorights++;
611: ip_reference(reply_port);
612:
613: kmsg->ikm_header.msgh_bits =
614: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
615: MACH_MSG_TYPE_PORT_SEND_ONCE);
616: kmsg->ikm_header.msgh_remote_port =
617: (mach_port_t) dest_port;
618: kmsg->ikm_header.msgh_local_port =
619: (mach_port_t) reply_port;
620:
621: /* make sure we can queue to the destination */
622:
623: if (dest_port->ip_receiver == ipc_space_kernel) {
624: /*
625: * The kernel server has a reference to
626: * the reply port, which it hands back
627: * to us in the reply message. We do
628: * not need to keep another reference to
629: * it.
630: */
631: ip_unlock(reply_port);
632:
633: assert(ip_active(dest_port));
634: ip_unlock(dest_port);
635: goto kernel_send;
636: }
637:
638: #if NORMA_IPC
639: if (IP_NORMA_IS_PROXY(dest_port)) {
640: ip_unlock(dest_port);
641: ip_unlock(reply_port);
642: goto norma_send;
643: }
644: #endif /* NORMA_IPC */
645:
646: if (dest_port->ip_msgcount >= dest_port->ip_qlimit)
647: goto abort_request_send_receive;
648:
649: /* optimized ipc_mqueue_copyin */
650:
651: if (reply_port->ip_pset != IPS_NULL)
652: goto abort_request_send_receive;
653:
654: rcv_object = (ipc_object_t) reply_port;
655: io_reference(rcv_object);
656: rcv_mqueue = &reply_port->ip_messages;
657: imq_lock(rcv_mqueue);
658: io_unlock(rcv_object);
659: goto fast_send_receive;
660:
661: abort_request_copyin:
662: is_read_unlock(space);
663: goto slow_copyin;
664:
665: abort_request_send_receive:
666: ip_unlock(dest_port);
667: ip_unlock(reply_port);
668: goto slow_send;
669: }
670:
671: case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
672: register ipc_entry_num_t size;
673: register ipc_entry_t table;
674:
675: /* sending a reply message */
676:
677: {
678: register mach_port_t reply_name =
679: kmsg->ikm_header.msgh_local_port;
680:
681: if (reply_name != MACH_PORT_NULL)
682: goto slow_copyin;
683: }
684:
685: is_write_lock(space);
686: assert(space->is_active);
687:
688: /* optimized ipc_entry_lookup */
689:
690: size = space->is_table_size;
691: table = space->is_table;
692:
693: {
694: register ipc_entry_t entry;
695: register mach_port_gen_t gen;
696: register mach_port_index_t index;
697:
698: {
699: register mach_port_t dest_name =
700: kmsg->ikm_header.msgh_remote_port;
701:
702: index = MACH_PORT_INDEX(dest_name);
703: gen = MACH_PORT_GEN(dest_name);
704: }
705:
706: if (index >= size)
707: goto abort_reply_dest_copyin;
708:
709: entry = &table[index];
710:
711: /* check generation, collision bit, and type bit */
712:
713: if ((entry->ie_bits & (IE_BITS_GEN_MASK|
714: IE_BITS_COLLISION|
715: MACH_PORT_TYPE_SEND_ONCE)) !=
716: (gen | MACH_PORT_TYPE_SEND_ONCE))
717: goto abort_reply_dest_copyin;
718:
719: /* optimized ipc_right_copyin */
720:
721: assert(IE_BITS_TYPE(entry->ie_bits) ==
722: MACH_PORT_TYPE_SEND_ONCE);
723: assert(IE_BITS_UREFS(entry->ie_bits) == 1);
724: assert((entry->ie_bits & IE_BITS_MAREQUEST) == 0);
725:
726: if (entry->ie_request != 0)
727: goto abort_reply_dest_copyin;
728:
729: dest_port = (ipc_port_t) entry->ie_object;
730: assert(dest_port != IP_NULL);
731:
732: ip_lock(dest_port);
733: if (!ip_active(dest_port)) {
734: ip_unlock(dest_port);
735: goto abort_reply_dest_copyin;
736: }
737:
738: assert(dest_port->ip_sorights > 0);
739:
740: /* optimized ipc_entry_dealloc */
741:
742: entry->ie_next = table->ie_next;
743: table->ie_next = index;
744: entry->ie_bits = gen;
745: entry->ie_object = IO_NULL;
746: }
747:
748: kmsg->ikm_header.msgh_bits =
749: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
750: 0);
751: kmsg->ikm_header.msgh_remote_port =
752: (mach_port_t) dest_port;
753:
754: /* make sure we can queue to the destination */
755:
756: assert(dest_port->ip_receiver != ipc_space_kernel);
757: #if NORMA_IPC
758: if (IP_NORMA_IS_PROXY(dest_port)) {
759: is_write_unlock(space);
760: ip_unlock(dest_port);
761: goto norma_send;
762: }
763: #endif /* NORMA_IPC */
764:
765: /* optimized ipc_entry_lookup/ipc_mqueue_copyin */
766:
767: {
768: register ipc_entry_t entry;
769: register ipc_entry_bits_t bits;
770:
771: {
772: register mach_port_index_t index;
773: register mach_port_gen_t gen;
774:
775: index = MACH_PORT_INDEX(rcv_name);
776: gen = MACH_PORT_GEN(rcv_name);
777:
778: if (index >= size)
779: goto abort_reply_rcv_copyin;
780:
781: entry = &table[index];
782: bits = entry->ie_bits;
783:
784: /* check generation number */
785:
786: if ((bits & IE_BITS_GEN_MASK) != gen)
787: goto abort_reply_rcv_copyin;
788: }
789:
790: /* check type bits; looking for receive or set */
791:
792: if (bits & MACH_PORT_TYPE_PORT_SET) {
793: register ipc_pset_t rcv_pset;
794:
795: rcv_pset = (ipc_pset_t) entry->ie_object;
796: assert(rcv_pset != IPS_NULL);
797:
798: ips_lock(rcv_pset);
799: assert(ips_active(rcv_pset));
800:
801: rcv_object = (ipc_object_t) rcv_pset;
802: rcv_mqueue = &rcv_pset->ips_messages;
803: } else if (bits & MACH_PORT_TYPE_RECEIVE) {
804: register ipc_port_t rcv_port;
805:
806: rcv_port = (ipc_port_t) entry->ie_object;
807: assert(rcv_port != IP_NULL);
808:
809: if (!ip_lock_try(rcv_port))
810: goto abort_reply_rcv_copyin;
811: assert(ip_active(rcv_port));
812:
813: if (rcv_port->ip_pset != IPS_NULL) {
814: ip_unlock(rcv_port);
815: goto abort_reply_rcv_copyin;
816: }
817:
818: rcv_object = (ipc_object_t) rcv_port;
819: rcv_mqueue = &rcv_port->ip_messages;
820: } else
821: goto abort_reply_rcv_copyin;
822: }
823:
824: is_write_unlock(space);
825: io_reference(rcv_object);
826: imq_lock(rcv_mqueue);
827: io_unlock(rcv_object);
828: goto fast_send_receive;
829:
830: abort_reply_dest_copyin:
831: is_write_unlock(space);
832: goto slow_copyin;
833:
834: abort_reply_rcv_copyin:
835: ip_unlock(dest_port);
836: is_write_unlock(space);
837: goto slow_send;
838: }
839:
840: default:
841: goto slow_copyin;
842: }
843: /*NOTREACHED*/
844:
845: fast_send_receive:
846: /*
847: * optimized ipc_mqueue_send/ipc_mqueue_receive
848: *
849: * Finished get/copyin of kmsg and copyin of rcv_name.
850: * space is unlocked, dest_port is locked,
851: * we can queue kmsg to dest_port,
852: * rcv_mqueue is locked, rcv_object holds a ref,
853: * if rcv_object is a port it isn't in a port set
854: *
855: * Note that if simple locking is turned off,
856: * then we could have dest_mqueue == rcv_mqueue
857: * and not abort when we try to lock dest_mqueue.
858: */
859:
860: assert(ip_active(dest_port));
861: assert(dest_port->ip_receiver != ipc_space_kernel);
862: #if NORMA_IPC
863: assert(! IP_NORMA_IS_PROXY(dest_port));
864: #endif /* NORMA_IPC */
865: assert((dest_port->ip_msgcount < dest_port->ip_qlimit) ||
866: (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
867: MACH_MSG_TYPE_PORT_SEND_ONCE));
868: assert((kmsg->ikm_header.msgh_bits &
869: MACH_MSGH_BITS_CIRCULAR) == 0);
870:
871: {
872: register ipc_mqueue_t dest_mqueue;
873: register ipc_thread_t receiver;
874:
875: {
876: register ipc_pset_t dest_pset;
877:
878: dest_pset = dest_port->ip_pset;
879: if (dest_pset == IPS_NULL)
880: dest_mqueue = &dest_port->ip_messages;
881: else
882: dest_mqueue = &dest_pset->ips_messages;
883: }
884:
885: if (!imq_lock_try(dest_mqueue)) {
886: abort_send_receive:
887: ip_unlock(dest_port);
888: imq_unlock(rcv_mqueue);
889: ipc_object_release(rcv_object);
890: goto slow_send;
891: }
892:
893: receiver = ipc_thread_queue_first(&dest_mqueue->imq_threads);
894: if ((receiver == ITH_NULL) ||
895: (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages)
896: != IKM_NULL)) {
897: imq_unlock(dest_mqueue);
898: goto abort_send_receive;
899: }
900:
901: /*
902: * There is a receiver thread waiting, and
903: * there is no reply message for us to pick up.
904: * We have hope of hand-off, so save state.
905: */
906:
907: self->ith_msg = msg;
908: self->ith_rcv_size = rcv_size;
909: self->ith_object = rcv_object;
910: self->ith_mqueue = rcv_mqueue;
911:
912: if ((receiver->swap_func == (void (*)()) mach_msg_continue) &&
913: thread_handoff(self, mach_msg_continue, receiver)) {
914: assert(current_thread() == receiver);
915:
916: /*
917: * We can use the optimized receive code,
918: * because the receiver is using no options.
919: */
920: } else if ((receiver->swap_func ==
921: (void (*)()) exception_raise_continue) &&
922: thread_handoff(self, mach_msg_continue, receiver)) {
923: counter(c_mach_msg_trap_block_exc++);
924: assert(current_thread() == receiver);
925:
926: /*
927: * We are a reply message coming back through
928: * the optimized exception-handling path.
929: * Finish with rcv_mqueue and dest_mqueue,
930: * and then jump to exception code with
931: * dest_port still locked. We don't bother
932: * with a sequence number in this case.
933: */
934:
935: ipc_thread_enqueue_macro(
936: &rcv_mqueue->imq_threads, self);
937: self->ith_state = MACH_RCV_IN_PROGRESS;
938: self->ith_msize = MACH_MSG_SIZE_MAX;
939: imq_unlock(rcv_mqueue);
940:
941: ipc_thread_rmqueue_first_macro(
942: &dest_mqueue->imq_threads, receiver);
943: imq_unlock(dest_mqueue);
944:
945: exception_raise_continue_fast(dest_port, kmsg);
946: /*NOTREACHED*/
947: return MACH_MSG_SUCCESS;
948: } else if ((send_size <= receiver->ith_msize) &&
949: thread_handoff(self, mach_msg_continue, receiver)) {
950: assert(current_thread() == receiver);
951:
952: if ((receiver->swap_func ==
953: (void (*)()) mach_msg_receive_continue) &&
954: ((receiver->ith_option & MACH_RCV_NOTIFY) == 0)) {
955: /*
956: * We can still use the optimized code.
957: */
958: } else {
959: counter(c_mach_msg_trap_block_slow++);
960: /*
961: * We are running as the receiver,
962: * but we can't use the optimized code.
963: * Finish send/receive processing.
964: */
965:
966: dest_port->ip_msgcount++;
967: ip_unlock(dest_port);
968:
969: ipc_thread_enqueue_macro(
970: &rcv_mqueue->imq_threads, self);
971: self->ith_state = MACH_RCV_IN_PROGRESS;
972: self->ith_msize = MACH_MSG_SIZE_MAX;
973: imq_unlock(rcv_mqueue);
974:
975: ipc_thread_rmqueue_first_macro(
976: &dest_mqueue->imq_threads, receiver);
977: receiver->ith_state = MACH_MSG_SUCCESS;
978: receiver->ith_kmsg = kmsg;
979: receiver->ith_seqno = dest_port->ip_seqno++;
980: imq_unlock(dest_mqueue);
981:
982: /*
983: * Call the receiver's continuation.
984: */
985:
986: receiver->wait_result = THREAD_AWAKENED;
987: (*receiver->swap_func)();
988: /*NOTREACHED*/
989: return MACH_MSG_SUCCESS;
990: }
991: } else {
992: /*
993: * The receiver can't accept the message,
994: * or we can't switch to the receiver.
995: */
996:
997: imq_unlock(dest_mqueue);
998: goto abort_send_receive;
999: }
1000: counter(c_mach_msg_trap_block_fast++);
1001:
1002: /*
1003: * Safe to unlock dest_port now that we are
1004: * committed to this path, because we hold
1005: * dest_mqueue locked. We never bother changing
1006: * dest_port->ip_msgcount.
1007: */
1008:
1009: ip_unlock(dest_port);
1010:
1011: /*
1012: * We need to finish preparing self for its
1013: * time asleep in rcv_mqueue.
1014: */
1015:
1016: ipc_thread_enqueue_macro(&rcv_mqueue->imq_threads, self);
1017: self->ith_state = MACH_RCV_IN_PROGRESS;
1018: self->ith_msize = MACH_MSG_SIZE_MAX;
1019: imq_unlock(rcv_mqueue);
1020:
1021: /*
1022: * Finish extracting receiver from dest_mqueue.
1023: */
1024:
1025: ipc_thread_rmqueue_first_macro(
1026: &dest_mqueue->imq_threads, receiver);
1027: kmsg->ikm_header.msgh_seqno = dest_port->ip_seqno++;
1028: imq_unlock(dest_mqueue);
1029:
1030: /*
1031: * We don't have to do any post-dequeue processing of
1032: * the message. We never incremented ip_msgcount, we
1033: * know it has no msg-accepted request, and blocked
1034: * senders aren't a worry because we found the port
1035: * with a receiver waiting.
1036: */
1037:
1038: self = receiver;
1039: space = self->task->itk_space;
1040:
1041: msg = self->ith_msg;
1042: rcv_size = self->ith_rcv_size;
1043: rcv_object = self->ith_object;
1044:
1045: /* inline ipc_object_release */
1046: io_lock(rcv_object);
1047: io_release(rcv_object);
1048: io_check_unlock(rcv_object);
1049: }
1050:
1051: fast_copyout:
1052: /*
1053: * Nothing locked and no references held, except
1054: * we have kmsg with msgh_seqno filled in. Must
1055: * still check against rcv_size and do
1056: * ipc_kmsg_copyout/ipc_kmsg_put.
1057: */
1058:
1059: assert((ipc_port_t) kmsg->ikm_header.msgh_remote_port
1060: == dest_port);
1061:
1062: reply_size = kmsg->ikm_header.msgh_size;
1063: if (rcv_size < reply_size)
1064: goto slow_copyout;
1065:
1066: /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */
1067:
1068: switch (kmsg->ikm_header.msgh_bits) {
1069: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
1070: MACH_MSG_TYPE_PORT_SEND_ONCE): {
1071: ipc_port_t reply_port =
1072: (ipc_port_t) kmsg->ikm_header.msgh_local_port;
1073: mach_port_t dest_name, reply_name;
1074:
1075: /* receiving a request message */
1076:
1077: if (!IP_VALID(reply_port))
1078: goto slow_copyout;
1079:
1080: is_write_lock(space);
1081: assert(space->is_active);
1082:
1083: /*
1084: * To do an atomic copyout, need simultaneous
1085: * locks on both ports and the space. If
1086: * dest_port == reply_port, and simple locking is
1087: * enabled, then we will abort. Otherwise it's
1088: * OK to unlock twice.
1089: */
1090:
1091: ip_lock(dest_port);
1092: if (!ip_active(dest_port) ||
1093: !ip_lock_try(reply_port))
1094: goto abort_request_copyout;
1095:
1096: if (!ip_active(reply_port)) {
1097: ip_unlock(reply_port);
1098: goto abort_request_copyout;
1099: }
1100:
1101: assert(reply_port->ip_sorights > 0);
1102: ip_unlock(reply_port);
1103:
1104: {
1105: register ipc_entry_t table;
1106: register ipc_entry_t entry;
1107: register mach_port_index_t index;
1108:
1109: /* optimized ipc_entry_get */
1110:
1111: table = space->is_table;
1112: index = table->ie_next;
1113:
1114: if (index == 0)
1115: goto abort_request_copyout;
1116:
1117: entry = &table[index];
1118: table->ie_next = entry->ie_next;
1119: entry->ie_request = 0;
1120:
1121: {
1122: register mach_port_gen_t gen;
1123:
1124: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
1125: gen = entry->ie_bits + IE_BITS_GEN_ONE;
1126:
1127: reply_name = MACH_PORT_MAKE(index, gen);
1128:
1129: /* optimized ipc_right_copyout */
1130:
1131: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
1132: }
1133:
1134: assert(MACH_PORT_VALID(reply_name));
1135: entry->ie_object = (ipc_object_t) reply_port;
1136: is_write_unlock(space);
1137: }
1138:
1139: /* optimized ipc_object_copyout_dest */
1140:
1141: assert(dest_port->ip_srights > 0);
1142: ip_release(dest_port);
1143:
1144: if (dest_port->ip_receiver == space)
1145: dest_name = dest_port->ip_receiver_name;
1146: else
1147: dest_name = MACH_PORT_NULL;
1148:
1149: if ((--dest_port->ip_srights == 0) &&
1150: (dest_port->ip_nsrequest != IP_NULL)) {
1151: ipc_port_t nsrequest;
1152: mach_port_mscount_t mscount;
1153:
1154: /* a rather rare case */
1155:
1156: nsrequest = dest_port->ip_nsrequest;
1157: mscount = dest_port->ip_mscount;
1158: dest_port->ip_nsrequest = IP_NULL;
1159: ip_unlock(dest_port);
1160:
1161: ipc_notify_no_senders(nsrequest, mscount);
1162: } else
1163: ip_unlock(dest_port);
1164:
1165: kmsg->ikm_header.msgh_bits =
1166: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
1167: MACH_MSG_TYPE_PORT_SEND);
1168: kmsg->ikm_header.msgh_remote_port = reply_name;
1169: kmsg->ikm_header.msgh_local_port = dest_name;
1170: goto fast_put;
1171:
1172: abort_request_copyout:
1173: ip_unlock(dest_port);
1174: is_write_unlock(space);
1175: goto slow_copyout;
1176: }
1177:
1178: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1179: register mach_port_t dest_name;
1180:
1181: /* receiving a reply message */
1182:
1183: ip_lock(dest_port);
1184: if (!ip_active(dest_port))
1185: goto slow_copyout;
1186:
1187: /* optimized ipc_object_copyout_dest */
1188:
1189: assert(dest_port->ip_sorights > 0);
1190:
1191: if (dest_port->ip_receiver == space) {
1192: ip_release(dest_port);
1193: dest_port->ip_sorights--;
1194: dest_name = dest_port->ip_receiver_name;
1195: ip_unlock(dest_port);
1196: } else {
1197: ip_unlock(dest_port);
1198:
1199: ipc_notify_send_once(dest_port);
1200: dest_name = MACH_PORT_NULL;
1201: }
1202:
1203: kmsg->ikm_header.msgh_bits =
1204: MACH_MSGH_BITS(0,
1205: MACH_MSG_TYPE_PORT_SEND_ONCE);
1206: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
1207: kmsg->ikm_header.msgh_local_port = dest_name;
1208: goto fast_put;
1209: }
1210:
1211: case MACH_MSGH_BITS_COMPLEX|
1212: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1213: register mach_port_t dest_name;
1214:
1215: /* receiving a complex reply message */
1216:
1217: ip_lock(dest_port);
1218: if (!ip_active(dest_port))
1219: goto slow_copyout;
1220:
1221: /* optimized ipc_object_copyout_dest */
1222:
1223: assert(dest_port->ip_sorights > 0);
1224:
1225: if (dest_port->ip_receiver == space) {
1226: ip_release(dest_port);
1227: dest_port->ip_sorights--;
1228: dest_name = dest_port->ip_receiver_name;
1229: ip_unlock(dest_port);
1230: } else {
1231: ip_unlock(dest_port);
1232:
1233: ipc_notify_send_once(dest_port);
1234: dest_name = MACH_PORT_NULL;
1235: }
1236:
1237: kmsg->ikm_header.msgh_bits =
1238: MACH_MSGH_BITS_COMPLEX |
1239: MACH_MSGH_BITS(0,
1240: MACH_MSG_TYPE_PORT_SEND_ONCE);
1241: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
1242: kmsg->ikm_header.msgh_local_port = dest_name;
1243:
1244: mr = ipc_kmsg_copyout_body(
1245: (vm_offset_t) (&kmsg->ikm_header + 1),
1246: (vm_offset_t) &kmsg->ikm_header
1247: + kmsg->ikm_header.msgh_size,
1248: space,
1249: current_map());
1250:
1251: if (mr != MACH_MSG_SUCCESS) {
1252: (void) ipc_kmsg_put(msg, kmsg,
1253: kmsg->ikm_header.msgh_size);
1254: return mr | MACH_RCV_BODY_ERROR;
1255: }
1256: goto fast_put;
1257: }
1258:
1259: default:
1260: goto slow_copyout;
1261: }
1262: /*NOTREACHED*/
1263:
1264: fast_put:
1265: /*
1266: * We have the reply message data in kmsg,
1267: * and the reply message size in reply_size.
1268: * Just need to copy it out to the user and free kmsg.
1269: * We must check ikm_cache after copyoutmsg.
1270: */
1271:
1272: ikm_check_initialized(kmsg, kmsg->ikm_size);
1273:
1274: if ((kmsg->ikm_size != IKM_SAVED_KMSG_SIZE) ||
1275: copyoutmsg((vm_offset_t) &kmsg->ikm_header, (vm_offset_t) msg,
1276: reply_size) ||
1277: (ikm_cache() != IKM_NULL))
1278: goto slow_put;
1279:
1280: ikm_cache() = kmsg;
1281: thread_syscall_return(MACH_MSG_SUCCESS);
1282: /*NOTREACHED*/
1283: return MACH_MSG_SUCCESS; /* help for the compiler */
1284:
1285: /*
1286: * The slow path has a few non-register temporary
1287: * variables used only for call-by-reference.
1288: */
1289:
1290: {
1291: ipc_kmsg_t temp_kmsg;
1292: mach_port_seqno_t temp_seqno;
1293: ipc_object_t temp_rcv_object;
1294: ipc_mqueue_t temp_rcv_mqueue;
1295:
1296: slow_get:
1297: /*
1298: * No locks, references, or messages held.
1299: * Still have to get the request, send it,
1300: * receive reply, etc.
1301: */
1302:
1303: mr = ipc_kmsg_get(msg, send_size, &temp_kmsg);
1304: if (mr != MACH_MSG_SUCCESS) {
1305: thread_syscall_return(mr);
1306: /*NOTREACHED*/
1307: }
1308: kmsg = temp_kmsg;
1309:
1310: /* try to get back on optimized path */
1311: goto fast_copyin;
1312:
1313: slow_copyin:
1314: /*
1315: * We have the message data in kmsg, but
1316: * we still need to copyin, send it,
1317: * receive a reply, and do copyout.
1318: */
1319:
1320: mr = ipc_kmsg_copyin(kmsg, space, current_map(),
1321: MACH_PORT_NULL);
1322: if (mr != MACH_MSG_SUCCESS) {
1323: ikm_free(kmsg);
1324: thread_syscall_return(mr);
1325: /*NOTREACHED*/
1326: }
1327:
1328: /* try to get back on optimized path */
1329:
1330: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR)
1331: goto slow_send;
1332:
1333: dest_port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
1334: assert(IP_VALID(dest_port));
1335:
1336: ip_lock(dest_port);
1337: if (dest_port->ip_receiver == ipc_space_kernel) {
1338: assert(ip_active(dest_port));
1339: ip_unlock(dest_port);
1340: goto kernel_send;
1341: }
1342:
1343: if (ip_active(dest_port) &&
1344: #if NORMA_IPC
1345: (! IP_NORMA_IS_PROXY(dest_port)) &&
1346: #endif /* NORMA_IPC */
1347: ((dest_port->ip_msgcount < dest_port->ip_qlimit) ||
1348: (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
1349: MACH_MSG_TYPE_PORT_SEND_ONCE)))
1350: {
1351: /*
1352: * Try an optimized ipc_mqueue_copyin.
1353: * It will work if this is a request message.
1354: */
1355:
1356: register ipc_port_t reply_port;
1357:
1358: reply_port = (ipc_port_t)
1359: kmsg->ikm_header.msgh_local_port;
1360: if (IP_VALID(reply_port)) {
1361: if (ip_lock_try(reply_port)) {
1362: if (ip_active(reply_port) &&
1363: reply_port->ip_receiver == space &&
1364: reply_port->ip_receiver_name == rcv_name &&
1365: reply_port->ip_pset == IPS_NULL)
1366: {
1367: /* Grab a reference to the reply port. */
1368: rcv_object = (ipc_object_t) reply_port;
1369: io_reference(rcv_object);
1370: rcv_mqueue = &reply_port->ip_messages;
1371: imq_lock(rcv_mqueue);
1372: io_unlock(rcv_object);
1373: goto fast_send_receive;
1374: }
1375: ip_unlock(reply_port);
1376: }
1377: }
1378: }
1379:
1380: ip_unlock(dest_port);
1381: goto slow_send;
1382:
1383: #if NORMA_IPC
1384: norma_send:
1385: /*
1386: * Nothing is locked. We have acquired kmsg, but
1387: * we still need to send it and receive a reply.
1388: */
1389:
1390: mr = norma_ipc_send(kmsg);
1391: if (mr != MACH_MSG_SUCCESS) {
1392: mr |= ipc_kmsg_copyout_pseudo(kmsg, space,
1393: current_map());
1394:
1395: assert(kmsg->ikm_marequest == IMAR_NULL);
1396: (void) ipc_kmsg_put(msg, kmsg,
1397: kmsg->ikm_header.msgh_size);
1398: thread_syscall_return(mr);
1399: /*NOTREACHED*/
1400: }
1401:
1402: goto slow_get_rcv_port;
1403: #endif /* NORMA_IPC */
1404:
1405: kernel_send:
1406: /*
1407: * Special case: send message to kernel services.
1408: * The request message has been copied into the
1409: * kmsg. Nothing is locked.
1410: */
1411:
1412: {
1413: register ipc_port_t reply_port;
1414:
1415: /*
1416: * Perform the kernel function.
1417: */
1418:
1419: kmsg = ipc_kobject_server(kmsg);
1420: if (kmsg == IKM_NULL) {
1421: /*
1422: * No reply. Take the
1423: * slow receive path.
1424: */
1425: goto slow_get_rcv_port;
1426: }
1427:
1428: /*
1429: * Check that:
1430: * the reply port is alive
1431: * we hold the receive right
1432: * the name has not changed.
1433: * the port is not in a set
1434: * If any of these are not true,
1435: * we cannot directly receive the reply
1436: * message.
1437: */
1438: reply_port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
1439: ip_lock(reply_port);
1440:
1441: if ((!ip_active(reply_port)) ||
1442: (reply_port->ip_receiver != space) ||
1443: (reply_port->ip_receiver_name != rcv_name) ||
1444: (reply_port->ip_pset != IPS_NULL))
1445: {
1446: ip_unlock(reply_port);
1447: ipc_mqueue_send_always(kmsg);
1448: goto slow_get_rcv_port;
1449: }
1450:
1451: rcv_mqueue = &reply_port->ip_messages;
1452: imq_lock(rcv_mqueue);
1453: /* keep port locked, and don`t change ref count yet */
1454:
1455: /*
1456: * If there are messages on the port
1457: * or other threads waiting for a message,
1458: * we cannot directly receive the reply.
1459: */
1460: if ((ipc_thread_queue_first(&rcv_mqueue->imq_threads)
1461: != ITH_NULL) ||
1462: (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages)
1463: != IKM_NULL))
1464: {
1465: imq_unlock(rcv_mqueue);
1466: ip_unlock(reply_port);
1467: ipc_mqueue_send_always(kmsg);
1468: goto slow_get_rcv_port;
1469: }
1470:
1471: /*
1472: * We can directly receive this reply.
1473: * Since the kernel reply never blocks,
1474: * it holds no message_accepted request.
1475: * Since there were no messages queued
1476: * on the reply port, there should be
1477: * no threads blocked waiting to send.
1478: */
1479:
1480: assert(kmsg->ikm_marequest == IMAR_NULL);
1481: assert(ipc_thread_queue_first(&reply_port->ip_blocked)
1482: == ITH_NULL);
1483:
1484: dest_port = reply_port;
1485: kmsg->ikm_header.msgh_seqno = dest_port->ip_seqno++;
1486: imq_unlock(rcv_mqueue);
1487:
1488: /*
1489: * inline ipc_object_release.
1490: * Port is still locked.
1491: * Reference count was not incremented.
1492: */
1493: ip_check_unlock(reply_port);
1494:
1495: /* copy out the kernel reply */
1496: goto fast_copyout;
1497: }
1498:
1499: slow_send:
1500: /*
1501: * Nothing is locked. We have acquired kmsg, but
1502: * we still need to send it and receive a reply.
1503: */
1504:
1505: mr = ipc_mqueue_send(kmsg, MACH_MSG_OPTION_NONE,
1506: MACH_MSG_TIMEOUT_NONE);
1507: if (mr != MACH_MSG_SUCCESS) {
1508: mr |= ipc_kmsg_copyout_pseudo(kmsg, space,
1509: current_map());
1510:
1511: assert(kmsg->ikm_marequest == IMAR_NULL);
1512: (void) ipc_kmsg_put(msg, kmsg,
1513: kmsg->ikm_header.msgh_size);
1514: thread_syscall_return(mr);
1515: /*NOTREACHED*/
1516: }
1517:
1518: slow_get_rcv_port:
1519: /*
1520: * We have sent the message. Copy in the receive port.
1521: */
1522: mr = ipc_mqueue_copyin(space, rcv_name,
1523: &temp_rcv_mqueue, &temp_rcv_object);
1524: if (mr != MACH_MSG_SUCCESS) {
1525: thread_syscall_return(mr);
1526: /*NOTREACHED*/
1527: }
1528: rcv_mqueue = temp_rcv_mqueue;
1529: rcv_object = temp_rcv_object;
1530: /* hold ref for rcv_object; rcv_mqueue is locked */
1531:
1532: /*
1533: slow_receive:
1534: */
1535: /*
1536: * Now we have sent the request and copied in rcv_name,
1537: * so rcv_mqueue is locked and hold ref for rcv_object.
1538: * Just receive a reply and try to get back to fast path.
1539: *
1540: * ipc_mqueue_receive may not return, because if we block
1541: * then our kernel stack may be discarded. So we save
1542: * state here for mach_msg_continue to pick up.
1543: */
1544:
1545: self->ith_msg = msg;
1546: self->ith_rcv_size = rcv_size;
1547: self->ith_object = rcv_object;
1548: self->ith_mqueue = rcv_mqueue;
1549:
1550: mr = ipc_mqueue_receive(rcv_mqueue,
1551: MACH_MSG_OPTION_NONE,
1552: MACH_MSG_SIZE_MAX,
1553: MACH_MSG_TIMEOUT_NONE,
1554: FALSE, mach_msg_continue,
1555: &temp_kmsg, &temp_seqno);
1556: /* rcv_mqueue is unlocked */
1557: ipc_object_release(rcv_object);
1558: if (mr != MACH_MSG_SUCCESS) {
1559: thread_syscall_return(mr);
1560: /*NOTREACHED*/
1561: }
1562:
1563: (kmsg = temp_kmsg)->ikm_header.msgh_seqno = temp_seqno;
1564: dest_port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
1565: goto fast_copyout;
1566:
1567: slow_copyout:
1568: /*
1569: * Nothing locked and no references held, except
1570: * we have kmsg with msgh_seqno filled in. Must
1571: * still check against rcv_size and do
1572: * ipc_kmsg_copyout/ipc_kmsg_put.
1573: */
1574:
1575: reply_size = kmsg->ikm_header.msgh_size;
1576: if (rcv_size < reply_size) {
1577: ipc_kmsg_copyout_dest(kmsg, space);
1578: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
1579: thread_syscall_return(MACH_RCV_TOO_LARGE);
1580: /*NOTREACHED*/
1581: }
1582:
1583: mr = ipc_kmsg_copyout(kmsg, space, current_map(),
1584: MACH_PORT_NULL);
1585: if (mr != MACH_MSG_SUCCESS) {
1586: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
1587: (void) ipc_kmsg_put(msg, kmsg,
1588: kmsg->ikm_header.msgh_size);
1589: } else {
1590: ipc_kmsg_copyout_dest(kmsg, space);
1591: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
1592: }
1593:
1594: thread_syscall_return(mr);
1595: /*NOTREACHED*/
1596: }
1597:
1598: /* try to get back on optimized path */
1599:
1600: goto fast_put;
1601:
1602: slow_put:
1603: mr = ipc_kmsg_put(msg, kmsg, reply_size);
1604: thread_syscall_return(mr);
1605: /*NOTREACHED*/
1606: }
1607: } else if (option == MACH_SEND_MSG) {
1608: ipc_space_t space = current_space();
1609: vm_map_t map = current_map();
1610: ipc_kmsg_t kmsg;
1611:
1612: mr = ipc_kmsg_get(msg, send_size, &kmsg);
1613: if (mr != MACH_MSG_SUCCESS)
1614: return mr;
1615:
1616: mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
1617: if (mr != MACH_MSG_SUCCESS) {
1618: ikm_free(kmsg);
1619: return mr;
1620: }
1621:
1622: mr = ipc_mqueue_send(kmsg, MACH_MSG_OPTION_NONE,
1623: MACH_MSG_TIMEOUT_NONE);
1624: if (mr != MACH_MSG_SUCCESS) {
1625: mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map);
1626:
1627: assert(kmsg->ikm_marequest == IMAR_NULL);
1628: (void) ipc_kmsg_put(msg, kmsg,
1629: kmsg->ikm_header.msgh_size);
1630: }
1631:
1632: return mr;
1633: } else if (option == MACH_RCV_MSG) {
1634: ipc_thread_t self = current_thread();
1635: ipc_space_t space = current_space();
1636: vm_map_t map = current_map();
1637: ipc_object_t object;
1638: ipc_mqueue_t mqueue;
1639: ipc_kmsg_t kmsg;
1640: mach_port_seqno_t seqno;
1641:
1642: mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
1643: if (mr != MACH_MSG_SUCCESS)
1644: return mr;
1645: /* hold ref for object; mqueue is locked */
1646:
1647: /*
1648: * ipc_mqueue_receive may not return, because if we block
1649: * then our kernel stack may be discarded. So we save
1650: * state here for mach_msg_continue to pick up.
1651: */
1652:
1653: self->ith_msg = msg;
1654: self->ith_rcv_size = rcv_size;
1655: self->ith_object = object;
1656: self->ith_mqueue = mqueue;
1657:
1658: mr = ipc_mqueue_receive(mqueue,
1659: MACH_MSG_OPTION_NONE,
1660: MACH_MSG_SIZE_MAX,
1661: MACH_MSG_TIMEOUT_NONE,
1662: FALSE, mach_msg_continue,
1663: &kmsg, &seqno);
1664: /* mqueue is unlocked */
1665: ipc_object_release(object);
1666: if (mr != MACH_MSG_SUCCESS)
1667: return mr;
1668:
1669: kmsg->ikm_header.msgh_seqno = seqno;
1670: if (rcv_size < kmsg->ikm_header.msgh_size) {
1671: ipc_kmsg_copyout_dest(kmsg, space);
1672: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
1673: return MACH_RCV_TOO_LARGE;
1674: }
1675:
1676: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
1677: if (mr != MACH_MSG_SUCCESS) {
1678: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
1679: (void) ipc_kmsg_put(msg, kmsg,
1680: kmsg->ikm_header.msgh_size);
1681: } else {
1682: ipc_kmsg_copyout_dest(kmsg, space);
1683: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
1684: }
1685:
1686: return mr;
1687: }
1688:
1689: return ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
1690: } else if (option == MACH_MSG_OPTION_NONE) {
1691: /*
1692: * We can measure the "null mach_msg_trap"
1693: * (syscall entry and thread_syscall_return exit)
1694: * with this path.
1695: */
1696:
1697: thread_syscall_return(MACH_MSG_SUCCESS);
1698: /*NOTREACHED*/
1699: }
1700: #endif /* CONTINUATIONS */
1701:
1702: if (option & MACH_SEND_MSG) {
1703: mr = mach_msg_send(msg, option, send_size,
1704: time_out, notify);
1705: if (mr != MACH_MSG_SUCCESS)
1706: return mr;
1707: }
1708:
1709: if (option & MACH_RCV_MSG) {
1710: mr = mach_msg_receive(msg, option, rcv_size, rcv_name,
1711: time_out, notify);
1712: if (mr != MACH_MSG_SUCCESS)
1713: return mr;
1714: }
1715:
1716: return MACH_MSG_SUCCESS;
1717: }
1718:
1719: #ifdef CONTINUATIONS
1720: /*
1721: * Routine: mach_msg_continue
1722: * Purpose:
1723: * Continue after blocking for a message.
1724: * Conditions:
1725: * Nothing locked. We are running on a new kernel stack,
1726: * with the receive state saved in the thread. From here
1727: * control goes back to user space.
1728: */
1729:
1730: void
1731: mach_msg_continue()
1732: {
1733: ipc_thread_t thread = current_thread();
1734: task_t task = thread->task;
1735: ipc_space_t space = task->itk_space;
1736: vm_map_t map = task->map;
1737: mach_msg_header_t *msg = thread->ith_msg;
1738: mach_msg_size_t rcv_size = thread->ith_rcv_size;
1739: ipc_object_t object = thread->ith_object;
1740: ipc_mqueue_t mqueue = thread->ith_mqueue;
1741: ipc_kmsg_t kmsg;
1742: mach_port_seqno_t seqno;
1743: mach_msg_return_t mr;
1744:
1745: mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
1746: MACH_MSG_SIZE_MAX, MACH_MSG_TIMEOUT_NONE,
1747: TRUE, mach_msg_continue, &kmsg, &seqno);
1748: /* mqueue is unlocked */
1749: ipc_object_release(object);
1750: if (mr != MACH_MSG_SUCCESS) {
1751: thread_syscall_return(mr);
1752: /*NOTREACHED*/
1753: }
1754:
1755: kmsg->ikm_header.msgh_seqno = seqno;
1756: if (kmsg->ikm_header.msgh_size > rcv_size) {
1757: ipc_kmsg_copyout_dest(kmsg, space);
1758: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
1759: thread_syscall_return(MACH_RCV_TOO_LARGE);
1760: /*NOTREACHED*/
1761: }
1762:
1763: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
1764: if (mr != MACH_MSG_SUCCESS) {
1765: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
1766: (void) ipc_kmsg_put(msg, kmsg,
1767: kmsg->ikm_header.msgh_size);
1768: } else {
1769: ipc_kmsg_copyout_dest(kmsg, space);
1770: (void) ipc_kmsg_put(msg, kmsg, sizeof *msg);
1771: }
1772:
1773: thread_syscall_return(mr);
1774: /*NOTREACHED*/
1775: }
1776:
1777: mr = ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
1778: thread_syscall_return(mr);
1779: /*NOTREACHED*/
1780: }
1781:
1782: /*
1783: * Routine: mach_msg_interrupt
1784: * Purpose:
1785: * Attempts to force a thread waiting at mach_msg_continue or
1786: * mach_msg_receive_continue into a clean point. Returns TRUE
1787: * if this was possible.
1788: * Conditions:
1789: * Nothing locked. The thread must NOT be runnable.
1790: */
1791:
1792: boolean_t
1793: mach_msg_interrupt(thread)
1794: thread_t thread;
1795: {
1796: ipc_mqueue_t mqueue;
1797:
1798: assert((thread->swap_func == (void (*)()) mach_msg_continue) ||
1799: (thread->swap_func == (void (*)()) mach_msg_receive_continue));
1800:
1801: mqueue = thread->ith_mqueue;
1802: imq_lock(mqueue);
1803: if (thread->ith_state != MACH_RCV_IN_PROGRESS) {
1804: /*
1805: * The thread is no longer waiting for a message.
1806: * It may have a message sitting in ith_kmsg.
1807: * We can't clean this up.
1808: */
1809:
1810: imq_unlock(mqueue);
1811: return FALSE;
1812: }
1813: ipc_thread_rmqueue(&mqueue->imq_threads, thread);
1814: imq_unlock(mqueue);
1815:
1816: ipc_object_release(thread->ith_object);
1817:
1818: thread_set_syscall_return(thread, MACH_RCV_INTERRUPTED);
1819: thread->swap_func = thread_exception_return;
1820: return TRUE;
1821: }
1822: #endif /* CONTINUATIONS */
1823:
1824: #if MACH_IPC_COMPAT
1825:
1826: /*
1827: * Routine: msg_return_translate
1828: * Purpose:
1829: * Translate from new error code to old error code.
1830: */
1831:
1832: msg_return_t
1833: msg_return_translate(mr)
1834: mach_msg_return_t mr;
1835: {
1836: switch (mr &~ MACH_MSG_MASK) {
1837: case MACH_MSG_SUCCESS:
1838: return 0; /* SEND_SUCCESS/RCV_SUCCESS/RPC_SUCCESS */
1839:
1840: case MACH_SEND_NO_BUFFER:
1841: case MACH_SEND_NO_NOTIFY:
1842: printf("msg_return_translate: %x -> interrupted\n", mr);
1843: return SEND_INTERRUPTED;
1844:
1845: case MACH_SEND_MSG_TOO_SMALL:
1846: return SEND_MSG_TOO_SMALL;
1847: case MACH_SEND_INVALID_DATA:
1848: case MACH_SEND_INVALID_MEMORY:
1849: return SEND_INVALID_MEMORY;
1850: case MACH_SEND_TIMED_OUT:
1851: return SEND_TIMED_OUT;
1852: case MACH_SEND_INTERRUPTED:
1853: return SEND_INTERRUPTED;
1854: case MACH_SEND_INVALID_DEST:
1855: case MACH_SEND_INVALID_REPLY:
1856: case MACH_SEND_INVALID_RIGHT:
1857: case MACH_SEND_INVALID_TYPE:
1858: return SEND_INVALID_PORT;
1859: case MACH_SEND_WILL_NOTIFY:
1860: return SEND_WILL_NOTIFY;
1861: case MACH_SEND_NOTIFY_IN_PROGRESS:
1862: return SEND_NOTIFY_IN_PROGRESS;
1863:
1864: case MACH_RCV_INVALID_NAME:
1865: case MACH_RCV_IN_SET:
1866: case MACH_RCV_PORT_DIED:
1867: return RCV_INVALID_PORT;
1868: case MACH_RCV_TOO_LARGE:
1869: return RCV_TOO_LARGE;
1870: case MACH_RCV_TIMED_OUT:
1871: return RCV_TIMED_OUT;
1872: case MACH_RCV_INTERRUPTED:
1873: return RCV_INTERRUPTED;
1874: case MACH_RCV_PORT_CHANGED:
1875: return RCV_PORT_CHANGE;
1876: case MACH_RCV_INVALID_DATA:
1877: return RCV_INVALID_MEMORY;
1878:
1879: case MACH_SEND_IN_PROGRESS:
1880: case MACH_SEND_INVALID_NOTIFY:
1881: case MACH_SEND_INVALID_HEADER:
1882: case MACH_RCV_IN_PROGRESS:
1883: case MACH_RCV_INVALID_NOTIFY:
1884: case MACH_RCV_HEADER_ERROR:
1885: case MACH_RCV_BODY_ERROR:
1886: default:
1887: #if MACH_ASSERT
1888: assert(!"msg_return_translate");
1889: #else
1890: panic("msg_return_translate");
1891: #endif
1892: }
1893: }
1894:
1895: /*
1896: * Routine: msg_send_trap [mach trap]
1897: * Purpose:
1898: * Send a message.
1899: * Conditions:
1900: * Nothing locked.
1901: * Returns:
1902: */
1903:
1904: msg_return_t
1905: msg_send_trap(msg, option, send_size, time_out)
1906: msg_header_t *msg;
1907: msg_option_t option;
1908: msg_size_t send_size;
1909: msg_timeout_t time_out;
1910: {
1911: ipc_space_t space = current_space();
1912: vm_map_t map = current_map();
1913: ipc_kmsg_t kmsg;
1914: mach_msg_return_t mr;
1915:
1916: send_size = (send_size + 3) & ~3; /* round up */
1917:
1918: if (send_size > MSG_SIZE_MAX)
1919: return SEND_MSG_TOO_LARGE;
1920:
1921: mr = ipc_kmsg_get((mach_msg_header_t *) msg,
1922: (mach_msg_size_t) send_size,
1923: &kmsg);
1924: if (mr != MACH_MSG_SUCCESS)
1925: return msg_return_translate(mr);
1926:
1927: mr = ipc_kmsg_copyin_compat(kmsg, space, map);
1928: if (mr != MACH_MSG_SUCCESS) {
1929: ikm_free(kmsg);
1930: return msg_return_translate(mr);
1931: }
1932:
1933: if (option & SEND_NOTIFY) {
1934: mr = ipc_mqueue_send(kmsg, MACH_SEND_TIMEOUT,
1935: ((option & SEND_TIMEOUT) ?
1936: (mach_msg_timeout_t) time_out :
1937: MACH_MSG_TIMEOUT_NONE));
1938: if (mr == MACH_SEND_TIMED_OUT) {
1939: ipc_port_t dest = (ipc_port_t)
1940: kmsg->ikm_header.msgh_remote_port;
1941:
1942: mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
1943: &kmsg->ikm_marequest);
1944: if (mr == MACH_MSG_SUCCESS) {
1945: ipc_mqueue_send_always(kmsg);
1946: return SEND_WILL_NOTIFY;
1947: }
1948: }
1949: } else
1950: mr = ipc_mqueue_send(kmsg,
1951: ((option & SEND_TIMEOUT) ?
1952: MACH_SEND_TIMEOUT :
1953: MACH_MSG_OPTION_NONE),
1954: (mach_msg_timeout_t) time_out);
1955:
1956: if (mr != MACH_MSG_SUCCESS)
1957: ipc_kmsg_destroy(kmsg);
1958:
1959: return msg_return_translate(mr);
1960: }
1961:
1962: /*
1963: * Routine: msg_receive_trap [mach trap]
1964: * Purpose:
1965: * Receive a message.
1966: * Conditions:
1967: * Nothing locked.
1968: * Returns:
1969: */
1970:
1971: msg_return_t
1972: msg_receive_trap(msg, option, rcv_size, rcv_name, time_out)
1973: msg_header_t *msg;
1974: msg_option_t option;
1975: msg_size_t rcv_size;
1976: port_name_t rcv_name;
1977: msg_timeout_t time_out;
1978: {
1979: ipc_thread_t self;
1980: ipc_space_t space = current_space();
1981: vm_map_t map = current_map();
1982: ipc_object_t object;
1983: ipc_mqueue_t mqueue;
1984: ipc_kmsg_t kmsg;
1985: mach_port_seqno_t seqno;
1986: mach_msg_return_t mr;
1987:
1988: mr = ipc_mqueue_copyin(space, (mach_port_t) rcv_name,
1989: &mqueue, &object);
1990: if (mr != MACH_MSG_SUCCESS)
1991: return msg_return_translate(mr);
1992: /* hold ref for object; mqueue is locked */
1993:
1994: #ifdef CONTINUATIONS
1995: /*
1996: * ipc_mqueue_receive may not return, because if we block
1997: * then our kernel stack may be discarded. So we save
1998: * state here for msg_receive_continue to pick up.
1999: */
2000:
2001: self = current_thread();
2002: self->ith_msg = (mach_msg_header_t *) msg;
2003: self->ith_option = (mach_msg_option_t) option;
2004: self->ith_rcv_size = (mach_msg_size_t) rcv_size;
2005: self->ith_timeout = (mach_msg_timeout_t) time_out;
2006: self->ith_object = object;
2007: self->ith_mqueue = mqueue;
2008: #endif /* CONTINUATIONS */
2009:
2010: mr = ipc_mqueue_receive(mqueue,
2011: (option & RCV_TIMEOUT) ?
2012: MACH_RCV_TIMEOUT : MACH_MSG_OPTION_NONE,
2013: (mach_msg_size_t) rcv_size,
2014: (mach_msg_timeout_t) time_out,
2015: FALSE, msg_receive_continue,
2016: &kmsg, &seqno);
2017: /* mqueue is unlocked */
2018: ipc_object_release(object);
2019: if (mr != MACH_MSG_SUCCESS) {
2020: if (mr == MACH_RCV_TOO_LARGE) {
2021: msg_size_t real_size =
2022: (msg_size_t) (mach_msg_size_t) kmsg;
2023:
2024: assert(real_size > rcv_size);
2025:
2026: (void) copyout((vm_offset_t) &real_size,
2027: (vm_offset_t) &msg->msg_size,
2028: sizeof(msg_size_t));
2029: }
2030:
2031: return msg_return_translate(mr);
2032: }
2033:
2034: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
2035:
2036: mr = ipc_kmsg_copyout_compat(kmsg, space, map);
2037: assert(mr == MACH_MSG_SUCCESS);
2038:
2039: mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
2040: kmsg->ikm_header.msgh_size);
2041: return msg_return_translate(mr);
2042: }
2043:
2044: /*
2045: * Routine: msg_rpc_trap [mach trap]
2046: * Purpose:
2047: * Send and receive a message.
2048: * Conditions:
2049: * Nothing locked.
2050: * Returns:
2051: */
2052:
2053: msg_return_t
2054: msg_rpc_trap(msg, option, send_size, rcv_size, send_timeout, rcv_timeout)
2055: msg_header_t *msg;
2056: msg_option_t option;
2057: msg_size_t send_size;
2058: msg_size_t rcv_size;
2059: msg_timeout_t send_timeout;
2060: msg_timeout_t rcv_timeout;
2061: {
2062: ipc_thread_t self;
2063: ipc_space_t space = current_space();
2064: vm_map_t map = current_map();
2065: ipc_port_t reply;
2066: ipc_pset_t pset;
2067: ipc_mqueue_t mqueue;
2068: ipc_kmsg_t kmsg;
2069: mach_port_seqno_t seqno;
2070: mach_msg_return_t mr;
2071:
2072: /*
2073: * Instead of using msg_send_trap and msg_receive_trap,
2074: * we implement msg_rpc_trap directly. The difference
2075: * is how the reply port is handled. Instead of using
2076: * ipc_mqueue_copyin, we save a reference for the reply
2077: * port carried in the sent message. For example,
2078: * consider a rename kernel call which changes the name
2079: * of the call's own reply port. This is the behaviour
2080: * of the Mach 2.5 msg_rpc_trap.
2081: */
2082:
2083: send_size = (send_size + 3) & ~3; /* round up */
2084:
2085: if (send_size > MSG_SIZE_MAX)
2086: return SEND_MSG_TOO_LARGE;
2087:
2088: mr = ipc_kmsg_get((mach_msg_header_t *) msg,
2089: (mach_msg_size_t) send_size,
2090: &kmsg);
2091: if (mr != MACH_MSG_SUCCESS)
2092: return msg_return_translate(mr);
2093:
2094: mr = ipc_kmsg_copyin_compat(kmsg, space, map);
2095: if (mr != MACH_MSG_SUCCESS) {
2096: ikm_free(kmsg);
2097: return msg_return_translate(mr);
2098: }
2099:
2100: reply = (ipc_port_t) kmsg->ikm_header.msgh_local_port;
2101: if (IP_VALID(reply))
2102: ipc_port_reference(reply);
2103:
2104: if (option & SEND_NOTIFY) {
2105: mr = ipc_mqueue_send(kmsg, MACH_SEND_TIMEOUT,
2106: ((option & SEND_TIMEOUT) ?
2107: (mach_msg_timeout_t) send_timeout :
2108: MACH_MSG_TIMEOUT_NONE));
2109: if (mr == MACH_SEND_TIMED_OUT) {
2110: ipc_port_t dest = (ipc_port_t)
2111: kmsg->ikm_header.msgh_remote_port;
2112:
2113: mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
2114: &kmsg->ikm_marequest);
2115: if (mr == MACH_MSG_SUCCESS) {
2116: ipc_mqueue_send_always(kmsg);
2117: if (IP_VALID(reply))
2118: ipc_port_release(reply);
2119: return SEND_WILL_NOTIFY;
2120: }
2121: }
2122: } else
2123: mr = ipc_mqueue_send(kmsg,
2124: ((option & SEND_TIMEOUT) ?
2125: MACH_SEND_TIMEOUT :
2126: MACH_MSG_OPTION_NONE),
2127: (mach_msg_timeout_t) send_timeout);
2128:
2129: if (mr != MACH_MSG_SUCCESS) {
2130: ipc_kmsg_destroy(kmsg);
2131: if (IP_VALID(reply))
2132: ipc_port_release(reply);
2133: return msg_return_translate(mr);
2134: }
2135:
2136: if (!IP_VALID(reply))
2137: return RCV_INVALID_PORT;
2138:
2139: ip_lock(reply);
2140: if (reply->ip_receiver != space) {
2141: ip_release(reply);
2142: ip_check_unlock(reply);
2143: return RCV_INVALID_PORT;
2144: }
2145:
2146: assert(ip_active(reply));
2147: pset = reply->ip_pset;
2148:
2149: if (pset != IPS_NULL) {
2150: ips_lock(pset);
2151: if (ips_active(pset)) {
2152: ips_unlock(pset);
2153: ip_release(reply);
2154: ip_unlock(reply);
2155: return RCV_INVALID_PORT;
2156: }
2157:
2158: ipc_pset_remove(pset, reply);
2159: ips_check_unlock(pset);
2160: assert(reply->ip_pset == IPS_NULL);
2161: }
2162:
2163: mqueue = &reply->ip_messages;
2164: imq_lock(mqueue);
2165: ip_unlock(reply);
2166:
2167: #ifdef CONTINUATIONS
2168: /*
2169: * ipc_mqueue_receive may not return, because if we block
2170: * then our kernel stack may be discarded. So we save
2171: * state here for msg_receive_continue to pick up.
2172: */
2173:
2174: self = current_thread();
2175: self->ith_msg = (mach_msg_header_t *) msg;
2176: self->ith_option = (mach_msg_option_t) option;
2177: self->ith_rcv_size = (mach_msg_size_t) rcv_size;
2178: self->ith_timeout = (mach_msg_timeout_t) rcv_timeout;
2179: self->ith_object = (ipc_object_t) reply;
2180: self->ith_mqueue = mqueue;
2181: #endif /* CONTINUATIONS */
2182:
2183: mr = ipc_mqueue_receive(mqueue,
2184: (option & RCV_TIMEOUT) ?
2185: MACH_RCV_TIMEOUT : MACH_MSG_OPTION_NONE,
2186: (mach_msg_size_t) rcv_size,
2187: (mach_msg_timeout_t) rcv_timeout,
2188: FALSE, msg_receive_continue,
2189: &kmsg, &seqno);
2190: /* mqueue is unlocked */
2191: ipc_port_release(reply);
2192: if (mr != MACH_MSG_SUCCESS) {
2193: if (mr == MACH_RCV_TOO_LARGE) {
2194: msg_size_t real_size =
2195: (msg_size_t) (mach_msg_size_t) kmsg;
2196:
2197: assert(real_size > rcv_size);
2198:
2199: (void) copyout((vm_offset_t) &real_size,
2200: (vm_offset_t) &msg->msg_size,
2201: sizeof(msg_size_t));
2202: }
2203:
2204: return msg_return_translate(mr);
2205: }
2206:
2207: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
2208:
2209: mr = ipc_kmsg_copyout_compat(kmsg, space, map);
2210: assert(mr == MACH_MSG_SUCCESS);
2211:
2212: mr = ipc_kmsg_put((mach_msg_header_t *) msg,
2213: kmsg, kmsg->ikm_header.msgh_size);
2214: return msg_return_translate(mr);
2215: }
2216:
2217: #ifdef CONTINUATIONS
2218: /*
2219: * Routine: msg_receive_continue
2220: * Purpose:
2221: * Continue after blocking for a message.
2222: * Conditions:
2223: * Nothing locked. We are running on a new kernel stack,
2224: * with the receive state saved in the thread. From here
2225: * control goes back to user space.
2226: */
2227:
2228: void
2229: msg_receive_continue()
2230: {
2231: ipc_thread_t self = current_thread();
2232: msg_header_t *msg = (msg_header_t *) self->ith_msg;
2233: msg_option_t option = (msg_option_t) self->ith_option;
2234: msg_size_t rcv_size = (msg_size_t) self->ith_rcv_size;
2235: msg_timeout_t time_out = (msg_timeout_t) self->ith_timeout;
2236: ipc_object_t object = self->ith_object;
2237: ipc_mqueue_t mqueue = self->ith_mqueue;
2238: ipc_kmsg_t kmsg;
2239: mach_port_seqno_t seqno;
2240: mach_msg_return_t mr;
2241:
2242: mr = ipc_mqueue_receive(mqueue,
2243: (option & RCV_TIMEOUT) ?
2244: MACH_RCV_TIMEOUT : MACH_MSG_OPTION_NONE,
2245: (mach_msg_size_t) rcv_size,
2246: (mach_msg_timeout_t) time_out,
2247: TRUE, msg_receive_continue,
2248: &kmsg, &seqno);
2249: /* mqueue is unlocked */
2250: ipc_object_release(object);
2251: if (mr != MACH_MSG_SUCCESS) {
2252: if (mr == MACH_RCV_TOO_LARGE) {
2253: msg_size_t real_size =
2254: (msg_size_t) (mach_msg_size_t) kmsg;
2255:
2256: assert(real_size > rcv_size);
2257:
2258: (void) copyout((vm_offset_t) &real_size,
2259: (vm_offset_t) &msg->msg_size,
2260: sizeof(msg_size_t));
2261: }
2262:
2263: thread_syscall_return(msg_return_translate(mr));
2264: /*NOTREACHED*/
2265: }
2266:
2267: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
2268:
2269: mr = ipc_kmsg_copyout_compat(kmsg, current_space(), current_map());
2270: assert(mr == MACH_MSG_SUCCESS);
2271:
2272: mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
2273: kmsg->ikm_header.msgh_size);
2274: thread_syscall_return(msg_return_translate(mr));
2275: /*NOTREACHED*/
2276: }
2277: #endif /* CONTINUATIONS */
2278:
2279: #endif /* MACH_IPC_COMPAT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.