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 msg_and_trailer_size
= send_size
+ MAX_TRAILER_SIZE
;
188 kmsg
= ipc_kmsg_alloc(msg_and_trailer_size
);
190 if (kmsg
== IKM_NULL
)
191 return MACH_SEND_NO_BUFFER
;
193 (void) memcpy((void *) kmsg
->ikm_header
, (const void *) msg
, send_size
);
195 kmsg
->ikm_header
->msgh_size
= send_size
;
198 * reserve for the trailer the largest space (MAX_TRAILER_SIZE)
199 * However, the internal size field of the trailer (msgh_trailer_size)
200 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
201 * the cases where no implicit data is requested.
203 trailer
= (mach_msg_max_trailer_t
*) ((vm_offset_t
)kmsg
->ikm_header
+ send_size
);
204 trailer
->msgh_sender
= current_thread()->task
->sec_token
;
205 trailer
->msgh_audit
= current_thread()->task
->audit_token
;
206 trailer
->msgh_trailer_type
= MACH_MSG_TRAILER_FORMAT_0
;
207 trailer
->msgh_trailer_size
= MACH_MSG_TRAILER_MINIMUM_SIZE
;
209 if (option
& MACH_SEND_CANCEL
) {
210 if (notify
== MACH_PORT_NULL
)
211 mr
= MACH_SEND_INVALID_NOTIFY
;
213 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, notify
);
215 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
216 if (mr
!= MACH_MSG_SUCCESS
) {
221 mr
= ipc_kmsg_send(kmsg
, option
& MACH_SEND_TIMEOUT
, send_timeout
);
223 if (mr
!= MACH_MSG_SUCCESS
) {
224 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
);
225 (void) memcpy((void *) msg
, (const void *) kmsg
->ikm_header
,
226 kmsg
->ikm_header
->msgh_size
);
234 * Routine: mach_msg_receive
240 * MACH_MSG_SUCCESS Received a message.
241 * MACH_RCV_INVALID_NAME The name doesn't denote a right,
242 * or the denoted right is not receive or port set.
243 * MACH_RCV_IN_SET Receive right is a member of a set.
244 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
245 * MACH_RCV_TIMED_OUT Timeout expired without a message.
246 * MACH_RCV_INTERRUPTED Reception interrupted.
247 * MACH_RCV_PORT_DIED Port/set died while receiving.
248 * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
249 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
250 * MACH_RCV_INVALID_NOTIFY Bad notify port.
251 * MACH_RCV_HEADER_ERROR
255 mach_msg_receive_results(void)
257 thread_t self
= current_thread();
258 ipc_space_t space
= current_space();
259 vm_map_t map
= current_map();
261 ipc_object_t object
= self
->ith_object
;
262 mach_msg_return_t mr
= self
->ith_state
;
263 mach_vm_address_t msg_addr
= self
->ith_msg_addr
;
264 mach_msg_option_t option
= self
->ith_option
;
265 ipc_kmsg_t kmsg
= self
->ith_kmsg
;
266 mach_port_seqno_t seqno
= self
->ith_seqno
;
268 mach_msg_format_0_trailer_t
*trailer
;
270 ipc_object_release(object
);
272 if (mr
!= MACH_MSG_SUCCESS
) {
274 if (mr
== MACH_RCV_TOO_LARGE
) {
275 if (option
& MACH_RCV_LARGE
) {
277 * We need to inform the user-level code that it needs more
278 * space. The value for how much space was returned in the
279 * msize save area instead of the message (which was left on
282 if (copyout((char *) &self
->ith_msize
,
283 msg_addr
+ offsetof(mach_msg_header_t
, msgh_size
),
284 sizeof(mach_msg_size_t
)))
285 mr
= MACH_RCV_INVALID_DATA
;
289 if (msg_receive_error(kmsg
, msg_addr
, option
, seqno
, space
)
290 == MACH_RCV_INVALID_DATA
)
291 mr
= MACH_RCV_INVALID_DATA
;
296 trailer
= (mach_msg_format_0_trailer_t
*)
297 ((vm_offset_t
)kmsg
->ikm_header
+
298 round_msg(kmsg
->ikm_header
->msgh_size
));
299 if (option
& MACH_RCV_TRAILER_MASK
) {
300 trailer
->msgh_seqno
= seqno
;
301 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
305 * If MACH_RCV_OVERWRITE was specified, try to get the scatter
306 * list and verify it against the contents of the message. If
307 * there is any problem with it, we will continue without it as
310 if (option
& MACH_RCV_OVERWRITE
) {
311 mach_msg_size_t slist_size
= self
->ith_scatter_list_size
;
312 mach_msg_body_t
*slist
;
314 slist
= ipc_kmsg_get_scatter(msg_addr
, slist_size
, kmsg
);
315 mr
= ipc_kmsg_copyout(kmsg
, space
, map
, MACH_PORT_NULL
, slist
);
316 ipc_kmsg_free_scatter(slist
, slist_size
);
318 mr
= ipc_kmsg_copyout(kmsg
, space
, map
,
319 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
322 if (mr
!= MACH_MSG_SUCCESS
) {
323 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
324 if (ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
+
325 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
326 mr
= MACH_RCV_INVALID_DATA
;
329 if (msg_receive_error(kmsg
, msg_addr
, option
, seqno
, space
)
330 == MACH_RCV_INVALID_DATA
)
331 mr
= MACH_RCV_INVALID_DATA
;
335 mr
= ipc_kmsg_put(msg_addr
,
337 kmsg
->ikm_header
->msgh_size
+
338 trailer
->msgh_trailer_size
);
345 mach_msg_header_t
*msg
,
346 mach_msg_option_t option
,
347 mach_msg_size_t rcv_size
,
348 mach_port_name_t rcv_name
,
349 mach_msg_timeout_t rcv_timeout
,
350 void (*continuation
)(mach_msg_return_t
),
351 mach_msg_size_t slist_size
)
353 thread_t self
= current_thread();
354 ipc_space_t space
= current_space();
357 mach_msg_return_t mr
;
359 mr
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
);
360 if (mr
!= MACH_MSG_SUCCESS
) {
363 /* hold ref for object */
365 self
->ith_msg_addr
= CAST_DOWN(mach_vm_address_t
, msg
);
366 self
->ith_object
= object
;
367 self
->ith_msize
= rcv_size
;
368 self
->ith_option
= option
;
369 self
->ith_scatter_list_size
= slist_size
;
370 self
->ith_continuation
= continuation
;
372 ipc_mqueue_receive(mqueue
, option
, rcv_size
, rcv_timeout
, THREAD_ABORTSAFE
);
373 if ((option
& MACH_RCV_TIMEOUT
) && rcv_timeout
== 0)
374 thread_poll_yield(self
);
375 return mach_msg_receive_results();
379 mach_msg_receive_continue(void)
381 thread_t self
= current_thread();
383 (*self
->ith_continuation
)(mach_msg_receive_results());
387 * Toggle this to compile the hotpath in/out
388 * If compiled in, the run-time toggle "enable_hotpath" below
389 * eases testing & debugging
391 #define ENABLE_HOTPATH 1 /* Hacked on for now */
395 * These counters allow tracing of hotpath behavior under test loads.
396 * A couple key counters are unconditional (see below).
398 #define HOTPATH_DEBUG 0 /* Toggle to include lots of counters */
400 #define HOT(expr) expr
402 unsigned int c_mmot_FIRST
= 0; /* Unused First Counter */
403 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
404 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
405 unsigned int c_mmot_kernel_send
= 0; /* kernel server */
406 unsigned int c_mmot_cold_000
= 0; /* see below ... */
407 unsigned int c_mmot_smallsendsize
= 0;
408 unsigned int c_mmot_oddsendsize
= 0;
409 unsigned int c_mmot_bigsendsize
= 0;
410 unsigned int c_mmot_copyinmsg_fail
= 0;
411 unsigned int c_mmot_g_slow_copyin3
= 0;
412 unsigned int c_mmot_cold_006
= 0;
413 unsigned int c_mmot_cold_007
= 0;
414 unsigned int c_mmot_cold_008
= 0;
415 unsigned int c_mmot_cold_009
= 0;
416 unsigned int c_mmot_cold_010
= 0;
417 unsigned int c_mmot_cold_012
= 0;
418 unsigned int c_mmot_cold_013
= 0;
419 unsigned int c_mmot_cold_014
= 0;
420 unsigned int c_mmot_cold_016
= 0;
421 unsigned int c_mmot_cold_018
= 0;
422 unsigned int c_mmot_cold_019
= 0;
423 unsigned int c_mmot_cold_020
= 0;
424 unsigned int c_mmot_cold_021
= 0;
425 unsigned int c_mmot_cold_022
= 0;
426 unsigned int c_mmot_cold_023
= 0;
427 unsigned int c_mmot_cold_024
= 0;
428 unsigned int c_mmot_cold_025
= 0;
429 unsigned int c_mmot_cold_026
= 0;
430 unsigned int c_mmot_cold_027
= 0;
431 unsigned int c_mmot_hot_fSR_ok
= 0;
432 unsigned int c_mmot_cold_029
= 0;
433 unsigned int c_mmot_cold_030
= 0;
434 unsigned int c_mmot_cold_031
= 0;
435 unsigned int c_mmot_cold_032
= 0;
436 unsigned int c_mmot_cold_033
= 0;
437 unsigned int c_mmot_bad_rcvr
= 0;
438 unsigned int c_mmot_rcvr_swapped
= 0;
439 unsigned int c_mmot_rcvr_locked
= 0;
440 unsigned int c_mmot_rcvr_tswapped
= 0;
441 unsigned int c_mmot_rcvr_freed
= 0;
442 unsigned int c_mmot_g_slow_copyout6
= 0;
443 unsigned int c_mmot_g_slow_copyout5
= 0;
444 unsigned int c_mmot_cold_037
= 0;
445 unsigned int c_mmot_cold_038
= 0;
446 unsigned int c_mmot_cold_039
= 0;
447 unsigned int c_mmot_g_slow_copyout4
= 0;
448 unsigned int c_mmot_g_slow_copyout3
= 0;
449 unsigned int c_mmot_hot_ok1
= 0;
450 unsigned int c_mmot_hot_ok2
= 0;
451 unsigned int c_mmot_hot_ok3
= 0;
452 unsigned int c_mmot_g_slow_copyout1
= 0;
453 unsigned int c_mmot_g_slow_copyout2
= 0;
454 unsigned int c_mmot_getback_fast_copyin
= 0;
455 unsigned int c_mmot_cold_048
= 0;
456 unsigned int c_mmot_getback_FastSR
= 0;
457 unsigned int c_mmot_cold_050
= 0;
458 unsigned int c_mmot_cold_051
= 0;
459 unsigned int c_mmot_cold_052
= 0;
460 unsigned int c_mmot_cold_053
= 0;
461 unsigned int c_mmot_fastkernelreply
= 0;
462 unsigned int c_mmot_cold_055
= 0;
463 unsigned int c_mmot_getback_fast_put
= 0;
464 unsigned int c_mmot_LAST
= 0; /* End Marker - Unused */
466 void db_mmot_zero_counters(void); /* forward; */
467 void db_mmot_show_counters(void); /* forward; */
469 void /* Call from the debugger to clear all counters */
470 db_mmot_zero_counters(void)
472 register unsigned int *ip
= &c_mmot_FIRST
;
473 while (ip
<= &c_mmot_LAST
)
477 void /* Call from the debugger to show all counters */
478 db_mmot_show_counters(void)
480 #define xx(str) printf("%s: %d\n", # str, str);
482 xx(c_mmot_combined_S_R
);
483 xx(c_mach_msg_trap_switch_fast
);
484 xx(c_mmot_kernel_send
);
486 xx(c_mmot_smallsendsize
);
487 xx(c_mmot_oddsendsize
);
488 xx(c_mmot_bigsendsize
);
489 xx(c_mmot_copyinmsg_fail
);
490 xx(c_mmot_g_slow_copyin3
);
510 xx(c_mmot_hot_fSR_ok
);
517 xx(c_mmot_rcvr_swapped
);
518 xx(c_mmot_rcvr_locked
);
519 xx(c_mmot_rcvr_tswapped
);
520 xx(c_mmot_rcvr_freed
);
521 xx(c_mmot_g_slow_copyout6
);
522 xx(c_mmot_g_slow_copyout5
);
526 xx(c_mmot_g_slow_copyout4
);
527 xx(c_mmot_g_slow_copyout3
);
528 xx(c_mmot_g_slow_copyout1
);
532 xx(c_mmot_g_slow_copyout2
);
533 xx(c_mmot_getback_fast_copyin
);
535 xx(c_mmot_getback_FastSR
);
540 xx(c_mmot_fastkernelreply
);
542 xx(c_mmot_getback_fast_put
);
547 #else /* !HOTPATH_DEBUG */
550 * Duplicate just these few so we can always do a quick sanity check
552 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
553 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
554 unsigned int c_mmot_kernel_send
= 0; /* kernel server calls */
555 #define HOT(expr) /* no optional counters */
557 #endif /* !HOTPATH_DEBUG */
559 boolean_t enable_hotpath
= TRUE
; /* Patchable, just in case ... */
560 #endif /* HOTPATH_ENABLE */
563 * Routine: mach_msg_overwrite_trap [mach trap]
565 * Possibly send a message; possibly receive a message.
569 * All of mach_msg_send and mach_msg_receive error codes.
573 mach_msg_overwrite_trap(
574 struct mach_msg_overwrite_trap_args
*args
)
576 mach_vm_address_t msg_addr
= args
->msg
;
577 mach_msg_option_t option
= args
->option
;
578 mach_msg_size_t send_size
= args
->send_size
;
579 mach_msg_size_t rcv_size
= args
->rcv_size
;
580 mach_port_name_t rcv_name
= args
->rcv_name
;
581 mach_msg_timeout_t msg_timeout
= args
->timeout
;
582 mach_port_name_t notify
= args
->notify
;
583 mach_vm_address_t rcv_msg_addr
= args
->rcv_msg
;
584 mach_msg_size_t scatter_list_size
= 0; /* NOT INITIALIZED - but not used in pactice */
585 mach_port_seqno_t temp_seqno
= 0;
587 register mach_msg_header_t
*hdr
;
588 mach_msg_return_t mr
= MACH_MSG_SUCCESS
;
589 /* mask out some of the options before entering the hot path */
590 mach_msg_option_t masked_option
=
591 option
& ~(MACH_SEND_TRAILER
|MACH_RCV_TRAILER_MASK
|MACH_RCV_LARGE
);
594 /* BEGINNING OF HOT PATH */
595 if ((masked_option
== (MACH_SEND_MSG
|MACH_RCV_MSG
)) && enable_hotpath
) {
596 thread_t self
= current_thread();
597 mach_msg_format_0_trailer_t
*trailer
;
598 ipc_space_t space
= self
->task
->itk_space
;
600 register ipc_port_t dest_port
;
601 ipc_object_t rcv_object
;
602 ipc_mqueue_t rcv_mqueue
;
603 mach_msg_size_t reply_size
;
605 c_mmot_combined_S_R
++;
608 * This case is divided into ten sections, each
609 * with a label. There are five optimized
610 * sections and six unoptimized sections, which
611 * do the same thing but handle all possible
612 * cases and are slower.
614 * The five sections for an RPC are
615 * 1) Get request message into a buffer.
616 * 2) Copyin request message and rcv_name.
617 * (fast_copyin or slow_copyin)
618 * 3) Enqueue request and dequeue reply.
619 * (fast_send_receive or
620 * slow_send and slow_receive)
621 * 4) Copyout reply message.
622 * (fast_copyout or slow_copyout)
623 * 5) Put reply message to user's buffer.
625 * Keep the locking hierarchy firmly in mind.
626 * (First spaces, then ports, then port sets,
627 * then message queues.) Only a non-blocking
628 * attempt can be made to acquire locks out of
629 * order, or acquire two locks on the same level.
630 * Acquiring two locks on the same level will
631 * fail if the objects are really the same,
632 * unless simple locking is disabled. This is OK,
633 * because then the extra unlock does nothing.
635 * There are two major reasons these RPCs can't use
636 * ipc_thread_switch, and use slow_send/slow_receive:
638 * 2) Servers fall behind clients, so
639 * client doesn't find a blocked server thread and
640 * server finds waiting messages and can't block.
643 mr
= ipc_kmsg_get(msg_addr
, send_size
, &kmsg
);
644 if (mr
!= KERN_SUCCESS
) {
647 hdr
= kmsg
->ikm_header
;
648 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
654 * optimized ipc_kmsg_copyin/ipc_mqueue_copyin
656 * We have the request message data in kmsg.
657 * Must still do copyin, send, receive, etc.
659 * If the message isn't simple, we can't combine
660 * ipc_kmsg_copyin_header and ipc_mqueue_copyin,
661 * because copyin of the message body might
665 switch (hdr
->msgh_bits
) {
666 case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,
667 MACH_MSG_TYPE_MAKE_SEND_ONCE
): {
668 register ipc_entry_t table
;
669 register ipc_entry_num_t size
;
670 register ipc_port_t reply_port
;
672 /* sending a request message */
675 register mach_port_index_t index
;
676 register mach_port_gen_t gen
;
679 register mach_port_name_t reply_name
=
680 (mach_port_name_t
)hdr
->msgh_local_port
;
682 if (reply_name
!= rcv_name
) {
683 HOT(c_mmot_g_slow_copyin3
++);
687 /* optimized ipc_entry_lookup of reply_name */
689 index
= MACH_PORT_INDEX(reply_name
);
690 gen
= MACH_PORT_GEN(reply_name
);
693 assert(space
->is_active
);
695 size
= space
->is_table_size
;
696 table
= space
->is_table
;
699 register ipc_entry_t entry
;
700 register ipc_entry_bits_t bits
;
703 entry
= &table
[index
];
704 bits
= entry
->ie_bits
;
705 if (IE_BITS_GEN(bits
) != gen
||
706 (bits
& IE_BITS_COLLISION
)) {
713 if (entry
== IE_NULL
) {
714 entry
= ipc_entry_lookup(space
, reply_name
);
715 if (entry
== IE_NULL
) {
716 HOT(c_mmot_cold_006
++);
717 goto abort_request_copyin
;
719 bits
= entry
->ie_bits
;
724 if (! (bits
& MACH_PORT_TYPE_RECEIVE
)) {
725 HOT(c_mmot_cold_007
++);
726 goto abort_request_copyin
;
729 reply_port
= (ipc_port_t
) entry
->ie_object
;
730 assert(reply_port
!= IP_NULL
);
735 /* optimized ipc_entry_lookup of dest_name */
738 register mach_port_index_t index
;
739 register mach_port_gen_t gen
;
742 register mach_port_name_t dest_name
=
743 (mach_port_name_t
)hdr
->msgh_remote_port
;
745 index
= MACH_PORT_INDEX(dest_name
);
746 gen
= MACH_PORT_GEN(dest_name
);
749 register ipc_entry_t entry
;
750 register ipc_entry_bits_t bits
;
753 entry
= &table
[index
];
754 bits
= entry
->ie_bits
;
755 if (IE_BITS_GEN(bits
) != gen
||
756 (bits
& IE_BITS_COLLISION
)) {
763 if (entry
== IE_NULL
) {
764 entry
= ipc_entry_lookup(space
, dest_name
);
765 if (entry
== IE_NULL
) {
766 HOT(c_mmot_cold_008
++);
767 goto abort_request_copyin
;
769 bits
= entry
->ie_bits
;
774 if (! (bits
& MACH_PORT_TYPE_SEND
)) {
775 HOT(c_mmot_cold_009
++);
776 goto abort_request_copyin
;
779 assert(IE_BITS_UREFS(bits
) > 0);
781 dest_port
= (ipc_port_t
) entry
->ie_object
;
782 assert(dest_port
!= IP_NULL
);
788 * To do an atomic copyin, need simultaneous
789 * locks on both ports and the space. If
790 * dest_port == reply_port, and simple locking is
791 * enabled, then we will abort. Otherwise it's
792 * OK to unlock twice.
796 if (!ip_active(dest_port
) ||
797 !ip_lock_try(reply_port
)) {
798 ip_unlock(dest_port
);
799 HOT(c_mmot_cold_010
++);
800 goto abort_request_copyin
;
802 is_read_unlock(space
);
804 assert(dest_port
->ip_srights
> 0);
805 dest_port
->ip_srights
++;
806 ip_reference(dest_port
);
808 assert(ip_active(reply_port
));
809 assert(reply_port
->ip_receiver_name
==
810 (mach_port_name_t
)hdr
->msgh_local_port
);
811 assert(reply_port
->ip_receiver
== space
);
813 reply_port
->ip_sorights
++;
814 ip_reference(reply_port
);
817 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
818 MACH_MSG_TYPE_PORT_SEND_ONCE
);
819 hdr
->msgh_remote_port
= dest_port
;
820 hdr
->msgh_local_port
= reply_port
;
822 /* make sure we can queue to the destination */
824 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
826 * The kernel server has a reference to
827 * the reply port, which it hands back
828 * to us in the reply message. We do
829 * not need to keep another reference to
832 ip_unlock(reply_port
);
834 assert(ip_active(dest_port
));
835 dest_port
->ip_messages
.imq_seqno
++;
836 ip_unlock(dest_port
);
840 if (imq_full(&dest_port
->ip_messages
)) {
841 HOT(c_mmot_cold_013
++);
842 goto abort_request_send_receive
;
845 /* optimized ipc_mqueue_copyin */
847 rcv_object
= (ipc_object_t
) reply_port
;
848 io_reference(rcv_object
);
849 rcv_mqueue
= &reply_port
->ip_messages
;
850 io_unlock(rcv_object
);
851 HOT(c_mmot_hot_fSR_ok
++);
852 goto fast_send_receive
;
854 abort_request_copyin
:
855 is_read_unlock(space
);
858 abort_request_send_receive
:
859 ip_unlock(dest_port
);
860 ip_unlock(reply_port
);
864 case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0): {
865 register ipc_entry_num_t size
;
866 register ipc_entry_t table
;
868 /* sending a reply message */
871 register mach_port_name_t reply_name
=
872 (mach_port_name_t
)hdr
->msgh_local_port
;
874 if (reply_name
!= MACH_PORT_NULL
) {
875 HOT(c_mmot_cold_018
++);
880 is_write_lock(space
);
881 assert(space
->is_active
);
883 /* optimized ipc_entry_lookup */
885 size
= space
->is_table_size
;
886 table
= space
->is_table
;
889 register ipc_entry_t entry
;
890 register mach_port_gen_t gen
;
891 register mach_port_index_t index
;
894 register mach_port_name_t dest_name
=
895 (mach_port_name_t
)hdr
->msgh_remote_port
;
897 index
= MACH_PORT_INDEX(dest_name
);
898 gen
= MACH_PORT_GEN(dest_name
);
902 HOT(c_mmot_cold_019
++);
903 goto abort_reply_dest_copyin
;
906 entry
= &table
[index
];
908 /* check generation, collision bit, and type bit */
910 if ((entry
->ie_bits
& (IE_BITS_GEN_MASK
|
912 MACH_PORT_TYPE_SEND_ONCE
)) !=
913 (gen
| MACH_PORT_TYPE_SEND_ONCE
)) {
914 HOT(c_mmot_cold_020
++);
915 goto abort_reply_dest_copyin
;
918 /* optimized ipc_right_copyin */
920 assert(IE_BITS_TYPE(entry
->ie_bits
) ==
921 MACH_PORT_TYPE_SEND_ONCE
);
922 assert(IE_BITS_UREFS(entry
->ie_bits
) == 1);
924 if (entry
->ie_request
!= 0) {
925 HOT(c_mmot_cold_021
++);
926 goto abort_reply_dest_copyin
;
929 dest_port
= (ipc_port_t
) entry
->ie_object
;
930 assert(dest_port
!= IP_NULL
);
933 if (!ip_active(dest_port
)) {
934 ip_unlock(dest_port
);
935 HOT(c_mmot_cold_022
++);
936 goto abort_reply_dest_copyin
;
939 assert(dest_port
->ip_sorights
> 0);
941 /* optimized ipc_entry_dealloc */
944 entry
->ie_bits
= gen
;
945 entry
->ie_next
= table
->ie_next
;
946 table
->ie_next
= index
;
947 entry
->ie_object
= IO_NULL
;
951 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
953 hdr
->msgh_remote_port
= dest_port
;
955 /* make sure we can queue to the destination */
957 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
959 /* optimized ipc_entry_lookup/ipc_mqueue_copyin */
962 register ipc_entry_t entry
;
963 register ipc_entry_bits_t bits
;
966 register mach_port_index_t index
;
967 register mach_port_gen_t gen
;
969 index
= MACH_PORT_INDEX(rcv_name
);
970 gen
= MACH_PORT_GEN(rcv_name
);
973 entry
= &table
[index
];
974 bits
= entry
->ie_bits
;
975 if (IE_BITS_GEN(bits
) != gen
||
976 (bits
& IE_BITS_COLLISION
)) {
983 if (entry
== IE_NULL
) {
984 entry
= ipc_entry_lookup(space
, rcv_name
);
985 if (entry
== IE_NULL
) {
986 HOT(c_mmot_cold_024
++);
987 goto abort_reply_rcv_copyin
;
989 bits
= entry
->ie_bits
;
994 /* check type bits; looking for receive or set */
997 * JMM - The check below for messages in the receive
998 * mqueue is insufficient to work with port sets, since
999 * the messages stay in the port queues. For now, don't
1000 * allow portsets (but receiving on portsets when sending
1001 * a message to a send-once right is actually a very
1002 * common case (so we should re-enable).
1004 if (bits
& MACH_PORT_TYPE_PORT_SET
) {
1005 register ipc_pset_t rcv_pset
;
1007 rcv_pset
= (ipc_pset_t
) entry
->ie_object
;
1008 assert(rcv_pset
!= IPS_NULL
);
1011 assert(ips_active(rcv_pset
));
1013 rcv_object
= (ipc_object_t
) rcv_pset
;
1014 rcv_mqueue
= &rcv_pset
->ips_messages
;
1017 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1018 register ipc_port_t rcv_port
;
1020 rcv_port
= (ipc_port_t
) entry
->ie_object
;
1021 assert(rcv_port
!= IP_NULL
);
1023 if (!ip_lock_try(rcv_port
)) {
1024 HOT(c_mmot_cold_025
++);
1025 goto abort_reply_rcv_copyin
;
1027 assert(ip_active(rcv_port
));
1029 if (rcv_port
->ip_pset_count
!= 0) {
1030 ip_unlock(rcv_port
);
1031 HOT(c_mmot_cold_026
++);
1032 goto abort_reply_rcv_copyin
;
1035 rcv_object
= (ipc_object_t
) rcv_port
;
1036 rcv_mqueue
= &rcv_port
->ip_messages
;
1038 HOT(c_mmot_cold_027
++);
1039 goto abort_reply_rcv_copyin
;
1043 is_write_unlock(space
);
1044 io_reference(rcv_object
);
1045 io_unlock(rcv_object
);
1046 HOT(c_mmot_hot_fSR_ok
++);
1047 goto fast_send_receive
;
1049 abort_reply_dest_copyin
:
1050 is_write_unlock(space
);
1051 HOT(c_mmot_cold_029
++);
1054 abort_reply_rcv_copyin
:
1055 ip_unlock(dest_port
);
1056 is_write_unlock(space
);
1057 HOT(c_mmot_cold_030
++);
1062 HOT(c_mmot_cold_031
++);
1069 * optimized ipc_mqueue_send/ipc_mqueue_receive
1071 * Finished get/copyin of kmsg and copyin of rcv_name.
1072 * space is unlocked, dest_port is locked,
1073 * we can queue kmsg to dest_port,
1074 * rcv_mqueue is set, and rcv_object holds a ref
1075 * so the mqueue cannot go away.
1077 * JMM - For now, rcv_object is just a port. Portsets
1078 * are disabled for the time being.
1081 assert(ip_active(dest_port
));
1082 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
1083 // assert(!imq_full(&dest_port->ip_messages) ||
1084 // (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) ==
1085 // MACH_MSG_TYPE_PORT_SEND_ONCE));
1086 assert((hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
) == 0);
1089 register ipc_mqueue_t dest_mqueue
;
1092 processor_t processor
;
1093 boolean_t still_running
;
1097 processor
= current_processor();
1098 if (processor
->current_pri
>= BASEPRI_RTQUEUES
)
1099 goto abort_send_receive1
;
1101 dest_mqueue
= &dest_port
->ip_messages
;
1102 waitq
= &dest_mqueue
->imq_wait_queue
;
1103 imq_lock(dest_mqueue
);
1105 wait_queue_peek64_locked(waitq
, IPC_MQUEUE_RECEIVE
, &receiver
, &waitq
);
1106 /* queue still locked, thread locked - but still on q */
1108 if ( receiver
== THREAD_NULL
) {
1110 imq_unlock(dest_mqueue
);
1111 abort_send_receive1
:
1113 ip_unlock(dest_port
);
1114 ipc_object_release(rcv_object
);
1115 HOT(c_mmot_cold_032
++);
1119 assert(receiver
->state
& TH_WAIT
);
1120 assert(receiver
->wait_queue
== waitq
);
1121 assert(receiver
->wait_event
== IPC_MQUEUE_RECEIVE
);
1124 * Make sure that the scheduling restrictions of the receiver
1125 * are consistent with a handoff here (if it comes down to that).
1127 if ( receiver
->sched_pri
>= BASEPRI_RTQUEUES
||
1128 receiver
->processor_set
!= processor
->processor_set
||
1129 (receiver
->bound_processor
!= PROCESSOR_NULL
&&
1130 receiver
->bound_processor
!= processor
)) {
1131 HOT(c_mmot_cold_033
++);
1133 thread_unlock(receiver
);
1134 if (waitq
!= &dest_mqueue
->imq_wait_queue
)
1135 wait_queue_unlock(waitq
);
1136 goto abort_send_receive
;
1140 * Check that the receiver can stay on the hot path.
1142 if (ipc_kmsg_copyout_size(kmsg
, receiver
->map
) +
1143 REQUESTED_TRAILER_SIZE(receiver
->ith_option
) > receiver
->ith_msize
) {
1145 * The receiver can't accept the message.
1147 HOT(c_mmot_bad_rcvr
++);
1152 * Before committing to the handoff, make sure that we are
1153 * really going to block (i.e. there are no messages already
1154 * queued for us. This violates lock ordering, so make sure
1155 * we don't deadlock. After the trylock succeeds below, we
1156 * may have up to 3 message queues locked:
1157 * - the dest port mqueue
1158 * - a portset mqueue (where waiting receiver was found)
1159 * - finally our own rcv_mqueue
1161 * JMM - Need to make this check appropriate for portsets as
1162 * well before re-enabling them.
1164 if (!imq_lock_try(rcv_mqueue
)) {
1167 if (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
) {
1168 imq_unlock(rcv_mqueue
);
1169 HOT(c_mmot_cold_033
++);
1173 /* At this point we are committed to do the "handoff". */
1174 c_mach_msg_trap_switch_fast
++;
1177 * Go ahead and pull the receiver from the waitq. If the
1178 * waitq wasn't the one for the mqueue, unlock it.
1180 wait_queue_pull_thread_locked(waitq
,
1182 (waitq
!= &dest_mqueue
->imq_wait_queue
));
1185 * Store the kmsg and seqno where the receiver can pick it up.
1187 receiver
->ith_state
= MACH_MSG_SUCCESS
;
1188 receiver
->ith_kmsg
= kmsg
;
1189 receiver
->ith_seqno
= dest_mqueue
->imq_seqno
++;
1192 * Unblock the receiver. If it was still running on another
1193 * CPU, we'll give it a chance to run with the message where
1194 * it is (and just select someother thread to run here).
1195 * Otherwise, we'll invoke it here as part of the handoff.
1197 still_running
= thread_unblock(receiver
, THREAD_AWAKENED
);
1199 thread_unlock(receiver
);
1201 imq_unlock(dest_mqueue
);
1202 ip_unlock(dest_port
);
1203 current_task()->messages_sent
++;
1207 * Put self on receive port's queue.
1208 * Also save state that the sender of
1209 * our reply message needs to determine if it
1210 * can hand off directly back to us.
1213 self
->ith_msg_addr
= (rcv_msg_addr
) ? rcv_msg_addr
: msg_addr
;
1214 self
->ith_object
= rcv_object
; /* still holds reference */
1215 self
->ith_msize
= rcv_size
;
1216 self
->ith_option
= option
;
1217 self
->ith_scatter_list_size
= scatter_list_size
;
1218 self
->ith_continuation
= thread_syscall_return
;
1220 waitq
= &rcv_mqueue
->imq_wait_queue
;
1221 (void)wait_queue_assert_wait64_locked(waitq
,
1223 THREAD_ABORTSAFE
, 0,
1225 thread_unlock(self
);
1226 imq_unlock(rcv_mqueue
);
1229 * If the receiving thread wasn't still running, we switch directly
1230 * to it here. Otherwise we let the scheduler pick something for
1231 * here. In either case, block this thread as though it had called
1232 * ipc_mqueue_receive.
1234 if (still_running
) {
1236 thread_block(ipc_mqueue_receive_continue
);
1238 thread_run(self
, ipc_mqueue_receive_continue
, NULL
, receiver
);
1245 * Nothing locked and no references held, except
1246 * we have kmsg with msgh_seqno filled in. Must
1247 * still check against rcv_size and do
1248 * ipc_kmsg_copyout/ipc_kmsg_put.
1251 reply_size
= send_size
+ trailer
->msgh_trailer_size
;
1252 if (rcv_size
< reply_size
) {
1253 HOT(c_mmot_g_slow_copyout6
++);
1257 /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */
1259 switch (hdr
->msgh_bits
) {
1260 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
1261 MACH_MSG_TYPE_PORT_SEND_ONCE
): {
1262 ipc_port_t reply_port
=
1263 (ipc_port_t
) hdr
->msgh_local_port
;
1264 mach_port_name_t dest_name
, reply_name
;
1266 /* receiving a request message */
1268 if (!IP_VALID(reply_port
)) {
1269 HOT(c_mmot_g_slow_copyout5
++);
1273 is_write_lock(space
);
1274 assert(space
->is_active
);
1277 * To do an atomic copyout, need simultaneous
1278 * locks on both ports and the space. If
1279 * dest_port == reply_port, and simple locking is
1280 * enabled, then we will abort. Otherwise it's
1281 * OK to unlock twice.
1285 if (!ip_active(dest_port
) ||
1286 !ip_lock_try(reply_port
)) {
1287 HOT(c_mmot_cold_037
++);
1288 goto abort_request_copyout
;
1291 if (!ip_active(reply_port
)) {
1292 ip_unlock(reply_port
);
1293 HOT(c_mmot_cold_038
++);
1294 goto abort_request_copyout
;
1297 assert(reply_port
->ip_sorights
> 0);
1298 ip_unlock(reply_port
);
1301 register ipc_entry_t table
;
1302 register ipc_entry_t entry
;
1303 register mach_port_index_t index
;
1305 /* optimized ipc_entry_get */
1307 table
= space
->is_table
;
1308 index
= table
->ie_next
;
1311 HOT(c_mmot_cold_039
++);
1312 goto abort_request_copyout
;
1315 entry
= &table
[index
];
1316 table
->ie_next
= entry
->ie_next
;
1317 entry
->ie_request
= 0;
1320 register mach_port_gen_t gen
;
1322 assert((entry
->ie_bits
&~ IE_BITS_GEN_MASK
) == 0);
1323 gen
= IE_BITS_NEW_GEN(entry
->ie_bits
);
1325 reply_name
= MACH_PORT_MAKE(index
, gen
);
1327 /* optimized ipc_right_copyout */
1329 entry
->ie_bits
= gen
| (MACH_PORT_TYPE_SEND_ONCE
| 1);
1332 assert(MACH_PORT_VALID(reply_name
));
1333 entry
->ie_object
= (ipc_object_t
) reply_port
;
1334 is_write_unlock(space
);
1337 /* optimized ipc_object_copyout_dest */
1339 assert(dest_port
->ip_srights
> 0);
1340 ip_release(dest_port
);
1342 if (dest_port
->ip_receiver
== space
)
1343 dest_name
= dest_port
->ip_receiver_name
;
1345 dest_name
= MACH_PORT_NULL
;
1347 if ((--dest_port
->ip_srights
== 0) &&
1348 (dest_port
->ip_nsrequest
!= IP_NULL
)) {
1349 ipc_port_t nsrequest
;
1350 mach_port_mscount_t mscount
;
1352 /* a rather rare case */
1354 nsrequest
= dest_port
->ip_nsrequest
;
1355 mscount
= dest_port
->ip_mscount
;
1356 dest_port
->ip_nsrequest
= IP_NULL
;
1357 ip_unlock(dest_port
);
1358 ipc_notify_no_senders(nsrequest
, mscount
);
1360 ip_unlock(dest_port
);
1363 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
1364 MACH_MSG_TYPE_PORT_SEND
);
1365 hdr
->msgh_remote_port
= (mach_port_t
)reply_name
;
1366 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1367 HOT(c_mmot_hot_ok1
++);
1370 abort_request_copyout
:
1371 ip_unlock(dest_port
);
1372 is_write_unlock(space
);
1373 HOT(c_mmot_g_slow_copyout4
++);
1377 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1378 register mach_port_name_t dest_name
;
1380 /* receiving a reply message */
1383 if (!ip_active(dest_port
)) {
1384 ip_unlock(dest_port
);
1385 HOT(c_mmot_g_slow_copyout3
++);
1389 /* optimized ipc_object_copyout_dest */
1391 assert(dest_port
->ip_sorights
> 0);
1393 if (dest_port
->ip_receiver
== space
) {
1394 ip_release(dest_port
);
1395 dest_port
->ip_sorights
--;
1396 dest_name
= dest_port
->ip_receiver_name
;
1397 ip_unlock(dest_port
);
1399 ip_unlock(dest_port
);
1401 ipc_notify_send_once(dest_port
);
1402 dest_name
= MACH_PORT_NULL
;
1405 hdr
->msgh_bits
= MACH_MSGH_BITS(0,
1406 MACH_MSG_TYPE_PORT_SEND_ONCE
);
1407 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1408 hdr
->msgh_local_port
= (ipc_port_t
)dest_name
;
1409 HOT(c_mmot_hot_ok2
++);
1413 case MACH_MSGH_BITS_COMPLEX
|
1414 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1415 register mach_port_name_t dest_name
;
1417 /* receiving a complex reply message */
1420 if (!ip_active(dest_port
)) {
1421 ip_unlock(dest_port
);
1422 HOT(c_mmot_g_slow_copyout1
++);
1426 /* optimized ipc_object_copyout_dest */
1428 assert(dest_port
->ip_sorights
> 0);
1430 if (dest_port
->ip_receiver
== space
) {
1431 ip_release(dest_port
);
1432 dest_port
->ip_sorights
--;
1433 dest_name
= dest_port
->ip_receiver_name
;
1434 ip_unlock(dest_port
);
1436 ip_unlock(dest_port
);
1438 ipc_notify_send_once(dest_port
);
1439 dest_name
= MACH_PORT_NULL
;
1443 MACH_MSGH_BITS_COMPLEX
|
1444 MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE
);
1445 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1446 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1448 mr
= ipc_kmsg_copyout_body(kmsg
, space
,
1450 MACH_MSG_BODY_NULL
);
1451 /* hdr and send_size may be invalid now - done use */
1452 if (mr
!= MACH_MSG_SUCCESS
) {
1453 if (ipc_kmsg_put(msg_addr
, kmsg
,
1454 kmsg
->ikm_header
->msgh_size
+
1455 trailer
->msgh_trailer_size
) ==
1456 MACH_RCV_INVALID_DATA
)
1457 return MACH_RCV_INVALID_DATA
;
1459 return mr
| MACH_RCV_BODY_ERROR
;
1461 HOT(c_mmot_hot_ok3
++);
1466 HOT(c_mmot_g_slow_copyout2
++);
1472 mr
= ipc_kmsg_put(rcv_msg_addr
? rcv_msg_addr
: msg_addr
,
1474 kmsg
->ikm_header
->msgh_size
+
1475 trailer
->msgh_trailer_size
);
1476 if (mr
!= MACH_MSG_SUCCESS
) {
1477 return MACH_RCV_INVALID_DATA
;
1479 current_task()->messages_received
++;
1483 /* BEGINNING OF WARM PATH */
1486 * The slow path has a few non-register temporary
1487 * variables used only for call-by-reference.
1492 register mach_port_name_t reply_name
=
1493 (mach_port_name_t
)hdr
->msgh_local_port
;
1497 * We have the message data in kmsg, but
1498 * we still need to copyin, send it,
1499 * receive a reply, and do copyout.
1502 mr
= ipc_kmsg_copyin(kmsg
, space
, current_map(),
1504 if (mr
!= MACH_MSG_SUCCESS
) {
1505 ipc_kmsg_free(kmsg
);
1510 * LP64support - We have to recompute the header pointer
1511 * and send_size - as they could have changed during the
1514 hdr
= kmsg
->ikm_header
;
1515 send_size
= hdr
->msgh_size
;
1517 /* try to get back on optimized path */
1518 if ((reply_name
!= rcv_name
) ||
1519 (hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
)) {
1520 HOT(c_mmot_cold_048
++);
1524 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1525 assert(IP_VALID(dest_port
));
1528 if (!ip_active(dest_port
)) {
1529 ip_unlock(dest_port
);
1533 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
1534 dest_port
->ip_messages
.imq_seqno
++;
1535 ip_unlock(dest_port
);
1539 if (!imq_full(&dest_port
->ip_messages
) ||
1540 (MACH_MSGH_BITS_REMOTE(hdr
->msgh_bits
) ==
1541 MACH_MSG_TYPE_PORT_SEND_ONCE
))
1544 * Try an optimized ipc_mqueue_copyin.
1545 * It will work if this is a request message.
1548 register ipc_port_t reply_port
;
1550 reply_port
= (ipc_port_t
) hdr
->msgh_local_port
;
1551 if (IP_VALID(reply_port
)) {
1552 if (ip_lock_try(reply_port
)) {
1553 if (ip_active(reply_port
) &&
1554 reply_port
->ip_receiver
== space
&&
1555 reply_port
->ip_receiver_name
== rcv_name
&&
1556 reply_port
->ip_pset_count
== 0)
1558 /* Grab a reference to the reply port. */
1559 rcv_object
= (ipc_object_t
) reply_port
;
1560 io_reference(rcv_object
);
1561 rcv_mqueue
= &reply_port
->ip_messages
;
1562 io_unlock(rcv_object
);
1563 HOT(c_mmot_getback_FastSR
++);
1564 goto fast_send_receive
;
1566 ip_unlock(reply_port
);
1571 ip_unlock(dest_port
);
1572 HOT(c_mmot_cold_050
++);
1577 * Special case: send message to kernel services.
1578 * The request message has been copied into the
1579 * kmsg. Nothing is locked.
1583 register ipc_port_t reply_port
;
1587 * Perform the kernel function.
1589 c_mmot_kernel_send
++;
1591 current_task()->messages_sent
++;
1593 kmsg
= ipc_kobject_server(kmsg
);
1594 if (kmsg
== IKM_NULL
) {
1596 * No reply. Take the
1597 * slow receive path.
1599 HOT(c_mmot_cold_051
++);
1600 goto slow_get_rcv_port
;
1605 * the reply port is alive
1606 * we hold the receive right
1607 * the name has not changed.
1608 * the port is not in a set
1609 * If any of these are not true,
1610 * we cannot directly receive the reply
1613 hdr
= kmsg
->ikm_header
;
1614 send_size
= hdr
->msgh_size
;
1615 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1616 round_msg(send_size
));
1617 reply_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1618 ip_lock(reply_port
);
1620 if ((!ip_active(reply_port
)) ||
1621 (reply_port
->ip_receiver
!= space
) ||
1622 (reply_port
->ip_receiver_name
!= rcv_name
) ||
1623 (reply_port
->ip_pset_count
!= 0))
1625 ip_unlock(reply_port
);
1626 ipc_kmsg_send_always(kmsg
);
1627 HOT(c_mmot_cold_052
++);
1628 goto slow_get_rcv_port
;
1632 rcv_mqueue
= &reply_port
->ip_messages
;
1633 imq_lock(rcv_mqueue
);
1635 /* keep port locked, and don`t change ref count yet */
1638 * If there are messages on the port
1639 * or other threads waiting for a message,
1640 * we cannot directly receive the reply.
1642 if (!wait_queue_empty(&rcv_mqueue
->imq_wait_queue
) ||
1643 (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
))
1645 imq_unlock(rcv_mqueue
);
1647 ip_unlock(reply_port
);
1648 ipc_kmsg_send_always(kmsg
);
1649 HOT(c_mmot_cold_053
++);
1650 goto slow_get_rcv_port
;
1654 * We can directly receive this reply.
1655 * Since there were no messages queued
1656 * on the reply port, there should be
1657 * no threads blocked waiting to send.
1659 dest_port
= reply_port
;
1660 temp_seqno
= rcv_mqueue
->imq_seqno
++;
1661 imq_unlock(rcv_mqueue
);
1665 * inline ipc_object_release.
1666 * Port is still locked.
1667 * Reference count was not incremented.
1669 ip_check_unlock(reply_port
);
1671 if (option
& MACH_RCV_TRAILER_MASK
) {
1672 trailer
->msgh_seqno
= temp_seqno
;
1673 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1675 /* copy out the kernel reply */
1676 HOT(c_mmot_fastkernelreply
++);
1682 * Nothing is locked. We have acquired kmsg, but
1683 * we still need to send it and receive a reply.
1686 mr
= ipc_kmsg_send(kmsg
, MACH_MSG_OPTION_NONE
,
1687 MACH_MSG_TIMEOUT_NONE
);
1688 if (mr
!= MACH_MSG_SUCCESS
) {
1689 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
,
1691 MACH_MSG_BODY_NULL
);
1693 (void) ipc_kmsg_put(msg_addr
, kmsg
,
1694 kmsg
->ikm_header
->msgh_size
);
1700 * We have sent the message. Copy in the receive port.
1702 mr
= ipc_mqueue_copyin(space
, rcv_name
,
1703 &rcv_mqueue
, &rcv_object
);
1704 if (mr
!= MACH_MSG_SUCCESS
) {
1707 /* hold ref for rcv_object */
1712 * Now we have sent the request and copied in rcv_name,
1713 * and hold ref for rcv_object (to keep mqueue alive).
1714 * Just receive a reply and try to get back to fast path.
1717 self
->ith_continuation
= (void (*)(mach_msg_return_t
))0;
1718 ipc_mqueue_receive(rcv_mqueue
,
1719 MACH_MSG_OPTION_NONE
,
1721 MACH_MSG_TIMEOUT_NONE
,
1724 mr
= self
->ith_state
;
1725 temp_seqno
= self
->ith_seqno
;
1727 ipc_object_release(rcv_object
);
1729 if (mr
!= MACH_MSG_SUCCESS
) {
1733 kmsg
= self
->ith_kmsg
;
1734 hdr
= kmsg
->ikm_header
;
1735 send_size
= hdr
->msgh_size
;
1736 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1737 round_msg(send_size
));
1738 if (option
& MACH_RCV_TRAILER_MASK
) {
1739 trailer
->msgh_seqno
= temp_seqno
;
1740 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1742 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1743 HOT(c_mmot_cold_055
++);
1748 * Nothing locked and no references held, except
1749 * we have kmsg with msgh_seqno filled in. Must
1750 * still check against rcv_size and do
1751 * ipc_kmsg_copyout/ipc_kmsg_put.
1754 /* LP64support - have to compute real size as it would be received */
1755 reply_size
= ipc_kmsg_copyout_size(kmsg
, current_map()) +
1756 REQUESTED_TRAILER_SIZE(option
);
1757 temp_seqno
= trailer
->msgh_seqno
;
1758 if (rcv_size
< reply_size
) {
1759 if (msg_receive_error(kmsg
, msg_addr
, option
, temp_seqno
,
1760 space
) == MACH_RCV_INVALID_DATA
) {
1761 mr
= MACH_RCV_INVALID_DATA
;
1765 mr
= MACH_RCV_TOO_LARGE
;
1770 mr
= ipc_kmsg_copyout(kmsg
, space
, current_map(),
1771 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
1772 if (mr
!= MACH_MSG_SUCCESS
) {
1773 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
1774 if (ipc_kmsg_put(msg_addr
, kmsg
, reply_size
) ==
1775 MACH_RCV_INVALID_DATA
)
1776 mr
= MACH_RCV_INVALID_DATA
;
1779 if (msg_receive_error(kmsg
, msg_addr
, option
,
1780 temp_seqno
, space
) == MACH_RCV_INVALID_DATA
)
1781 mr
= MACH_RCV_INVALID_DATA
;
1787 /* try to get back on optimized path */
1788 HOT(c_mmot_getback_fast_put
++);
1793 } /* END OF HOT PATH */
1794 #endif /* ENABLE_HOTPATH */
1796 if (option
& MACH_SEND_MSG
) {
1797 ipc_space_t space
= current_space();
1798 vm_map_t map
= current_map();
1801 mr
= ipc_kmsg_get(msg_addr
, send_size
, &kmsg
);
1803 if (mr
!= MACH_MSG_SUCCESS
)
1806 if (option
& MACH_SEND_CANCEL
) {
1807 if (notify
== MACH_PORT_NULL
)
1808 mr
= MACH_SEND_INVALID_NOTIFY
;
1810 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, notify
);
1812 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
1813 if (mr
!= MACH_MSG_SUCCESS
) {
1814 ipc_kmsg_free(kmsg
);
1818 mr
= ipc_kmsg_send(kmsg
, option
& MACH_SEND_TIMEOUT
, msg_timeout
);
1820 if (mr
!= MACH_MSG_SUCCESS
) {
1821 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
);
1822 (void) ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
);
1828 if (option
& MACH_RCV_MSG
) {
1829 thread_t self
= current_thread();
1830 ipc_space_t space
= current_space();
1831 ipc_object_t object
;
1832 ipc_mqueue_t mqueue
;
1834 mr
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
);
1835 if (mr
!= MACH_MSG_SUCCESS
) {
1838 /* hold ref for object */
1841 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
1842 * and receive buffer
1843 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
1844 * alternate receive buffer (separate send and receive buffers).
1846 if (option
& MACH_RCV_OVERWRITE
)
1847 self
->ith_msg_addr
= rcv_msg_addr
;
1848 else if (rcv_msg_addr
!= (mach_vm_address_t
)0)
1849 self
->ith_msg_addr
= rcv_msg_addr
;
1851 self
->ith_msg_addr
= msg_addr
;
1852 self
->ith_object
= object
;
1853 self
->ith_msize
= rcv_size
;
1854 self
->ith_option
= option
;
1855 self
->ith_scatter_list_size
= scatter_list_size
;
1856 self
->ith_continuation
= thread_syscall_return
;
1858 ipc_mqueue_receive(mqueue
, option
, rcv_size
, msg_timeout
, THREAD_ABORTSAFE
);
1859 if ((option
& MACH_RCV_TIMEOUT
) && msg_timeout
== 0)
1860 thread_poll_yield(self
);
1861 return mach_msg_receive_results();
1864 return MACH_MSG_SUCCESS
;
1868 * Routine: mach_msg_trap [mach trap]
1870 * Possibly send a message; possibly receive a message.
1874 * All of mach_msg_send and mach_msg_receive error codes.
1879 struct mach_msg_overwrite_trap_args
*args
)
1882 args
->rcv_msg
= (mach_vm_address_t
)0;
1884 kr
= mach_msg_overwrite_trap(args
);
1890 * Routine: msg_receive_error [internal]
1892 * Builds a minimal header/trailer and copies it to
1893 * the user message buffer. Invoked when in the case of a
1894 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
1898 * MACH_MSG_SUCCESS minimal header/trailer copied
1899 * MACH_RCV_INVALID_DATA copyout to user buffer failed
1905 mach_vm_address_t msg_addr
,
1906 mach_msg_option_t option
,
1907 mach_port_seqno_t seqno
,
1910 mach_msg_format_0_trailer_t
*trailer
;
1913 * Copy out the destination port in the message.
1914 * Destroy all other rights and memory in the message.
1916 ipc_kmsg_copyout_dest(kmsg
, space
);
1919 * Build a minimal message with the requested trailer.
1921 trailer
= (mach_msg_format_0_trailer_t
*)
1922 ((vm_offset_t
)kmsg
->ikm_header
+
1923 round_msg(sizeof(mach_msg_header_t
)));
1924 kmsg
->ikm_header
->msgh_size
= sizeof(mach_msg_header_t
);
1925 bcopy( (char *)&trailer_template
,
1927 sizeof(trailer_template
));
1928 if (option
& MACH_RCV_TRAILER_MASK
) {
1929 trailer
->msgh_seqno
= seqno
;
1930 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1934 * Copy the message to user space
1936 if (ipc_kmsg_put(msg_addr
, kmsg
, kmsg
->ikm_header
->msgh_size
+
1937 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
1938 return(MACH_RCV_INVALID_DATA
);
1940 return(MACH_MSG_SUCCESS
);