2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
61 * File: ipc/mach_msg.c
65 * Exported message traps. See mach/message.h.
68 #include <mach/mach_types.h>
69 #include <mach/kern_return.h>
70 #include <mach/port.h>
71 #include <mach/message.h>
72 #include <mach/mig_errors.h>
73 #include <mach/mach_traps.h>
75 #include <kern/kern_types.h>
76 #include <kern/assert.h>
77 #include <kern/counters.h>
78 #include <kern/cpu_number.h>
79 #include <kern/ipc_kobject.h>
80 #include <kern/ipc_mig.h>
81 #include <kern/task.h>
82 #include <kern/thread.h>
83 #include <kern/lock.h>
84 #include <kern/sched_prim.h>
85 #include <kern/exception.h>
86 #include <kern/misc_protos.h>
87 #include <kern/kalloc.h>
88 #include <kern/processor.h>
89 #include <kern/syscall_subr.h>
91 #include <vm/vm_map.h>
93 #include <ipc/ipc_types.h>
94 #include <ipc/ipc_kmsg.h>
95 #include <ipc/ipc_mqueue.h>
96 #include <ipc/ipc_object.h>
97 #include <ipc/ipc_notify.h>
98 #include <ipc/ipc_port.h>
99 #include <ipc/ipc_pset.h>
100 #include <ipc/ipc_space.h>
101 #include <ipc/ipc_entry.h>
103 #include <machine/machine_routines.h>
105 #include <sys/kdebug.h>
108 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
109 #endif /* offsetof */
112 * Forward declarations - kernel internal routines
115 mach_msg_return_t
mach_msg_send(
116 mach_msg_header_t
*msg
,
117 mach_msg_option_t option
,
118 mach_msg_size_t send_size
,
119 mach_msg_timeout_t send_timeout
,
120 mach_port_name_t notify
);
122 mach_msg_return_t
mach_msg_receive(
123 mach_msg_header_t
*msg
,
124 mach_msg_option_t option
,
125 mach_msg_size_t rcv_size
,
126 mach_port_name_t rcv_name
,
127 mach_msg_timeout_t rcv_timeout
,
128 void (*continuation
)(mach_msg_return_t
),
129 mach_msg_size_t slist_size
);
132 mach_msg_return_t
mach_msg_receive_results(void);
134 mach_msg_return_t
msg_receive_error(
136 mach_vm_address_t msg_addr
,
137 mach_msg_option_t option
,
138 mach_port_seqno_t seqno
,
141 security_token_t KERNEL_SECURITY_TOKEN
= KERNEL_SECURITY_TOKEN_VALUE
;
142 audit_token_t KERNEL_AUDIT_TOKEN
= KERNEL_AUDIT_TOKEN_VALUE
;
144 mach_msg_format_0_trailer_t trailer_template
= {
145 /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0
,
146 /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE
,
147 /* mach_port_seqno_t */ 0,
148 /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE
152 * Routine: mach_msg_send
158 * MACH_MSG_SUCCESS Sent the message.
159 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
160 * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
161 * MACH_SEND_INVALID_DATA Couldn't copy message data.
162 * MACH_SEND_INVALID_HEADER
163 * Illegal value in the message header bits.
164 * MACH_SEND_INVALID_DEST The space is dead.
165 * MACH_SEND_INVALID_NOTIFY Bad notify port.
166 * MACH_SEND_INVALID_DEST Can't copyin destination port.
167 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
168 * MACH_SEND_TIMED_OUT Timeout expired without delivery.
169 * MACH_SEND_INTERRUPTED Delivery interrupted.
170 * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
171 * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
172 * MACH_SEND_NOTIFY_IN_PROGRESS
173 * This space has already forced a message to this port.
178 mach_msg_header_t
*msg
,
179 mach_msg_option_t option
,
180 mach_msg_size_t send_size
,
181 mach_msg_timeout_t send_timeout
,
182 mach_port_name_t notify
)
184 ipc_space_t space
= current_space();
185 vm_map_t map
= current_map();
187 mach_msg_return_t mr
;
188 mach_msg_size_t msg_and_trailer_size
;
189 mach_msg_max_trailer_t
*trailer
;
191 if ((send_size
< sizeof(mach_msg_header_t
)) || (send_size
& 3))
192 return MACH_SEND_MSG_TOO_SMALL
;
194 if (send_size
> MACH_MSG_SIZE_MAX
- MAX_TRAILER_SIZE
)
195 return MACH_SEND_TOO_LARGE
;
197 msg_and_trailer_size
= send_size
+ MAX_TRAILER_SIZE
;
199 kmsg
= ipc_kmsg_alloc(msg_and_trailer_size
);
201 if (kmsg
== IKM_NULL
)
202 return MACH_SEND_NO_BUFFER
;
204 (void) memcpy((void *) kmsg
->ikm_header
, (const void *) msg
, send_size
);
206 kmsg
->ikm_header
->msgh_size
= send_size
;
209 * reserve for the trailer the largest space (MAX_TRAILER_SIZE)
210 * However, the internal size field of the trailer (msgh_trailer_size)
211 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
212 * the cases where no implicit data is requested.
214 trailer
= (mach_msg_max_trailer_t
*) ((vm_offset_t
)kmsg
->ikm_header
+ send_size
);
215 trailer
->msgh_sender
= current_thread()->task
->sec_token
;
216 trailer
->msgh_audit
= current_thread()->task
->audit_token
;
217 trailer
->msgh_trailer_type
= MACH_MSG_TRAILER_FORMAT_0
;
218 trailer
->msgh_trailer_size
= MACH_MSG_TRAILER_MINIMUM_SIZE
;
220 if (option
& MACH_SEND_CANCEL
) {
221 if (notify
== MACH_PORT_NULL
)
222 mr
= MACH_SEND_INVALID_NOTIFY
;
224 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, notify
);
226 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
227 if (mr
!= MACH_MSG_SUCCESS
) {
232 mr
= ipc_kmsg_send(kmsg
, option
& MACH_SEND_TIMEOUT
, send_timeout
);
234 if (mr
!= MACH_MSG_SUCCESS
) {
235 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
);
236 (void) memcpy((void *) msg
, (const void *) kmsg
->ikm_header
,
237 kmsg
->ikm_header
->msgh_size
);
245 * Routine: mach_msg_receive
251 * MACH_MSG_SUCCESS Received a message.
252 * MACH_RCV_INVALID_NAME The name doesn't denote a right,
253 * or the denoted right is not receive or port set.
254 * MACH_RCV_IN_SET Receive right is a member of a set.
255 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
256 * MACH_RCV_TIMED_OUT Timeout expired without a message.
257 * MACH_RCV_INTERRUPTED Reception interrupted.
258 * MACH_RCV_PORT_DIED Port/set died while receiving.
259 * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
260 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
261 * MACH_RCV_INVALID_NOTIFY Bad notify port.
262 * MACH_RCV_HEADER_ERROR
266 mach_msg_receive_results(void)
268 thread_t self
= current_thread();
269 ipc_space_t space
= current_space();
270 vm_map_t map
= current_map();
272 ipc_object_t object
= self
->ith_object
;
273 mach_msg_return_t mr
= self
->ith_state
;
274 mach_vm_address_t msg_addr
= self
->ith_msg_addr
;
275 mach_msg_option_t option
= self
->ith_option
;
276 ipc_kmsg_t kmsg
= self
->ith_kmsg
;
277 mach_port_seqno_t seqno
= self
->ith_seqno
;
279 mach_msg_format_0_trailer_t
*trailer
;
281 ipc_object_release(object
);
283 if (mr
!= MACH_MSG_SUCCESS
) {
285 if (mr
== MACH_RCV_TOO_LARGE
) {
286 if (option
& MACH_RCV_LARGE
) {
288 * We need to inform the user-level code that it needs more
289 * space. The value for how much space was returned in the
290 * msize save area instead of the message (which was left on
293 if (copyout((char *) &self
->ith_msize
,
294 msg_addr
+ offsetof(mach_msg_header_t
, msgh_size
),
295 sizeof(mach_msg_size_t
)))
296 mr
= MACH_RCV_INVALID_DATA
;
300 if (msg_receive_error(kmsg
, msg_addr
, option
, seqno
, space
)
301 == MACH_RCV_INVALID_DATA
)
302 mr
= MACH_RCV_INVALID_DATA
;
307 trailer
= (mach_msg_format_0_trailer_t
*)
308 ((vm_offset_t
)kmsg
->ikm_header
+
309 round_msg(kmsg
->ikm_header
->msgh_size
));
310 if (option
& MACH_RCV_TRAILER_MASK
) {
311 trailer
->msgh_seqno
= seqno
;
312 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
316 * If MACH_RCV_OVERWRITE was specified, try to get the scatter
317 * list and verify it against the contents of the message. If
318 * there is any problem with it, we will continue without it as
321 if (option
& MACH_RCV_OVERWRITE
) {
322 mach_msg_size_t slist_size
= self
->ith_scatter_list_size
;
323 mach_msg_body_t
*slist
;
325 slist
= ipc_kmsg_get_scatter(msg_addr
, slist_size
, kmsg
);
326 mr
= ipc_kmsg_copyout(kmsg
, space
, map
, MACH_PORT_NULL
, slist
);
327 ipc_kmsg_free_scatter(slist
, slist_size
);
329 mr
= ipc_kmsg_copyout(kmsg
, space
, map
,
330 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
333 if (mr
!= MACH_MSG_SUCCESS
) {
334 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
335 if (ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
+
336 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
337 mr
= MACH_RCV_INVALID_DATA
;
340 if (msg_receive_error(kmsg
, msg_addr
, option
, seqno
, space
)
341 == MACH_RCV_INVALID_DATA
)
342 mr
= MACH_RCV_INVALID_DATA
;
346 mr
= ipc_kmsg_put(msg_addr
,
348 kmsg
->ikm_header
->msgh_size
+
349 trailer
->msgh_trailer_size
);
356 mach_msg_header_t
*msg
,
357 mach_msg_option_t option
,
358 mach_msg_size_t rcv_size
,
359 mach_port_name_t rcv_name
,
360 mach_msg_timeout_t rcv_timeout
,
361 void (*continuation
)(mach_msg_return_t
),
362 mach_msg_size_t slist_size
)
364 thread_t self
= current_thread();
365 ipc_space_t space
= current_space();
368 mach_msg_return_t mr
;
370 mr
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
);
371 if (mr
!= MACH_MSG_SUCCESS
) {
374 /* hold ref for object */
376 self
->ith_msg_addr
= CAST_DOWN(mach_vm_address_t
, msg
);
377 self
->ith_object
= object
;
378 self
->ith_msize
= rcv_size
;
379 self
->ith_option
= option
;
380 self
->ith_scatter_list_size
= slist_size
;
381 self
->ith_continuation
= continuation
;
383 ipc_mqueue_receive(mqueue
, option
, rcv_size
, rcv_timeout
, THREAD_ABORTSAFE
);
384 if ((option
& MACH_RCV_TIMEOUT
) && rcv_timeout
== 0)
385 thread_poll_yield(self
);
386 return mach_msg_receive_results();
390 mach_msg_receive_continue(void)
392 thread_t self
= current_thread();
394 (*self
->ith_continuation
)(mach_msg_receive_results());
398 * Toggle this to compile the hotpath in/out
399 * If compiled in, the run-time toggle "enable_hotpath" below
400 * eases testing & debugging
402 #define ENABLE_HOTPATH 1 /* Hacked on for now */
406 * These counters allow tracing of hotpath behavior under test loads.
407 * A couple key counters are unconditional (see below).
409 #define HOTPATH_DEBUG 0 /* Toggle to include lots of counters */
411 #define HOT(expr) expr
413 unsigned int c_mmot_FIRST
= 0; /* Unused First Counter */
414 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
415 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
416 unsigned int c_mmot_kernel_send
= 0; /* kernel server */
417 unsigned int c_mmot_cold_000
= 0; /* see below ... */
418 unsigned int c_mmot_smallsendsize
= 0;
419 unsigned int c_mmot_oddsendsize
= 0;
420 unsigned int c_mmot_bigsendsize
= 0;
421 unsigned int c_mmot_copyinmsg_fail
= 0;
422 unsigned int c_mmot_g_slow_copyin3
= 0;
423 unsigned int c_mmot_cold_006
= 0;
424 unsigned int c_mmot_cold_007
= 0;
425 unsigned int c_mmot_cold_008
= 0;
426 unsigned int c_mmot_cold_009
= 0;
427 unsigned int c_mmot_cold_010
= 0;
428 unsigned int c_mmot_cold_012
= 0;
429 unsigned int c_mmot_cold_013
= 0;
430 unsigned int c_mmot_cold_014
= 0;
431 unsigned int c_mmot_cold_016
= 0;
432 unsigned int c_mmot_cold_018
= 0;
433 unsigned int c_mmot_cold_019
= 0;
434 unsigned int c_mmot_cold_020
= 0;
435 unsigned int c_mmot_cold_021
= 0;
436 unsigned int c_mmot_cold_022
= 0;
437 unsigned int c_mmot_cold_023
= 0;
438 unsigned int c_mmot_cold_024
= 0;
439 unsigned int c_mmot_cold_025
= 0;
440 unsigned int c_mmot_cold_026
= 0;
441 unsigned int c_mmot_cold_027
= 0;
442 unsigned int c_mmot_hot_fSR_ok
= 0;
443 unsigned int c_mmot_cold_029
= 0;
444 unsigned int c_mmot_cold_030
= 0;
445 unsigned int c_mmot_cold_031
= 0;
446 unsigned int c_mmot_cold_032
= 0;
447 unsigned int c_mmot_cold_033
= 0;
448 unsigned int c_mmot_bad_rcvr
= 0;
449 unsigned int c_mmot_rcvr_swapped
= 0;
450 unsigned int c_mmot_rcvr_locked
= 0;
451 unsigned int c_mmot_rcvr_tswapped
= 0;
452 unsigned int c_mmot_rcvr_freed
= 0;
453 unsigned int c_mmot_g_slow_copyout6
= 0;
454 unsigned int c_mmot_g_slow_copyout5
= 0;
455 unsigned int c_mmot_cold_037
= 0;
456 unsigned int c_mmot_cold_038
= 0;
457 unsigned int c_mmot_cold_039
= 0;
458 unsigned int c_mmot_g_slow_copyout4
= 0;
459 unsigned int c_mmot_g_slow_copyout3
= 0;
460 unsigned int c_mmot_hot_ok1
= 0;
461 unsigned int c_mmot_hot_ok2
= 0;
462 unsigned int c_mmot_hot_ok3
= 0;
463 unsigned int c_mmot_g_slow_copyout1
= 0;
464 unsigned int c_mmot_g_slow_copyout2
= 0;
465 unsigned int c_mmot_getback_fast_copyin
= 0;
466 unsigned int c_mmot_cold_048
= 0;
467 unsigned int c_mmot_getback_FastSR
= 0;
468 unsigned int c_mmot_cold_050
= 0;
469 unsigned int c_mmot_cold_051
= 0;
470 unsigned int c_mmot_cold_052
= 0;
471 unsigned int c_mmot_cold_053
= 0;
472 unsigned int c_mmot_fastkernelreply
= 0;
473 unsigned int c_mmot_cold_055
= 0;
474 unsigned int c_mmot_getback_fast_put
= 0;
475 unsigned int c_mmot_LAST
= 0; /* End Marker - Unused */
477 void db_mmot_zero_counters(void); /* forward; */
478 void db_mmot_show_counters(void); /* forward; */
480 void /* Call from the debugger to clear all counters */
481 db_mmot_zero_counters(void)
483 register unsigned int *ip
= &c_mmot_FIRST
;
484 while (ip
<= &c_mmot_LAST
)
488 void /* Call from the debugger to show all counters */
489 db_mmot_show_counters(void)
491 #define xx(str) printf("%s: %d\n", # str, str);
493 xx(c_mmot_combined_S_R
);
494 xx(c_mach_msg_trap_switch_fast
);
495 xx(c_mmot_kernel_send
);
497 xx(c_mmot_smallsendsize
);
498 xx(c_mmot_oddsendsize
);
499 xx(c_mmot_bigsendsize
);
500 xx(c_mmot_copyinmsg_fail
);
501 xx(c_mmot_g_slow_copyin3
);
521 xx(c_mmot_hot_fSR_ok
);
528 xx(c_mmot_rcvr_swapped
);
529 xx(c_mmot_rcvr_locked
);
530 xx(c_mmot_rcvr_tswapped
);
531 xx(c_mmot_rcvr_freed
);
532 xx(c_mmot_g_slow_copyout6
);
533 xx(c_mmot_g_slow_copyout5
);
537 xx(c_mmot_g_slow_copyout4
);
538 xx(c_mmot_g_slow_copyout3
);
539 xx(c_mmot_g_slow_copyout1
);
543 xx(c_mmot_g_slow_copyout2
);
544 xx(c_mmot_getback_fast_copyin
);
546 xx(c_mmot_getback_FastSR
);
551 xx(c_mmot_fastkernelreply
);
553 xx(c_mmot_getback_fast_put
);
558 #else /* !HOTPATH_DEBUG */
561 * Duplicate just these few so we can always do a quick sanity check
563 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
564 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
565 unsigned int c_mmot_kernel_send
= 0; /* kernel server calls */
566 #define HOT(expr) /* no optional counters */
568 #endif /* !HOTPATH_DEBUG */
570 boolean_t enable_hotpath
= TRUE
; /* Patchable, just in case ... */
571 #endif /* HOTPATH_ENABLE */
574 * Routine: mach_msg_overwrite_trap [mach trap]
576 * Possibly send a message; possibly receive a message.
580 * All of mach_msg_send and mach_msg_receive error codes.
584 mach_msg_overwrite_trap(
585 struct mach_msg_overwrite_trap_args
*args
)
587 mach_vm_address_t msg_addr
= args
->msg
;
588 mach_msg_option_t option
= args
->option
;
589 mach_msg_size_t send_size
= args
->send_size
;
590 mach_msg_size_t rcv_size
= args
->rcv_size
;
591 mach_port_name_t rcv_name
= args
->rcv_name
;
592 mach_msg_timeout_t msg_timeout
= args
->timeout
;
593 mach_port_name_t notify
= args
->notify
;
594 mach_vm_address_t rcv_msg_addr
= args
->rcv_msg
;
595 mach_msg_size_t scatter_list_size
= 0; /* NOT INITIALIZED - but not used in pactice */
597 register mach_msg_header_t
*hdr
;
598 mach_msg_return_t mr
= MACH_MSG_SUCCESS
;
599 /* mask out some of the options before entering the hot path */
600 mach_msg_option_t masked_option
=
601 option
& ~(MACH_SEND_TRAILER
|MACH_RCV_TRAILER_MASK
|MACH_RCV_LARGE
);
604 /* BEGINNING OF HOT PATH */
605 if ((masked_option
== (MACH_SEND_MSG
|MACH_RCV_MSG
)) && enable_hotpath
) {
606 thread_t self
= current_thread();
607 mach_msg_format_0_trailer_t
*trailer
;
608 ipc_space_t space
= self
->task
->itk_space
;
610 register ipc_port_t dest_port
;
611 ipc_object_t rcv_object
;
612 ipc_mqueue_t rcv_mqueue
;
613 mach_msg_size_t reply_size
;
615 c_mmot_combined_S_R
++;
618 * This case is divided into ten sections, each
619 * with a label. There are five optimized
620 * sections and six unoptimized sections, which
621 * do the same thing but handle all possible
622 * cases and are slower.
624 * The five sections for an RPC are
625 * 1) Get request message into a buffer.
626 * 2) Copyin request message and rcv_name.
627 * (fast_copyin or slow_copyin)
628 * 3) Enqueue request and dequeue reply.
629 * (fast_send_receive or
630 * slow_send and slow_receive)
631 * 4) Copyout reply message.
632 * (fast_copyout or slow_copyout)
633 * 5) Put reply message to user's buffer.
635 * Keep the locking hierarchy firmly in mind.
636 * (First spaces, then ports, then port sets,
637 * then message queues.) Only a non-blocking
638 * attempt can be made to acquire locks out of
639 * order, or acquire two locks on the same level.
640 * Acquiring two locks on the same level will
641 * fail if the objects are really the same,
642 * unless simple locking is disabled. This is OK,
643 * because then the extra unlock does nothing.
645 * There are two major reasons these RPCs can't use
646 * ipc_thread_switch, and use slow_send/slow_receive:
648 * 2) Servers fall behind clients, so
649 * client doesn't find a blocked server thread and
650 * server finds waiting messages and can't block.
653 mr
= ipc_kmsg_get(msg_addr
, send_size
, &kmsg
);
654 if (mr
!= KERN_SUCCESS
) {
657 hdr
= kmsg
->ikm_header
;
658 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
664 * optimized ipc_kmsg_copyin/ipc_mqueue_copyin
666 * We have the request message data in kmsg.
667 * Must still do copyin, send, receive, etc.
669 * If the message isn't simple, we can't combine
670 * ipc_kmsg_copyin_header and ipc_mqueue_copyin,
671 * because copyin of the message body might
675 switch (hdr
->msgh_bits
) {
676 case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,
677 MACH_MSG_TYPE_MAKE_SEND_ONCE
): {
678 register ipc_entry_t table
;
679 register ipc_entry_num_t size
;
680 register ipc_port_t reply_port
;
682 /* sending a request message */
685 register mach_port_index_t index
;
686 register mach_port_gen_t gen
;
689 register mach_port_name_t reply_name
=
690 (mach_port_name_t
)hdr
->msgh_local_port
;
692 if (reply_name
!= rcv_name
) {
693 HOT(c_mmot_g_slow_copyin3
++);
697 /* optimized ipc_entry_lookup of reply_name */
699 index
= MACH_PORT_INDEX(reply_name
);
700 gen
= MACH_PORT_GEN(reply_name
);
703 assert(space
->is_active
);
705 size
= space
->is_table_size
;
706 table
= space
->is_table
;
709 register ipc_entry_t entry
;
710 register ipc_entry_bits_t bits
;
713 entry
= &table
[index
];
714 bits
= entry
->ie_bits
;
715 if (IE_BITS_GEN(bits
) != gen
||
716 (bits
& IE_BITS_COLLISION
)) {
723 if (entry
== IE_NULL
) {
724 entry
= ipc_entry_lookup(space
, reply_name
);
725 if (entry
== IE_NULL
) {
726 HOT(c_mmot_cold_006
++);
727 goto abort_request_copyin
;
729 bits
= entry
->ie_bits
;
734 if (! (bits
& MACH_PORT_TYPE_RECEIVE
)) {
735 HOT(c_mmot_cold_007
++);
736 goto abort_request_copyin
;
739 reply_port
= (ipc_port_t
) entry
->ie_object
;
740 assert(reply_port
!= IP_NULL
);
745 /* optimized ipc_entry_lookup of dest_name */
748 register mach_port_index_t index
;
749 register mach_port_gen_t gen
;
752 register mach_port_name_t dest_name
=
753 (mach_port_name_t
)hdr
->msgh_remote_port
;
755 index
= MACH_PORT_INDEX(dest_name
);
756 gen
= MACH_PORT_GEN(dest_name
);
759 register ipc_entry_t entry
;
760 register ipc_entry_bits_t bits
;
763 entry
= &table
[index
];
764 bits
= entry
->ie_bits
;
765 if (IE_BITS_GEN(bits
) != gen
||
766 (bits
& IE_BITS_COLLISION
)) {
773 if (entry
== IE_NULL
) {
774 entry
= ipc_entry_lookup(space
, dest_name
);
775 if (entry
== IE_NULL
) {
776 HOT(c_mmot_cold_008
++);
777 goto abort_request_copyin
;
779 bits
= entry
->ie_bits
;
784 if (! (bits
& MACH_PORT_TYPE_SEND
)) {
785 HOT(c_mmot_cold_009
++);
786 goto abort_request_copyin
;
789 assert(IE_BITS_UREFS(bits
) > 0);
791 dest_port
= (ipc_port_t
) entry
->ie_object
;
792 assert(dest_port
!= IP_NULL
);
798 * To do an atomic copyin, need simultaneous
799 * locks on both ports and the space. If
800 * dest_port == reply_port, and simple locking is
801 * enabled, then we will abort. Otherwise it's
802 * OK to unlock twice.
806 if (!ip_active(dest_port
) ||
807 !ip_lock_try(reply_port
)) {
808 ip_unlock(dest_port
);
809 HOT(c_mmot_cold_010
++);
810 goto abort_request_copyin
;
812 is_read_unlock(space
);
814 assert(dest_port
->ip_srights
> 0);
815 dest_port
->ip_srights
++;
816 ip_reference(dest_port
);
818 assert(ip_active(reply_port
));
819 assert(reply_port
->ip_receiver_name
==
820 (mach_port_name_t
)hdr
->msgh_local_port
);
821 assert(reply_port
->ip_receiver
== space
);
823 reply_port
->ip_sorights
++;
824 ip_reference(reply_port
);
827 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
828 MACH_MSG_TYPE_PORT_SEND_ONCE
);
829 hdr
->msgh_remote_port
= dest_port
;
830 hdr
->msgh_local_port
= reply_port
;
832 /* make sure we can queue to the destination */
834 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
836 * The kernel server has a reference to
837 * the reply port, which it hands back
838 * to us in the reply message. We do
839 * not need to keep another reference to
842 ip_unlock(reply_port
);
844 assert(ip_active(dest_port
));
845 dest_port
->ip_messages
.imq_seqno
++;
846 ip_unlock(dest_port
);
850 if (imq_full(&dest_port
->ip_messages
)) {
851 HOT(c_mmot_cold_013
++);
852 goto abort_request_send_receive
;
855 /* optimized ipc_mqueue_copyin */
857 rcv_object
= (ipc_object_t
) reply_port
;
858 io_reference(rcv_object
);
859 rcv_mqueue
= &reply_port
->ip_messages
;
860 io_unlock(rcv_object
);
861 HOT(c_mmot_hot_fSR_ok
++);
862 goto fast_send_receive
;
864 abort_request_copyin
:
865 is_read_unlock(space
);
868 abort_request_send_receive
:
869 ip_unlock(dest_port
);
870 ip_unlock(reply_port
);
874 case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0): {
875 register ipc_entry_num_t size
;
876 register ipc_entry_t table
;
878 /* sending a reply message */
881 register mach_port_name_t reply_name
=
882 (mach_port_name_t
)hdr
->msgh_local_port
;
884 if (reply_name
!= MACH_PORT_NULL
) {
885 HOT(c_mmot_cold_018
++);
890 is_write_lock(space
);
891 assert(space
->is_active
);
893 /* optimized ipc_entry_lookup */
895 size
= space
->is_table_size
;
896 table
= space
->is_table
;
899 register ipc_entry_t entry
;
900 register mach_port_gen_t gen
;
901 register mach_port_index_t index
;
904 register mach_port_name_t dest_name
=
905 (mach_port_name_t
)hdr
->msgh_remote_port
;
907 index
= MACH_PORT_INDEX(dest_name
);
908 gen
= MACH_PORT_GEN(dest_name
);
912 HOT(c_mmot_cold_019
++);
913 goto abort_reply_dest_copyin
;
916 entry
= &table
[index
];
918 /* check generation, collision bit, and type bit */
920 if ((entry
->ie_bits
& (IE_BITS_GEN_MASK
|
922 MACH_PORT_TYPE_SEND_ONCE
)) !=
923 (gen
| MACH_PORT_TYPE_SEND_ONCE
)) {
924 HOT(c_mmot_cold_020
++);
925 goto abort_reply_dest_copyin
;
928 /* optimized ipc_right_copyin */
930 assert(IE_BITS_TYPE(entry
->ie_bits
) ==
931 MACH_PORT_TYPE_SEND_ONCE
);
932 assert(IE_BITS_UREFS(entry
->ie_bits
) == 1);
934 if (entry
->ie_request
!= 0) {
935 HOT(c_mmot_cold_021
++);
936 goto abort_reply_dest_copyin
;
939 dest_port
= (ipc_port_t
) entry
->ie_object
;
940 assert(dest_port
!= IP_NULL
);
943 if (!ip_active(dest_port
)) {
944 ip_unlock(dest_port
);
945 HOT(c_mmot_cold_022
++);
946 goto abort_reply_dest_copyin
;
949 assert(dest_port
->ip_sorights
> 0);
951 /* optimized ipc_entry_dealloc */
954 entry
->ie_bits
= gen
;
955 entry
->ie_next
= table
->ie_next
;
956 table
->ie_next
= index
;
957 entry
->ie_object
= IO_NULL
;
961 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
963 hdr
->msgh_remote_port
= dest_port
;
965 /* make sure we can queue to the destination */
967 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
969 /* optimized ipc_entry_lookup/ipc_mqueue_copyin */
972 register ipc_entry_t entry
;
973 register ipc_entry_bits_t bits
;
976 register mach_port_index_t index
;
977 register mach_port_gen_t gen
;
979 index
= MACH_PORT_INDEX(rcv_name
);
980 gen
= MACH_PORT_GEN(rcv_name
);
983 entry
= &table
[index
];
984 bits
= entry
->ie_bits
;
985 if (IE_BITS_GEN(bits
) != gen
||
986 (bits
& IE_BITS_COLLISION
)) {
993 if (entry
== IE_NULL
) {
994 entry
= ipc_entry_lookup(space
, rcv_name
);
995 if (entry
== IE_NULL
) {
996 HOT(c_mmot_cold_024
++);
997 goto abort_reply_rcv_copyin
;
999 bits
= entry
->ie_bits
;
1004 /* check type bits; looking for receive or set */
1007 * JMM - The check below for messages in the receive
1008 * mqueue is insufficient to work with port sets, since
1009 * the messages stay in the port queues. For now, don't
1010 * allow portsets (but receiving on portsets when sending
1011 * a message to a send-once right is actually a very
1012 * common case (so we should re-enable).
1014 if (bits
& MACH_PORT_TYPE_PORT_SET
) {
1015 register ipc_pset_t rcv_pset
;
1017 rcv_pset
= (ipc_pset_t
) entry
->ie_object
;
1018 assert(rcv_pset
!= IPS_NULL
);
1021 assert(ips_active(rcv_pset
));
1023 rcv_object
= (ipc_object_t
) rcv_pset
;
1024 rcv_mqueue
= &rcv_pset
->ips_messages
;
1027 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1028 register ipc_port_t rcv_port
;
1030 rcv_port
= (ipc_port_t
) entry
->ie_object
;
1031 assert(rcv_port
!= IP_NULL
);
1033 if (!ip_lock_try(rcv_port
)) {
1034 HOT(c_mmot_cold_025
++);
1035 goto abort_reply_rcv_copyin
;
1037 assert(ip_active(rcv_port
));
1039 if (rcv_port
->ip_pset_count
!= 0) {
1040 ip_unlock(rcv_port
);
1041 HOT(c_mmot_cold_026
++);
1042 goto abort_reply_rcv_copyin
;
1045 rcv_object
= (ipc_object_t
) rcv_port
;
1046 rcv_mqueue
= &rcv_port
->ip_messages
;
1048 HOT(c_mmot_cold_027
++);
1049 goto abort_reply_rcv_copyin
;
1053 is_write_unlock(space
);
1054 io_reference(rcv_object
);
1055 io_unlock(rcv_object
);
1056 HOT(c_mmot_hot_fSR_ok
++);
1057 goto fast_send_receive
;
1059 abort_reply_dest_copyin
:
1060 is_write_unlock(space
);
1061 HOT(c_mmot_cold_029
++);
1064 abort_reply_rcv_copyin
:
1065 ip_unlock(dest_port
);
1066 is_write_unlock(space
);
1067 HOT(c_mmot_cold_030
++);
1072 HOT(c_mmot_cold_031
++);
1079 * optimized ipc_mqueue_send/ipc_mqueue_receive
1081 * Finished get/copyin of kmsg and copyin of rcv_name.
1082 * space is unlocked, dest_port is locked,
1083 * we can queue kmsg to dest_port,
1084 * rcv_mqueue is set, and rcv_object holds a ref
1085 * so the mqueue cannot go away.
1087 * JMM - For now, rcv_object is just a port. Portsets
1088 * are disabled for the time being.
1091 assert(ip_active(dest_port
));
1092 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
1093 // assert(!imq_full(&dest_port->ip_messages) ||
1094 // (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) ==
1095 // MACH_MSG_TYPE_PORT_SEND_ONCE));
1096 assert((hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
) == 0);
1099 register ipc_mqueue_t dest_mqueue
;
1102 processor_t processor
;
1103 boolean_t still_running
;
1107 processor
= current_processor();
1108 if (processor
->current_pri
>= BASEPRI_RTQUEUES
)
1109 goto abort_send_receive1
;
1111 dest_mqueue
= &dest_port
->ip_messages
;
1112 waitq
= &dest_mqueue
->imq_wait_queue
;
1113 imq_lock(dest_mqueue
);
1115 wait_queue_peek64_locked(waitq
, IPC_MQUEUE_RECEIVE
, &receiver
, &waitq
);
1116 /* queue still locked, thread locked - but still on q */
1118 if ( receiver
== THREAD_NULL
) {
1120 imq_unlock(dest_mqueue
);
1121 abort_send_receive1
:
1123 ip_unlock(dest_port
);
1124 ipc_object_release(rcv_object
);
1125 HOT(c_mmot_cold_032
++);
1129 assert(receiver
->state
& TH_WAIT
);
1130 assert(receiver
->wait_queue
== waitq
);
1131 assert(receiver
->wait_event
== IPC_MQUEUE_RECEIVE
);
1134 * Make sure that the scheduling restrictions of the receiver
1135 * are consistent with a handoff here (if it comes down to that).
1137 if ( receiver
->sched_pri
>= BASEPRI_RTQUEUES
||
1138 receiver
->processor_set
!= processor
->processor_set
||
1139 (receiver
->bound_processor
!= PROCESSOR_NULL
&&
1140 receiver
->bound_processor
!= processor
)) {
1141 HOT(c_mmot_cold_033
++);
1143 thread_unlock(receiver
);
1144 if (waitq
!= &dest_mqueue
->imq_wait_queue
)
1145 wait_queue_unlock(waitq
);
1146 goto abort_send_receive
;
1150 * Check that the receiver can stay on the hot path.
1152 if (ipc_kmsg_copyout_size(kmsg
, receiver
->map
) +
1153 REQUESTED_TRAILER_SIZE(receiver
->ith_option
) > receiver
->ith_msize
) {
1155 * The receiver can't accept the message.
1157 HOT(c_mmot_bad_rcvr
++);
1162 * Before committing to the handoff, make sure that we are
1163 * really going to block (i.e. there are no messages already
1164 * queued for us. This violates lock ordering, so make sure
1165 * we don't deadlock. After the trylock succeeds below, we
1166 * may have up to 3 message queues locked:
1167 * - the dest port mqueue
1168 * - a portset mqueue (where waiting receiver was found)
1169 * - finally our own rcv_mqueue
1171 * JMM - Need to make this check appropriate for portsets as
1172 * well before re-enabling them.
1174 if (!imq_lock_try(rcv_mqueue
)) {
1177 if (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
) {
1178 imq_unlock(rcv_mqueue
);
1179 HOT(c_mmot_cold_033
++);
1183 /* At this point we are committed to do the "handoff". */
1184 c_mach_msg_trap_switch_fast
++;
1187 * Go ahead and pull the receiver from the waitq. If the
1188 * waitq wasn't the one for the mqueue, unlock it.
1190 wait_queue_pull_thread_locked(waitq
,
1192 (waitq
!= &dest_mqueue
->imq_wait_queue
));
1195 * Store the kmsg and seqno where the receiver can pick it up.
1197 receiver
->ith_state
= MACH_MSG_SUCCESS
;
1198 receiver
->ith_kmsg
= kmsg
;
1199 receiver
->ith_seqno
= dest_mqueue
->imq_seqno
++;
1202 * Unblock the receiver. If it was still running on another
1203 * CPU, we'll give it a chance to run with the message where
1204 * it is (and just select someother thread to run here).
1205 * Otherwise, we'll invoke it here as part of the handoff.
1207 still_running
= thread_unblock(receiver
, THREAD_AWAKENED
);
1209 thread_unlock(receiver
);
1211 imq_unlock(dest_mqueue
);
1212 ip_unlock(dest_port
);
1213 current_task()->messages_sent
++;
1217 * Put self on receive port's queue.
1218 * Also save state that the sender of
1219 * our reply message needs to determine if it
1220 * can hand off directly back to us.
1223 self
->ith_msg_addr
= (rcv_msg_addr
) ? rcv_msg_addr
: msg_addr
;
1224 self
->ith_object
= rcv_object
; /* still holds reference */
1225 self
->ith_msize
= rcv_size
;
1226 self
->ith_option
= option
;
1227 self
->ith_scatter_list_size
= scatter_list_size
;
1228 self
->ith_continuation
= thread_syscall_return
;
1230 waitq
= &rcv_mqueue
->imq_wait_queue
;
1231 (void)wait_queue_assert_wait64_locked(waitq
,
1233 THREAD_ABORTSAFE
, 0,
1235 thread_unlock(self
);
1236 imq_unlock(rcv_mqueue
);
1239 * If the receiving thread wasn't still running, we switch directly
1240 * to it here. Otherwise we let the scheduler pick something for
1241 * here. In either case, block this thread as though it had called
1242 * ipc_mqueue_receive.
1244 if (still_running
) {
1246 thread_block(ipc_mqueue_receive_continue
);
1248 thread_run(self
, ipc_mqueue_receive_continue
, NULL
, receiver
);
1255 * Nothing locked and no references held, except
1256 * we have kmsg with msgh_seqno filled in. Must
1257 * still check against rcv_size and do
1258 * ipc_kmsg_copyout/ipc_kmsg_put.
1261 reply_size
= send_size
+ trailer
->msgh_trailer_size
;
1262 if (rcv_size
< reply_size
) {
1263 HOT(c_mmot_g_slow_copyout6
++);
1267 /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */
1269 switch (hdr
->msgh_bits
) {
1270 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
1271 MACH_MSG_TYPE_PORT_SEND_ONCE
): {
1272 ipc_port_t reply_port
=
1273 (ipc_port_t
) hdr
->msgh_local_port
;
1274 mach_port_name_t dest_name
, reply_name
;
1276 /* receiving a request message */
1278 if (!IP_VALID(reply_port
)) {
1279 HOT(c_mmot_g_slow_copyout5
++);
1283 is_write_lock(space
);
1284 assert(space
->is_active
);
1287 * To do an atomic copyout, need simultaneous
1288 * locks on both ports and the space. If
1289 * dest_port == reply_port, and simple locking is
1290 * enabled, then we will abort. Otherwise it's
1291 * OK to unlock twice.
1295 if (!ip_active(dest_port
) ||
1296 !ip_lock_try(reply_port
)) {
1297 HOT(c_mmot_cold_037
++);
1298 goto abort_request_copyout
;
1301 if (!ip_active(reply_port
)) {
1302 ip_unlock(reply_port
);
1303 HOT(c_mmot_cold_038
++);
1304 goto abort_request_copyout
;
1307 assert(reply_port
->ip_sorights
> 0);
1308 ip_unlock(reply_port
);
1311 register ipc_entry_t table
;
1312 register ipc_entry_t entry
;
1313 register mach_port_index_t index
;
1315 /* optimized ipc_entry_get */
1317 table
= space
->is_table
;
1318 index
= table
->ie_next
;
1321 HOT(c_mmot_cold_039
++);
1322 goto abort_request_copyout
;
1325 entry
= &table
[index
];
1326 table
->ie_next
= entry
->ie_next
;
1327 entry
->ie_request
= 0;
1330 register mach_port_gen_t gen
;
1332 assert((entry
->ie_bits
&~ IE_BITS_GEN_MASK
) == 0);
1333 gen
= IE_BITS_NEW_GEN(entry
->ie_bits
);
1335 reply_name
= MACH_PORT_MAKE(index
, gen
);
1337 /* optimized ipc_right_copyout */
1339 entry
->ie_bits
= gen
| (MACH_PORT_TYPE_SEND_ONCE
| 1);
1342 assert(MACH_PORT_VALID(reply_name
));
1343 entry
->ie_object
= (ipc_object_t
) reply_port
;
1344 is_write_unlock(space
);
1347 /* optimized ipc_object_copyout_dest */
1349 assert(dest_port
->ip_srights
> 0);
1350 ip_release(dest_port
);
1352 if (dest_port
->ip_receiver
== space
)
1353 dest_name
= dest_port
->ip_receiver_name
;
1355 dest_name
= MACH_PORT_NULL
;
1357 if ((--dest_port
->ip_srights
== 0) &&
1358 (dest_port
->ip_nsrequest
!= IP_NULL
)) {
1359 ipc_port_t nsrequest
;
1360 mach_port_mscount_t mscount
;
1362 /* a rather rare case */
1364 nsrequest
= dest_port
->ip_nsrequest
;
1365 mscount
= dest_port
->ip_mscount
;
1366 dest_port
->ip_nsrequest
= IP_NULL
;
1367 ip_unlock(dest_port
);
1368 ipc_notify_no_senders(nsrequest
, mscount
);
1370 ip_unlock(dest_port
);
1373 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
1374 MACH_MSG_TYPE_PORT_SEND
);
1375 hdr
->msgh_remote_port
= (mach_port_t
)reply_name
;
1376 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1377 HOT(c_mmot_hot_ok1
++);
1380 abort_request_copyout
:
1381 ip_unlock(dest_port
);
1382 is_write_unlock(space
);
1383 HOT(c_mmot_g_slow_copyout4
++);
1387 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1388 register mach_port_name_t dest_name
;
1390 /* receiving a reply message */
1393 if (!ip_active(dest_port
)) {
1394 ip_unlock(dest_port
);
1395 HOT(c_mmot_g_slow_copyout3
++);
1399 /* optimized ipc_object_copyout_dest */
1401 assert(dest_port
->ip_sorights
> 0);
1403 if (dest_port
->ip_receiver
== space
) {
1404 ip_release(dest_port
);
1405 dest_port
->ip_sorights
--;
1406 dest_name
= dest_port
->ip_receiver_name
;
1407 ip_unlock(dest_port
);
1409 ip_unlock(dest_port
);
1411 ipc_notify_send_once(dest_port
);
1412 dest_name
= MACH_PORT_NULL
;
1415 hdr
->msgh_bits
= MACH_MSGH_BITS(0,
1416 MACH_MSG_TYPE_PORT_SEND_ONCE
);
1417 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1418 hdr
->msgh_local_port
= (ipc_port_t
)dest_name
;
1419 HOT(c_mmot_hot_ok2
++);
1423 case MACH_MSGH_BITS_COMPLEX
|
1424 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1425 register mach_port_name_t dest_name
;
1427 /* receiving a complex reply message */
1430 if (!ip_active(dest_port
)) {
1431 ip_unlock(dest_port
);
1432 HOT(c_mmot_g_slow_copyout1
++);
1436 /* optimized ipc_object_copyout_dest */
1438 assert(dest_port
->ip_sorights
> 0);
1440 if (dest_port
->ip_receiver
== space
) {
1441 ip_release(dest_port
);
1442 dest_port
->ip_sorights
--;
1443 dest_name
= dest_port
->ip_receiver_name
;
1444 ip_unlock(dest_port
);
1446 ip_unlock(dest_port
);
1448 ipc_notify_send_once(dest_port
);
1449 dest_name
= MACH_PORT_NULL
;
1453 MACH_MSGH_BITS_COMPLEX
|
1454 MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE
);
1455 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1456 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1458 mr
= ipc_kmsg_copyout_body(kmsg
, space
,
1460 MACH_MSG_BODY_NULL
);
1461 /* hdr and send_size may be invalid now - done use */
1462 if (mr
!= MACH_MSG_SUCCESS
) {
1463 if (ipc_kmsg_put(msg_addr
, kmsg
,
1464 kmsg
->ikm_header
->msgh_size
+
1465 trailer
->msgh_trailer_size
) ==
1466 MACH_RCV_INVALID_DATA
)
1467 return MACH_RCV_INVALID_DATA
;
1469 return mr
| MACH_RCV_BODY_ERROR
;
1471 HOT(c_mmot_hot_ok3
++);
1476 HOT(c_mmot_g_slow_copyout2
++);
1482 mr
= ipc_kmsg_put(rcv_msg_addr
? rcv_msg_addr
: msg_addr
,
1484 kmsg
->ikm_header
->msgh_size
+
1485 trailer
->msgh_trailer_size
);
1486 if (mr
!= MACH_MSG_SUCCESS
) {
1487 return MACH_RCV_INVALID_DATA
;
1489 current_task()->messages_received
++;
1493 /* BEGINNING OF WARM PATH */
1496 * The slow path has a few non-register temporary
1497 * variables used only for call-by-reference.
1502 mach_port_seqno_t temp_seqno
= 0;
1503 register mach_port_name_t reply_name
=
1504 (mach_port_name_t
)hdr
->msgh_local_port
;
1508 * We have the message data in kmsg, but
1509 * we still need to copyin, send it,
1510 * receive a reply, and do copyout.
1513 mr
= ipc_kmsg_copyin(kmsg
, space
, current_map(),
1515 if (mr
!= MACH_MSG_SUCCESS
) {
1516 ipc_kmsg_free(kmsg
);
1521 * LP64support - We have to recompute the header pointer
1522 * and send_size - as they could have changed during the
1525 hdr
= kmsg
->ikm_header
;
1526 send_size
= hdr
->msgh_size
;
1528 /* try to get back on optimized path */
1529 if ((reply_name
!= rcv_name
) ||
1530 (hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
)) {
1531 HOT(c_mmot_cold_048
++);
1535 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1536 assert(IP_VALID(dest_port
));
1539 if (!ip_active(dest_port
)) {
1540 ip_unlock(dest_port
);
1544 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
1545 dest_port
->ip_messages
.imq_seqno
++;
1546 ip_unlock(dest_port
);
1550 if (!imq_full(&dest_port
->ip_messages
) ||
1551 (MACH_MSGH_BITS_REMOTE(hdr
->msgh_bits
) ==
1552 MACH_MSG_TYPE_PORT_SEND_ONCE
))
1555 * Try an optimized ipc_mqueue_copyin.
1556 * It will work if this is a request message.
1559 register ipc_port_t reply_port
;
1561 reply_port
= (ipc_port_t
) hdr
->msgh_local_port
;
1562 if (IP_VALID(reply_port
)) {
1563 if (ip_lock_try(reply_port
)) {
1564 if (ip_active(reply_port
) &&
1565 reply_port
->ip_receiver
== space
&&
1566 reply_port
->ip_receiver_name
== rcv_name
&&
1567 reply_port
->ip_pset_count
== 0)
1569 /* Grab a reference to the reply port. */
1570 rcv_object
= (ipc_object_t
) reply_port
;
1571 io_reference(rcv_object
);
1572 rcv_mqueue
= &reply_port
->ip_messages
;
1573 io_unlock(rcv_object
);
1574 HOT(c_mmot_getback_FastSR
++);
1575 goto fast_send_receive
;
1577 ip_unlock(reply_port
);
1582 ip_unlock(dest_port
);
1583 HOT(c_mmot_cold_050
++);
1588 * Special case: send message to kernel services.
1589 * The request message has been copied into the
1590 * kmsg. Nothing is locked.
1594 register ipc_port_t reply_port
;
1595 mach_port_seqno_t local_seqno
;
1599 * Perform the kernel function.
1601 c_mmot_kernel_send
++;
1603 current_task()->messages_sent
++;
1605 kmsg
= ipc_kobject_server(kmsg
);
1606 if (kmsg
== IKM_NULL
) {
1608 * No reply. Take the
1609 * slow receive path.
1611 HOT(c_mmot_cold_051
++);
1612 goto slow_get_rcv_port
;
1617 * the reply port is alive
1618 * we hold the receive right
1619 * the name has not changed.
1620 * the port is not in a set
1621 * If any of these are not true,
1622 * we cannot directly receive the reply
1625 hdr
= kmsg
->ikm_header
;
1626 send_size
= hdr
->msgh_size
;
1627 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1628 round_msg(send_size
));
1629 reply_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1630 ip_lock(reply_port
);
1632 if ((!ip_active(reply_port
)) ||
1633 (reply_port
->ip_receiver
!= space
) ||
1634 (reply_port
->ip_receiver_name
!= rcv_name
) ||
1635 (reply_port
->ip_pset_count
!= 0))
1637 ip_unlock(reply_port
);
1638 ipc_kmsg_send_always(kmsg
);
1639 HOT(c_mmot_cold_052
++);
1640 goto slow_get_rcv_port
;
1644 rcv_mqueue
= &reply_port
->ip_messages
;
1645 imq_lock(rcv_mqueue
);
1647 /* keep port locked, and don`t change ref count yet */
1650 * If there are messages on the port
1651 * or other threads waiting for a message,
1652 * we cannot directly receive the reply.
1654 if (!wait_queue_empty(&rcv_mqueue
->imq_wait_queue
) ||
1655 (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
))
1657 imq_unlock(rcv_mqueue
);
1659 ip_unlock(reply_port
);
1660 ipc_kmsg_send_always(kmsg
);
1661 HOT(c_mmot_cold_053
++);
1662 goto slow_get_rcv_port
;
1666 * We can directly receive this reply.
1667 * Since there were no messages queued
1668 * on the reply port, there should be
1669 * no threads blocked waiting to send.
1671 dest_port
= reply_port
;
1672 local_seqno
= rcv_mqueue
->imq_seqno
++;
1673 imq_unlock(rcv_mqueue
);
1677 * inline ipc_object_release.
1678 * Port is still locked.
1679 * Reference count was not incremented.
1681 ip_check_unlock(reply_port
);
1683 if (option
& MACH_RCV_TRAILER_MASK
) {
1684 trailer
->msgh_seqno
= local_seqno
;
1685 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1687 /* copy out the kernel reply */
1688 HOT(c_mmot_fastkernelreply
++);
1694 * Nothing is locked. We have acquired kmsg, but
1695 * we still need to send it and receive a reply.
1698 mr
= ipc_kmsg_send(kmsg
, MACH_MSG_OPTION_NONE
,
1699 MACH_MSG_TIMEOUT_NONE
);
1700 if (mr
!= MACH_MSG_SUCCESS
) {
1701 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
,
1703 MACH_MSG_BODY_NULL
);
1705 (void) ipc_kmsg_put(msg_addr
, kmsg
,
1706 kmsg
->ikm_header
->msgh_size
);
1712 * We have sent the message. Copy in the receive port.
1714 mr
= ipc_mqueue_copyin(space
, rcv_name
,
1715 &rcv_mqueue
, &rcv_object
);
1716 if (mr
!= MACH_MSG_SUCCESS
) {
1719 /* hold ref for rcv_object */
1724 * Now we have sent the request and copied in rcv_name,
1725 * and hold ref for rcv_object (to keep mqueue alive).
1726 * Just receive a reply and try to get back to fast path.
1729 self
->ith_continuation
= (void (*)(mach_msg_return_t
))0;
1730 ipc_mqueue_receive(rcv_mqueue
,
1731 MACH_MSG_OPTION_NONE
,
1733 MACH_MSG_TIMEOUT_NONE
,
1736 mr
= self
->ith_state
;
1737 temp_seqno
= self
->ith_seqno
;
1739 ipc_object_release(rcv_object
);
1741 if (mr
!= MACH_MSG_SUCCESS
) {
1745 kmsg
= self
->ith_kmsg
;
1746 hdr
= kmsg
->ikm_header
;
1747 send_size
= hdr
->msgh_size
;
1748 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1749 round_msg(send_size
));
1750 if (option
& MACH_RCV_TRAILER_MASK
) {
1751 trailer
->msgh_seqno
= temp_seqno
;
1752 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1754 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1755 HOT(c_mmot_cold_055
++);
1760 * Nothing locked and no references held, except
1761 * we have kmsg with msgh_seqno filled in. Must
1762 * still check against rcv_size and do
1763 * ipc_kmsg_copyout/ipc_kmsg_put.
1766 /* LP64support - have to compute real size as it would be received */
1767 reply_size
= ipc_kmsg_copyout_size(kmsg
, current_map()) +
1768 REQUESTED_TRAILER_SIZE(option
);
1769 if (rcv_size
< reply_size
) {
1770 if (msg_receive_error(kmsg
, msg_addr
, option
, temp_seqno
,
1771 space
) == MACH_RCV_INVALID_DATA
) {
1772 mr
= MACH_RCV_INVALID_DATA
;
1776 mr
= MACH_RCV_TOO_LARGE
;
1781 mr
= ipc_kmsg_copyout(kmsg
, space
, current_map(),
1782 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
1783 if (mr
!= MACH_MSG_SUCCESS
) {
1784 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
1785 if (ipc_kmsg_put(msg_addr
, kmsg
, reply_size
) ==
1786 MACH_RCV_INVALID_DATA
)
1787 mr
= MACH_RCV_INVALID_DATA
;
1790 if (msg_receive_error(kmsg
, msg_addr
, option
,
1791 temp_seqno
, space
) == MACH_RCV_INVALID_DATA
)
1792 mr
= MACH_RCV_INVALID_DATA
;
1798 /* try to get back on optimized path */
1799 HOT(c_mmot_getback_fast_put
++);
1804 } /* END OF HOT PATH */
1805 #endif /* ENABLE_HOTPATH */
1807 if (option
& MACH_SEND_MSG
) {
1808 ipc_space_t space
= current_space();
1809 vm_map_t map
= current_map();
1812 mr
= ipc_kmsg_get(msg_addr
, send_size
, &kmsg
);
1814 if (mr
!= MACH_MSG_SUCCESS
)
1817 if (option
& MACH_SEND_CANCEL
) {
1818 if (notify
== MACH_PORT_NULL
)
1819 mr
= MACH_SEND_INVALID_NOTIFY
;
1821 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, notify
);
1823 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
1824 if (mr
!= MACH_MSG_SUCCESS
) {
1825 ipc_kmsg_free(kmsg
);
1829 mr
= ipc_kmsg_send(kmsg
, option
& MACH_SEND_TIMEOUT
, msg_timeout
);
1831 if (mr
!= MACH_MSG_SUCCESS
) {
1832 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
);
1833 (void) ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
);
1839 if (option
& MACH_RCV_MSG
) {
1840 thread_t self
= current_thread();
1841 ipc_space_t space
= current_space();
1842 ipc_object_t object
;
1843 ipc_mqueue_t mqueue
;
1845 mr
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
);
1846 if (mr
!= MACH_MSG_SUCCESS
) {
1849 /* hold ref for object */
1852 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
1853 * and receive buffer
1854 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
1855 * alternate receive buffer (separate send and receive buffers).
1857 if (option
& MACH_RCV_OVERWRITE
)
1858 self
->ith_msg_addr
= rcv_msg_addr
;
1859 else if (rcv_msg_addr
!= (mach_vm_address_t
)0)
1860 self
->ith_msg_addr
= rcv_msg_addr
;
1862 self
->ith_msg_addr
= msg_addr
;
1863 self
->ith_object
= object
;
1864 self
->ith_msize
= rcv_size
;
1865 self
->ith_option
= option
;
1866 self
->ith_scatter_list_size
= scatter_list_size
;
1867 self
->ith_continuation
= thread_syscall_return
;
1869 ipc_mqueue_receive(mqueue
, option
, rcv_size
, msg_timeout
, THREAD_ABORTSAFE
);
1870 if ((option
& MACH_RCV_TIMEOUT
) && msg_timeout
== 0)
1871 thread_poll_yield(self
);
1872 return mach_msg_receive_results();
1875 return MACH_MSG_SUCCESS
;
1879 * Routine: mach_msg_trap [mach trap]
1881 * Possibly send a message; possibly receive a message.
1885 * All of mach_msg_send and mach_msg_receive error codes.
1890 struct mach_msg_overwrite_trap_args
*args
)
1893 args
->rcv_msg
= (mach_vm_address_t
)0;
1895 kr
= mach_msg_overwrite_trap(args
);
1901 * Routine: msg_receive_error [internal]
1903 * Builds a minimal header/trailer and copies it to
1904 * the user message buffer. Invoked when in the case of a
1905 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
1909 * MACH_MSG_SUCCESS minimal header/trailer copied
1910 * MACH_RCV_INVALID_DATA copyout to user buffer failed
1916 mach_vm_address_t msg_addr
,
1917 mach_msg_option_t option
,
1918 mach_port_seqno_t seqno
,
1921 mach_msg_format_0_trailer_t
*trailer
;
1924 * Copy out the destination port in the message.
1925 * Destroy all other rights and memory in the message.
1927 ipc_kmsg_copyout_dest(kmsg
, space
);
1930 * Build a minimal message with the requested trailer.
1932 trailer
= (mach_msg_format_0_trailer_t
*)
1933 ((vm_offset_t
)kmsg
->ikm_header
+
1934 round_msg(sizeof(mach_msg_header_t
)));
1935 kmsg
->ikm_header
->msgh_size
= sizeof(mach_msg_header_t
);
1936 bcopy( (char *)&trailer_template
,
1938 sizeof(trailer_template
));
1939 if (option
& MACH_RCV_TRAILER_MASK
) {
1940 trailer
->msgh_seqno
= seqno
;
1941 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1945 * Copy the message to user space
1947 if (ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
+
1948 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
1949 return(MACH_RCV_INVALID_DATA
);
1951 return(MACH_MSG_SUCCESS
);