|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * File: ipc/mach_msg.c
54: * Author: Rich Draves
55: * Date: 1989
56: *
57: * Exported message traps. See mach/message.h.
58: */
59:
60: #include <cpus.h>
61: #include <dipc.h>
62: #include <mach_rt.h>
63:
64: #include <mach/kern_return.h>
65: #include <mach/port.h>
66: #include <mach/message.h>
67: #include <mach/mig_errors.h>
68: #include <kern/assert.h>
69: #include <kern/counters.h>
70: #include <kern/cpu_number.h>
71: #include <kern/task.h>
72: #include <kern/thread.h>
73: #include <kern/lock.h>
74: #include <kern/sched_prim.h>
75: #include <kern/exception.h>
76: #include <kern/misc_protos.h>
77: #include <vm/vm_map.h>
78: #include <ipc/ipc_kmsg.h>
79: #include <ipc/ipc_mqueue.h>
80: #include <ipc/ipc_object.h>
81: #include <ipc/ipc_notify.h>
82: #include <ipc/ipc_port.h>
83: #include <ipc/ipc_pset.h>
84: #include <ipc/ipc_space.h>
85: #include <ipc/ipc_entry.h>
86: #include <kern/kalloc.h>
87: #include <kern/thread_swap.h>
88: #include <kern/processor.h>
89: #include <kern/rtmalloc.h>
90:
91: #include <kern/sf.h>
92: #include <kern/mk_sp.h> /* JMM - to support handoff hack */
93:
94:
95: /*
96: * Forward declarations
97: */
98:
99: mach_msg_return_t mach_msg_send(
100: mach_msg_header_t *msg,
101: mach_msg_option_t option,
102: mach_msg_size_t send_size,
103: mach_msg_timeout_t timeout,
104: mach_port_name_t notify);
105:
106: mach_msg_return_t mach_msg_receive(
107: mach_msg_header_t *msg,
108: mach_msg_option_t option,
109: mach_msg_size_t rcv_size,
110: mach_port_name_t rcv_name,
111: mach_msg_timeout_t timeout,
112: mach_port_name_t notify,
113: mach_msg_size_t slist_size);
114:
115: mach_msg_return_t msg_receive_error(
116: ipc_kmsg_t kmsg,
117: mach_msg_header_t *msg,
118: mach_msg_option_t option,
119: mach_port_seqno_t seqno,
120: ipc_space_t space);
121:
122: /* the size of each trailer has to be listed here for copyout purposes */
123: mach_msg_trailer_size_t trailer_size[] = {
124: sizeof(mach_msg_trailer_t),
125: sizeof(mach_msg_seqno_trailer_t),
126: sizeof(mach_msg_security_trailer_t) };
127:
128: security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE;
129:
130: mach_msg_format_0_trailer_t trailer_template = {
131: /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0,
132: /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE,
133: /* mach_port_seqno_t */ 0,
134: /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE
135: };
136:
137: /*
138: * Routine: mach_msg_send
139: * Purpose:
140: * Send a message.
141: * Conditions:
142: * Nothing locked.
143: * Returns:
144: * MACH_MSG_SUCCESS Sent the message.
145: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
146: * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
147: * MACH_SEND_INVALID_DATA Couldn't copy message data.
148: * MACH_SEND_INVALID_HEADER
149: * Illegal value in the message header bits.
150: * MACH_SEND_INVALID_DEST The space is dead.
151: * MACH_SEND_INVALID_NOTIFY Bad notify port.
152: * MACH_SEND_INVALID_DEST Can't copyin destination port.
153: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
154: * MACH_SEND_TIMED_OUT Timeout expired without delivery.
155: * MACH_SEND_INTERRUPTED Delivery interrupted.
156: * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
157: * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
158: * MACH_SEND_NOTIFY_IN_PROGRESS
159: * This space has already forced a message to this port.
160: */
161:
162: mach_msg_return_t
163: mach_msg_send(
164: mach_msg_header_t *msg,
165: mach_msg_option_t option,
166: mach_msg_size_t send_size,
167: mach_msg_timeout_t timeout,
168: mach_port_name_t notify)
169: {
170: ipc_space_t space = current_space();
171: vm_map_t map = current_map();
172: ipc_kmsg_t kmsg;
173: mach_msg_return_t mr;
174:
175: mr = ipc_kmsg_get(msg, send_size, &kmsg, space);
176:
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_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, timeout);
193:
194: if (mr != MACH_MSG_SUCCESS) {
195: mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL);
196: (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
197: }
198:
199: return mr;
200: }
201:
202: #define FREE_SCATTER_LIST(s, l, rt) \
203: MACRO_BEGIN \
204: if((s) != MACH_MSG_BODY_NULL) { \
205: KFREE(((vm_offset_t)(s)), (l), rt); \
206: } \
207: MACRO_END
208:
209: /*
210: * Routine: mach_msg_receive
211: * Purpose:
212: * Receive a message.
213: * Conditions:
214: * Nothing locked.
215: * Returns:
216: * MACH_MSG_SUCCESS Received a message.
217: * MACH_RCV_INVALID_NAME The name doesn't denote a right,
218: * or the denoted right is not receive or port set.
219: * MACH_RCV_IN_SET Receive right is a member of a set.
220: * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
221: * MACH_RCV_TIMED_OUT Timeout expired without a message.
222: * MACH_RCV_INTERRUPTED Reception interrupted.
223: * MACH_RCV_PORT_DIED Port/set died while receiving.
224: * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
225: * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
226: * MACH_RCV_INVALID_NOTIFY Bad notify port.
227: * MACH_RCV_HEADER_ERROR
228: */
229:
230: mach_msg_return_t
231: mach_msg_receive(
232: mach_msg_header_t *msg,
233: mach_msg_option_t option,
234: mach_msg_size_t rcv_size,
235: mach_port_name_t rcv_name,
236: mach_msg_timeout_t timeout,
237: mach_port_name_t notify,
238: mach_msg_size_t slist_size)
239: {
240: thread_t self = current_thread();
241: ipc_space_t space = current_space();
242: vm_map_t map = current_map();
243: ipc_object_t object;
244: ipc_mqueue_t mqueue;
245: ipc_kmsg_t kmsg;
246: mach_port_seqno_t seqno;
247: mach_msg_return_t mr;
248: mach_msg_body_t *slist;
249: mach_msg_format_0_trailer_t *trailer;
250: #if MACH_RT
251: boolean_t slist_rt;
252: #endif /* MACH_RT */
253:
254: mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
255: if (mr != MACH_MSG_SUCCESS) {
256: return mr;
257: }
258: /* hold ref for object; mqueue is locked */
259:
260: #if MACH_RT
261: /* NOTE: This only works for true ports, and not port sets */
262: slist_rt = ipc_object_is_rt(object);
263: #endif /* MACH_RT */
264:
265: /*
266: * If MACH_RCV_OVERWRITE was specified, both receive_msg (msg)
267: * and receive_msg_size (slist_size) need to be non NULL.
268: */
269: if (option & MACH_RCV_OVERWRITE) {
270: if (slist_size < sizeof(mach_msg_base_t)) {
271: ipc_object_release(object);
272: return MACH_RCV_SCATTER_SMALL;
273: } else {
274: slist_size -= sizeof(mach_msg_header_t);
275: slist = (mach_msg_body_t *)KALLOC(slist_size, slist_rt);
276: if (slist == MACH_MSG_BODY_NULL ||
277: copyin((char *) (msg + 1), (char *)slist,
278: slist_size)) {
279: ipc_object_release(object);
280: return MACH_RCV_INVALID_DATA;
281: }
282: if ((slist->msgh_descriptor_count*
283: sizeof(mach_msg_descriptor_t)
284: + sizeof(mach_msg_size_t)) > slist_size) {
285: FREE_SCATTER_LIST(slist, slist_size, slist_rt);
286: ipc_object_release(object);
287: return MACH_RCV_INVALID_TYPE;
288: }
289: }
290: } else {
291: slist = MACH_MSG_BODY_NULL;
292: }
293:
294: self->ith_option = option;
295: self->ith_scatter_list = slist;
296: self->ith_scatter_list_size = slist_size;
297:
298: mr = ipc_mqueue_receive(mqueue, option, rcv_size,
299: timeout, THREAD_ABORTSAFE,
300: &kmsg, &seqno);
301:
302: ipc_object_release(object);
303:
304: if (mr != MACH_MSG_SUCCESS) {
305:
306: if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) {
307: if (option & MACH_RCV_LARGE) {
308: /*
309: * We need to inform the user-level code that it needs more
310: * space. The value for how much space was returned in the
311: * kmsg pointer instead of the message (which was left on the
312: * queue).
313: */
314: if (copyout((char *) &kmsg,
315: (char *) &msg->msgh_size,
316: sizeof(mach_msg_size_t)))
317: mr = MACH_RCV_INVALID_DATA;
318: return mr;
319: }
320:
321: if (msg_receive_error(kmsg, msg, option, seqno, space)
322: == MACH_RCV_INVALID_DATA)
323: mr = MACH_RCV_INVALID_DATA;
324: }
325:
326: FREE_SCATTER_LIST(slist, slist_size, slist_rt);
327: return mr;
328: }
329:
330: trailer = (mach_msg_format_0_trailer_t *)
331: ((vm_offset_t)&kmsg->ikm_header +
332: round_msg(kmsg->ikm_header.msgh_size));
333: if (option & MACH_RCV_TRAILER_MASK) {
334: trailer->msgh_seqno = seqno;
335: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
336: }
337:
338: if (option & MACH_RCV_NOTIFY) {
339: if (notify == MACH_PORT_NULL)
340: mr = MACH_RCV_INVALID_NOTIFY;
341: else
342: mr = ipc_kmsg_copyout(kmsg, space, map, notify, slist);
343: } else {
344: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, slist);
345: }
346: if (mr != MACH_MSG_SUCCESS) {
347: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
348: if (ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size +
349: trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA)
350: mr = MACH_RCV_INVALID_DATA;
351: }
352: else {
353: if (msg_receive_error(kmsg, msg, option, seqno, space)
354: == MACH_RCV_INVALID_DATA)
355: mr = MACH_RCV_INVALID_DATA;
356: }
357:
358: FREE_SCATTER_LIST(slist, slist_size, slist_rt);
359: return mr;
360: }
361: mr = ipc_kmsg_put(msg, kmsg,
362: kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size);
363: FREE_SCATTER_LIST(slist, slist_size, slist_rt);
364:
365: return mr;
366: }
367:
368:
369: /*
370: * Toggle this to compile the hotpath in/out
371: * If compiled in, the run-time toggle "enable_hotpath" below
372: * eases testing & debugging
373: */
374: #define ENABLE_HOTPATH 1 /* Hacked on for now */
375:
376: #ifndef ENABLE_HOTPATH
377: #if NCPUS == 1 && !MACH_RT
378: #define ENABLE_HOTPATH 1
379: #else /* NCPUS == 1 && !MACH_RT */
380: #define ENABLE_HOTPATH 0
381: #endif /* NCPUS == 1 && !MACH_RT */
382: #endif
383:
384: #if ENABLE_HOTPATH
385: /*
386: * These counters allow tracing of hotpath behavior under test loads.
387: * A couple key counters are unconditional (see below).
388: */
389: #define HOTPATH_DEBUG 0 /* Toggle to include lots of counters */
390: #if HOTPATH_DEBUG
391: #define HOT(expr) expr
392:
393: unsigned int c_mmot_FIRST = 0; /* Unused First Counter */
394: unsigned int c_mmot_combined_S_R = 0; /* hotpath candidates */
395: unsigned int c_mach_msg_trap_switch_fast = 0; /* hotpath successes */
396: unsigned int c_mmot_ikm_cache_miss = 0; /* Reasons to Fall Off: */
397: unsigned int c_mmot_kernel_send = 0; /* kernel server */
398: unsigned int c_mmot_cold_000 = 0; /* see below ... */
399: unsigned int c_mmot_smallsendsize = 0;
400: unsigned int c_mmot_oddsendsize = 0;
401: unsigned int c_mmot_bigsendsize = 0;
402: unsigned int c_mmot_copyinmsg_fail = 0;
403: unsigned int c_mmot_g_slow_copyin3 = 0;
404: unsigned int c_mmot_cold_006 = 0;
405: unsigned int c_mmot_cold_007 = 0;
406: unsigned int c_mmot_cold_008 = 0;
407: unsigned int c_mmot_cold_009 = 0;
408: unsigned int c_mmot_cold_010 = 0;
409: unsigned int c_mmot_cold_012 = 0;
410: unsigned int c_mmot_cold_013 = 0;
411: unsigned int c_mmot_cold_014 = 0;
412: unsigned int c_mmot_cold_016 = 0;
413: unsigned int c_mmot_cold_018 = 0;
414: unsigned int c_mmot_cold_019 = 0;
415: unsigned int c_mmot_cold_020 = 0;
416: unsigned int c_mmot_cold_021 = 0;
417: unsigned int c_mmot_cold_022 = 0;
418: unsigned int c_mmot_cold_023 = 0;
419: unsigned int c_mmot_cold_024 = 0;
420: unsigned int c_mmot_cold_025 = 0;
421: unsigned int c_mmot_cold_026 = 0;
422: unsigned int c_mmot_cold_027 = 0;
423: unsigned int c_mmot_hot_fSR_ok = 0;
424: unsigned int c_mmot_cold_029 = 0;
425: unsigned int c_mmot_cold_030 = 0;
426: unsigned int c_mmot_cold_031 = 0;
427: unsigned int c_mmot_cold_032 = 0;
428: unsigned int c_mmot_cold_033 = 0;
429: unsigned int c_mmot_bad_rcvr = 0;
430: unsigned int c_mmot_rcvr_swapped = 0;
431: unsigned int c_mmot_rcvr_locked = 0;
432: unsigned int c_mmot_rcvr_tswapped = 0;
433: unsigned int c_mmot_rcvr_freed = 0;
434: unsigned int c_mmot_g_slow_copyout6 = 0;
435: unsigned int c_mmot_g_slow_copyout5 = 0;
436: unsigned int c_mmot_cold_037 = 0;
437: unsigned int c_mmot_cold_038 = 0;
438: unsigned int c_mmot_cold_039 = 0;
439: unsigned int c_mmot_g_slow_copyout4 = 0;
440: unsigned int c_mmot_g_slow_copyout3 = 0;
441: unsigned int c_mmot_hot_ok1 = 0;
442: unsigned int c_mmot_hot_ok2 = 0;
443: unsigned int c_mmot_hot_ok3 = 0;
444: unsigned int c_mmot_g_slow_copyout1 = 0;
445: unsigned int c_mmot_g_slow_copyout2 = 0;
446: unsigned int c_mmot_getback_fast_copyin = 0;
447: unsigned int c_mmot_cold_048 = 0;
448: unsigned int c_mmot_getback_FastSR = 0;
449: unsigned int c_mmot_cold_050 = 0;
450: unsigned int c_mmot_cold_051 = 0;
451: unsigned int c_mmot_cold_052 = 0;
452: unsigned int c_mmot_cold_053 = 0;
453: unsigned int c_mmot_fastkernelreply = 0;
454: unsigned int c_mmot_cold_055 = 0;
455: unsigned int c_mmot_getback_fast_put = 0;
456: unsigned int c_mmot_LAST = 0; /* End Marker - Unused */
457:
458: void db_mmot_zero_counters(void); /* forward; */
459: void db_mmot_show_counters(void); /* forward; */
460:
461: void /* Call from the debugger to clear all counters */
462: db_mmot_zero_counters(void)
463: {
464: register unsigned int *ip = &c_mmot_FIRST;
465: while (ip <= &c_mmot_LAST)
466: *ip++ = 0;
467: }
468:
469: void /* Call from the debugger to show all counters */
470: db_mmot_show_counters(void)
471: {
472: #define xx(str) printf("%s: %d\n", # str, str);
473:
474: xx(c_mmot_combined_S_R);
475: xx(c_mach_msg_trap_switch_fast);
476: xx(c_mmot_ikm_cache_miss);
477: xx(c_mmot_kernel_send);
478: xx(c_mmot_cold_000);
479: xx(c_mmot_smallsendsize);
480: xx(c_mmot_oddsendsize);
481: xx(c_mmot_bigsendsize);
482: xx(c_mmot_copyinmsg_fail);
483: xx(c_mmot_g_slow_copyin3);
484: xx(c_mmot_cold_006);
485: xx(c_mmot_cold_007);
486: xx(c_mmot_cold_008);
487: xx(c_mmot_cold_009);
488: xx(c_mmot_cold_010);
489: xx(c_mmot_cold_012);
490: xx(c_mmot_cold_013);
491: xx(c_mmot_cold_014);
492: xx(c_mmot_cold_016);
493: xx(c_mmot_cold_018);
494: xx(c_mmot_cold_019);
495: xx(c_mmot_cold_020);
496: xx(c_mmot_cold_021);
497: xx(c_mmot_cold_022);
498: xx(c_mmot_cold_023);
499: xx(c_mmot_cold_024);
500: xx(c_mmot_cold_025);
501: xx(c_mmot_cold_026);
502: xx(c_mmot_cold_027);
503: xx(c_mmot_hot_fSR_ok);
504: xx(c_mmot_cold_029);
505: xx(c_mmot_cold_030);
506: xx(c_mmot_cold_031);
507: xx(c_mmot_cold_032);
508: xx(c_mmot_cold_033);
509: xx(c_mmot_bad_rcvr);
510: xx(c_mmot_rcvr_swapped);
511: xx(c_mmot_rcvr_locked);
512: xx(c_mmot_rcvr_tswapped);
513: xx(c_mmot_rcvr_freed);
514: xx(c_mmot_g_slow_copyout6);
515: xx(c_mmot_g_slow_copyout5);
516: xx(c_mmot_cold_037);
517: xx(c_mmot_cold_038);
518: xx(c_mmot_cold_039);
519: xx(c_mmot_g_slow_copyout4);
520: xx(c_mmot_g_slow_copyout3);
521: xx(c_mmot_g_slow_copyout1);
522: xx(c_mmot_hot_ok3);
523: xx(c_mmot_hot_ok2);
524: xx(c_mmot_hot_ok1);
525: xx(c_mmot_g_slow_copyout2);
526: xx(c_mmot_getback_fast_copyin);
527: xx(c_mmot_cold_048);
528: xx(c_mmot_getback_FastSR);
529: xx(c_mmot_cold_050);
530: xx(c_mmot_cold_051);
531: xx(c_mmot_cold_052);
532: xx(c_mmot_cold_053);
533: xx(c_mmot_fastkernelreply);
534: xx(c_mmot_cold_055);
535: xx(c_mmot_getback_fast_put);
536:
537: #undef xx
538: }
539:
540: #else /* !HOTPATH_DEBUG */
541:
542: /*
543: * Duplicate just these few so we can always do a quick sanity check
544: */
545: unsigned int c_mmot_combined_S_R = 0; /* hotpath candidates */
546: unsigned int c_mach_msg_trap_switch_fast = 0; /* hotpath successes */
547: unsigned int c_mmot_kernel_send = 0; /* kernel server calls */
548: #define HOT(expr) /* no optional counters */
549:
550: #endif /* !HOTPATH_DEBUG */
551:
552: boolean_t enable_hotpath = TRUE; /* Patchable, just in case ... */
553: #endif /* HOTPATH_ENABLE */
554:
555: /*
556: * Routine: mach_msg_overwrite_trap [mach trap]
557: * Purpose:
558: * Possibly send a message; possibly receive a message.
559: * Conditions:
560: * Nothing locked.
561: * Returns:
562: * All of mach_msg_send and mach_msg_receive error codes.
563: */
564:
565: mach_msg_return_t
566: mach_msg_overwrite_trap(
567: mach_msg_header_t *msg,
568: mach_msg_option_t option,
569: mach_msg_size_t send_size,
570: mach_msg_size_t rcv_size,
571: mach_port_name_t rcv_name,
572: mach_msg_timeout_t timeout,
573: mach_port_name_t notify,
574: mach_msg_header_t *rcv_msg,
575: mach_msg_size_t scatter_list_size)
576: {
577: register mach_msg_header_t *hdr;
578: mach_msg_return_t mr = MACH_MSG_SUCCESS;
579: /* mask out some of the options before entering the hot path */
580: mach_msg_option_t masked_option =
581: option & ~(MACH_SEND_TRAILER|MACH_RCV_TRAILER_MASK|MACH_RCV_LARGE);
582: int i;
583:
584: #if ENABLE_HOTPATH
585: /* BEGINNING OF HOT PATH */
586: if ((masked_option == (MACH_SEND_MSG|MACH_RCV_MSG)) && enable_hotpath) {
587: register thread_t self = current_thread();
588: register mach_msg_format_0_trailer_t *trailer;
589:
590: ipc_space_t space = current_act()->task->itk_space;
591: ipc_kmsg_t kmsg;
592: register ipc_port_t dest_port;
593: ipc_object_t rcv_object;
594: register ipc_mqueue_t rcv_mqueue;
595: mach_msg_size_t reply_size;
596: ipc_kmsg_t rcv_kmsg;
597:
598: c_mmot_combined_S_R++;
599: self->ith_scatter_list = MACH_MSG_BODY_NULL;
600:
601: /*
602: * This case is divided into ten sections, each
603: * with a label. There are five optimized
604: * sections and six unoptimized sections, which
605: * do the same thing but handle all possible
606: * cases and are slower.
607: *
608: * The five sections for an RPC are
609: * 1) Get request message into a buffer.
610: * (fast_get or slow_get)
611: * 2) Copyin request message and rcv_name.
612: * (fast_copyin or slow_copyin)
613: * 3) Enqueue request and dequeue reply.
614: * (fast_send_receive or
615: * slow_send and slow_receive)
616: * 4) Copyout reply message.
617: * (fast_copyout or slow_copyout)
618: * 5) Put reply message to user's buffer.
619: * (fast_put or slow_put)
620: *
621: * Keep the locking hierarchy firmly in mind.
622: * (First spaces, then ports, then port sets,
623: * then message queues.) Only a non-blocking
624: * attempt can be made to acquire locks out of
625: * order, or acquire two locks on the same level.
626: * Acquiring two locks on the same level will
627: * fail if the objects are really the same,
628: * unless simple locking is disabled. This is OK,
629: * because then the extra unlock does nothing.
630: *
631: * There are two major reasons these RPCs can't use
632: * ipc_thread_switch, and use slow_send/slow_receive:
633: * 1) Kernel RPCs.
634: * 2) Servers fall behind clients, so
635: * client doesn't find a blocked server thread and
636: * server finds waiting messages and can't block.
637: */
638:
639: fast_get:
640: /*
641: * optimized ipc_kmsg_get
642: *
643: * No locks, references, or messages held.
644: * We must clear ikm_cache before copyinmsg.
645: */
646:
647: if ((send_size < sizeof(mach_msg_header_t)) ||
648: (send_size & 3) ||
649: (send_size > (IKM_SAVED_MSG_SIZE - MAX_TRAILER_SIZE)) ||
650: !ikm_cache_get(&kmsg)) {
651: #if HOTPATH_DEBUG
652: if (send_size < sizeof(mach_msg_header_t)) {
653: HOT(c_mmot_smallsendsize++);
654: } else if (send_size & 3) {
655: HOT(c_mmot_oddsendsize++);
656: } else if (send_size >
657: (IKM_SAVED_MSG_SIZE - MAX_TRAILER_SIZE)) {
658: HOT(c_mmot_bigsendsize++);
659: } else if (!kmsg) {
660: HOT(c_mmot_ikm_cache_miss++);
661: }
662: #endif
663: goto slow_get;
664: }
665:
666: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
667:
668: hdr = &kmsg->ikm_header;
669: if (copyinmsg((char *) msg, (char *) hdr, send_size)) {
670: if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE ||
671: KMSG_IS_RT(kmsg) || !ikm_cache_put(kmsg))
672: ikm_free(kmsg);
673: HOT(c_mmot_copyinmsg_fail++);
674: goto slow_get;
675: }
676:
677: hdr->msgh_size = send_size;
678:
679: /* naturally align the message before tacking on the trailer */
680: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
681: send_size);
682: bcopy((char *)&trailer_template, (char *)trailer,
683: sizeof(trailer_template));
684: trailer->msgh_sender = current_act()->task->sec_token;
685:
686: fast_copyin:
687: /*
688: * optimized ipc_kmsg_copyin/ipc_mqueue_copyin
689: *
690: * We have the request message data in kmsg.
691: * Must still do copyin, send, receive, etc.
692: *
693: * If the message isn't simple, we can't combine
694: * ipc_kmsg_copyin_header and ipc_mqueue_copyin,
695: * because copyin of the message body might
696: * affect rcv_name.
697: */
698:
699: switch (hdr->msgh_bits) {
700: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
701: MACH_MSG_TYPE_MAKE_SEND_ONCE): {
702: register ipc_entry_t table;
703: register ipc_entry_num_t size;
704: register ipc_port_t reply_port;
705:
706: /* sending a request message */
707:
708: {
709: register mach_port_index_t index;
710: register mach_port_gen_t gen;
711:
712: {
713: register mach_port_name_t reply_name =
714: (mach_port_name_t)hdr->msgh_local_port;
715:
716: if (reply_name != rcv_name) {
717: HOT(c_mmot_g_slow_copyin3++);
718: goto slow_copyin;
719: }
720:
721: /* optimized ipc_entry_lookup of reply_name */
722:
723: index = MACH_PORT_INDEX(reply_name);
724: gen = MACH_PORT_GEN(reply_name);
725:
726: is_read_lock(space);
727: assert(space->is_active);
728:
729: size = space->is_table_size;
730: table = space->is_table;
731:
732: {
733: register ipc_entry_t entry;
734: register ipc_entry_bits_t bits;
735:
736: if (index < size) {
737: entry = &table[index];
738: bits = entry->ie_bits;
739: if (IE_BITS_GEN(bits) != gen ||
740: (bits & IE_BITS_COLLISION)) {
741: entry = IE_NULL;
742: }
743: } else {
744: entry = IE_NULL;
745: }
746: if (entry == IE_NULL) {
747: entry = ipc_entry_lookup(space, reply_name);
748: if (entry == IE_NULL) {
749: HOT(c_mmot_cold_006++);
750: goto abort_request_copyin;
751: }
752: bits = entry->ie_bits;
753: }
754:
755: /* check type bit */
756:
757: if (! (bits & MACH_PORT_TYPE_RECEIVE)) {
758: HOT(c_mmot_cold_007++);
759: goto abort_request_copyin;
760: }
761:
762: reply_port = (ipc_port_t) entry->ie_object;
763: assert(reply_port != IP_NULL);
764: }
765: }
766: }
767:
768: /* optimized ipc_entry_lookup of dest_name */
769:
770: {
771: register mach_port_index_t index;
772: register mach_port_gen_t gen;
773:
774: {
775: register mach_port_name_t dest_name =
776: (mach_port_name_t)hdr->msgh_remote_port;
777:
778: index = MACH_PORT_INDEX(dest_name);
779: gen = MACH_PORT_GEN(dest_name);
780:
781: {
782: register ipc_entry_t entry;
783: register ipc_entry_bits_t bits;
784:
785: if (index < size) {
786: entry = &table[index];
787: bits = entry->ie_bits;
788: if (IE_BITS_GEN(bits) != gen ||
789: (bits & IE_BITS_COLLISION)) {
790: entry = IE_NULL;
791: }
792: } else {
793: entry = IE_NULL;
794: }
795: if (entry == IE_NULL) {
796: entry = ipc_entry_lookup(space, dest_name);
797: if (entry == IE_NULL) {
798: HOT(c_mmot_cold_008++);
799: goto abort_request_copyin;
800: }
801: bits = entry->ie_bits;
802: }
803:
804: /* check type bit */
805:
806: if (! (bits & MACH_PORT_TYPE_SEND)) {
807: HOT(c_mmot_cold_009++);
808: goto abort_request_copyin;
809: }
810:
811: assert(IE_BITS_UREFS(bits) > 0);
812:
813: dest_port = (ipc_port_t) entry->ie_object;
814: assert(dest_port != IP_NULL);
815: }
816: }
817: }
818:
819: /*
820: * To do an atomic copyin, need simultaneous
821: * locks on both ports and the space. If
822: * dest_port == reply_port, and simple locking is
823: * enabled, then we will abort. Otherwise it's
824: * OK to unlock twice.
825: */
826:
827: ip_lock(dest_port);
828: if (!ip_active(dest_port) ||
829: !ip_lock_try(reply_port)) {
830: ip_unlock(dest_port);
831: HOT(c_mmot_cold_010++);
832: goto abort_request_copyin;
833: }
834: is_read_unlock(space);
835:
836: assert(dest_port->ip_srights > 0);
837: dest_port->ip_srights++;
838: ip_reference(dest_port);
839:
840: assert(ip_active(reply_port));
841: assert(reply_port->ip_receiver_name ==
842: (mach_port_name_t)hdr->msgh_local_port);
843: assert(reply_port->ip_receiver == space);
844:
845: reply_port->ip_sorights++;
846: ip_reference(reply_port);
847:
848: hdr->msgh_bits =
849: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
850: MACH_MSG_TYPE_PORT_SEND_ONCE);
851: hdr->msgh_remote_port = dest_port;
852: hdr->msgh_local_port = reply_port;
853:
854: /* make sure we can queue to the destination */
855:
856: if (dest_port->ip_receiver == ipc_space_kernel) {
857: /*
858: * The kernel server has a reference to
859: * the reply port, which it hands back
860: * to us in the reply message. We do
861: * not need to keep another reference to
862: * it.
863: */
864: ip_unlock(reply_port);
865:
866: assert(ip_active(dest_port));
867: dest_port->ip_messages.imq_seqno++;
868: ip_unlock(dest_port);
869: goto kernel_send;
870: }
871:
872: if (imq_full(&dest_port->ip_messages)) {
873: HOT(c_mmot_cold_013++);
874: goto abort_request_send_receive;
875: }
876:
877: /* optimized ipc_mqueue_copyin */
878:
879: if (reply_port->ip_pset_count != 0) {
880: HOT(c_mmot_cold_014++);
881: goto abort_request_send_receive;
882: }
883:
884: rcv_object = (ipc_object_t) reply_port;
885: io_reference(rcv_object);
886: rcv_mqueue = &reply_port->ip_messages;
887: imq_lock(rcv_mqueue);
888: io_unlock(rcv_object);
889: HOT(c_mmot_hot_fSR_ok++);
890: goto fast_send_receive;
891:
892: abort_request_copyin:
893: is_read_unlock(space);
894: goto slow_copyin;
895:
896: abort_request_send_receive:
897: ip_unlock(dest_port);
898: ip_unlock(reply_port);
899: goto slow_send;
900: }
901:
902: case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
903: register ipc_entry_num_t size;
904: register ipc_entry_t table;
905:
906: /* sending a reply message */
907:
908: {
909: register mach_port_name_t reply_name =
910: (mach_port_name_t)hdr->msgh_local_port;
911:
912: if (reply_name != MACH_PORT_NULL) {
913: HOT(c_mmot_cold_018++);
914: goto slow_copyin;
915: }
916: }
917:
918: is_write_lock(space);
919: assert(space->is_active);
920:
921: /* optimized ipc_entry_lookup */
922:
923: size = space->is_table_size;
924: table = space->is_table;
925:
926: {
927: register ipc_entry_t entry;
928: register mach_port_gen_t gen;
929: register mach_port_index_t index;
930: ipc_table_index_t *requests;
931:
932: {
933: register mach_port_name_t dest_name =
934: (mach_port_name_t)hdr->msgh_remote_port;
935:
936: index = MACH_PORT_INDEX(dest_name);
937: gen = MACH_PORT_GEN(dest_name);
938: }
939:
940: if (index >= size) {
941: HOT(c_mmot_cold_019++);
942: goto abort_reply_dest_copyin;
943: }
944:
945: entry = &table[index];
946:
947: /* check generation, collision bit, and type bit */
948:
949: if ((entry->ie_bits & (IE_BITS_GEN_MASK|
950: IE_BITS_COLLISION|
951: MACH_PORT_TYPE_SEND_ONCE)) !=
952: (gen | MACH_PORT_TYPE_SEND_ONCE)) {
953: HOT(c_mmot_cold_020++);
954: goto abort_reply_dest_copyin;
955: }
956:
957: /* optimized ipc_right_copyin */
958:
959: assert(IE_BITS_TYPE(entry->ie_bits) ==
960: MACH_PORT_TYPE_SEND_ONCE);
961: assert(IE_BITS_UREFS(entry->ie_bits) == 1);
962:
963: if (entry->ie_request != 0) {
964: HOT(c_mmot_cold_021++);
965: goto abort_reply_dest_copyin;
966: }
967:
968: dest_port = (ipc_port_t) entry->ie_object;
969: assert(dest_port != IP_NULL);
970:
971: ip_lock(dest_port);
972: if (!ip_active(dest_port)) {
973: ip_unlock(dest_port);
974: HOT(c_mmot_cold_022++);
975: goto abort_reply_dest_copyin;
976: }
977:
978: assert(dest_port->ip_sorights > 0);
979:
980: /* optimized ipc_entry_dealloc */
981:
982:
983: entry->ie_bits = gen;
984: entry->ie_next = table->ie_next;
985: table->ie_next = index;
986: entry->ie_object = IO_NULL;
987: }
988:
989: hdr->msgh_bits =
990: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
991: 0);
992: hdr->msgh_remote_port = dest_port;
993:
994: /* make sure we can queue to the destination */
995:
996: assert(dest_port->ip_receiver != ipc_space_kernel);
997:
998: /* optimized ipc_entry_lookup/ipc_mqueue_copyin */
999:
1000: {
1001: register ipc_entry_t entry;
1002: register ipc_entry_bits_t bits;
1003:
1004: {
1005: register mach_port_index_t index;
1006: register mach_port_gen_t gen;
1007:
1008: index = MACH_PORT_INDEX(rcv_name);
1009: gen = MACH_PORT_GEN(rcv_name);
1010:
1011: if (index < size) {
1012: entry = &table[index];
1013: bits = entry->ie_bits;
1014: if (IE_BITS_GEN(bits) != gen ||
1015: (bits & IE_BITS_COLLISION)) {
1016: entry = IE_NULL;
1017: }
1018: } else {
1019: entry = IE_NULL;
1020: }
1021: if (entry == IE_NULL) {
1022: entry = ipc_entry_lookup(space, rcv_name);
1023: if (entry == IE_NULL) {
1024: HOT(c_mmot_cold_024++);
1025: goto abort_reply_rcv_copyin;
1026: }
1027: bits = entry->ie_bits;
1028: }
1029:
1030: }
1031:
1032: /* check type bits; looking for receive or set */
1033:
1034: if (bits & MACH_PORT_TYPE_PORT_SET) {
1035: register ipc_pset_t rcv_pset;
1036:
1037: rcv_pset = (ipc_pset_t) entry->ie_object;
1038: assert(rcv_pset != IPS_NULL);
1039:
1040: ips_lock(rcv_pset);
1041: assert(ips_active(rcv_pset));
1042:
1043: rcv_object = (ipc_object_t) rcv_pset;
1044: rcv_mqueue = &rcv_pset->ips_messages;
1045: } else if (bits & MACH_PORT_TYPE_RECEIVE) {
1046: register ipc_port_t rcv_port;
1047:
1048: rcv_port = (ipc_port_t) entry->ie_object;
1049: assert(rcv_port != IP_NULL);
1050:
1051: if (!ip_lock_try(rcv_port)) {
1052: HOT(c_mmot_cold_025++);
1053: goto abort_reply_rcv_copyin;
1054: }
1055: assert(ip_active(rcv_port));
1056:
1057: if (rcv_port->ip_pset_count != 0) {
1058: ip_unlock(rcv_port);
1059: HOT(c_mmot_cold_026++);
1060: goto abort_reply_rcv_copyin;
1061: }
1062:
1063: rcv_object = (ipc_object_t) rcv_port;
1064: rcv_mqueue = &rcv_port->ip_messages;
1065: } else {
1066: HOT(c_mmot_cold_027++);
1067: goto abort_reply_rcv_copyin;
1068: }
1069: }
1070:
1071: is_write_unlock(space);
1072: io_reference(rcv_object);
1073: imq_lock(rcv_mqueue);
1074: io_unlock(rcv_object);
1075: HOT(c_mmot_hot_fSR_ok++);
1076: goto fast_send_receive;
1077:
1078: abort_reply_dest_copyin:
1079: is_write_unlock(space);
1080: HOT(c_mmot_cold_029++);
1081: goto slow_copyin;
1082:
1083: abort_reply_rcv_copyin:
1084: ip_unlock(dest_port);
1085: is_write_unlock(space);
1086: HOT(c_mmot_cold_030++);
1087: goto slow_send;
1088: }
1089:
1090: default:
1091: HOT(c_mmot_cold_031++);
1092: goto slow_copyin;
1093: }
1094: /*NOTREACHED*/
1095:
1096: fast_send_receive:
1097: /*
1098: * optimized ipc_mqueue_send/ipc_mqueue_receive
1099: *
1100: * Finished get/copyin of kmsg and copyin of rcv_name.
1101: * space is unlocked, dest_port is locked,
1102: * we can queue kmsg to dest_port,
1103: * rcv_mqueue is locked, rcv_object holds a ref,
1104: * if rcv_object is a port it isn't in a port set
1105: */
1106:
1107: assert(ip_active(dest_port));
1108: assert(dest_port->ip_receiver != ipc_space_kernel);
1109: assert(!imq_full(&dest_port->ip_messages) ||
1110: (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) ==
1111: MACH_MSG_TYPE_PORT_SEND_ONCE));
1112: assert((hdr->msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0);
1113:
1114: {
1115: register ipc_mqueue_t dest_mqueue;
1116: wait_queue_t waitq;
1117: thread_t receiver;
1118: spl_t s;
1119: #if THREAD_SWAPPER
1120: thread_act_t rcv_act;
1121: #endif
1122:
1123: dest_mqueue = &dest_port->ip_messages;
1124:
1125: if (!imq_lock_try(dest_mqueue)) {
1126: abort_send_receive:
1127: ip_unlock(dest_port);
1128: imq_unlock(rcv_mqueue);
1129: ipc_object_release(rcv_object);
1130: HOT(c_mmot_cold_032++);
1131: goto slow_send;
1132: }
1133: if (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages) != IKM_NULL) {
1134: imq_unlock(dest_mqueue);
1135: HOT(c_mmot_cold_033++);
1136: goto abort_send_receive;
1137: }
1138:
1139: waitq = &dest_mqueue->imq_wait_queue;
1140: s = splsched();
1141: wait_queue_peek_locked(waitq, IPC_MQUEUE_RECEIVE, &receiver, &waitq);
1142: /* queue still locked, thread locked - but still on q */
1143:
1144: if (receiver == THREAD_NULL) {
1145: splx(s);
1146: imq_unlock(dest_mqueue);
1147: HOT(c_mmot_cold_033++);
1148: goto abort_send_receive;
1149: }
1150:
1151: assert(receiver->wait_queue == waitq);
1152: assert(receiver->wait_event == IPC_MQUEUE_RECEIVE);
1153:
1154: /*
1155: * See if it is still running on another processor (trying to
1156: * block itself). If so, fall off.
1157: *
1158: * JMM - We have an opportunity here. Since the thread is locked
1159: * and we find it runnable, it must still be trying to get into
1160: * thread_block on itself. We could just "hand him the message"
1161: * and let him go (thread_go_locked()) and then fall down into a
1162: * slow receive for ourselves. Only his RECEIVE_TOO_LARGE handling
1163: * runs afoul of that. Clean this up!
1164: */
1165: if ((receiver->state & TH_RUN) != TH_WAIT) {
1166: assert(NCPUS > 1);
1167: HOT(c_mmot_cold_033++);
1168: fall_off:
1169: thread_unlock(receiver);
1170: if (waitq != &dest_mqueue->imq_wait_queue)
1171: wait_queue_unlock(waitq);
1172: splx(s);
1173: imq_unlock(dest_mqueue);
1174: goto abort_send_receive;
1175: }
1176:
1177: /*
1178: * Check that the receiver can stay on the hot path.
1179: */
1180: if ((send_size + REQUESTED_TRAILER_SIZE(receiver->ith_option)
1181: > receiver->ith_msize) ||
1182: (receiver->ith_option & MACH_RCV_NOTIFY) ||
1183: (receiver->ith_scatter_list != MACH_MSG_BODY_NULL)) {
1184: /*
1185: * The receiver can't accept the message.
1186: */
1187: HOT(c_mmot_bad_rcvr++);
1188: goto fall_off;
1189: }
1190:
1191: #if THREAD_SWAPPER
1192: /*
1193: * Receiver looks okay -- is it swapped in?
1194: */
1195: rpc_lock(receiver);
1196: rcv_act = receiver->top_act;
1197: if (rcv_act->swap_state != TH_SW_IN &&
1198: rcv_act->swap_state != TH_SW_UNSWAPPABLE) {
1199: rpc_unlock(receiver);
1200: HOT(c_mmot_rcvr_swapped++);
1201: goto fall_off;
1202: }
1203:
1204: /*
1205: * Make sure receiver stays swapped in (if we can).
1206: */
1207: if (!act_lock_try(rcv_act)) { /* out of order! */
1208: rpc_unlock(receiver);
1209: HOT(c_mmot_rcvr_locked++);
1210: goto fall_off;
1211: }
1212:
1213: /*
1214: * Check for task swapping in progress affecting
1215: * receiver. Since rcv_act is attached to a shuttle,
1216: * its swap_state is covered by shuttle's thread_lock()
1217: * (sigh).
1218: */
1219: if ((rcv_act->swap_state != TH_SW_IN &&
1220: rcv_act->swap_state != TH_SW_UNSWAPPABLE) ||
1221: rcv_act->ast & AST_SWAPOUT) {
1222: act_unlock(rcv_act);
1223: rpc_unlock(receiver);
1224: HOT(c_mmot_rcvr_tswapped++);
1225: goto fall_off;
1226: }
1227:
1228: /*
1229: * We don't need to make receiver unswappable here -- holding
1230: * act_lock() of rcv_act is sufficient to prevent either thread
1231: * or task swapping from changing its state (see swapout_scan(),
1232: * task_swapout()). Don't release lock till receiver's state
1233: * is consistent. Its task may then be marked for swapout,
1234: * but that's life.
1235: */
1236: rpc_unlock(receiver);
1237: /*
1238: * NB: act_lock(rcv_act) still held
1239: */
1240: #endif /* THREAD_SWAPPER */
1241:
1242: /* At this point we are committed to do the "handoff". */
1243: c_mach_msg_trap_switch_fast++;
1244:
1245: /*
1246: * JMM - Go ahead and pull the receiver from the runq. If the
1247: * runq wasn't the one for the mqueue, unlock it.
1248: */
1249: wait_queue_pull_thread_locked(waitq,
1250: receiver,
1251: (waitq != &dest_mqueue->imq_wait_queue));
1252:
1253: /*
1254: * Store the kmsg and seqno where the receiver can pick it up.
1255: */
1256: receiver->ith_state = MACH_MSG_SUCCESS;
1257: receiver->ith_kmsg = kmsg;
1258: receiver->ith_seqno = dest_mqueue->imq_seqno++;
1259: ipc_mqueue_release_msgcount(dest_mqueue);
1260: imq_unlock(dest_mqueue);
1261: ip_unlock(dest_port);
1262:
1263:
1264: /*
1265: * Put sender on reply port's queue.
1266: * Also save state that the sender of
1267: * our reply message needs to determine if it
1268: * can hand off directly back to us.
1269: */
1270:
1271: self->ith_state = MACH_RCV_IN_PROGRESS;
1272: self->ith_msize = rcv_size;
1273:
1274: self->ith_option = option;
1275: self->ith_scatter_list = MACH_MSG_BODY_NULL;
1276: self->ith_scatter_list_size = scatter_list_size;
1277:
1278: waitq = &rcv_mqueue->imq_wait_queue;
1279: wait_queue_assert_wait_locked(waitq,
1280: IPC_MQUEUE_RECEIVE,
1281: THREAD_ABORTSAFE,
1282: TRUE); /* unlock? */
1283: /* rcv_mqueue is unlocked */
1284:
1285: current_task()->messages_sent++;
1286:
1287: /*
1288: * Switch directly to receiving thread, and block
1289: * this thread as though it had called ipc_mqueue_receive.
1290: */
1291: {
1292: extern unsigned sched_tick; /* kern/sched_prim.c */
1293:
1294: /* from thread_block_reason() */
1295: ast_off(AST_QUANTUM|AST_BLOCK|AST_URGENT);
1296:
1297: /*
1298: * JMM - Hacked in version of setrun scheduler op
1299: * that doesn't try to put thread on a runq. Safe
1300: * for now because we only do this for sp_mk threads.
1301: */
1302: {
1303: mk_sp_info_t sched_info;
1304:
1305: assert(receiver->sp_info != SP_INFO_NULL);
1306: sched_info = (mk_sp_info_t)receiver->sp_info;
1307: sched_info->th_state = MK_SP_RUNNABLE;
1308: }
1309:
1310: assert((receiver->state & (TH_RUN|TH_WAIT)) == TH_WAIT);
1311: assert(receiver != self);
1312:
1313: receiver->state &= ~(TH_WAIT|TH_UNINT);
1314:
1315: receiver->state |= TH_RUN;
1316: receiver->wait_result = THREAD_AWAKENED;
1317: #if NCPUS > 1 /* from thread_invoke inline */
1318: mp_disable_preemption();
1319: receiver->last_processor = current_processor();
1320: mp_enable_preemption();
1321: #endif /* NCPUS > 1 */
1322: thread_unlock(receiver);
1323: assert( receiver != self );
1324: #if THREAD_SWAPPER
1325: act_unlock(rcv_act);
1326: #endif /* THREAD_SWAPPER */
1327:
1328: /*
1329: * Prepare self (the sender) to block.
1330: */
1331: thread_lock(self);
1332:
1333: assert(!(self->state & TH_ABORT));
1334: assert(self->wait_result = -1); /* for assertions */
1335: assert(self->state & TH_RUN);
1336: self->state |= TH_WAIT;
1337: self->reason = 0; /* inline thread_invoke */
1338: thread_unlock(self);
1339:
1340: /*
1341: * Switch to the receiver now.
1342: * Inlined: thread_invoke(self, receiver, 0);
1343: */
1344: {
1345: thread_t old_thread;
1346: sched_policy_t *policy;
1347: sf_return_t sfr;
1348:
1349: mp_disable_preemption();
1350: ast_context(receiver->top_act, cpu_number());
1351: timer_switch(&receiver->system_timer);
1352:
1353: current_task()->csw++;
1354:
1355: policy = &sched_policy[self->policy];
1356: sfr = policy->sp_ops.sp_thread_done(policy, self);
1357: assert(sfr == SF_SUCCESS);
1358:
1359: old_thread = switch_context(self, 0, receiver);
1360:
1361: /* We're back! */
1362: assert(current_thread() == self);
1363: policy = &sched_policy[self->policy];
1364: sfr = policy->sp_ops.sp_thread_begin(policy, self);
1365: assert(sfr == SF_SUCCESS);
1366:
1367: assert(old_thread != self);
1368: thread_dispatch(old_thread);
1369: enable_preemption();
1370: }
1371:
1372: splx(s);
1373: }
1374:
1375: switch (self->wait_result) {
1376:
1377: case THREAD_INTERRUPTED:
1378: ipc_object_release(rcv_object);
1379: return MACH_RCV_INTERRUPTED;
1380:
1381: case THREAD_RESTART:
1382: /*
1383: * something bad happened to the port/set. If the port
1384: * is still active, it must have just changed membership.
1385: */
1386: if (!io_active(rcv_object)) {
1387: ipc_object_release(rcv_object);
1388: return MACH_RCV_PORT_DIED;
1389: } else {
1390: ipc_object_release(rcv_object);
1391: return MACH_RCV_PORT_CHANGED;
1392: }
1393:
1394: case THREAD_AWAKENED:
1395: ipc_object_release(rcv_object);
1396: break;
1397:
1398: default:
1399: panic("mmot_hotpath: bad wait result");
1400: }
1401:
1402:
1403: /*
1404: * If we allowed for just a receive too large indication
1405: * and we got one, copy out the size (stored in our kmsg
1406: * pointer) instead of the message. If we got the error,
1407: * but didn't set the flag, we just need to try the copy
1408: * out of the message and see where that takes us.
1409: */
1410: if ((option & MACH_RCV_LARGE) &&
1411: (self->ith_state == MACH_RCV_TOO_LARGE)) {
1412: mach_msg_header_t *out_msg;
1413:
1414: out_msg = (rcv_msg != MACH_MSG_NULL)?rcv_msg:msg;
1415: if (copyout((char *) &self->ith_kmsg,
1416: (char *) &msg->msgh_size,
1417: sizeof(mach_msg_size_t)))
1418: return MACH_RCV_INVALID_DATA;
1419: return MACH_RCV_TOO_LARGE;
1420: }
1421:
1422:
1423: /*
1424: * Restore state saved in sending thread's send path.
1425: */
1426: kmsg = self->ith_kmsg;
1427: assert(kmsg != IKM_NULL);
1428: dest_port = (ipc_port_t)kmsg->ikm_header.msgh_remote_port;
1429:
1430: {
1431: ip_lock(dest_port);
1432: assert(dest_port->ip_messages.imq_msgcount > 0);
1433: dest_port->ip_messages.imq_msgcount--;
1434: ip_unlock(dest_port);
1435: }
1436:
1437: hdr = &kmsg->ikm_header;
1438: send_size = hdr->msgh_size;
1439: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
1440: round_msg(send_size));
1441:
1442: if (option & MACH_RCV_TRAILER_MASK) {
1443: trailer->msgh_seqno = self->ith_seqno;
1444: trailer->msgh_trailer_size =
1445: REQUESTED_TRAILER_SIZE(option);
1446: }
1447: }
1448:
1449: fast_copyout:
1450: /*
1451: * Nothing locked and no references held, except
1452: * we have kmsg with msgh_seqno filled in. Must
1453: * still check against rcv_size and do
1454: * ipc_kmsg_copyout/ipc_kmsg_put.
1455: */
1456:
1457: reply_size = send_size + trailer->msgh_trailer_size;
1458: if (rcv_size < reply_size) {
1459: HOT(c_mmot_g_slow_copyout6++);
1460: goto slow_copyout;
1461: }
1462:
1463: /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */
1464:
1465: switch (hdr->msgh_bits) {
1466: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
1467: MACH_MSG_TYPE_PORT_SEND_ONCE): {
1468: ipc_port_t reply_port =
1469: (ipc_port_t) hdr->msgh_local_port;
1470: mach_port_name_t dest_name, reply_name;
1471:
1472: /* receiving a request message */
1473:
1474: if (!IP_VALID(reply_port)) {
1475: HOT(c_mmot_g_slow_copyout5++);
1476: goto slow_copyout;
1477: }
1478:
1479: is_write_lock(space);
1480: assert(space->is_active);
1481:
1482: /*
1483: * To do an atomic copyout, need simultaneous
1484: * locks on both ports and the space. If
1485: * dest_port == reply_port, and simple locking is
1486: * enabled, then we will abort. Otherwise it's
1487: * OK to unlock twice.
1488: */
1489:
1490: ip_lock(dest_port);
1491: if (!ip_active(dest_port) ||
1492: !ip_lock_try(reply_port)) {
1493: HOT(c_mmot_cold_037++);
1494: goto abort_request_copyout;
1495: }
1496:
1497: if (!ip_active(reply_port)) {
1498: ip_unlock(reply_port);
1499: HOT(c_mmot_cold_038++);
1500: goto abort_request_copyout;
1501: }
1502:
1503: assert(reply_port->ip_sorights > 0);
1504: ip_unlock(reply_port);
1505:
1506: {
1507: register ipc_entry_t table;
1508: register ipc_entry_t entry;
1509: register mach_port_index_t index;
1510:
1511: /* optimized ipc_entry_get */
1512:
1513: table = space->is_table;
1514: index = table->ie_next;
1515:
1516: if (index == 0) {
1517: HOT(c_mmot_cold_039++);
1518: goto abort_request_copyout;
1519: }
1520:
1521: entry = &table[index];
1522: table->ie_next = entry->ie_next;
1523: entry->ie_request = 0;
1524:
1525: {
1526: register mach_port_gen_t gen;
1527:
1528: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
1529: gen = IE_BITS_NEW_GEN(entry->ie_bits);
1530:
1531: reply_name = MACH_PORT_MAKE(index, gen);
1532:
1533: /* optimized ipc_right_copyout */
1534:
1535: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
1536: }
1537:
1538: assert(MACH_PORT_VALID(reply_name));
1539: entry->ie_object = (ipc_object_t) reply_port;
1540: is_write_unlock(space);
1541: }
1542:
1543: /* optimized ipc_object_copyout_dest */
1544:
1545: assert(dest_port->ip_srights > 0);
1546: ip_release(dest_port);
1547:
1548: if (dest_port->ip_receiver == space)
1549: dest_name = dest_port->ip_receiver_name;
1550: else
1551: dest_name = MACH_PORT_NULL;
1552:
1553: if ((--dest_port->ip_srights == 0) &&
1554: (dest_port->ip_nsrequest != IP_NULL)) {
1555: ipc_port_t nsrequest;
1556: mach_port_mscount_t mscount;
1557:
1558: /* a rather rare case */
1559:
1560: nsrequest = dest_port->ip_nsrequest;
1561: mscount = dest_port->ip_mscount;
1562: dest_port->ip_nsrequest = IP_NULL;
1563: ip_unlock(dest_port);
1564: ipc_notify_no_senders(nsrequest, mscount);
1565: } else
1566: ip_unlock(dest_port);
1567:
1568: hdr->msgh_bits =
1569: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
1570: MACH_MSG_TYPE_PORT_SEND);
1571: hdr->msgh_remote_port = (mach_port_t)reply_name;
1572: hdr->msgh_local_port = (mach_port_t)dest_name;
1573: HOT(c_mmot_hot_ok1++);
1574: goto fast_put;
1575:
1576: abort_request_copyout:
1577: ip_unlock(dest_port);
1578: is_write_unlock(space);
1579: HOT(c_mmot_g_slow_copyout4++);
1580: goto slow_copyout;
1581: }
1582:
1583: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1584: register mach_port_name_t dest_name;
1585:
1586: /* receiving a reply message */
1587:
1588: ip_lock(dest_port);
1589: if (!ip_active(dest_port)) {
1590: ip_unlock(dest_port);
1591: HOT(c_mmot_g_slow_copyout3++);
1592: goto slow_copyout;
1593: }
1594:
1595: /* optimized ipc_object_copyout_dest */
1596:
1597: assert(dest_port->ip_sorights > 0);
1598:
1599: if (dest_port->ip_receiver == space) {
1600: ip_release(dest_port);
1601: dest_port->ip_sorights--;
1602: dest_name = dest_port->ip_receiver_name;
1603: ip_unlock(dest_port);
1604: } else {
1605: ip_unlock(dest_port);
1606:
1607: ipc_notify_send_once(dest_port);
1608: dest_name = MACH_PORT_NULL;
1609: }
1610:
1611: hdr->msgh_bits = MACH_MSGH_BITS(0,
1612: MACH_MSG_TYPE_PORT_SEND_ONCE);
1613: hdr->msgh_remote_port = MACH_PORT_NULL;
1614: hdr->msgh_local_port = (ipc_port_t)dest_name;
1615: HOT(c_mmot_hot_ok2++);
1616: goto fast_put;
1617: }
1618:
1619: case MACH_MSGH_BITS_COMPLEX|
1620: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1621: register mach_port_name_t dest_name;
1622:
1623: /* receiving a complex reply message */
1624:
1625: ip_lock(dest_port);
1626: if (!ip_active(dest_port)) {
1627: ip_unlock(dest_port);
1628: HOT(c_mmot_g_slow_copyout1++);
1629: goto slow_copyout;
1630: }
1631:
1632: /* optimized ipc_object_copyout_dest */
1633:
1634: assert(dest_port->ip_sorights > 0);
1635:
1636: if (dest_port->ip_receiver == space) {
1637: ip_release(dest_port);
1638: dest_port->ip_sorights--;
1639: dest_name = dest_port->ip_receiver_name;
1640: ip_unlock(dest_port);
1641: } else {
1642: ip_unlock(dest_port);
1643:
1644: ipc_notify_send_once(dest_port);
1645: dest_name = MACH_PORT_NULL;
1646: }
1647:
1648: hdr->msgh_bits =
1649: MACH_MSGH_BITS_COMPLEX |
1650: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE);
1651: hdr->msgh_remote_port = MACH_PORT_NULL;
1652: hdr->msgh_local_port = (mach_port_t)dest_name;
1653:
1654: mr = ipc_kmsg_copyout_body(kmsg, space,
1655: current_map(),
1656: MACH_MSG_BODY_NULL);
1657: if (mr != MACH_MSG_SUCCESS) {
1658: if (ipc_kmsg_put(msg, kmsg, hdr->msgh_size +
1659: trailer->msgh_trailer_size) ==
1660: MACH_RCV_INVALID_DATA)
1661: return MACH_RCV_INVALID_DATA;
1662: else
1663: return mr | MACH_RCV_BODY_ERROR;
1664: }
1665: HOT(c_mmot_hot_ok3++);
1666: goto fast_put;
1667: }
1668:
1669: default:
1670: HOT(c_mmot_g_slow_copyout2++);
1671: goto slow_copyout;
1672: }
1673: /*NOTREACHED*/ panic("happy birthday rwd");
1674:
1675: fast_put:
1676: /*
1677: * We have the reply message data in kmsg,
1678: * and the reply message size (plus trailer size)
1679: * in reply_size. Just need to copy it out to the
1680: * user and free kmsg. Must check ikm_cache after
1681: * copyoutmsg. Inlined ipc_kmsg_put() here.
1682: */
1683: mr = MACH_MSG_SUCCESS;
1684: if (copyoutmsg((char *) &kmsg->ikm_header,
1685: (char *)(rcv_msg ? rcv_msg : msg),
1686: hdr->msgh_size + trailer->msgh_trailer_size))
1687: mr = MACH_RCV_INVALID_DATA;
1688: else
1689: current_task()->messages_received++;
1690:
1691: if ((kmsg->ikm_size != IKM_SAVED_KMSG_SIZE) ||
1692: KMSG_IS_RT(kmsg) || !ikm_cache_put(kmsg)) {
1693: ikm_free(kmsg);
1694: }
1695:
1696: return(mr);
1697:
1698:
1699: /* BEGINNING OF WARM PATH */
1700:
1701: /*
1702: * The slow path has a few non-register temporary
1703: * variables used only for call-by-reference.
1704: */
1705:
1706: {
1707: ipc_kmsg_t temp_kmsg;
1708: mach_port_seqno_t temp_seqno;
1709: ipc_object_t temp_rcv_object;
1710: ipc_mqueue_t temp_rcv_mqueue;
1711:
1712: slow_get:
1713: /*
1714: * No locks, references, or messages held.
1715: * Still have to get the request, send it,
1716: * receive reply, etc.
1717: */
1718:
1719: mr = ipc_kmsg_get(msg, send_size, &temp_kmsg, current_space());
1720: if (mr != MACH_MSG_SUCCESS) {
1721: return(mr);
1722: /*NOTREACHED*/
1723: }
1724: kmsg = temp_kmsg;
1725: hdr = &kmsg->ikm_header;
1726: /* naturally align the message before tacking on the trailer */
1727: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
1728: send_size);
1729: /* try to get back on optimized path */
1730: HOT(c_mmot_getback_fast_copyin++);
1731: goto fast_copyin;
1732:
1733: slow_copyin:
1734: /*
1735: * We have the message data in kmsg, but
1736: * we still need to copyin, send it,
1737: * receive a reply, and do copyout.
1738: */
1739:
1740: mr = ipc_kmsg_copyin(kmsg, space, current_map(),
1741: MACH_PORT_NULL);
1742: if (mr != MACH_MSG_SUCCESS) {
1743: if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE ||
1744: KMSG_IS_RT(kmsg) || !ikm_cache_put(kmsg))
1745: ikm_free(kmsg);
1746: return(mr);
1747: }
1748:
1749: /* try to get back on optimized path */
1750:
1751: if (hdr->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
1752: HOT(c_mmot_cold_048++);
1753: goto slow_send;
1754: }
1755:
1756: dest_port = (ipc_port_t) hdr->msgh_remote_port;
1757: assert(IP_VALID(dest_port));
1758:
1759: ip_lock(dest_port);
1760: if (!ip_active(dest_port)) {
1761: ip_unlock(dest_port);
1762: goto slow_send;
1763: }
1764:
1765: if (dest_port->ip_receiver == ipc_space_kernel) {
1766: dest_port->ip_messages.imq_seqno++;
1767: ip_unlock(dest_port);
1768: goto kernel_send;
1769: }
1770:
1771: if (!imq_full(&dest_port->ip_messages) ||
1772: (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) ==
1773: MACH_MSG_TYPE_PORT_SEND_ONCE))
1774: {
1775: /*
1776: * Try an optimized ipc_mqueue_copyin.
1777: * It will work if this is a request message.
1778: */
1779:
1780: register ipc_port_t reply_port;
1781:
1782: reply_port = (ipc_port_t) hdr->msgh_local_port;
1783: if (IP_VALID(reply_port)) {
1784: if (ip_lock_try(reply_port)) {
1785: if (ip_active(reply_port) &&
1786: reply_port->ip_receiver == space &&
1787: reply_port->ip_receiver_name == rcv_name &&
1788: reply_port->ip_pset_count == 0)
1789: {
1790: /* Grab a reference to the reply port. */
1791: rcv_object = (ipc_object_t) reply_port;
1792: io_reference(rcv_object);
1793: rcv_mqueue = &reply_port->ip_messages;
1794: imq_lock(rcv_mqueue);
1795: io_unlock(rcv_object);
1796: HOT(c_mmot_getback_FastSR++);
1797: goto fast_send_receive;
1798: }
1799: ip_unlock(reply_port);
1800: }
1801: }
1802: }
1803:
1804: ip_unlock(dest_port);
1805: HOT(c_mmot_cold_050++);
1806: goto slow_send;
1807:
1808: kernel_send:
1809: /*
1810: * Special case: send message to kernel services.
1811: * The request message has been copied into the
1812: * kmsg. Nothing is locked.
1813: */
1814:
1815: {
1816: register ipc_port_t reply_port;
1817: mach_port_seqno_t local_seqno;
1818:
1819: /*
1820: * Perform the kernel function.
1821: */
1822: c_mmot_kernel_send++;
1823:
1824: current_task()->messages_sent++;
1825:
1826: kmsg = ipc_kobject_server(kmsg);
1827: if (kmsg == IKM_NULL) {
1828: /*
1829: * No reply. Take the
1830: * slow receive path.
1831: */
1832: HOT(c_mmot_cold_051++);
1833: goto slow_get_rcv_port;
1834: }
1835:
1836: /*
1837: * Check that:
1838: * the reply port is alive
1839: * we hold the receive right
1840: * the name has not changed.
1841: * the port is not in a set
1842: * If any of these are not true,
1843: * we cannot directly receive the reply
1844: * message.
1845: */
1846: hdr = &kmsg->ikm_header;
1847: send_size = hdr->msgh_size;
1848: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
1849: round_msg(send_size));
1850: reply_port = (ipc_port_t) hdr->msgh_remote_port;
1851: ip_lock(reply_port);
1852:
1853: if ((!ip_active(reply_port)) ||
1854: (reply_port->ip_receiver != space) ||
1855: (reply_port->ip_receiver_name != rcv_name) ||
1856: (reply_port->ip_pset_count != 0))
1857: {
1858: ip_unlock(reply_port);
1859: ipc_kmsg_send_always(kmsg);
1860: HOT(c_mmot_cold_052++);
1861: goto slow_get_rcv_port;
1862: }
1863:
1864: rcv_mqueue = &reply_port->ip_messages;
1865: imq_lock(rcv_mqueue);
1866: /* keep port locked, and don`t change ref count yet */
1867:
1868: /*
1869: * If there are messages on the port
1870: * or other threads waiting for a message,
1871: * we cannot directly receive the reply.
1872: */
1873: if (!wait_queue_empty(&rcv_mqueue->imq_wait_queue) ||
1874: (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages) != IKM_NULL))
1875: {
1876: imq_unlock(rcv_mqueue);
1877: ip_unlock(reply_port);
1878: ipc_kmsg_send_always(kmsg);
1879: HOT(c_mmot_cold_053++);
1880: goto slow_get_rcv_port;
1881: }
1882:
1883: /*
1884: * We can directly receive this reply.
1885: * Since there were no messages queued
1886: * on the reply port, there should be
1887: * no threads blocked waiting to send.
1888: */
1889: dest_port = reply_port;
1890: local_seqno = rcv_mqueue->imq_seqno++;
1891: imq_unlock(rcv_mqueue);
1892:
1893: /*
1894: * inline ipc_object_release.
1895: * Port is still locked.
1896: * Reference count was not incremented.
1897: */
1898: ip_check_unlock(reply_port);
1899:
1900: if (option & MACH_RCV_TRAILER_MASK) {
1901: trailer->msgh_seqno = local_seqno;
1902: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
1903: }
1904: /* copy out the kernel reply */
1905: HOT(c_mmot_fastkernelreply++);
1906: goto fast_copyout;
1907: }
1908:
1909: slow_send:
1910: /*
1911: * Nothing is locked. We have acquired kmsg, but
1912: * we still need to send it and receive a reply.
1913: */
1914:
1915: mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE,
1916: MACH_MSG_TIMEOUT_NONE);
1917: if (mr != MACH_MSG_SUCCESS) {
1918: mr |= ipc_kmsg_copyout_pseudo(kmsg, space,
1919: current_map(),
1920: MACH_MSG_BODY_NULL);
1921:
1922: (void) ipc_kmsg_put(msg, kmsg, hdr->msgh_size);
1923: return(mr);
1924: }
1925:
1926: slow_get_rcv_port:
1927: /*
1928: * We have sent the message. Copy in the receive port.
1929: */
1930: mr = ipc_mqueue_copyin(space, rcv_name,
1931: &temp_rcv_mqueue, &temp_rcv_object);
1932: if (mr != MACH_MSG_SUCCESS) {
1933: return(mr);
1934: }
1935: rcv_mqueue = temp_rcv_mqueue;
1936: rcv_object = temp_rcv_object;
1937: /* hold ref for rcv_object */
1938:
1939: slow_receive:
1940: /*
1941: * Now we have sent the request and copied in rcv_name,
1942: * so rcv_mqueue is locked and hold ref for rcv_object.
1943: * Just receive a reply and try to get back to fast path.
1944: */
1945:
1946: self->ith_option = option;
1947: self->ith_scatter_list = MACH_MSG_BODY_NULL;
1948: self->ith_scatter_list_size = scatter_list_size;
1949:
1950: mr = ipc_mqueue_receive(rcv_mqueue,
1951: MACH_MSG_OPTION_NONE,
1952: MACH_MSG_SIZE_MAX,
1953: MACH_MSG_TIMEOUT_NONE,
1954: THREAD_ABORTSAFE,
1955: &temp_kmsg, &temp_seqno);
1956: ipc_object_release(rcv_object);
1957:
1958: if (mr != MACH_MSG_SUCCESS) {
1959: return(mr);
1960: }
1961:
1962: kmsg = temp_kmsg;
1963: hdr = &kmsg->ikm_header;
1964: send_size = hdr->msgh_size;
1965: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
1966: round_msg(send_size));
1967: if (option & MACH_RCV_TRAILER_MASK) {
1968: trailer->msgh_seqno = temp_seqno;
1969: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
1970: }
1971: dest_port = (ipc_port_t) hdr->msgh_remote_port;
1972: HOT(c_mmot_cold_055++);
1973: goto fast_copyout;
1974:
1975: slow_copyout:
1976: /*
1977: * Nothing locked and no references held, except
1978: * we have kmsg with msgh_seqno filled in. Must
1979: * still check against rcv_size and do
1980: * ipc_kmsg_copyout/ipc_kmsg_put.
1981: */
1982:
1983: reply_size = send_size + trailer->msgh_trailer_size;
1984: if (rcv_size < reply_size) {
1985: if (msg_receive_error(kmsg, msg, option, temp_seqno,
1986: space) == MACH_RCV_INVALID_DATA) {
1987: mr = MACH_RCV_INVALID_DATA;
1988: return(mr);
1989: }
1990: else {
1991: mr = MACH_RCV_TOO_LARGE;
1992: return(mr);
1993: }
1994: }
1995:
1996: mr = ipc_kmsg_copyout(kmsg, space, current_map(),
1997: MACH_PORT_NULL, MACH_MSG_BODY_NULL);
1998: if (mr != MACH_MSG_SUCCESS) {
1999: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
2000: if (ipc_kmsg_put(msg, kmsg, reply_size) ==
2001: MACH_RCV_INVALID_DATA)
2002: mr = MACH_RCV_INVALID_DATA;
2003: }
2004: else {
2005: if (msg_receive_error(kmsg, msg, option,
2006: temp_seqno, space) == MACH_RCV_INVALID_DATA)
2007: mr = MACH_RCV_INVALID_DATA;
2008: }
2009:
2010: return(mr);
2011: }
2012:
2013: /* try to get back on optimized path */
2014: HOT(c_mmot_getback_fast_put++);
2015: goto fast_put;
2016:
2017: slow_put:
2018: mr = ipc_kmsg_put((rcv_msg != MACH_MSG_NULL)?rcv_msg:msg,
2019: kmsg,
2020: hdr->msgh_size + trailer->msgh_trailer_size);
2021: return(mr);
2022: /*NOTREACHED*/
2023: }
2024: } /* END OF HOT PATH */
2025: #endif /* ENABLE_HOTPATH */
2026:
2027: if (option & MACH_SEND_MSG) {
2028: mr = mach_msg_send(msg, option, send_size,
2029: timeout, notify);
2030: if (mr != MACH_MSG_SUCCESS) {
2031: return mr;
2032: }
2033: }
2034:
2035: if (option & MACH_RCV_MSG) {
2036: mach_msg_header_t *rcv;
2037:
2038: /*
2039: * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
2040: * and receive buffer
2041: * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
2042: * alternate receive buffer (separate send and receive buffers).
2043: */
2044: if (option & MACH_RCV_OVERWRITE)
2045: rcv = rcv_msg;
2046: else if (rcv_msg != MACH_MSG_NULL)
2047: rcv = rcv_msg;
2048: else
2049: rcv = msg;
2050: mr = mach_msg_receive(rcv, option, rcv_size, rcv_name,
2051: timeout, notify, scatter_list_size);
2052: if (mr != MACH_MSG_SUCCESS) {
2053: return mr;
2054: }
2055: }
2056:
2057: return MACH_MSG_SUCCESS;
2058: }
2059:
2060: /*
2061: * Routine: msg_receive_error [internal]
2062: * Purpose:
2063: * Builds a minimal header/trailer and copies it to
2064: * the user message buffer. Invoked when in the case of a
2065: * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
2066: * Conditions:
2067: * Nothing locked.
2068: * Returns:
2069: * MACH_MSG_SUCCESS minimal header/trailer copied
2070: * MACH_RCV_INVALID_DATA copyout to user buffer failed
2071: */
2072:
2073: mach_msg_return_t
2074: msg_receive_error(
2075: ipc_kmsg_t kmsg,
2076: mach_msg_header_t *msg,
2077: mach_msg_option_t option,
2078: mach_port_seqno_t seqno,
2079: ipc_space_t space)
2080: {
2081: mach_msg_format_0_trailer_t *trailer;
2082:
2083: /*
2084: * Copy out the destination port in the message.
2085: * Destroy all other rights and memory in the message.
2086: */
2087: ipc_kmsg_copyout_dest(kmsg, space);
2088:
2089: /*
2090: * Build a minimal message with the requested trailer.
2091: */
2092: trailer = (mach_msg_format_0_trailer_t *)
2093: ((vm_offset_t)&kmsg->ikm_header +
2094: round_msg(sizeof(mach_msg_header_t)));
2095: kmsg->ikm_header.msgh_size = sizeof(mach_msg_header_t);
2096: bcopy( (char *)&trailer_template,
2097: (char *)trailer,
2098: sizeof(trailer_template));
2099: if (option & MACH_RCV_TRAILER_MASK) {
2100: trailer->msgh_seqno = seqno;
2101: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
2102: }
2103:
2104: /*
2105: * Copy the message to user space
2106: */
2107: if (ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size +
2108: trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA)
2109: return(MACH_RCV_INVALID_DATA);
2110: else
2111: return(MACH_MSG_SUCCESS);
2112: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.