2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 * File: ipc/mach_msg.c
57 * Exported message traps. See mach/message.h.
60 #include <mach/mach_types.h>
61 #include <mach/kern_return.h>
62 #include <mach/port.h>
63 #include <mach/message.h>
64 #include <mach/mig_errors.h>
65 #include <mach/mach_traps.h>
67 #include <kern/kern_types.h>
68 #include <kern/assert.h>
69 #include <kern/counters.h>
70 #include <kern/cpu_number.h>
71 #include <kern/ipc_kobject.h>
72 #include <kern/ipc_mig.h>
73 #include <kern/task.h>
74 #include <kern/thread.h>
75 #include <kern/lock.h>
76 #include <kern/sched_prim.h>
77 #include <kern/exception.h>
78 #include <kern/misc_protos.h>
79 #include <kern/kalloc.h>
80 #include <kern/processor.h>
81 #include <kern/syscall_subr.h>
83 #include <vm/vm_map.h>
85 #include <ipc/ipc_types.h>
86 #include <ipc/ipc_kmsg.h>
87 #include <ipc/ipc_mqueue.h>
88 #include <ipc/ipc_object.h>
89 #include <ipc/ipc_notify.h>
90 #include <ipc/ipc_port.h>
91 #include <ipc/ipc_pset.h>
92 #include <ipc/ipc_space.h>
93 #include <ipc/ipc_entry.h>
95 #include <machine/machine_routines.h>
97 #include <sys/kdebug.h>
100 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
101 #endif /* offsetof */
104 * Forward declarations - kernel internal routines
107 mach_msg_return_t
mach_msg_send(
108 mach_msg_header_t
*msg
,
109 mach_msg_option_t option
,
110 mach_msg_size_t send_size
,
111 mach_msg_timeout_t send_timeout
,
112 mach_port_name_t notify
);
114 mach_msg_return_t
mach_msg_receive(
115 mach_msg_header_t
*msg
,
116 mach_msg_option_t option
,
117 mach_msg_size_t rcv_size
,
118 mach_port_name_t rcv_name
,
119 mach_msg_timeout_t rcv_timeout
,
120 void (*continuation
)(mach_msg_return_t
),
121 mach_msg_size_t slist_size
);
124 mach_msg_return_t
mach_msg_receive_results(void);
126 mach_msg_return_t
msg_receive_error(
128 mach_vm_address_t msg_addr
,
129 mach_msg_option_t option
,
130 mach_port_seqno_t seqno
,
133 security_token_t KERNEL_SECURITY_TOKEN
= KERNEL_SECURITY_TOKEN_VALUE
;
134 audit_token_t KERNEL_AUDIT_TOKEN
= KERNEL_AUDIT_TOKEN_VALUE
;
136 mach_msg_format_0_trailer_t trailer_template
= {
137 /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0
,
138 /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE
,
139 /* mach_port_seqno_t */ 0,
140 /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE
144 * Routine: mach_msg_send
150 * MACH_MSG_SUCCESS Sent the message.
151 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
152 * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
153 * MACH_SEND_INVALID_DATA Couldn't copy message data.
154 * MACH_SEND_INVALID_HEADER
155 * Illegal value in the message header bits.
156 * MACH_SEND_INVALID_DEST The space is dead.
157 * MACH_SEND_INVALID_NOTIFY Bad notify port.
158 * MACH_SEND_INVALID_DEST Can't copyin destination port.
159 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
160 * MACH_SEND_TIMED_OUT Timeout expired without delivery.
161 * MACH_SEND_INTERRUPTED Delivery interrupted.
162 * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
163 * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
164 * MACH_SEND_NOTIFY_IN_PROGRESS
165 * This space has already forced a message to this port.
170 mach_msg_header_t
*msg
,
171 mach_msg_option_t option
,
172 mach_msg_size_t send_size
,
173 mach_msg_timeout_t send_timeout
,
174 mach_port_name_t notify
)
176 ipc_space_t space
= current_space();
177 vm_map_t map
= current_map();
179 mach_msg_return_t mr
;
180 mach_msg_size_t msg_and_trailer_size
;
181 mach_msg_max_trailer_t
*trailer
;
183 if ((send_size
< sizeof(mach_msg_header_t
)) || (send_size
& 3))
184 return MACH_SEND_MSG_TOO_SMALL
;
186 if (send_size
> MACH_MSG_SIZE_MAX
- MAX_TRAILER_SIZE
)
187 return MACH_SEND_TOO_LARGE
;
189 msg_and_trailer_size
= send_size
+ MAX_TRAILER_SIZE
;
191 kmsg
= ipc_kmsg_alloc(msg_and_trailer_size
);
193 if (kmsg
== IKM_NULL
)
194 return MACH_SEND_NO_BUFFER
;
196 (void) memcpy((void *) kmsg
->ikm_header
, (const void *) msg
, send_size
);
198 kmsg
->ikm_header
->msgh_size
= send_size
;
201 * reserve for the trailer the largest space (MAX_TRAILER_SIZE)
202 * However, the internal size field of the trailer (msgh_trailer_size)
203 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
204 * the cases where no implicit data is requested.
206 trailer
= (mach_msg_max_trailer_t
*) ((vm_offset_t
)kmsg
->ikm_header
+ send_size
);
207 trailer
->msgh_sender
= current_thread()->task
->sec_token
;
208 trailer
->msgh_audit
= current_thread()->task
->audit_token
;
209 trailer
->msgh_trailer_type
= MACH_MSG_TRAILER_FORMAT_0
;
210 trailer
->msgh_trailer_size
= MACH_MSG_TRAILER_MINIMUM_SIZE
;
212 if (option
& MACH_SEND_CANCEL
) {
213 if (notify
== MACH_PORT_NULL
)
214 mr
= MACH_SEND_INVALID_NOTIFY
;
216 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, notify
);
218 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
219 if (mr
!= MACH_MSG_SUCCESS
) {
224 mr
= ipc_kmsg_send(kmsg
, option
& MACH_SEND_TIMEOUT
, send_timeout
);
226 if (mr
!= MACH_MSG_SUCCESS
) {
227 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
);
228 (void) memcpy((void *) msg
, (const void *) kmsg
->ikm_header
,
229 kmsg
->ikm_header
->msgh_size
);
237 * Routine: mach_msg_receive
243 * MACH_MSG_SUCCESS Received a message.
244 * MACH_RCV_INVALID_NAME The name doesn't denote a right,
245 * or the denoted right is not receive or port set.
246 * MACH_RCV_IN_SET Receive right is a member of a set.
247 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
248 * MACH_RCV_TIMED_OUT Timeout expired without a message.
249 * MACH_RCV_INTERRUPTED Reception interrupted.
250 * MACH_RCV_PORT_DIED Port/set died while receiving.
251 * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
252 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
253 * MACH_RCV_INVALID_NOTIFY Bad notify port.
254 * MACH_RCV_HEADER_ERROR
258 mach_msg_receive_results(void)
260 thread_t self
= current_thread();
261 ipc_space_t space
= current_space();
262 vm_map_t map
= current_map();
264 ipc_object_t object
= self
->ith_object
;
265 mach_msg_return_t mr
= self
->ith_state
;
266 mach_vm_address_t msg_addr
= self
->ith_msg_addr
;
267 mach_msg_option_t option
= self
->ith_option
;
268 ipc_kmsg_t kmsg
= self
->ith_kmsg
;
269 mach_port_seqno_t seqno
= self
->ith_seqno
;
271 mach_msg_format_0_trailer_t
*trailer
;
273 ipc_object_release(object
);
275 if (mr
!= MACH_MSG_SUCCESS
) {
277 if (mr
== MACH_RCV_TOO_LARGE
) {
278 if (option
& MACH_RCV_LARGE
) {
280 * We need to inform the user-level code that it needs more
281 * space. The value for how much space was returned in the
282 * msize save area instead of the message (which was left on
285 if (copyout((char *) &self
->ith_msize
,
286 msg_addr
+ offsetof(mach_msg_header_t
, msgh_size
),
287 sizeof(mach_msg_size_t
)))
288 mr
= MACH_RCV_INVALID_DATA
;
292 if (msg_receive_error(kmsg
, msg_addr
, option
, seqno
, space
)
293 == MACH_RCV_INVALID_DATA
)
294 mr
= MACH_RCV_INVALID_DATA
;
299 trailer
= (mach_msg_format_0_trailer_t
*)
300 ((vm_offset_t
)kmsg
->ikm_header
+
301 round_msg(kmsg
->ikm_header
->msgh_size
));
302 if (option
& MACH_RCV_TRAILER_MASK
) {
303 trailer
->msgh_seqno
= seqno
;
304 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
308 * If MACH_RCV_OVERWRITE was specified, try to get the scatter
309 * list and verify it against the contents of the message. If
310 * there is any problem with it, we will continue without it as
313 if (option
& MACH_RCV_OVERWRITE
) {
314 mach_msg_size_t slist_size
= self
->ith_scatter_list_size
;
315 mach_msg_body_t
*slist
;
317 slist
= ipc_kmsg_get_scatter(msg_addr
, slist_size
, kmsg
);
318 mr
= ipc_kmsg_copyout(kmsg
, space
, map
, MACH_PORT_NULL
, slist
);
319 ipc_kmsg_free_scatter(slist
, slist_size
);
321 mr
= ipc_kmsg_copyout(kmsg
, space
, map
,
322 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
325 if (mr
!= MACH_MSG_SUCCESS
) {
326 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
327 if (ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
+
328 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
329 mr
= MACH_RCV_INVALID_DATA
;
332 if (msg_receive_error(kmsg
, msg_addr
, option
, seqno
, space
)
333 == MACH_RCV_INVALID_DATA
)
334 mr
= MACH_RCV_INVALID_DATA
;
338 mr
= ipc_kmsg_put(msg_addr
,
340 kmsg
->ikm_header
->msgh_size
+
341 trailer
->msgh_trailer_size
);
348 mach_msg_header_t
*msg
,
349 mach_msg_option_t option
,
350 mach_msg_size_t rcv_size
,
351 mach_port_name_t rcv_name
,
352 mach_msg_timeout_t rcv_timeout
,
353 void (*continuation
)(mach_msg_return_t
),
354 mach_msg_size_t slist_size
)
356 thread_t self
= current_thread();
357 ipc_space_t space
= current_space();
360 mach_msg_return_t mr
;
362 mr
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
);
363 if (mr
!= MACH_MSG_SUCCESS
) {
366 /* hold ref for object */
368 self
->ith_msg_addr
= CAST_DOWN(mach_vm_address_t
, msg
);
369 self
->ith_object
= object
;
370 self
->ith_msize
= rcv_size
;
371 self
->ith_option
= option
;
372 self
->ith_scatter_list_size
= slist_size
;
373 self
->ith_continuation
= continuation
;
375 ipc_mqueue_receive(mqueue
, option
, rcv_size
, rcv_timeout
, THREAD_ABORTSAFE
);
376 if ((option
& MACH_RCV_TIMEOUT
) && rcv_timeout
== 0)
377 thread_poll_yield(self
);
378 return mach_msg_receive_results();
382 mach_msg_receive_continue(void)
384 thread_t self
= current_thread();
386 (*self
->ith_continuation
)(mach_msg_receive_results());
390 * Toggle this to compile the hotpath in/out
391 * If compiled in, the run-time toggle "enable_hotpath" below
392 * eases testing & debugging
394 #define ENABLE_HOTPATH 1 /* Hacked on for now */
398 * These counters allow tracing of hotpath behavior under test loads.
399 * A couple key counters are unconditional (see below).
401 #define HOTPATH_DEBUG 0 /* Toggle to include lots of counters */
403 #define HOT(expr) expr
405 unsigned int c_mmot_FIRST
= 0; /* Unused First Counter */
406 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
407 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
408 unsigned int c_mmot_kernel_send
= 0; /* kernel server */
409 unsigned int c_mmot_cold_000
= 0; /* see below ... */
410 unsigned int c_mmot_smallsendsize
= 0;
411 unsigned int c_mmot_oddsendsize
= 0;
412 unsigned int c_mmot_bigsendsize
= 0;
413 unsigned int c_mmot_copyinmsg_fail
= 0;
414 unsigned int c_mmot_g_slow_copyin3
= 0;
415 unsigned int c_mmot_cold_006
= 0;
416 unsigned int c_mmot_cold_007
= 0;
417 unsigned int c_mmot_cold_008
= 0;
418 unsigned int c_mmot_cold_009
= 0;
419 unsigned int c_mmot_cold_010
= 0;
420 unsigned int c_mmot_cold_012
= 0;
421 unsigned int c_mmot_cold_013
= 0;
422 unsigned int c_mmot_cold_014
= 0;
423 unsigned int c_mmot_cold_016
= 0;
424 unsigned int c_mmot_cold_018
= 0;
425 unsigned int c_mmot_cold_019
= 0;
426 unsigned int c_mmot_cold_020
= 0;
427 unsigned int c_mmot_cold_021
= 0;
428 unsigned int c_mmot_cold_022
= 0;
429 unsigned int c_mmot_cold_023
= 0;
430 unsigned int c_mmot_cold_024
= 0;
431 unsigned int c_mmot_cold_025
= 0;
432 unsigned int c_mmot_cold_026
= 0;
433 unsigned int c_mmot_cold_027
= 0;
434 unsigned int c_mmot_hot_fSR_ok
= 0;
435 unsigned int c_mmot_cold_029
= 0;
436 unsigned int c_mmot_cold_030
= 0;
437 unsigned int c_mmot_cold_031
= 0;
438 unsigned int c_mmot_cold_032
= 0;
439 unsigned int c_mmot_cold_033
= 0;
440 unsigned int c_mmot_bad_rcvr
= 0;
441 unsigned int c_mmot_rcvr_swapped
= 0;
442 unsigned int c_mmot_rcvr_locked
= 0;
443 unsigned int c_mmot_rcvr_tswapped
= 0;
444 unsigned int c_mmot_rcvr_freed
= 0;
445 unsigned int c_mmot_g_slow_copyout6
= 0;
446 unsigned int c_mmot_g_slow_copyout5
= 0;
447 unsigned int c_mmot_cold_037
= 0;
448 unsigned int c_mmot_cold_038
= 0;
449 unsigned int c_mmot_cold_039
= 0;
450 unsigned int c_mmot_g_slow_copyout4
= 0;
451 unsigned int c_mmot_g_slow_copyout3
= 0;
452 unsigned int c_mmot_hot_ok1
= 0;
453 unsigned int c_mmot_hot_ok2
= 0;
454 unsigned int c_mmot_hot_ok3
= 0;
455 unsigned int c_mmot_g_slow_copyout1
= 0;
456 unsigned int c_mmot_g_slow_copyout2
= 0;
457 unsigned int c_mmot_getback_fast_copyin
= 0;
458 unsigned int c_mmot_cold_048
= 0;
459 unsigned int c_mmot_getback_FastSR
= 0;
460 unsigned int c_mmot_cold_050
= 0;
461 unsigned int c_mmot_cold_051
= 0;
462 unsigned int c_mmot_cold_052
= 0;
463 unsigned int c_mmot_cold_053
= 0;
464 unsigned int c_mmot_fastkernelreply
= 0;
465 unsigned int c_mmot_cold_055
= 0;
466 unsigned int c_mmot_getback_fast_put
= 0;
467 unsigned int c_mmot_LAST
= 0; /* End Marker - Unused */
469 void db_mmot_zero_counters(void); /* forward; */
470 void db_mmot_show_counters(void); /* forward; */
472 void /* Call from the debugger to clear all counters */
473 db_mmot_zero_counters(void)
475 register unsigned int *ip
= &c_mmot_FIRST
;
476 while (ip
<= &c_mmot_LAST
)
480 void /* Call from the debugger to show all counters */
481 db_mmot_show_counters(void)
483 #define xx(str) printf("%s: %d\n", # str, str);
485 xx(c_mmot_combined_S_R
);
486 xx(c_mach_msg_trap_switch_fast
);
487 xx(c_mmot_kernel_send
);
489 xx(c_mmot_smallsendsize
);
490 xx(c_mmot_oddsendsize
);
491 xx(c_mmot_bigsendsize
);
492 xx(c_mmot_copyinmsg_fail
);
493 xx(c_mmot_g_slow_copyin3
);
513 xx(c_mmot_hot_fSR_ok
);
520 xx(c_mmot_rcvr_swapped
);
521 xx(c_mmot_rcvr_locked
);
522 xx(c_mmot_rcvr_tswapped
);
523 xx(c_mmot_rcvr_freed
);
524 xx(c_mmot_g_slow_copyout6
);
525 xx(c_mmot_g_slow_copyout5
);
529 xx(c_mmot_g_slow_copyout4
);
530 xx(c_mmot_g_slow_copyout3
);
531 xx(c_mmot_g_slow_copyout1
);
535 xx(c_mmot_g_slow_copyout2
);
536 xx(c_mmot_getback_fast_copyin
);
538 xx(c_mmot_getback_FastSR
);
543 xx(c_mmot_fastkernelreply
);
545 xx(c_mmot_getback_fast_put
);
550 #else /* !HOTPATH_DEBUG */
553 * Duplicate just these few so we can always do a quick sanity check
555 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
556 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
557 unsigned int c_mmot_kernel_send
= 0; /* kernel server calls */
558 #define HOT(expr) /* no optional counters */
560 #endif /* !HOTPATH_DEBUG */
562 boolean_t enable_hotpath
= TRUE
; /* Patchable, just in case ... */
563 #endif /* HOTPATH_ENABLE */
566 * Routine: mach_msg_overwrite_trap [mach trap]
568 * Possibly send a message; possibly receive a message.
572 * All of mach_msg_send and mach_msg_receive error codes.
576 mach_msg_overwrite_trap(
577 struct mach_msg_overwrite_trap_args
*args
)
579 mach_vm_address_t msg_addr
= args
->msg
;
580 mach_msg_option_t option
= args
->option
;
581 mach_msg_size_t send_size
= args
->send_size
;
582 mach_msg_size_t rcv_size
= args
->rcv_size
;
583 mach_port_name_t rcv_name
= args
->rcv_name
;
584 mach_msg_timeout_t msg_timeout
= args
->timeout
;
585 mach_port_name_t notify
= args
->notify
;
586 mach_vm_address_t rcv_msg_addr
= args
->rcv_msg
;
587 mach_msg_size_t scatter_list_size
= 0; /* NOT INITIALIZED - but not used in pactice */
589 register mach_msg_header_t
*hdr
;
590 mach_msg_return_t mr
= MACH_MSG_SUCCESS
;
591 /* mask out some of the options before entering the hot path */
592 mach_msg_option_t masked_option
=
593 option
& ~(MACH_SEND_TRAILER
|MACH_RCV_TRAILER_MASK
|MACH_RCV_LARGE
);
596 /* BEGINNING OF HOT PATH */
597 if ((masked_option
== (MACH_SEND_MSG
|MACH_RCV_MSG
)) && enable_hotpath
) {
598 thread_t self
= current_thread();
599 mach_msg_format_0_trailer_t
*trailer
;
600 ipc_space_t space
= self
->task
->itk_space
;
602 register ipc_port_t dest_port
;
603 ipc_object_t rcv_object
;
604 ipc_mqueue_t rcv_mqueue
;
605 mach_msg_size_t reply_size
;
607 c_mmot_combined_S_R
++;
610 * This case is divided into ten sections, each
611 * with a label. There are five optimized
612 * sections and six unoptimized sections, which
613 * do the same thing but handle all possible
614 * cases and are slower.
616 * The five sections for an RPC are
617 * 1) Get request message into a buffer.
618 * 2) Copyin request message and rcv_name.
619 * (fast_copyin or slow_copyin)
620 * 3) Enqueue request and dequeue reply.
621 * (fast_send_receive or
622 * slow_send and slow_receive)
623 * 4) Copyout reply message.
624 * (fast_copyout or slow_copyout)
625 * 5) Put reply message to user's buffer.
627 * Keep the locking hierarchy firmly in mind.
628 * (First spaces, then ports, then port sets,
629 * then message queues.) Only a non-blocking
630 * attempt can be made to acquire locks out of
631 * order, or acquire two locks on the same level.
632 * Acquiring two locks on the same level will
633 * fail if the objects are really the same,
634 * unless simple locking is disabled. This is OK,
635 * because then the extra unlock does nothing.
637 * There are two major reasons these RPCs can't use
638 * ipc_thread_switch, and use slow_send/slow_receive:
640 * 2) Servers fall behind clients, so
641 * client doesn't find a blocked server thread and
642 * server finds waiting messages and can't block.
645 mr
= ipc_kmsg_get(msg_addr
, send_size
, &kmsg
);
646 if (mr
!= KERN_SUCCESS
) {
649 hdr
= kmsg
->ikm_header
;
650 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
656 * optimized ipc_kmsg_copyin/ipc_mqueue_copyin
658 * We have the request message data in kmsg.
659 * Must still do copyin, send, receive, etc.
661 * If the message isn't simple, we can't combine
662 * ipc_kmsg_copyin_header and ipc_mqueue_copyin,
663 * because copyin of the message body might
667 switch (hdr
->msgh_bits
) {
668 case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,
669 MACH_MSG_TYPE_MAKE_SEND_ONCE
): {
670 register ipc_entry_t table
;
671 register ipc_entry_num_t size
;
672 register ipc_port_t reply_port
;
674 /* sending a request message */
677 register mach_port_index_t index
;
678 register mach_port_gen_t gen
;
681 register mach_port_name_t reply_name
=
682 (mach_port_name_t
)hdr
->msgh_local_port
;
684 if (reply_name
!= rcv_name
) {
685 HOT(c_mmot_g_slow_copyin3
++);
689 /* optimized ipc_entry_lookup of reply_name */
691 index
= MACH_PORT_INDEX(reply_name
);
692 gen
= MACH_PORT_GEN(reply_name
);
695 assert(space
->is_active
);
697 size
= space
->is_table_size
;
698 table
= space
->is_table
;
701 register ipc_entry_t entry
;
702 register ipc_entry_bits_t bits
;
705 entry
= &table
[index
];
706 bits
= entry
->ie_bits
;
707 if (IE_BITS_GEN(bits
) != gen
||
708 (bits
& IE_BITS_COLLISION
)) {
715 if (entry
== IE_NULL
) {
716 entry
= ipc_entry_lookup(space
, reply_name
);
717 if (entry
== IE_NULL
) {
718 HOT(c_mmot_cold_006
++);
719 goto abort_request_copyin
;
721 bits
= entry
->ie_bits
;
726 if (! (bits
& MACH_PORT_TYPE_RECEIVE
)) {
727 HOT(c_mmot_cold_007
++);
728 goto abort_request_copyin
;
731 reply_port
= (ipc_port_t
) entry
->ie_object
;
732 assert(reply_port
!= IP_NULL
);
737 /* optimized ipc_entry_lookup of dest_name */
740 register mach_port_index_t index
;
741 register mach_port_gen_t gen
;
744 register mach_port_name_t dest_name
=
745 (mach_port_name_t
)hdr
->msgh_remote_port
;
747 index
= MACH_PORT_INDEX(dest_name
);
748 gen
= MACH_PORT_GEN(dest_name
);
751 register ipc_entry_t entry
;
752 register ipc_entry_bits_t bits
;
755 entry
= &table
[index
];
756 bits
= entry
->ie_bits
;
757 if (IE_BITS_GEN(bits
) != gen
||
758 (bits
& IE_BITS_COLLISION
)) {
765 if (entry
== IE_NULL
) {
766 entry
= ipc_entry_lookup(space
, dest_name
);
767 if (entry
== IE_NULL
) {
768 HOT(c_mmot_cold_008
++);
769 goto abort_request_copyin
;
771 bits
= entry
->ie_bits
;
776 if (! (bits
& MACH_PORT_TYPE_SEND
)) {
777 HOT(c_mmot_cold_009
++);
778 goto abort_request_copyin
;
781 assert(IE_BITS_UREFS(bits
) > 0);
783 dest_port
= (ipc_port_t
) entry
->ie_object
;
784 assert(dest_port
!= IP_NULL
);
790 * To do an atomic copyin, need simultaneous
791 * locks on both ports and the space. If
792 * dest_port == reply_port, and simple locking is
793 * enabled, then we will abort. Otherwise it's
794 * OK to unlock twice.
798 if (!ip_active(dest_port
) ||
799 !ip_lock_try(reply_port
)) {
800 ip_unlock(dest_port
);
801 HOT(c_mmot_cold_010
++);
802 goto abort_request_copyin
;
804 is_read_unlock(space
);
806 assert(dest_port
->ip_srights
> 0);
807 dest_port
->ip_srights
++;
808 ip_reference(dest_port
);
810 assert(ip_active(reply_port
));
811 assert(reply_port
->ip_receiver_name
==
812 (mach_port_name_t
)hdr
->msgh_local_port
);
813 assert(reply_port
->ip_receiver
== space
);
815 reply_port
->ip_sorights
++;
816 ip_reference(reply_port
);
819 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
820 MACH_MSG_TYPE_PORT_SEND_ONCE
);
821 hdr
->msgh_remote_port
= dest_port
;
822 hdr
->msgh_local_port
= reply_port
;
824 /* make sure we can queue to the destination */
826 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
828 * The kernel server has a reference to
829 * the reply port, which it hands back
830 * to us in the reply message. We do
831 * not need to keep another reference to
834 ip_unlock(reply_port
);
836 assert(ip_active(dest_port
));
837 dest_port
->ip_messages
.imq_seqno
++;
838 ip_unlock(dest_port
);
842 if (imq_full(&dest_port
->ip_messages
)) {
843 HOT(c_mmot_cold_013
++);
844 goto abort_request_send_receive
;
847 /* optimized ipc_mqueue_copyin */
849 rcv_object
= (ipc_object_t
) reply_port
;
850 io_reference(rcv_object
);
851 rcv_mqueue
= &reply_port
->ip_messages
;
852 io_unlock(rcv_object
);
853 HOT(c_mmot_hot_fSR_ok
++);
854 goto fast_send_receive
;
856 abort_request_copyin
:
857 is_read_unlock(space
);
860 abort_request_send_receive
:
861 ip_unlock(dest_port
);
862 ip_unlock(reply_port
);
866 case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0): {
867 register ipc_entry_num_t size
;
868 register ipc_entry_t table
;
870 /* sending a reply message */
873 register mach_port_name_t reply_name
=
874 (mach_port_name_t
)hdr
->msgh_local_port
;
876 if (reply_name
!= MACH_PORT_NULL
) {
877 HOT(c_mmot_cold_018
++);
882 is_write_lock(space
);
883 assert(space
->is_active
);
885 /* optimized ipc_entry_lookup */
887 size
= space
->is_table_size
;
888 table
= space
->is_table
;
891 register ipc_entry_t entry
;
892 register mach_port_gen_t gen
;
893 register mach_port_index_t index
;
896 register mach_port_name_t dest_name
=
897 (mach_port_name_t
)hdr
->msgh_remote_port
;
899 index
= MACH_PORT_INDEX(dest_name
);
900 gen
= MACH_PORT_GEN(dest_name
);
904 HOT(c_mmot_cold_019
++);
905 goto abort_reply_dest_copyin
;
908 entry
= &table
[index
];
910 /* check generation, collision bit, and type bit */
912 if ((entry
->ie_bits
& (IE_BITS_GEN_MASK
|
914 MACH_PORT_TYPE_SEND_ONCE
)) !=
915 (gen
| MACH_PORT_TYPE_SEND_ONCE
)) {
916 HOT(c_mmot_cold_020
++);
917 goto abort_reply_dest_copyin
;
920 /* optimized ipc_right_copyin */
922 assert(IE_BITS_TYPE(entry
->ie_bits
) ==
923 MACH_PORT_TYPE_SEND_ONCE
);
924 assert(IE_BITS_UREFS(entry
->ie_bits
) == 1);
926 if (entry
->ie_request
!= 0) {
927 HOT(c_mmot_cold_021
++);
928 goto abort_reply_dest_copyin
;
931 dest_port
= (ipc_port_t
) entry
->ie_object
;
932 assert(dest_port
!= IP_NULL
);
935 if (!ip_active(dest_port
)) {
936 ip_unlock(dest_port
);
937 HOT(c_mmot_cold_022
++);
938 goto abort_reply_dest_copyin
;
941 assert(dest_port
->ip_sorights
> 0);
943 /* optimized ipc_entry_dealloc */
946 entry
->ie_bits
= gen
;
947 entry
->ie_next
= table
->ie_next
;
948 table
->ie_next
= index
;
949 entry
->ie_object
= IO_NULL
;
953 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
955 hdr
->msgh_remote_port
= dest_port
;
957 /* make sure we can queue to the destination */
959 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
961 /* optimized ipc_entry_lookup/ipc_mqueue_copyin */
964 register ipc_entry_t entry
;
965 register ipc_entry_bits_t bits
;
968 register mach_port_index_t index
;
969 register mach_port_gen_t gen
;
971 index
= MACH_PORT_INDEX(rcv_name
);
972 gen
= MACH_PORT_GEN(rcv_name
);
975 entry
= &table
[index
];
976 bits
= entry
->ie_bits
;
977 if (IE_BITS_GEN(bits
) != gen
||
978 (bits
& IE_BITS_COLLISION
)) {
985 if (entry
== IE_NULL
) {
986 entry
= ipc_entry_lookup(space
, rcv_name
);
987 if (entry
== IE_NULL
) {
988 HOT(c_mmot_cold_024
++);
989 goto abort_reply_rcv_copyin
;
991 bits
= entry
->ie_bits
;
996 /* check type bits; looking for receive or set */
999 * JMM - The check below for messages in the receive
1000 * mqueue is insufficient to work with port sets, since
1001 * the messages stay in the port queues. For now, don't
1002 * allow portsets (but receiving on portsets when sending
1003 * a message to a send-once right is actually a very
1004 * common case (so we should re-enable).
1006 if (bits
& MACH_PORT_TYPE_PORT_SET
) {
1007 register ipc_pset_t rcv_pset
;
1009 rcv_pset
= (ipc_pset_t
) entry
->ie_object
;
1010 assert(rcv_pset
!= IPS_NULL
);
1013 assert(ips_active(rcv_pset
));
1015 rcv_object
= (ipc_object_t
) rcv_pset
;
1016 rcv_mqueue
= &rcv_pset
->ips_messages
;
1019 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1020 register ipc_port_t rcv_port
;
1022 rcv_port
= (ipc_port_t
) entry
->ie_object
;
1023 assert(rcv_port
!= IP_NULL
);
1025 if (!ip_lock_try(rcv_port
)) {
1026 HOT(c_mmot_cold_025
++);
1027 goto abort_reply_rcv_copyin
;
1029 assert(ip_active(rcv_port
));
1031 if (rcv_port
->ip_pset_count
!= 0) {
1032 ip_unlock(rcv_port
);
1033 HOT(c_mmot_cold_026
++);
1034 goto abort_reply_rcv_copyin
;
1037 rcv_object
= (ipc_object_t
) rcv_port
;
1038 rcv_mqueue
= &rcv_port
->ip_messages
;
1040 HOT(c_mmot_cold_027
++);
1041 goto abort_reply_rcv_copyin
;
1045 is_write_unlock(space
);
1046 io_reference(rcv_object
);
1047 io_unlock(rcv_object
);
1048 HOT(c_mmot_hot_fSR_ok
++);
1049 goto fast_send_receive
;
1051 abort_reply_dest_copyin
:
1052 is_write_unlock(space
);
1053 HOT(c_mmot_cold_029
++);
1056 abort_reply_rcv_copyin
:
1057 ip_unlock(dest_port
);
1058 is_write_unlock(space
);
1059 HOT(c_mmot_cold_030
++);
1064 HOT(c_mmot_cold_031
++);
1071 * optimized ipc_mqueue_send/ipc_mqueue_receive
1073 * Finished get/copyin of kmsg and copyin of rcv_name.
1074 * space is unlocked, dest_port is locked,
1075 * we can queue kmsg to dest_port,
1076 * rcv_mqueue is set, and rcv_object holds a ref
1077 * so the mqueue cannot go away.
1079 * JMM - For now, rcv_object is just a port. Portsets
1080 * are disabled for the time being.
1083 assert(ip_active(dest_port
));
1084 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
1085 // assert(!imq_full(&dest_port->ip_messages) ||
1086 // (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) ==
1087 // MACH_MSG_TYPE_PORT_SEND_ONCE));
1088 assert((hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
) == 0);
1091 register ipc_mqueue_t dest_mqueue
;
1094 processor_t processor
;
1095 boolean_t still_running
;
1099 processor
= current_processor();
1100 if (processor
->current_pri
>= BASEPRI_RTQUEUES
)
1101 goto abort_send_receive1
;
1103 dest_mqueue
= &dest_port
->ip_messages
;
1104 waitq
= &dest_mqueue
->imq_wait_queue
;
1105 imq_lock(dest_mqueue
);
1107 wait_queue_peek64_locked(waitq
, IPC_MQUEUE_RECEIVE
, &receiver
, &waitq
);
1108 /* queue still locked, thread locked - but still on q */
1110 if ( receiver
== THREAD_NULL
) {
1112 imq_unlock(dest_mqueue
);
1113 abort_send_receive1
:
1115 ip_unlock(dest_port
);
1116 ipc_object_release(rcv_object
);
1117 HOT(c_mmot_cold_032
++);
1121 assert(receiver
->state
& TH_WAIT
);
1122 assert(receiver
->wait_queue
== waitq
);
1123 assert(receiver
->wait_event
== IPC_MQUEUE_RECEIVE
);
1126 * Make sure that the scheduling restrictions of the receiver
1127 * are consistent with a handoff here (if it comes down to that).
1129 if ( receiver
->sched_pri
>= BASEPRI_RTQUEUES
||
1130 receiver
->processor_set
!= processor
->processor_set
||
1131 (receiver
->bound_processor
!= PROCESSOR_NULL
&&
1132 receiver
->bound_processor
!= processor
)) {
1133 HOT(c_mmot_cold_033
++);
1135 thread_unlock(receiver
);
1136 if (waitq
!= &dest_mqueue
->imq_wait_queue
)
1137 wait_queue_unlock(waitq
);
1138 goto abort_send_receive
;
1142 * Check that the receiver can stay on the hot path.
1144 if (ipc_kmsg_copyout_size(kmsg
, receiver
->map
) +
1145 REQUESTED_TRAILER_SIZE(receiver
->ith_option
) > receiver
->ith_msize
) {
1147 * The receiver can't accept the message.
1149 HOT(c_mmot_bad_rcvr
++);
1154 * Before committing to the handoff, make sure that we are
1155 * really going to block (i.e. there are no messages already
1156 * queued for us. This violates lock ordering, so make sure
1157 * we don't deadlock. After the trylock succeeds below, we
1158 * may have up to 3 message queues locked:
1159 * - the dest port mqueue
1160 * - a portset mqueue (where waiting receiver was found)
1161 * - finally our own rcv_mqueue
1163 * JMM - Need to make this check appropriate for portsets as
1164 * well before re-enabling them.
1166 if (!imq_lock_try(rcv_mqueue
)) {
1169 if (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
) {
1170 imq_unlock(rcv_mqueue
);
1171 HOT(c_mmot_cold_033
++);
1175 /* At this point we are committed to do the "handoff". */
1176 c_mach_msg_trap_switch_fast
++;
1179 * Go ahead and pull the receiver from the waitq. If the
1180 * waitq wasn't the one for the mqueue, unlock it.
1182 wait_queue_pull_thread_locked(waitq
,
1184 (waitq
!= &dest_mqueue
->imq_wait_queue
));
1187 * Store the kmsg and seqno where the receiver can pick it up.
1189 receiver
->ith_state
= MACH_MSG_SUCCESS
;
1190 receiver
->ith_kmsg
= kmsg
;
1191 receiver
->ith_seqno
= dest_mqueue
->imq_seqno
++;
1194 * Unblock the receiver. If it was still running on another
1195 * CPU, we'll give it a chance to run with the message where
1196 * it is (and just select someother thread to run here).
1197 * Otherwise, we'll invoke it here as part of the handoff.
1199 still_running
= thread_unblock(receiver
, THREAD_AWAKENED
);
1201 thread_unlock(receiver
);
1203 imq_unlock(dest_mqueue
);
1204 ip_unlock(dest_port
);
1205 current_task()->messages_sent
++;
1209 * Put self on receive port's queue.
1210 * Also save state that the sender of
1211 * our reply message needs to determine if it
1212 * can hand off directly back to us.
1215 self
->ith_msg_addr
= (rcv_msg_addr
) ? rcv_msg_addr
: msg_addr
;
1216 self
->ith_object
= rcv_object
; /* still holds reference */
1217 self
->ith_msize
= rcv_size
;
1218 self
->ith_option
= option
;
1219 self
->ith_scatter_list_size
= scatter_list_size
;
1220 self
->ith_continuation
= thread_syscall_return
;
1222 waitq
= &rcv_mqueue
->imq_wait_queue
;
1223 (void)wait_queue_assert_wait64_locked(waitq
,
1225 THREAD_ABORTSAFE
, 0,
1227 thread_unlock(self
);
1228 imq_unlock(rcv_mqueue
);
1231 * If the receiving thread wasn't still running, we switch directly
1232 * to it here. Otherwise we let the scheduler pick something for
1233 * here. In either case, block this thread as though it had called
1234 * ipc_mqueue_receive.
1236 if (still_running
) {
1238 thread_block(ipc_mqueue_receive_continue
);
1240 thread_run(self
, ipc_mqueue_receive_continue
, NULL
, receiver
);
1247 * Nothing locked and no references held, except
1248 * we have kmsg with msgh_seqno filled in. Must
1249 * still check against rcv_size and do
1250 * ipc_kmsg_copyout/ipc_kmsg_put.
1253 reply_size
= send_size
+ trailer
->msgh_trailer_size
;
1254 if (rcv_size
< reply_size
) {
1255 HOT(c_mmot_g_slow_copyout6
++);
1259 /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */
1261 switch (hdr
->msgh_bits
) {
1262 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
1263 MACH_MSG_TYPE_PORT_SEND_ONCE
): {
1264 ipc_port_t reply_port
=
1265 (ipc_port_t
) hdr
->msgh_local_port
;
1266 mach_port_name_t dest_name
, reply_name
;
1268 /* receiving a request message */
1270 if (!IP_VALID(reply_port
)) {
1271 HOT(c_mmot_g_slow_copyout5
++);
1275 is_write_lock(space
);
1276 assert(space
->is_active
);
1279 * To do an atomic copyout, need simultaneous
1280 * locks on both ports and the space. If
1281 * dest_port == reply_port, and simple locking is
1282 * enabled, then we will abort. Otherwise it's
1283 * OK to unlock twice.
1287 if (!ip_active(dest_port
) ||
1288 !ip_lock_try(reply_port
)) {
1289 HOT(c_mmot_cold_037
++);
1290 goto abort_request_copyout
;
1293 if (!ip_active(reply_port
)) {
1294 ip_unlock(reply_port
);
1295 HOT(c_mmot_cold_038
++);
1296 goto abort_request_copyout
;
1299 assert(reply_port
->ip_sorights
> 0);
1300 ip_unlock(reply_port
);
1303 register ipc_entry_t table
;
1304 register ipc_entry_t entry
;
1305 register mach_port_index_t index
;
1307 /* optimized ipc_entry_get */
1309 table
= space
->is_table
;
1310 index
= table
->ie_next
;
1313 HOT(c_mmot_cold_039
++);
1314 goto abort_request_copyout
;
1317 entry
= &table
[index
];
1318 table
->ie_next
= entry
->ie_next
;
1319 entry
->ie_request
= 0;
1322 register mach_port_gen_t gen
;
1324 assert((entry
->ie_bits
&~ IE_BITS_GEN_MASK
) == 0);
1325 gen
= IE_BITS_NEW_GEN(entry
->ie_bits
);
1327 reply_name
= MACH_PORT_MAKE(index
, gen
);
1329 /* optimized ipc_right_copyout */
1331 entry
->ie_bits
= gen
| (MACH_PORT_TYPE_SEND_ONCE
| 1);
1334 assert(MACH_PORT_VALID(reply_name
));
1335 entry
->ie_object
= (ipc_object_t
) reply_port
;
1336 is_write_unlock(space
);
1339 /* optimized ipc_object_copyout_dest */
1341 assert(dest_port
->ip_srights
> 0);
1342 ip_release(dest_port
);
1344 if (dest_port
->ip_receiver
== space
)
1345 dest_name
= dest_port
->ip_receiver_name
;
1347 dest_name
= MACH_PORT_NULL
;
1349 if ((--dest_port
->ip_srights
== 0) &&
1350 (dest_port
->ip_nsrequest
!= IP_NULL
)) {
1351 ipc_port_t nsrequest
;
1352 mach_port_mscount_t mscount
;
1354 /* a rather rare case */
1356 nsrequest
= dest_port
->ip_nsrequest
;
1357 mscount
= dest_port
->ip_mscount
;
1358 dest_port
->ip_nsrequest
= IP_NULL
;
1359 ip_unlock(dest_port
);
1360 ipc_notify_no_senders(nsrequest
, mscount
);
1362 ip_unlock(dest_port
);
1365 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
1366 MACH_MSG_TYPE_PORT_SEND
);
1367 hdr
->msgh_remote_port
= (mach_port_t
)reply_name
;
1368 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1369 HOT(c_mmot_hot_ok1
++);
1372 abort_request_copyout
:
1373 ip_unlock(dest_port
);
1374 is_write_unlock(space
);
1375 HOT(c_mmot_g_slow_copyout4
++);
1379 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1380 register mach_port_name_t dest_name
;
1382 /* receiving a reply message */
1385 if (!ip_active(dest_port
)) {
1386 ip_unlock(dest_port
);
1387 HOT(c_mmot_g_slow_copyout3
++);
1391 /* optimized ipc_object_copyout_dest */
1393 assert(dest_port
->ip_sorights
> 0);
1395 if (dest_port
->ip_receiver
== space
) {
1396 ip_release(dest_port
);
1397 dest_port
->ip_sorights
--;
1398 dest_name
= dest_port
->ip_receiver_name
;
1399 ip_unlock(dest_port
);
1401 ip_unlock(dest_port
);
1403 ipc_notify_send_once(dest_port
);
1404 dest_name
= MACH_PORT_NULL
;
1407 hdr
->msgh_bits
= MACH_MSGH_BITS(0,
1408 MACH_MSG_TYPE_PORT_SEND_ONCE
);
1409 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1410 hdr
->msgh_local_port
= (ipc_port_t
)dest_name
;
1411 HOT(c_mmot_hot_ok2
++);
1415 case MACH_MSGH_BITS_COMPLEX
|
1416 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1417 register mach_port_name_t dest_name
;
1419 /* receiving a complex reply message */
1422 if (!ip_active(dest_port
)) {
1423 ip_unlock(dest_port
);
1424 HOT(c_mmot_g_slow_copyout1
++);
1428 /* optimized ipc_object_copyout_dest */
1430 assert(dest_port
->ip_sorights
> 0);
1432 if (dest_port
->ip_receiver
== space
) {
1433 ip_release(dest_port
);
1434 dest_port
->ip_sorights
--;
1435 dest_name
= dest_port
->ip_receiver_name
;
1436 ip_unlock(dest_port
);
1438 ip_unlock(dest_port
);
1440 ipc_notify_send_once(dest_port
);
1441 dest_name
= MACH_PORT_NULL
;
1445 MACH_MSGH_BITS_COMPLEX
|
1446 MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE
);
1447 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1448 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1450 mr
= ipc_kmsg_copyout_body(kmsg
, space
,
1452 MACH_MSG_BODY_NULL
);
1453 /* hdr and send_size may be invalid now - done use */
1454 if (mr
!= MACH_MSG_SUCCESS
) {
1455 if (ipc_kmsg_put(msg_addr
, kmsg
,
1456 kmsg
->ikm_header
->msgh_size
+
1457 trailer
->msgh_trailer_size
) ==
1458 MACH_RCV_INVALID_DATA
)
1459 return MACH_RCV_INVALID_DATA
;
1461 return mr
| MACH_RCV_BODY_ERROR
;
1463 HOT(c_mmot_hot_ok3
++);
1468 HOT(c_mmot_g_slow_copyout2
++);
1474 mr
= ipc_kmsg_put(rcv_msg_addr
? rcv_msg_addr
: msg_addr
,
1476 kmsg
->ikm_header
->msgh_size
+
1477 trailer
->msgh_trailer_size
);
1478 if (mr
!= MACH_MSG_SUCCESS
) {
1479 return MACH_RCV_INVALID_DATA
;
1481 current_task()->messages_received
++;
1485 /* BEGINNING OF WARM PATH */
1488 * The slow path has a few non-register temporary
1489 * variables used only for call-by-reference.
1494 mach_port_seqno_t temp_seqno
= 0;
1495 register mach_port_name_t reply_name
=
1496 (mach_port_name_t
)hdr
->msgh_local_port
;
1500 * We have the message data in kmsg, but
1501 * we still need to copyin, send it,
1502 * receive a reply, and do copyout.
1505 mr
= ipc_kmsg_copyin(kmsg
, space
, current_map(),
1507 if (mr
!= MACH_MSG_SUCCESS
) {
1508 ipc_kmsg_free(kmsg
);
1513 * LP64support - We have to recompute the header pointer
1514 * and send_size - as they could have changed during the
1517 hdr
= kmsg
->ikm_header
;
1518 send_size
= hdr
->msgh_size
;
1520 /* try to get back on optimized path */
1521 if ((reply_name
!= rcv_name
) ||
1522 (hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
)) {
1523 HOT(c_mmot_cold_048
++);
1527 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1528 assert(IP_VALID(dest_port
));
1531 if (!ip_active(dest_port
)) {
1532 ip_unlock(dest_port
);
1536 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
1537 dest_port
->ip_messages
.imq_seqno
++;
1538 ip_unlock(dest_port
);
1542 if (!imq_full(&dest_port
->ip_messages
) ||
1543 (MACH_MSGH_BITS_REMOTE(hdr
->msgh_bits
) ==
1544 MACH_MSG_TYPE_PORT_SEND_ONCE
))
1547 * Try an optimized ipc_mqueue_copyin.
1548 * It will work if this is a request message.
1551 register ipc_port_t reply_port
;
1553 reply_port
= (ipc_port_t
) hdr
->msgh_local_port
;
1554 if (IP_VALID(reply_port
)) {
1555 if (ip_lock_try(reply_port
)) {
1556 if (ip_active(reply_port
) &&
1557 reply_port
->ip_receiver
== space
&&
1558 reply_port
->ip_receiver_name
== rcv_name
&&
1559 reply_port
->ip_pset_count
== 0)
1561 /* Grab a reference to the reply port. */
1562 rcv_object
= (ipc_object_t
) reply_port
;
1563 io_reference(rcv_object
);
1564 rcv_mqueue
= &reply_port
->ip_messages
;
1565 io_unlock(rcv_object
);
1566 HOT(c_mmot_getback_FastSR
++);
1567 goto fast_send_receive
;
1569 ip_unlock(reply_port
);
1574 ip_unlock(dest_port
);
1575 HOT(c_mmot_cold_050
++);
1580 * Special case: send message to kernel services.
1581 * The request message has been copied into the
1582 * kmsg. Nothing is locked.
1586 register ipc_port_t reply_port
;
1587 mach_port_seqno_t local_seqno
;
1591 * Perform the kernel function.
1593 c_mmot_kernel_send
++;
1595 current_task()->messages_sent
++;
1597 kmsg
= ipc_kobject_server(kmsg
);
1598 if (kmsg
== IKM_NULL
) {
1600 * No reply. Take the
1601 * slow receive path.
1603 HOT(c_mmot_cold_051
++);
1604 goto slow_get_rcv_port
;
1609 * the reply port is alive
1610 * we hold the receive right
1611 * the name has not changed.
1612 * the port is not in a set
1613 * If any of these are not true,
1614 * we cannot directly receive the reply
1617 hdr
= kmsg
->ikm_header
;
1618 send_size
= hdr
->msgh_size
;
1619 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1620 round_msg(send_size
));
1621 reply_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1622 ip_lock(reply_port
);
1624 if ((!ip_active(reply_port
)) ||
1625 (reply_port
->ip_receiver
!= space
) ||
1626 (reply_port
->ip_receiver_name
!= rcv_name
) ||
1627 (reply_port
->ip_pset_count
!= 0))
1629 ip_unlock(reply_port
);
1630 ipc_kmsg_send_always(kmsg
);
1631 HOT(c_mmot_cold_052
++);
1632 goto slow_get_rcv_port
;
1636 rcv_mqueue
= &reply_port
->ip_messages
;
1637 imq_lock(rcv_mqueue
);
1639 /* keep port locked, and don`t change ref count yet */
1642 * If there are messages on the port
1643 * or other threads waiting for a message,
1644 * we cannot directly receive the reply.
1646 if (!wait_queue_empty(&rcv_mqueue
->imq_wait_queue
) ||
1647 (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
))
1649 imq_unlock(rcv_mqueue
);
1651 ip_unlock(reply_port
);
1652 ipc_kmsg_send_always(kmsg
);
1653 HOT(c_mmot_cold_053
++);
1654 goto slow_get_rcv_port
;
1658 * We can directly receive this reply.
1659 * Since there were no messages queued
1660 * on the reply port, there should be
1661 * no threads blocked waiting to send.
1663 dest_port
= reply_port
;
1664 local_seqno
= rcv_mqueue
->imq_seqno
++;
1665 imq_unlock(rcv_mqueue
);
1669 * inline ipc_object_release.
1670 * Port is still locked.
1671 * Reference count was not incremented.
1673 ip_check_unlock(reply_port
);
1675 if (option
& MACH_RCV_TRAILER_MASK
) {
1676 trailer
->msgh_seqno
= local_seqno
;
1677 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1679 /* copy out the kernel reply */
1680 HOT(c_mmot_fastkernelreply
++);
1686 * Nothing is locked. We have acquired kmsg, but
1687 * we still need to send it and receive a reply.
1690 mr
= ipc_kmsg_send(kmsg
, MACH_MSG_OPTION_NONE
,
1691 MACH_MSG_TIMEOUT_NONE
);
1692 if (mr
!= MACH_MSG_SUCCESS
) {
1693 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
,
1695 MACH_MSG_BODY_NULL
);
1697 (void) ipc_kmsg_put(msg_addr
, kmsg
,
1698 kmsg
->ikm_header
->msgh_size
);
1704 * We have sent the message. Copy in the receive port.
1706 mr
= ipc_mqueue_copyin(space
, rcv_name
,
1707 &rcv_mqueue
, &rcv_object
);
1708 if (mr
!= MACH_MSG_SUCCESS
) {
1711 /* hold ref for rcv_object */
1716 * Now we have sent the request and copied in rcv_name,
1717 * and hold ref for rcv_object (to keep mqueue alive).
1718 * Just receive a reply and try to get back to fast path.
1721 self
->ith_continuation
= (void (*)(mach_msg_return_t
))0;
1722 ipc_mqueue_receive(rcv_mqueue
,
1723 MACH_MSG_OPTION_NONE
,
1725 MACH_MSG_TIMEOUT_NONE
,
1728 mr
= self
->ith_state
;
1729 temp_seqno
= self
->ith_seqno
;
1731 ipc_object_release(rcv_object
);
1733 if (mr
!= MACH_MSG_SUCCESS
) {
1737 kmsg
= self
->ith_kmsg
;
1738 hdr
= kmsg
->ikm_header
;
1739 send_size
= hdr
->msgh_size
;
1740 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1741 round_msg(send_size
));
1742 if (option
& MACH_RCV_TRAILER_MASK
) {
1743 trailer
->msgh_seqno
= temp_seqno
;
1744 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1746 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1747 HOT(c_mmot_cold_055
++);
1752 * Nothing locked and no references held, except
1753 * we have kmsg with msgh_seqno filled in. Must
1754 * still check against rcv_size and do
1755 * ipc_kmsg_copyout/ipc_kmsg_put.
1758 /* LP64support - have to compute real size as it would be received */
1759 reply_size
= ipc_kmsg_copyout_size(kmsg
, current_map()) +
1760 REQUESTED_TRAILER_SIZE(option
);
1761 if (rcv_size
< reply_size
) {
1762 if (msg_receive_error(kmsg
, msg_addr
, option
, temp_seqno
,
1763 space
) == MACH_RCV_INVALID_DATA
) {
1764 mr
= MACH_RCV_INVALID_DATA
;
1768 mr
= MACH_RCV_TOO_LARGE
;
1773 mr
= ipc_kmsg_copyout(kmsg
, space
, current_map(),
1774 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
1775 if (mr
!= MACH_MSG_SUCCESS
) {
1776 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
1777 if (ipc_kmsg_put(msg_addr
, kmsg
, reply_size
) ==
1778 MACH_RCV_INVALID_DATA
)
1779 mr
= MACH_RCV_INVALID_DATA
;
1782 if (msg_receive_error(kmsg
, msg_addr
, option
,
1783 temp_seqno
, space
) == MACH_RCV_INVALID_DATA
)
1784 mr
= MACH_RCV_INVALID_DATA
;
1790 /* try to get back on optimized path */
1791 HOT(c_mmot_getback_fast_put
++);
1796 } /* END OF HOT PATH */
1797 #endif /* ENABLE_HOTPATH */
1799 if (option
& MACH_SEND_MSG
) {
1800 ipc_space_t space
= current_space();
1801 vm_map_t map
= current_map();
1804 mr
= ipc_kmsg_get(msg_addr
, send_size
, &kmsg
);
1806 if (mr
!= MACH_MSG_SUCCESS
)
1809 if (option
& MACH_SEND_CANCEL
) {
1810 if (notify
== MACH_PORT_NULL
)
1811 mr
= MACH_SEND_INVALID_NOTIFY
;
1813 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, notify
);
1815 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
1816 if (mr
!= MACH_MSG_SUCCESS
) {
1817 ipc_kmsg_free(kmsg
);
1821 mr
= ipc_kmsg_send(kmsg
, option
& MACH_SEND_TIMEOUT
, msg_timeout
);
1823 if (mr
!= MACH_MSG_SUCCESS
) {
1824 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
);
1825 (void) ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
);
1831 if (option
& MACH_RCV_MSG
) {
1832 thread_t self
= current_thread();
1833 ipc_space_t space
= current_space();
1834 ipc_object_t object
;
1835 ipc_mqueue_t mqueue
;
1837 mr
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
);
1838 if (mr
!= MACH_MSG_SUCCESS
) {
1841 /* hold ref for object */
1844 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
1845 * and receive buffer
1846 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
1847 * alternate receive buffer (separate send and receive buffers).
1849 if (option
& MACH_RCV_OVERWRITE
)
1850 self
->ith_msg_addr
= rcv_msg_addr
;
1851 else if (rcv_msg_addr
!= (mach_vm_address_t
)0)
1852 self
->ith_msg_addr
= rcv_msg_addr
;
1854 self
->ith_msg_addr
= msg_addr
;
1855 self
->ith_object
= object
;
1856 self
->ith_msize
= rcv_size
;
1857 self
->ith_option
= option
;
1858 self
->ith_scatter_list_size
= scatter_list_size
;
1859 self
->ith_continuation
= thread_syscall_return
;
1861 ipc_mqueue_receive(mqueue
, option
, rcv_size
, msg_timeout
, THREAD_ABORTSAFE
);
1862 if ((option
& MACH_RCV_TIMEOUT
) && msg_timeout
== 0)
1863 thread_poll_yield(self
);
1864 return mach_msg_receive_results();
1867 return MACH_MSG_SUCCESS
;
1871 * Routine: mach_msg_trap [mach trap]
1873 * Possibly send a message; possibly receive a message.
1877 * All of mach_msg_send and mach_msg_receive error codes.
1882 struct mach_msg_overwrite_trap_args
*args
)
1885 args
->rcv_msg
= (mach_vm_address_t
)0;
1887 kr
= mach_msg_overwrite_trap(args
);
1893 * Routine: msg_receive_error [internal]
1895 * Builds a minimal header/trailer and copies it to
1896 * the user message buffer. Invoked when in the case of a
1897 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
1901 * MACH_MSG_SUCCESS minimal header/trailer copied
1902 * MACH_RCV_INVALID_DATA copyout to user buffer failed
1908 mach_vm_address_t msg_addr
,
1909 mach_msg_option_t option
,
1910 mach_port_seqno_t seqno
,
1913 mach_msg_format_0_trailer_t
*trailer
;
1916 * Copy out the destination port in the message.
1917 * Destroy all other rights and memory in the message.
1919 ipc_kmsg_copyout_dest(kmsg
, space
);
1922 * Build a minimal message with the requested trailer.
1924 trailer
= (mach_msg_format_0_trailer_t
*)
1925 ((vm_offset_t
)kmsg
->ikm_header
+
1926 round_msg(sizeof(mach_msg_header_t
)));
1927 kmsg
->ikm_header
->msgh_size
= sizeof(mach_msg_header_t
);
1928 bcopy( (char *)&trailer_template
,
1930 sizeof(trailer_template
));
1931 if (option
& MACH_RCV_TRAILER_MASK
) {
1932 trailer
->msgh_seqno
= seqno
;
1933 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1937 * Copy the message to user space
1939 if (ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
+
1940 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
1941 return(MACH_RCV_INVALID_DATA
);
1943 return(MACH_MSG_SUCCESS
);