2 * Copyright (c) 2000 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.
62 #include <mach/kern_return.h>
63 #include <mach/port.h>
64 #include <mach/message.h>
65 #include <mach/mig_errors.h>
66 #include <kern/assert.h>
67 #include <kern/counters.h>
68 #include <kern/cpu_number.h>
69 #include <kern/task.h>
70 #include <kern/thread.h>
71 #include <kern/lock.h>
72 #include <kern/sched_prim.h>
73 #include <kern/exception.h>
74 #include <kern/misc_protos.h>
75 #include <vm/vm_map.h>
76 #include <ipc/ipc_kmsg.h>
77 #include <ipc/ipc_mqueue.h>
78 #include <ipc/ipc_object.h>
79 #include <ipc/ipc_notify.h>
80 #include <ipc/ipc_port.h>
81 #include <ipc/ipc_pset.h>
82 #include <ipc/ipc_space.h>
83 #include <ipc/ipc_entry.h>
84 #include <kern/kalloc.h>
85 #include <kern/thread_swap.h>
86 #include <kern/processor.h>
88 #include <kern/mk_sp.h>
90 #include <machine/machine_routines.h>
91 #include <sys/kdebug.h>
94 * Forward declarations
97 mach_msg_return_t
mach_msg_send(
98 mach_msg_header_t
*msg
,
99 mach_msg_option_t option
,
100 mach_msg_size_t send_size
,
101 mach_msg_timeout_t timeout
,
102 mach_port_name_t notify
);
104 mach_msg_return_t
mach_msg_receive(
105 mach_msg_header_t
*msg
,
106 mach_msg_option_t option
,
107 mach_msg_size_t rcv_size
,
108 mach_port_name_t rcv_name
,
109 mach_msg_timeout_t timeout
,
110 void (*continuation
)(mach_msg_return_t
),
111 mach_msg_size_t slist_size
);
114 mach_msg_return_t
msg_receive_error(
116 mach_msg_header_t
*msg
,
117 mach_msg_option_t option
,
118 mach_port_seqno_t seqno
,
121 /* the size of each trailer has to be listed here for copyout purposes */
122 mach_msg_trailer_size_t trailer_size
[] = {
123 sizeof(mach_msg_trailer_t
),
124 sizeof(mach_msg_seqno_trailer_t
),
125 sizeof(mach_msg_security_trailer_t
) };
127 security_token_t KERNEL_SECURITY_TOKEN
= KERNEL_SECURITY_TOKEN_VALUE
;
129 mach_msg_format_0_trailer_t trailer_template
= {
130 /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0
,
131 /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE
,
132 /* mach_port_seqno_t */ 0,
133 /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE
137 * Routine: mach_msg_send
143 * MACH_MSG_SUCCESS Sent the message.
144 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
145 * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
146 * MACH_SEND_INVALID_DATA Couldn't copy message data.
147 * MACH_SEND_INVALID_HEADER
148 * Illegal value in the message header bits.
149 * MACH_SEND_INVALID_DEST The space is dead.
150 * MACH_SEND_INVALID_NOTIFY Bad notify port.
151 * MACH_SEND_INVALID_DEST Can't copyin destination port.
152 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
153 * MACH_SEND_TIMED_OUT Timeout expired without delivery.
154 * MACH_SEND_INTERRUPTED Delivery interrupted.
155 * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
156 * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
157 * MACH_SEND_NOTIFY_IN_PROGRESS
158 * This space has already forced a message to this port.
163 mach_msg_header_t
*msg
,
164 mach_msg_option_t option
,
165 mach_msg_size_t send_size
,
166 mach_msg_timeout_t timeout
,
167 mach_port_name_t notify
)
169 ipc_space_t space
= current_space();
170 vm_map_t map
= current_map();
172 mach_msg_return_t mr
;
174 mr
= ipc_kmsg_get(msg
, send_size
, &kmsg
);
176 if (mr
!= MACH_MSG_SUCCESS
)
179 if (option
& MACH_SEND_CANCEL
) {
180 if (notify
== MACH_PORT_NULL
)
181 mr
= MACH_SEND_INVALID_NOTIFY
;
183 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, notify
);
185 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
186 if (mr
!= MACH_MSG_SUCCESS
) {
191 mr
= ipc_kmsg_send(kmsg
, option
& MACH_SEND_TIMEOUT
, timeout
);
193 if (mr
!= MACH_MSG_SUCCESS
) {
194 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
, map
, MACH_MSG_BODY_NULL
);
195 (void) ipc_kmsg_put(msg
, kmsg
, kmsg
->ikm_header
.msgh_size
);
202 * Routine: mach_msg_receive
208 * MACH_MSG_SUCCESS Received a message.
209 * MACH_RCV_INVALID_NAME The name doesn't denote a right,
210 * or the denoted right is not receive or port set.
211 * MACH_RCV_IN_SET Receive right is a member of a set.
212 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
213 * MACH_RCV_TIMED_OUT Timeout expired without a message.
214 * MACH_RCV_INTERRUPTED Reception interrupted.
215 * MACH_RCV_PORT_DIED Port/set died while receiving.
216 * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
217 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
218 * MACH_RCV_INVALID_NOTIFY Bad notify port.
219 * MACH_RCV_HEADER_ERROR
223 mach_msg_receive_results(void)
225 thread_t self
= current_thread();
226 ipc_space_t space
= current_space();
227 vm_map_t map
= current_map();
229 ipc_object_t object
= self
->ith_object
;
230 mach_msg_return_t mr
= self
->ith_state
;
231 mach_msg_header_t
*msg
= self
->ith_msg
;
232 mach_msg_option_t option
= self
->ith_option
;
233 ipc_kmsg_t kmsg
= self
->ith_kmsg
;
234 mach_port_seqno_t seqno
= self
->ith_seqno
;
235 mach_msg_size_t slist_size
= self
->ith_scatter_list_size
;
237 mach_msg_format_0_trailer_t
*trailer
;
239 ipc_object_release(object
);
241 if (mr
!= MACH_MSG_SUCCESS
) {
243 if (mr
== MACH_RCV_TOO_LARGE
) {
244 if (option
& MACH_RCV_LARGE
) {
246 * We need to inform the user-level code that it needs more
247 * space. The value for how much space was returned in the
248 * msize save area instead of the message (which was left on
251 if (copyout((char *) &self
->ith_msize
,
252 (char *) &msg
->msgh_size
,
253 sizeof(mach_msg_size_t
)))
254 mr
= MACH_RCV_INVALID_DATA
;
258 if (msg_receive_error(kmsg
, msg
, option
, seqno
, space
)
259 == MACH_RCV_INVALID_DATA
)
260 mr
= MACH_RCV_INVALID_DATA
;
265 trailer
= (mach_msg_format_0_trailer_t
*)
266 ((vm_offset_t
)&kmsg
->ikm_header
+
267 round_msg(kmsg
->ikm_header
.msgh_size
));
268 if (option
& MACH_RCV_TRAILER_MASK
) {
269 trailer
->msgh_seqno
= seqno
;
270 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
274 * If MACH_RCV_OVERWRITE was specified, try to get the scatter
275 * list and verify it against the contents of the message. If
276 * there is any problem with it, we will continue without it as
279 if (option
& MACH_RCV_OVERWRITE
) {
280 mach_msg_size_t slist_size
= self
->ith_scatter_list_size
;
281 mach_msg_body_t
*slist
;
283 slist
= ipc_kmsg_copyin_scatter(msg
, slist_size
, kmsg
);
284 mr
= ipc_kmsg_copyout(kmsg
, space
, map
, MACH_PORT_NULL
, slist
);
285 ipc_kmsg_free_scatter(slist
, slist_size
);
287 mr
= ipc_kmsg_copyout(kmsg
, space
, map
,
288 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
291 if (mr
!= MACH_MSG_SUCCESS
) {
292 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
293 if (ipc_kmsg_put(msg
, kmsg
, kmsg
->ikm_header
.msgh_size
+
294 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
295 mr
= MACH_RCV_INVALID_DATA
;
298 if (msg_receive_error(kmsg
, msg
, option
, seqno
, space
)
299 == MACH_RCV_INVALID_DATA
)
300 mr
= MACH_RCV_INVALID_DATA
;
304 mr
= ipc_kmsg_put(msg
,
306 kmsg
->ikm_header
.msgh_size
+
307 trailer
->msgh_trailer_size
);
314 mach_msg_header_t
*msg
,
315 mach_msg_option_t option
,
316 mach_msg_size_t rcv_size
,
317 mach_port_name_t rcv_name
,
318 mach_msg_timeout_t timeout
,
319 void (*continuation
)(mach_msg_return_t
),
320 mach_msg_size_t slist_size
)
322 thread_t self
= current_thread();
323 ipc_space_t space
= current_space();
324 vm_map_t map
= current_map();
328 mach_port_seqno_t seqno
;
329 mach_msg_return_t mr
;
330 mach_msg_body_t
*slist
;
331 mach_msg_format_0_trailer_t
*trailer
;
333 mr
= ipc_mqueue_copyin(space
, rcv_name
, &mqueue
, &object
);
334 if (mr
!= MACH_MSG_SUCCESS
) {
337 /* hold ref for object */
340 self
->ith_object
= object
;
341 self
->ith_msize
= rcv_size
;
342 self
->ith_option
= option
;
343 self
->ith_scatter_list_size
= slist_size
;
344 self
->ith_continuation
= continuation
;
346 ipc_mqueue_receive(mqueue
, option
, rcv_size
, timeout
, THREAD_ABORTSAFE
);
347 if ((option
& MACH_RCV_TIMEOUT
) && timeout
== 0)
348 _mk_sp_thread_perhaps_yield(self
);
349 return mach_msg_receive_results();
353 mach_msg_receive_continue(void)
355 thread_t self
= current_thread();
357 (*self
->ith_continuation
)(mach_msg_receive_results());
361 * Toggle this to compile the hotpath in/out
362 * If compiled in, the run-time toggle "enable_hotpath" below
363 * eases testing & debugging
365 #define ENABLE_HOTPATH 1 /* Hacked on for now */
369 * These counters allow tracing of hotpath behavior under test loads.
370 * A couple key counters are unconditional (see below).
372 #define HOTPATH_DEBUG 0 /* Toggle to include lots of counters */
374 #define HOT(expr) expr
376 unsigned int c_mmot_FIRST
= 0; /* Unused First Counter */
377 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
378 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
379 unsigned int c_mmot_kernel_send
= 0; /* kernel server */
380 unsigned int c_mmot_cold_000
= 0; /* see below ... */
381 unsigned int c_mmot_smallsendsize
= 0;
382 unsigned int c_mmot_oddsendsize
= 0;
383 unsigned int c_mmot_bigsendsize
= 0;
384 unsigned int c_mmot_copyinmsg_fail
= 0;
385 unsigned int c_mmot_g_slow_copyin3
= 0;
386 unsigned int c_mmot_cold_006
= 0;
387 unsigned int c_mmot_cold_007
= 0;
388 unsigned int c_mmot_cold_008
= 0;
389 unsigned int c_mmot_cold_009
= 0;
390 unsigned int c_mmot_cold_010
= 0;
391 unsigned int c_mmot_cold_012
= 0;
392 unsigned int c_mmot_cold_013
= 0;
393 unsigned int c_mmot_cold_014
= 0;
394 unsigned int c_mmot_cold_016
= 0;
395 unsigned int c_mmot_cold_018
= 0;
396 unsigned int c_mmot_cold_019
= 0;
397 unsigned int c_mmot_cold_020
= 0;
398 unsigned int c_mmot_cold_021
= 0;
399 unsigned int c_mmot_cold_022
= 0;
400 unsigned int c_mmot_cold_023
= 0;
401 unsigned int c_mmot_cold_024
= 0;
402 unsigned int c_mmot_cold_025
= 0;
403 unsigned int c_mmot_cold_026
= 0;
404 unsigned int c_mmot_cold_027
= 0;
405 unsigned int c_mmot_hot_fSR_ok
= 0;
406 unsigned int c_mmot_cold_029
= 0;
407 unsigned int c_mmot_cold_030
= 0;
408 unsigned int c_mmot_cold_031
= 0;
409 unsigned int c_mmot_cold_032
= 0;
410 unsigned int c_mmot_cold_033
= 0;
411 unsigned int c_mmot_bad_rcvr
= 0;
412 unsigned int c_mmot_rcvr_swapped
= 0;
413 unsigned int c_mmot_rcvr_locked
= 0;
414 unsigned int c_mmot_rcvr_tswapped
= 0;
415 unsigned int c_mmot_rcvr_freed
= 0;
416 unsigned int c_mmot_g_slow_copyout6
= 0;
417 unsigned int c_mmot_g_slow_copyout5
= 0;
418 unsigned int c_mmot_cold_037
= 0;
419 unsigned int c_mmot_cold_038
= 0;
420 unsigned int c_mmot_cold_039
= 0;
421 unsigned int c_mmot_g_slow_copyout4
= 0;
422 unsigned int c_mmot_g_slow_copyout3
= 0;
423 unsigned int c_mmot_hot_ok1
= 0;
424 unsigned int c_mmot_hot_ok2
= 0;
425 unsigned int c_mmot_hot_ok3
= 0;
426 unsigned int c_mmot_g_slow_copyout1
= 0;
427 unsigned int c_mmot_g_slow_copyout2
= 0;
428 unsigned int c_mmot_getback_fast_copyin
= 0;
429 unsigned int c_mmot_cold_048
= 0;
430 unsigned int c_mmot_getback_FastSR
= 0;
431 unsigned int c_mmot_cold_050
= 0;
432 unsigned int c_mmot_cold_051
= 0;
433 unsigned int c_mmot_cold_052
= 0;
434 unsigned int c_mmot_cold_053
= 0;
435 unsigned int c_mmot_fastkernelreply
= 0;
436 unsigned int c_mmot_cold_055
= 0;
437 unsigned int c_mmot_getback_fast_put
= 0;
438 unsigned int c_mmot_LAST
= 0; /* End Marker - Unused */
440 void db_mmot_zero_counters(void); /* forward; */
441 void db_mmot_show_counters(void); /* forward; */
443 void /* Call from the debugger to clear all counters */
444 db_mmot_zero_counters(void)
446 register unsigned int *ip
= &c_mmot_FIRST
;
447 while (ip
<= &c_mmot_LAST
)
451 void /* Call from the debugger to show all counters */
452 db_mmot_show_counters(void)
454 #define xx(str) printf("%s: %d\n", # str, str);
456 xx(c_mmot_combined_S_R
);
457 xx(c_mach_msg_trap_switch_fast
);
458 xx(c_mmot_kernel_send
);
460 xx(c_mmot_smallsendsize
);
461 xx(c_mmot_oddsendsize
);
462 xx(c_mmot_bigsendsize
);
463 xx(c_mmot_copyinmsg_fail
);
464 xx(c_mmot_g_slow_copyin3
);
484 xx(c_mmot_hot_fSR_ok
);
491 xx(c_mmot_rcvr_swapped
);
492 xx(c_mmot_rcvr_locked
);
493 xx(c_mmot_rcvr_tswapped
);
494 xx(c_mmot_rcvr_freed
);
495 xx(c_mmot_g_slow_copyout6
);
496 xx(c_mmot_g_slow_copyout5
);
500 xx(c_mmot_g_slow_copyout4
);
501 xx(c_mmot_g_slow_copyout3
);
502 xx(c_mmot_g_slow_copyout1
);
506 xx(c_mmot_g_slow_copyout2
);
507 xx(c_mmot_getback_fast_copyin
);
509 xx(c_mmot_getback_FastSR
);
514 xx(c_mmot_fastkernelreply
);
516 xx(c_mmot_getback_fast_put
);
521 #else /* !HOTPATH_DEBUG */
524 * Duplicate just these few so we can always do a quick sanity check
526 unsigned int c_mmot_combined_S_R
= 0; /* hotpath candidates */
527 unsigned int c_mach_msg_trap_switch_fast
= 0; /* hotpath successes */
528 unsigned int c_mmot_kernel_send
= 0; /* kernel server calls */
529 #define HOT(expr) /* no optional counters */
531 #endif /* !HOTPATH_DEBUG */
533 boolean_t enable_hotpath
= TRUE
; /* Patchable, just in case ... */
534 #endif /* HOTPATH_ENABLE */
537 * Routine: mach_msg_overwrite_trap [mach trap]
539 * Possibly send a message; possibly receive a message.
543 * All of mach_msg_send and mach_msg_receive error codes.
547 mach_msg_overwrite_trap(
548 mach_msg_header_t
*msg
,
549 mach_msg_option_t option
,
550 mach_msg_size_t send_size
,
551 mach_msg_size_t rcv_size
,
552 mach_port_name_t rcv_name
,
553 mach_msg_timeout_t timeout
,
554 mach_port_name_t notify
,
555 mach_msg_header_t
*rcv_msg
,
556 mach_msg_size_t scatter_list_size
)
558 register mach_msg_header_t
*hdr
;
559 mach_msg_return_t mr
= MACH_MSG_SUCCESS
;
560 /* mask out some of the options before entering the hot path */
561 mach_msg_option_t masked_option
=
562 option
& ~(MACH_SEND_TRAILER
|MACH_RCV_TRAILER_MASK
|MACH_RCV_LARGE
);
566 /* BEGINNING OF HOT PATH */
567 if ((masked_option
== (MACH_SEND_MSG
|MACH_RCV_MSG
)) && enable_hotpath
) {
568 register thread_t self
= current_thread();
569 register mach_msg_format_0_trailer_t
*trailer
;
571 ipc_space_t space
= current_act()->task
->itk_space
;
573 register ipc_port_t dest_port
;
574 ipc_object_t rcv_object
;
575 register ipc_mqueue_t rcv_mqueue
;
576 mach_msg_size_t reply_size
;
579 c_mmot_combined_S_R
++;
582 * This case is divided into ten sections, each
583 * with a label. There are five optimized
584 * sections and six unoptimized sections, which
585 * do the same thing but handle all possible
586 * cases and are slower.
588 * The five sections for an RPC are
589 * 1) Get request message into a buffer.
590 * 2) Copyin request message and rcv_name.
591 * (fast_copyin or slow_copyin)
592 * 3) Enqueue request and dequeue reply.
593 * (fast_send_receive or
594 * slow_send and slow_receive)
595 * 4) Copyout reply message.
596 * (fast_copyout or slow_copyout)
597 * 5) Put reply message to user's buffer.
599 * Keep the locking hierarchy firmly in mind.
600 * (First spaces, then ports, then port sets,
601 * then message queues.) Only a non-blocking
602 * attempt can be made to acquire locks out of
603 * order, or acquire two locks on the same level.
604 * Acquiring two locks on the same level will
605 * fail if the objects are really the same,
606 * unless simple locking is disabled. This is OK,
607 * because then the extra unlock does nothing.
609 * There are two major reasons these RPCs can't use
610 * ipc_thread_switch, and use slow_send/slow_receive:
612 * 2) Servers fall behind clients, so
613 * client doesn't find a blocked server thread and
614 * server finds waiting messages and can't block.
617 mr
= ipc_kmsg_get(msg
, send_size
, &kmsg
);
618 if (mr
!= KERN_SUCCESS
) {
621 hdr
= &kmsg
->ikm_header
;
622 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
627 * optimized ipc_kmsg_copyin/ipc_mqueue_copyin
629 * We have the request message data in kmsg.
630 * Must still do copyin, send, receive, etc.
632 * If the message isn't simple, we can't combine
633 * ipc_kmsg_copyin_header and ipc_mqueue_copyin,
634 * because copyin of the message body might
638 switch (hdr
->msgh_bits
) {
639 case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,
640 MACH_MSG_TYPE_MAKE_SEND_ONCE
): {
641 register ipc_entry_t table
;
642 register ipc_entry_num_t size
;
643 register ipc_port_t reply_port
;
645 /* sending a request message */
648 register mach_port_index_t index
;
649 register mach_port_gen_t gen
;
652 register mach_port_name_t reply_name
=
653 (mach_port_name_t
)hdr
->msgh_local_port
;
655 if (reply_name
!= rcv_name
) {
656 HOT(c_mmot_g_slow_copyin3
++);
660 /* optimized ipc_entry_lookup of reply_name */
662 index
= MACH_PORT_INDEX(reply_name
);
663 gen
= MACH_PORT_GEN(reply_name
);
666 assert(space
->is_active
);
668 size
= space
->is_table_size
;
669 table
= space
->is_table
;
672 register ipc_entry_t entry
;
673 register ipc_entry_bits_t bits
;
676 entry
= &table
[index
];
677 bits
= entry
->ie_bits
;
678 if (IE_BITS_GEN(bits
) != gen
||
679 (bits
& IE_BITS_COLLISION
)) {
685 if (entry
== IE_NULL
) {
686 entry
= ipc_entry_lookup(space
, reply_name
);
687 if (entry
== IE_NULL
) {
688 HOT(c_mmot_cold_006
++);
689 goto abort_request_copyin
;
691 bits
= entry
->ie_bits
;
696 if (! (bits
& MACH_PORT_TYPE_RECEIVE
)) {
697 HOT(c_mmot_cold_007
++);
698 goto abort_request_copyin
;
701 reply_port
= (ipc_port_t
) entry
->ie_object
;
702 assert(reply_port
!= IP_NULL
);
707 /* optimized ipc_entry_lookup of dest_name */
710 register mach_port_index_t index
;
711 register mach_port_gen_t gen
;
714 register mach_port_name_t dest_name
=
715 (mach_port_name_t
)hdr
->msgh_remote_port
;
717 index
= MACH_PORT_INDEX(dest_name
);
718 gen
= MACH_PORT_GEN(dest_name
);
721 register ipc_entry_t entry
;
722 register ipc_entry_bits_t bits
;
725 entry
= &table
[index
];
726 bits
= entry
->ie_bits
;
727 if (IE_BITS_GEN(bits
) != gen
||
728 (bits
& IE_BITS_COLLISION
)) {
734 if (entry
== IE_NULL
) {
735 entry
= ipc_entry_lookup(space
, dest_name
);
736 if (entry
== IE_NULL
) {
737 HOT(c_mmot_cold_008
++);
738 goto abort_request_copyin
;
740 bits
= entry
->ie_bits
;
745 if (! (bits
& MACH_PORT_TYPE_SEND
)) {
746 HOT(c_mmot_cold_009
++);
747 goto abort_request_copyin
;
750 assert(IE_BITS_UREFS(bits
) > 0);
752 dest_port
= (ipc_port_t
) entry
->ie_object
;
753 assert(dest_port
!= IP_NULL
);
759 * To do an atomic copyin, need simultaneous
760 * locks on both ports and the space. If
761 * dest_port == reply_port, and simple locking is
762 * enabled, then we will abort. Otherwise it's
763 * OK to unlock twice.
767 if (!ip_active(dest_port
) ||
768 !ip_lock_try(reply_port
)) {
769 ip_unlock(dest_port
);
770 HOT(c_mmot_cold_010
++);
771 goto abort_request_copyin
;
773 is_read_unlock(space
);
775 assert(dest_port
->ip_srights
> 0);
776 dest_port
->ip_srights
++;
777 ip_reference(dest_port
);
779 assert(ip_active(reply_port
));
780 assert(reply_port
->ip_receiver_name
==
781 (mach_port_name_t
)hdr
->msgh_local_port
);
782 assert(reply_port
->ip_receiver
== space
);
784 reply_port
->ip_sorights
++;
785 ip_reference(reply_port
);
788 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
789 MACH_MSG_TYPE_PORT_SEND_ONCE
);
790 hdr
->msgh_remote_port
= dest_port
;
791 hdr
->msgh_local_port
= reply_port
;
793 /* make sure we can queue to the destination */
795 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
797 * The kernel server has a reference to
798 * the reply port, which it hands back
799 * to us in the reply message. We do
800 * not need to keep another reference to
803 ip_unlock(reply_port
);
805 assert(ip_active(dest_port
));
806 dest_port
->ip_messages
.imq_seqno
++;
807 ip_unlock(dest_port
);
811 if (imq_full(&dest_port
->ip_messages
)) {
812 HOT(c_mmot_cold_013
++);
813 goto abort_request_send_receive
;
816 /* optimized ipc_mqueue_copyin */
818 rcv_object
= (ipc_object_t
) reply_port
;
819 io_reference(rcv_object
);
820 rcv_mqueue
= &reply_port
->ip_messages
;
821 io_unlock(rcv_object
);
822 HOT(c_mmot_hot_fSR_ok
++);
823 goto fast_send_receive
;
825 abort_request_copyin
:
826 is_read_unlock(space
);
829 abort_request_send_receive
:
830 ip_unlock(dest_port
);
831 ip_unlock(reply_port
);
835 case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0): {
836 register ipc_entry_num_t size
;
837 register ipc_entry_t table
;
839 /* sending a reply message */
842 register mach_port_name_t reply_name
=
843 (mach_port_name_t
)hdr
->msgh_local_port
;
845 if (reply_name
!= MACH_PORT_NULL
) {
846 HOT(c_mmot_cold_018
++);
851 is_write_lock(space
);
852 assert(space
->is_active
);
854 /* optimized ipc_entry_lookup */
856 size
= space
->is_table_size
;
857 table
= space
->is_table
;
860 register ipc_entry_t entry
;
861 register mach_port_gen_t gen
;
862 register mach_port_index_t index
;
863 ipc_table_index_t
*requests
;
866 register mach_port_name_t dest_name
=
867 (mach_port_name_t
)hdr
->msgh_remote_port
;
869 index
= MACH_PORT_INDEX(dest_name
);
870 gen
= MACH_PORT_GEN(dest_name
);
874 HOT(c_mmot_cold_019
++);
875 goto abort_reply_dest_copyin
;
878 entry
= &table
[index
];
880 /* check generation, collision bit, and type bit */
882 if ((entry
->ie_bits
& (IE_BITS_GEN_MASK
|
884 MACH_PORT_TYPE_SEND_ONCE
)) !=
885 (gen
| MACH_PORT_TYPE_SEND_ONCE
)) {
886 HOT(c_mmot_cold_020
++);
887 goto abort_reply_dest_copyin
;
890 /* optimized ipc_right_copyin */
892 assert(IE_BITS_TYPE(entry
->ie_bits
) ==
893 MACH_PORT_TYPE_SEND_ONCE
);
894 assert(IE_BITS_UREFS(entry
->ie_bits
) == 1);
896 if (entry
->ie_request
!= 0) {
897 HOT(c_mmot_cold_021
++);
898 goto abort_reply_dest_copyin
;
901 dest_port
= (ipc_port_t
) entry
->ie_object
;
902 assert(dest_port
!= IP_NULL
);
905 if (!ip_active(dest_port
)) {
906 ip_unlock(dest_port
);
907 HOT(c_mmot_cold_022
++);
908 goto abort_reply_dest_copyin
;
911 assert(dest_port
->ip_sorights
> 0);
913 /* optimized ipc_entry_dealloc */
916 entry
->ie_bits
= gen
;
917 entry
->ie_next
= table
->ie_next
;
918 table
->ie_next
= index
;
919 entry
->ie_object
= IO_NULL
;
923 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
925 hdr
->msgh_remote_port
= dest_port
;
927 /* make sure we can queue to the destination */
929 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
931 /* optimized ipc_entry_lookup/ipc_mqueue_copyin */
934 register ipc_entry_t entry
;
935 register ipc_entry_bits_t bits
;
938 register mach_port_index_t index
;
939 register mach_port_gen_t gen
;
941 index
= MACH_PORT_INDEX(rcv_name
);
942 gen
= MACH_PORT_GEN(rcv_name
);
945 entry
= &table
[index
];
946 bits
= entry
->ie_bits
;
947 if (IE_BITS_GEN(bits
) != gen
||
948 (bits
& IE_BITS_COLLISION
)) {
954 if (entry
== IE_NULL
) {
955 entry
= ipc_entry_lookup(space
, rcv_name
);
956 if (entry
== IE_NULL
) {
957 HOT(c_mmot_cold_024
++);
958 goto abort_reply_rcv_copyin
;
960 bits
= entry
->ie_bits
;
965 /* check type bits; looking for receive or set */
968 * JMM - The check below for messages in the receive
969 * mqueue is insufficient to work with port sets, since
970 * the messages stay in the port queues. For now, don't
971 * allow portsets (but receiving on portsets when sending
972 * a message to a send-once right is actually a very
973 * common case (so we should re-enable).
975 if (bits
& MACH_PORT_TYPE_PORT_SET
) {
976 register ipc_pset_t rcv_pset
;
978 rcv_pset
= (ipc_pset_t
) entry
->ie_object
;
979 assert(rcv_pset
!= IPS_NULL
);
982 assert(ips_active(rcv_pset
));
984 rcv_object
= (ipc_object_t
) rcv_pset
;
985 rcv_mqueue
= &rcv_pset
->ips_messages
;
988 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
989 register ipc_port_t rcv_port
;
991 rcv_port
= (ipc_port_t
) entry
->ie_object
;
992 assert(rcv_port
!= IP_NULL
);
994 if (!ip_lock_try(rcv_port
)) {
995 HOT(c_mmot_cold_025
++);
996 goto abort_reply_rcv_copyin
;
998 assert(ip_active(rcv_port
));
1000 if (rcv_port
->ip_pset_count
!= 0) {
1001 ip_unlock(rcv_port
);
1002 HOT(c_mmot_cold_026
++);
1003 goto abort_reply_rcv_copyin
;
1006 rcv_object
= (ipc_object_t
) rcv_port
;
1007 rcv_mqueue
= &rcv_port
->ip_messages
;
1009 HOT(c_mmot_cold_027
++);
1010 goto abort_reply_rcv_copyin
;
1014 is_write_unlock(space
);
1015 io_reference(rcv_object
);
1016 io_unlock(rcv_object
);
1017 HOT(c_mmot_hot_fSR_ok
++);
1018 goto fast_send_receive
;
1020 abort_reply_dest_copyin
:
1021 is_write_unlock(space
);
1022 HOT(c_mmot_cold_029
++);
1025 abort_reply_rcv_copyin
:
1026 ip_unlock(dest_port
);
1027 is_write_unlock(space
);
1028 HOT(c_mmot_cold_030
++);
1033 HOT(c_mmot_cold_031
++);
1040 * optimized ipc_mqueue_send/ipc_mqueue_receive
1042 * Finished get/copyin of kmsg and copyin of rcv_name.
1043 * space is unlocked, dest_port is locked,
1044 * we can queue kmsg to dest_port,
1045 * rcv_mqueue is set, and rcv_object holds a ref
1046 * so the mqueue cannot go away.
1048 * JMM - For now, rcv_object is just a port. Portsets
1049 * are disabled for the time being.
1052 assert(ip_active(dest_port
));
1053 assert(dest_port
->ip_receiver
!= ipc_space_kernel
);
1054 assert(!imq_full(&dest_port
->ip_messages
) ||
1055 (MACH_MSGH_BITS_REMOTE(hdr
->msgh_bits
) ==
1056 MACH_MSG_TYPE_PORT_SEND_ONCE
));
1057 assert((hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
) == 0);
1060 register ipc_mqueue_t dest_mqueue
;
1064 thread_act_t rcv_act
;
1069 dest_mqueue
= &dest_port
->ip_messages
;
1070 waitq
= &dest_mqueue
->imq_wait_queue
;
1071 imq_lock(dest_mqueue
);
1073 wait_queue_peek_locked(waitq
, IPC_MQUEUE_RECEIVE
, &receiver
, &waitq
);
1074 /* queue still locked, thread locked - but still on q */
1076 if (receiver
== THREAD_NULL
) {
1078 imq_unlock(dest_mqueue
);
1080 ip_unlock(dest_port
);
1081 ipc_object_release(rcv_object
);
1082 HOT(c_mmot_cold_032
++);
1086 assert(receiver
->wait_queue
== waitq
);
1087 assert(receiver
->wait_event
== IPC_MQUEUE_RECEIVE
);
1090 * See if it is still running on another processor (trying to
1091 * block itself). If so, fall off.
1093 * JMM - We have an opportunity here. Since the thread is locked
1094 * and we find it runnable, it must still be trying to get into
1095 * thread_block on itself. We could just "hand him the message"
1096 * and let him go (thread_go_locked()) and then fall down into a
1097 * slow receive for ourselves. Only his RECEIVE_TOO_LARGE handling
1098 * runs afoul of that. Clean this up!
1100 if ((receiver
->state
& TH_RUN
|TH_WAIT
) != TH_WAIT
) {
1102 HOT(c_mmot_cold_033
++);
1104 thread_unlock(receiver
);
1105 if (waitq
!= &dest_mqueue
->imq_wait_queue
)
1106 wait_queue_unlock(waitq
);
1107 goto abort_send_receive
;
1111 * Check that the receiver can stay on the hot path.
1113 if (send_size
+ REQUESTED_TRAILER_SIZE(receiver
->ith_option
) >
1114 receiver
->ith_msize
) {
1116 * The receiver can't accept the message.
1118 HOT(c_mmot_bad_rcvr
++);
1124 * Receiver looks okay -- is it swapped in?
1127 rcv_act
= receiver
->top_act
;
1128 if (rcv_act
->swap_state
!= TH_SW_IN
&&
1129 rcv_act
->swap_state
!= TH_SW_UNSWAPPABLE
) {
1130 rpc_unlock(receiver
);
1131 HOT(c_mmot_rcvr_swapped
++);
1136 * Make sure receiver stays swapped in (if we can).
1138 if (!act_lock_try(rcv_act
)) { /* out of order! */
1139 rpc_unlock(receiver
);
1140 HOT(c_mmot_rcvr_locked
++);
1145 * Check for task swapping in progress affecting
1146 * receiver. Since rcv_act is attached to a shuttle,
1147 * its swap_state is covered by shuttle's thread_lock()
1150 if ((rcv_act
->swap_state
!= TH_SW_IN
&&
1151 rcv_act
->swap_state
!= TH_SW_UNSWAPPABLE
) ||
1152 rcv_act
->ast
& AST_SWAPOUT
) {
1153 act_unlock(rcv_act
);
1154 rpc_unlock(receiver
);
1155 HOT(c_mmot_rcvr_tswapped
++);
1160 * We don't need to make receiver unswappable here -- holding
1161 * act_lock() of rcv_act is sufficient to prevent either thread
1162 * or task swapping from changing its state (see swapout_scan(),
1163 * task_swapout()). Don't release lock till receiver's state
1164 * is consistent. Its task may then be marked for swapout,
1167 rpc_unlock(receiver
);
1169 * NB: act_lock(rcv_act) still held
1171 #endif /* THREAD_SWAPPER */
1174 * Before committing to the handoff, make sure that we are
1175 * really going to block (i.e. there are no messages already
1176 * queued for us. This violates lock ordering, so make sure
1177 * we don't deadlock. After the trylock succeeds below, we
1178 * may have up to 3 message queues locked:
1179 * - the dest port mqueue
1180 * - a portset mqueue (where waiting receiver was found)
1181 * - finally our own rcv_mqueue
1183 * JMM - Need to make this check appropriate for portsets as
1184 * well before re-enabling them.
1186 if (!imq_lock_try(rcv_mqueue
)) {
1189 if (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
) {
1190 imq_unlock(rcv_mqueue
);
1191 HOT(c_mmot_cold_033
++);
1195 /* At this point we are committed to do the "handoff". */
1196 c_mach_msg_trap_switch_fast
++;
1199 * JMM - Go ahead and pull the receiver from the runq. If the
1200 * runq wasn't the one for the mqueue, unlock it.
1202 wait_queue_pull_thread_locked(waitq
,
1204 (waitq
!= &dest_mqueue
->imq_wait_queue
));
1207 * Store the kmsg and seqno where the receiver can pick it up.
1209 receiver
->ith_state
= MACH_MSG_SUCCESS
;
1210 receiver
->ith_kmsg
= kmsg
;
1211 receiver
->ith_seqno
= dest_mqueue
->imq_seqno
++;
1214 * Inline thread_go_locked
1216 * JMM - Including hacked in version of setrun scheduler op
1217 * that doesn't try to put thread on a runq.
1220 receiver
->state
&= ~(TH_WAIT
|TH_UNINT
);
1221 receiver
->state
|= TH_RUN
;
1222 receiver
->wait_result
= THREAD_AWAKENED
;
1224 receiver
->metered_computation
= 0;
1227 thread_unlock(receiver
);
1229 act_unlock(rcv_act
);
1230 #endif /* THREAD_SWAPPER */
1232 imq_unlock(dest_mqueue
);
1233 ip_unlock(dest_port
);
1234 current_task()->messages_sent
++;
1238 * Put self on receive port's queue.
1239 * Also save state that the sender of
1240 * our reply message needs to determine if it
1241 * can hand off directly back to us.
1243 self
->ith_msg
= (rcv_msg
) ? rcv_msg
: msg
;
1244 self
->ith_object
= rcv_object
; /* still holds reference */
1245 self
->ith_msize
= rcv_size
;
1246 self
->ith_option
= option
;
1247 self
->ith_scatter_list_size
= scatter_list_size
;
1248 self
->ith_continuation
= thread_syscall_return
;
1250 waitq
= &rcv_mqueue
->imq_wait_queue
;
1251 (void)wait_queue_assert_wait_locked(waitq
,
1254 TRUE
); /* unlock? */
1255 /* rcv_mqueue is unlocked */
1257 /* Inline thread_block_reason (except don't select a new
1258 * new thread (we already have one), and don't turn off ASTs
1259 * (we don't want two threads to hog all the CPU by handing
1260 * off to each other).
1263 if (self
->funnel_state
& TH_FN_OWNED
) {
1264 self
->funnel_state
= TH_FN_REFUNNEL
;
1265 KERNEL_DEBUG(0x603242c | DBG_FUNC_NONE
, self
->funnel_lock
, 3, 0, 0, 0);
1266 funnel_unlock(self
->funnel_lock
);
1270 machine_clock_assist();
1273 if (self
->state
& TH_ABORT
)
1274 clear_wait_internal(self
, THREAD_INTERRUPTED
);
1275 thread_unlock(self
);
1278 * Switch directly to receiving thread, and block
1279 * this thread as though it had called ipc_mqueue_receive.
1281 #if defined (__i386__)
1282 thread_run(self
, (void (*)(void))0, receiver
);
1284 thread_run(self
, ipc_mqueue_receive_continue
, receiver
);
1287 /* if we fell thru */
1288 if (self
->funnel_state
& TH_FN_REFUNNEL
) {
1289 kern_return_t wait_result2
;
1291 wait_result2
= self
->wait_result
;
1292 self
->funnel_state
= 0;
1293 KERNEL_DEBUG(0x6032428 | DBG_FUNC_NONE
, self
->funnel_lock
, 6, 0, 0, 0);
1294 funnel_lock(self
->funnel_lock
);
1295 KERNEL_DEBUG(0x6032430 | DBG_FUNC_NONE
, self
->funnel_lock
, 6, 0, 0, 0);
1296 self
->funnel_state
= TH_FN_OWNED
;
1297 self
->wait_result
= wait_result2
;
1302 ipc_mqueue_receive_continue();
1308 * Nothing locked and no references held, except
1309 * we have kmsg with msgh_seqno filled in. Must
1310 * still check against rcv_size and do
1311 * ipc_kmsg_copyout/ipc_kmsg_put.
1314 reply_size
= send_size
+ trailer
->msgh_trailer_size
;
1315 if (rcv_size
< reply_size
) {
1316 HOT(c_mmot_g_slow_copyout6
++);
1320 /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */
1322 switch (hdr
->msgh_bits
) {
1323 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND
,
1324 MACH_MSG_TYPE_PORT_SEND_ONCE
): {
1325 ipc_port_t reply_port
=
1326 (ipc_port_t
) hdr
->msgh_local_port
;
1327 mach_port_name_t dest_name
, reply_name
;
1329 /* receiving a request message */
1331 if (!IP_VALID(reply_port
)) {
1332 HOT(c_mmot_g_slow_copyout5
++);
1336 is_write_lock(space
);
1337 assert(space
->is_active
);
1340 * To do an atomic copyout, need simultaneous
1341 * locks on both ports and the space. If
1342 * dest_port == reply_port, and simple locking is
1343 * enabled, then we will abort. Otherwise it's
1344 * OK to unlock twice.
1348 if (!ip_active(dest_port
) ||
1349 !ip_lock_try(reply_port
)) {
1350 HOT(c_mmot_cold_037
++);
1351 goto abort_request_copyout
;
1354 if (!ip_active(reply_port
)) {
1355 ip_unlock(reply_port
);
1356 HOT(c_mmot_cold_038
++);
1357 goto abort_request_copyout
;
1360 assert(reply_port
->ip_sorights
> 0);
1361 ip_unlock(reply_port
);
1364 register ipc_entry_t table
;
1365 register ipc_entry_t entry
;
1366 register mach_port_index_t index
;
1368 /* optimized ipc_entry_get */
1370 table
= space
->is_table
;
1371 index
= table
->ie_next
;
1374 HOT(c_mmot_cold_039
++);
1375 goto abort_request_copyout
;
1378 entry
= &table
[index
];
1379 table
->ie_next
= entry
->ie_next
;
1380 entry
->ie_request
= 0;
1383 register mach_port_gen_t gen
;
1385 assert((entry
->ie_bits
&~ IE_BITS_GEN_MASK
) == 0);
1386 gen
= IE_BITS_NEW_GEN(entry
->ie_bits
);
1388 reply_name
= MACH_PORT_MAKE(index
, gen
);
1390 /* optimized ipc_right_copyout */
1392 entry
->ie_bits
= gen
| (MACH_PORT_TYPE_SEND_ONCE
| 1);
1395 assert(MACH_PORT_VALID(reply_name
));
1396 entry
->ie_object
= (ipc_object_t
) reply_port
;
1397 is_write_unlock(space
);
1400 /* optimized ipc_object_copyout_dest */
1402 assert(dest_port
->ip_srights
> 0);
1403 ip_release(dest_port
);
1405 if (dest_port
->ip_receiver
== space
)
1406 dest_name
= dest_port
->ip_receiver_name
;
1408 dest_name
= MACH_PORT_NULL
;
1410 if ((--dest_port
->ip_srights
== 0) &&
1411 (dest_port
->ip_nsrequest
!= IP_NULL
)) {
1412 ipc_port_t nsrequest
;
1413 mach_port_mscount_t mscount
;
1415 /* a rather rare case */
1417 nsrequest
= dest_port
->ip_nsrequest
;
1418 mscount
= dest_port
->ip_mscount
;
1419 dest_port
->ip_nsrequest
= IP_NULL
;
1420 ip_unlock(dest_port
);
1421 ipc_notify_no_senders(nsrequest
, mscount
);
1423 ip_unlock(dest_port
);
1426 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
,
1427 MACH_MSG_TYPE_PORT_SEND
);
1428 hdr
->msgh_remote_port
= (mach_port_t
)reply_name
;
1429 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1430 HOT(c_mmot_hot_ok1
++);
1433 abort_request_copyout
:
1434 ip_unlock(dest_port
);
1435 is_write_unlock(space
);
1436 HOT(c_mmot_g_slow_copyout4
++);
1440 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1441 register mach_port_name_t dest_name
;
1443 /* receiving a reply message */
1446 if (!ip_active(dest_port
)) {
1447 ip_unlock(dest_port
);
1448 HOT(c_mmot_g_slow_copyout3
++);
1452 /* optimized ipc_object_copyout_dest */
1454 assert(dest_port
->ip_sorights
> 0);
1456 if (dest_port
->ip_receiver
== space
) {
1457 ip_release(dest_port
);
1458 dest_port
->ip_sorights
--;
1459 dest_name
= dest_port
->ip_receiver_name
;
1460 ip_unlock(dest_port
);
1462 ip_unlock(dest_port
);
1464 ipc_notify_send_once(dest_port
);
1465 dest_name
= MACH_PORT_NULL
;
1468 hdr
->msgh_bits
= MACH_MSGH_BITS(0,
1469 MACH_MSG_TYPE_PORT_SEND_ONCE
);
1470 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1471 hdr
->msgh_local_port
= (ipc_port_t
)dest_name
;
1472 HOT(c_mmot_hot_ok2
++);
1476 case MACH_MSGH_BITS_COMPLEX
|
1477 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE
, 0): {
1478 register mach_port_name_t dest_name
;
1480 /* receiving a complex reply message */
1483 if (!ip_active(dest_port
)) {
1484 ip_unlock(dest_port
);
1485 HOT(c_mmot_g_slow_copyout1
++);
1489 /* optimized ipc_object_copyout_dest */
1491 assert(dest_port
->ip_sorights
> 0);
1493 if (dest_port
->ip_receiver
== space
) {
1494 ip_release(dest_port
);
1495 dest_port
->ip_sorights
--;
1496 dest_name
= dest_port
->ip_receiver_name
;
1497 ip_unlock(dest_port
);
1499 ip_unlock(dest_port
);
1501 ipc_notify_send_once(dest_port
);
1502 dest_name
= MACH_PORT_NULL
;
1506 MACH_MSGH_BITS_COMPLEX
|
1507 MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE
);
1508 hdr
->msgh_remote_port
= MACH_PORT_NULL
;
1509 hdr
->msgh_local_port
= (mach_port_t
)dest_name
;
1511 mr
= ipc_kmsg_copyout_body(kmsg
, space
,
1513 MACH_MSG_BODY_NULL
);
1514 if (mr
!= MACH_MSG_SUCCESS
) {
1515 if (ipc_kmsg_put(msg
, kmsg
, hdr
->msgh_size
+
1516 trailer
->msgh_trailer_size
) ==
1517 MACH_RCV_INVALID_DATA
)
1518 return MACH_RCV_INVALID_DATA
;
1520 return mr
| MACH_RCV_BODY_ERROR
;
1522 HOT(c_mmot_hot_ok3
++);
1527 HOT(c_mmot_g_slow_copyout2
++);
1533 mr
= ipc_kmsg_put(rcv_msg
? rcv_msg
: msg
,
1535 hdr
->msgh_size
+ trailer
->msgh_trailer_size
);
1536 if (mr
!= MACH_MSG_SUCCESS
) {
1537 return MACH_RCV_INVALID_DATA
;
1539 current_task()->messages_received
++;
1543 /* BEGINNING OF WARM PATH */
1546 * The slow path has a few non-register temporary
1547 * variables used only for call-by-reference.
1552 ipc_kmsg_t temp_kmsg
;
1553 mach_port_seqno_t temp_seqno
;
1554 ipc_object_t temp_rcv_object
;
1555 ipc_mqueue_t temp_rcv_mqueue
;
1556 register mach_port_name_t reply_name
=
1557 (mach_port_name_t
)hdr
->msgh_local_port
;
1561 * We have the message data in kmsg, but
1562 * we still need to copyin, send it,
1563 * receive a reply, and do copyout.
1566 mr
= ipc_kmsg_copyin(kmsg
, space
, current_map(),
1568 if (mr
!= MACH_MSG_SUCCESS
) {
1569 ipc_kmsg_free(kmsg
);
1573 /* try to get back on optimized path */
1575 if ((reply_name
!= rcv_name
) ||
1576 (hdr
->msgh_bits
& MACH_MSGH_BITS_CIRCULAR
)) {
1577 HOT(c_mmot_cold_048
++);
1581 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1582 assert(IP_VALID(dest_port
));
1585 if (!ip_active(dest_port
)) {
1586 ip_unlock(dest_port
);
1590 if (dest_port
->ip_receiver
== ipc_space_kernel
) {
1591 dest_port
->ip_messages
.imq_seqno
++;
1592 ip_unlock(dest_port
);
1596 if (!imq_full(&dest_port
->ip_messages
) ||
1597 (MACH_MSGH_BITS_REMOTE(hdr
->msgh_bits
) ==
1598 MACH_MSG_TYPE_PORT_SEND_ONCE
))
1601 * Try an optimized ipc_mqueue_copyin.
1602 * It will work if this is a request message.
1605 register ipc_port_t reply_port
;
1607 reply_port
= (ipc_port_t
) hdr
->msgh_local_port
;
1608 if (IP_VALID(reply_port
)) {
1609 if (ip_lock_try(reply_port
)) {
1610 if (ip_active(reply_port
) &&
1611 reply_port
->ip_receiver
== space
&&
1612 reply_port
->ip_receiver_name
== rcv_name
&&
1613 reply_port
->ip_pset_count
== 0)
1615 /* Grab a reference to the reply port. */
1616 rcv_object
= (ipc_object_t
) reply_port
;
1617 io_reference(rcv_object
);
1618 rcv_mqueue
= &reply_port
->ip_messages
;
1619 io_unlock(rcv_object
);
1620 HOT(c_mmot_getback_FastSR
++);
1621 goto fast_send_receive
;
1623 ip_unlock(reply_port
);
1628 ip_unlock(dest_port
);
1629 HOT(c_mmot_cold_050
++);
1634 * Special case: send message to kernel services.
1635 * The request message has been copied into the
1636 * kmsg. Nothing is locked.
1640 register ipc_port_t reply_port
;
1641 mach_port_seqno_t local_seqno
;
1645 * Perform the kernel function.
1647 c_mmot_kernel_send
++;
1649 current_task()->messages_sent
++;
1651 kmsg
= ipc_kobject_server(kmsg
);
1652 if (kmsg
== IKM_NULL
) {
1654 * No reply. Take the
1655 * slow receive path.
1657 HOT(c_mmot_cold_051
++);
1658 goto slow_get_rcv_port
;
1663 * the reply port is alive
1664 * we hold the receive right
1665 * the name has not changed.
1666 * the port is not in a set
1667 * If any of these are not true,
1668 * we cannot directly receive the reply
1671 hdr
= &kmsg
->ikm_header
;
1672 send_size
= hdr
->msgh_size
;
1673 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1674 round_msg(send_size
));
1675 reply_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1676 ip_lock(reply_port
);
1678 if ((!ip_active(reply_port
)) ||
1679 (reply_port
->ip_receiver
!= space
) ||
1680 (reply_port
->ip_receiver_name
!= rcv_name
) ||
1681 (reply_port
->ip_pset_count
!= 0))
1683 ip_unlock(reply_port
);
1684 ipc_kmsg_send_always(kmsg
);
1685 HOT(c_mmot_cold_052
++);
1686 goto slow_get_rcv_port
;
1690 rcv_mqueue
= &reply_port
->ip_messages
;
1691 imq_lock(rcv_mqueue
);
1693 /* keep port locked, and don`t change ref count yet */
1696 * If there are messages on the port
1697 * or other threads waiting for a message,
1698 * we cannot directly receive the reply.
1700 if (!wait_queue_empty(&rcv_mqueue
->imq_wait_queue
) ||
1701 (ipc_kmsg_queue_first(&rcv_mqueue
->imq_messages
) != IKM_NULL
))
1703 imq_unlock(rcv_mqueue
);
1705 ip_unlock(reply_port
);
1706 ipc_kmsg_send_always(kmsg
);
1707 HOT(c_mmot_cold_053
++);
1708 goto slow_get_rcv_port
;
1712 * We can directly receive this reply.
1713 * Since there were no messages queued
1714 * on the reply port, there should be
1715 * no threads blocked waiting to send.
1717 dest_port
= reply_port
;
1718 local_seqno
= rcv_mqueue
->imq_seqno
++;
1719 imq_unlock(rcv_mqueue
);
1723 * inline ipc_object_release.
1724 * Port is still locked.
1725 * Reference count was not incremented.
1727 ip_check_unlock(reply_port
);
1729 if (option
& MACH_RCV_TRAILER_MASK
) {
1730 trailer
->msgh_seqno
= local_seqno
;
1731 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1733 /* copy out the kernel reply */
1734 HOT(c_mmot_fastkernelreply
++);
1740 * Nothing is locked. We have acquired kmsg, but
1741 * we still need to send it and receive a reply.
1744 mr
= ipc_kmsg_send(kmsg
, MACH_MSG_OPTION_NONE
,
1745 MACH_MSG_TIMEOUT_NONE
);
1746 if (mr
!= MACH_MSG_SUCCESS
) {
1747 mr
|= ipc_kmsg_copyout_pseudo(kmsg
, space
,
1749 MACH_MSG_BODY_NULL
);
1751 (void) ipc_kmsg_put(msg
, kmsg
, hdr
->msgh_size
);
1757 * We have sent the message. Copy in the receive port.
1759 mr
= ipc_mqueue_copyin(space
, rcv_name
,
1760 &temp_rcv_mqueue
, &temp_rcv_object
);
1761 if (mr
!= MACH_MSG_SUCCESS
) {
1764 rcv_mqueue
= temp_rcv_mqueue
;
1765 rcv_object
= temp_rcv_object
;
1766 /* hold ref for rcv_object */
1770 * Now we have sent the request and copied in rcv_name,
1771 * and hold ref for rcv_object (to keep mqueue alive).
1772 * Just receive a reply and try to get back to fast path.
1775 self
->ith_continuation
= (void (*)(mach_msg_return_t
))0;
1776 ipc_mqueue_receive(rcv_mqueue
,
1777 MACH_MSG_OPTION_NONE
,
1779 MACH_MSG_TIMEOUT_NONE
,
1782 mr
= self
->ith_state
;
1783 temp_kmsg
= self
->ith_kmsg
;
1784 temp_seqno
= self
->ith_seqno
;
1786 ipc_object_release(rcv_object
);
1788 if (mr
!= MACH_MSG_SUCCESS
) {
1793 hdr
= &kmsg
->ikm_header
;
1794 send_size
= hdr
->msgh_size
;
1795 trailer
= (mach_msg_format_0_trailer_t
*) ((vm_offset_t
) hdr
+
1796 round_msg(send_size
));
1797 if (option
& MACH_RCV_TRAILER_MASK
) {
1798 trailer
->msgh_seqno
= temp_seqno
;
1799 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1801 dest_port
= (ipc_port_t
) hdr
->msgh_remote_port
;
1802 HOT(c_mmot_cold_055
++);
1807 * Nothing locked and no references held, except
1808 * we have kmsg with msgh_seqno filled in. Must
1809 * still check against rcv_size and do
1810 * ipc_kmsg_copyout/ipc_kmsg_put.
1813 reply_size
= send_size
+ trailer
->msgh_trailer_size
;
1814 if (rcv_size
< reply_size
) {
1815 if (msg_receive_error(kmsg
, msg
, option
, temp_seqno
,
1816 space
) == MACH_RCV_INVALID_DATA
) {
1817 mr
= MACH_RCV_INVALID_DATA
;
1821 mr
= MACH_RCV_TOO_LARGE
;
1826 mr
= ipc_kmsg_copyout(kmsg
, space
, current_map(),
1827 MACH_PORT_NULL
, MACH_MSG_BODY_NULL
);
1828 if (mr
!= MACH_MSG_SUCCESS
) {
1829 if ((mr
&~ MACH_MSG_MASK
) == MACH_RCV_BODY_ERROR
) {
1830 if (ipc_kmsg_put(msg
, kmsg
, reply_size
) ==
1831 MACH_RCV_INVALID_DATA
)
1832 mr
= MACH_RCV_INVALID_DATA
;
1835 if (msg_receive_error(kmsg
, msg
, option
,
1836 temp_seqno
, space
) == MACH_RCV_INVALID_DATA
)
1837 mr
= MACH_RCV_INVALID_DATA
;
1843 /* try to get back on optimized path */
1844 HOT(c_mmot_getback_fast_put
++);
1849 } /* END OF HOT PATH */
1850 #endif /* ENABLE_HOTPATH */
1852 if (option
& MACH_SEND_MSG
) {
1853 mr
= mach_msg_send(msg
, option
, send_size
,
1855 if (mr
!= MACH_MSG_SUCCESS
) {
1860 if (option
& MACH_RCV_MSG
) {
1861 mach_msg_header_t
*rcv
;
1864 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
1865 * and receive buffer
1866 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
1867 * alternate receive buffer (separate send and receive buffers).
1869 if (option
& MACH_RCV_OVERWRITE
)
1871 else if (rcv_msg
!= MACH_MSG_NULL
)
1875 mr
= mach_msg_receive(rcv
, option
, rcv_size
, rcv_name
,
1876 timeout
, thread_syscall_return
, scatter_list_size
);
1877 thread_syscall_return(mr
);
1880 return MACH_MSG_SUCCESS
;
1884 * Routine: msg_receive_error [internal]
1886 * Builds a minimal header/trailer and copies it to
1887 * the user message buffer. Invoked when in the case of a
1888 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
1892 * MACH_MSG_SUCCESS minimal header/trailer copied
1893 * MACH_RCV_INVALID_DATA copyout to user buffer failed
1899 mach_msg_header_t
*msg
,
1900 mach_msg_option_t option
,
1901 mach_port_seqno_t seqno
,
1904 mach_msg_format_0_trailer_t
*trailer
;
1907 * Copy out the destination port in the message.
1908 * Destroy all other rights and memory in the message.
1910 ipc_kmsg_copyout_dest(kmsg
, space
);
1913 * Build a minimal message with the requested trailer.
1915 trailer
= (mach_msg_format_0_trailer_t
*)
1916 ((vm_offset_t
)&kmsg
->ikm_header
+
1917 round_msg(sizeof(mach_msg_header_t
)));
1918 kmsg
->ikm_header
.msgh_size
= sizeof(mach_msg_header_t
);
1919 bcopy( (char *)&trailer_template
,
1921 sizeof(trailer_template
));
1922 if (option
& MACH_RCV_TRAILER_MASK
) {
1923 trailer
->msgh_seqno
= seqno
;
1924 trailer
->msgh_trailer_size
= REQUESTED_TRAILER_SIZE(option
);
1928 * Copy the message to user space
1930 if (ipc_kmsg_put(msg
, kmsg
, kmsg
->ikm_header
.msgh_size
+
1931 trailer
->msgh_trailer_size
) == MACH_RCV_INVALID_DATA
)
1932 return(MACH_RCV_INVALID_DATA
);
1934 return(MACH_MSG_SUCCESS
);