2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * @OSF_FREE_COPYRIGHT@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
59 * File: ipc/ipc_mqueue.c
63 * Functions to manipulate IPC message queues.
66 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
67 * support for mandatory and extensible security protections. This notice
68 * is included in support of clause 2.2 (b) of the Apple Public License,
73 #include <mach/port.h>
74 #include <mach/message.h>
75 #include <mach/sync_policy.h>
77 #include <kern/assert.h>
78 #include <kern/counters.h>
79 #include <kern/sched_prim.h>
80 #include <kern/ipc_kobject.h>
81 #include <kern/ipc_mig.h> /* XXX - for mach_msg_receive_continue */
82 #include <kern/misc_protos.h>
83 #include <kern/task.h>
84 #include <kern/thread.h>
85 #include <kern/waitq.h>
88 #include <ipc/ipc_mqueue.h>
89 #include <ipc/ipc_kmsg.h>
90 #include <ipc/ipc_port.h>
91 #include <ipc/ipc_pset.h>
92 #include <ipc/ipc_space.h>
95 #include <ipc/flipc.h>
99 #include <vm/vm_map.h>
102 #include <sys/event.h>
104 extern char *proc_name_address(void *p
);
106 int ipc_mqueue_full
; /* address is event for queue space */
107 int ipc_mqueue_rcv
; /* address is event for message arrival */
109 /* forward declarations */
110 static void ipc_mqueue_receive_results(wait_result_t result
);
111 static void ipc_mqueue_peek_on_thread(
112 ipc_mqueue_t port_mq
,
113 mach_msg_option_t option
,
117 * Routine: ipc_mqueue_init
119 * Initialize a newly-allocated message queue.
124 ipc_mqueue_kind_t kind
)
127 case IPC_MQUEUE_KIND_SET
:
128 waitq_set_init(&mqueue
->imq_set_queue
,
129 SYNC_POLICY_FIFO
| SYNC_POLICY_PREPOST
,
132 case IPC_MQUEUE_KIND_NONE
: /* cheat: we really should have "no" mqueue */
133 case IPC_MQUEUE_KIND_PORT
:
134 waitq_init(&mqueue
->imq_wait_queue
,
135 SYNC_POLICY_FIFO
| SYNC_POLICY_TURNSTILE_PROXY
);
136 ipc_kmsg_queue_init(&mqueue
->imq_messages
);
137 mqueue
->imq_seqno
= 0;
138 mqueue
->imq_msgcount
= 0;
139 mqueue
->imq_qlimit
= MACH_PORT_QLIMIT_DEFAULT
;
140 mqueue
->imq_context
= 0;
141 mqueue
->imq_fullwaiters
= FALSE
;
143 mqueue
->imq_fport
= FPORT_NULL
;
147 klist_init(&mqueue
->imq_klist
);
154 boolean_t is_set
= imq_is_set(mqueue
);
157 waitq_set_deinit(&mqueue
->imq_set_queue
);
159 waitq_deinit(&mqueue
->imq_wait_queue
);
164 * Routine: imq_reserve_and_lock
166 * Atomically lock an ipc_mqueue_t object and reserve
167 * an appropriate number of prepost linkage objects for
168 * use in wakeup operations.
173 imq_reserve_and_lock(ipc_mqueue_t mq
, uint64_t *reserved_prepost
)
175 *reserved_prepost
= waitq_prepost_reserve(&mq
->imq_wait_queue
, 0,
181 * Routine: imq_release_and_unlock
183 * Unlock an ipc_mqueue_t object, re-enable interrupts,
184 * and release any unused prepost object reservations.
189 imq_release_and_unlock(ipc_mqueue_t mq
, uint64_t reserved_prepost
)
191 assert(imq_held(mq
));
192 waitq_unlock(&mq
->imq_wait_queue
);
193 waitq_prepost_release_reserve(reserved_prepost
);
198 * Routine: ipc_mqueue_member
200 * Indicate whether the (port) mqueue is a member of
201 * this portset's mqueue. We do this by checking
202 * whether the portset mqueue's waitq is an member of
203 * the port's mqueue waitq.
205 * the portset's mqueue is not already a member
206 * this may block while allocating linkage structures.
211 ipc_mqueue_t port_mqueue
,
212 ipc_mqueue_t set_mqueue
)
214 struct waitq
*port_waitq
= &port_mqueue
->imq_wait_queue
;
215 struct waitq_set
*set_waitq
= &set_mqueue
->imq_set_queue
;
217 return waitq_member(port_waitq
, set_waitq
);
221 * Routine: ipc_mqueue_remove
223 * Remove the association between the queue and the specified
230 ipc_mqueue_t set_mqueue
)
232 struct waitq
*mq_waitq
= &mqueue
->imq_wait_queue
;
233 struct waitq_set
*set_waitq
= &set_mqueue
->imq_set_queue
;
235 return waitq_unlink(mq_waitq
, set_waitq
);
239 * Routine: ipc_mqueue_remove_from_all
241 * Remove the mqueue from all the sets it is a member of
245 * mqueue unlocked and set links deallocated
248 ipc_mqueue_remove_from_all(ipc_mqueue_t mqueue
)
250 struct waitq
*mq_waitq
= &mqueue
->imq_wait_queue
;
255 assert(waitq_valid(mq_waitq
));
256 kr
= waitq_unlink_all_unlock(mq_waitq
);
257 /* mqueue unlocked and set links deallocated */
261 * Routine: ipc_mqueue_remove_all
263 * Remove all the member queues from the specified set.
264 * Also removes the queue from any containing sets.
268 * mqueue unlocked all set links deallocated
271 ipc_mqueue_remove_all(ipc_mqueue_t mqueue
)
273 struct waitq_set
*mq_setq
= &mqueue
->imq_set_queue
;
276 assert(waitqs_is_set(mq_setq
));
277 waitq_set_unlink_all_unlock(mq_setq
);
278 /* mqueue unlocked set links deallocated */
283 * Routine: ipc_mqueue_add
285 * Associate the portset's mqueue with the port's mqueue.
286 * This has to be done so that posting the port will wakeup
287 * a portset waiter. If there are waiters on the portset
288 * mqueue and messages on the port mqueue, try to match them
295 ipc_mqueue_t port_mqueue
,
296 ipc_mqueue_t set_mqueue
,
297 uint64_t *reserved_link
,
298 uint64_t *reserved_prepost
)
300 struct waitq
*port_waitq
= &port_mqueue
->imq_wait_queue
;
301 struct waitq_set
*set_waitq
= &set_mqueue
->imq_set_queue
;
302 ipc_kmsg_queue_t kmsgq
;
303 ipc_kmsg_t kmsg
, next
;
306 assert(reserved_link
&& *reserved_link
!= 0);
307 assert(waitqs_is_linked(set_waitq
));
309 imq_lock(port_mqueue
);
312 * The link operation is now under the same lock-hold as
313 * message iteration and thread wakeup, but doesn't have to be...
315 kr
= waitq_link(port_waitq
, set_waitq
, WAITQ_ALREADY_LOCKED
, reserved_link
);
316 if (kr
!= KERN_SUCCESS
) {
317 imq_unlock(port_mqueue
);
322 * Now that the set has been added to the port, there may be
323 * messages queued on the port and threads waiting on the set
324 * waitq. Lets get them together.
326 kmsgq
= &port_mqueue
->imq_messages
;
327 for (kmsg
= ipc_kmsg_queue_first(kmsgq
);
330 next
= ipc_kmsg_queue_next(kmsgq
, kmsg
);
334 mach_msg_size_t msize
;
337 th
= waitq_wakeup64_identify_locked(
340 THREAD_AWAKENED
, &th_spl
,
341 reserved_prepost
, WAITQ_ALL_PRIORITIES
,
343 /* waitq/mqueue still locked, thread locked */
345 if (th
== THREAD_NULL
) {
350 * If the receiver waited with a facility not directly
351 * related to Mach messaging, then it isn't prepared to get
352 * handed the message directly. Just set it running, and
353 * go look for another thread that can.
355 if (th
->ith_state
!= MACH_RCV_IN_PROGRESS
) {
356 if (th
->ith_state
== MACH_PEEK_IN_PROGRESS
) {
358 * wakeup the peeking thread, but
359 * continue to loop over the threads
360 * waiting on the port's mqueue to see
361 * if there are any actual receivers
363 ipc_mqueue_peek_on_thread(port_mqueue
,
373 * Found a receiver. see if they can handle the message
374 * correctly (the message is not too large for them, or
375 * they didn't care to be informed that the message was
376 * too large). If they can't handle it, take them off
377 * the list and let them go back and figure it out and
378 * just move onto the next.
380 msize
= ipc_kmsg_copyout_size(kmsg
, th
->map
);
382 (msize
+ REQUESTED_TRAILER_SIZE(thread_is_64bit_addr(th
), th
->ith_option
))) {
383 th
->ith_state
= MACH_RCV_TOO_LARGE
;
384 th
->ith_msize
= msize
;
385 if (th
->ith_option
& MACH_RCV_LARGE
) {
387 * let him go without message
389 th
->ith_receiver_name
= port_mqueue
->imq_receiver_name
;
390 th
->ith_kmsg
= IKM_NULL
;
394 continue; /* find another thread */
397 th
->ith_state
= MACH_MSG_SUCCESS
;
401 * This thread is going to take this message,
404 ipc_kmsg_rmqueue(kmsgq
, kmsg
);
406 mach_node_t node
= kmsg
->ikm_node
;
408 ipc_mqueue_release_msgcount(port_mqueue
, IMQ_NULL
);
411 th
->ith_seqno
= port_mqueue
->imq_seqno
++;
415 if (MACH_NODE_VALID(node
) && FPORT_VALID(port_mqueue
->imq_fport
)) {
416 flipc_msg_ack(node
, port_mqueue
, TRUE
);
419 break; /* go to next message */
423 imq_unlock(port_mqueue
);
429 * Routine: ipc_mqueue_has_klist
431 * Returns whether the given mqueue imq_klist field can be used as a klist.
434 ipc_mqueue_has_klist(ipc_mqueue_t mqueue
)
436 ipc_object_t object
= imq_to_object(mqueue
);
437 if (io_otype(object
) != IOT_PORT
) {
440 ipc_port_t port
= ip_from_mq(mqueue
);
441 if (port
->ip_specialreply
) {
444 return port
->ip_sync_link_state
== PORT_SYNC_LINK_ANY
;
448 * Routine: ipc_mqueue_changed
450 * Wake up receivers waiting in a message queue.
452 * The message queue is locked.
459 if (ipc_mqueue_has_klist(mqueue
) && SLIST_FIRST(&mqueue
->imq_klist
)) {
461 * Indicate that this message queue is vanishing
463 * When this is called, the associated receive right may be in flight
464 * between two tasks: the one it used to live in, and the one that armed
465 * a port destroyed notification for it.
467 * The new process may want to register the port it gets back with an
468 * EVFILT_MACHPORT filter again, and may have pending sync IPC on this
469 * port pending already, in which case we want the imq_klist field to be
470 * reusable for nefarious purposes.
472 * Fortunately, we really don't need this linkage anymore after this
473 * point as EV_VANISHED / EV_EOF will be the last thing delivered ever.
475 * Note: we don't have the space lock here, however, this covers the
476 * case of when a task is terminating the space, triggering
477 * several knote_vanish() calls.
479 * We don't need the lock to observe that the space is inactive as
480 * we just deactivated it on the same thread.
482 * We still need to call knote_vanish() so that the knote is
483 * marked with EV_VANISHED or EV_EOF so that the detach step
484 * in filt_machportdetach is skipped correctly.
487 knote_vanish(&mqueue
->imq_klist
, is_active(space
));
490 if (io_otype(imq_to_object(mqueue
)) == IOT_PORT
) {
491 ipc_port_adjust_sync_link_state_locked(ip_from_mq(mqueue
), PORT_SYNC_LINK_ANY
, NULL
);
493 klist_init(&mqueue
->imq_klist
);
496 waitq_wakeup64_all_locked(&mqueue
->imq_wait_queue
,
500 WAITQ_ALL_PRIORITIES
,
508 * Routine: ipc_mqueue_send
510 * Send a message to a message queue. The message holds a reference
511 * for the destination port for this message queue in the
512 * msgh_remote_port field.
514 * If unsuccessful, the caller still has possession of
515 * the message and must do something with it. If successful,
516 * the message is queued, given to a receiver, or destroyed.
520 * MACH_MSG_SUCCESS The message was accepted.
521 * MACH_SEND_TIMED_OUT Caller still has message.
522 * MACH_SEND_INTERRUPTED Caller still has message.
528 mach_msg_option_t option
,
529 mach_msg_timeout_t send_timeout
)
535 * 1) We're under the queue limit.
536 * 2) Caller used the MACH_SEND_ALWAYS internal option.
537 * 3) Message is sent to a send-once right.
539 if (!imq_full(mqueue
) ||
540 (!imq_full_kernel(mqueue
) &&
541 ((option
& MACH_SEND_ALWAYS
) ||
542 (MACH_MSGH_BITS_REMOTE(kmsg
->ikm_header
->msgh_bits
) ==
543 MACH_MSG_TYPE_PORT_SEND_ONCE
)))) {
544 mqueue
->imq_msgcount
++;
545 assert(mqueue
->imq_msgcount
> 0);
548 thread_t cur_thread
= current_thread();
549 ipc_port_t port
= ip_from_mq(mqueue
);
550 struct turnstile
*send_turnstile
= TURNSTILE_NULL
;
554 * We have to wait for space to be granted to us.
556 if ((option
& MACH_SEND_TIMEOUT
) && (send_timeout
== 0)) {
558 return MACH_SEND_TIMED_OUT
;
560 if (imq_full_kernel(mqueue
)) {
562 return MACH_SEND_NO_BUFFER
;
564 mqueue
->imq_fullwaiters
= TRUE
;
566 if (option
& MACH_SEND_TIMEOUT
) {
567 clock_interval_to_deadline(send_timeout
, 1000 * NSEC_PER_USEC
, &deadline
);
572 thread_set_pending_block_hint(cur_thread
, kThreadWaitPortSend
);
574 send_turnstile
= turnstile_prepare((uintptr_t)port
,
575 port_send_turnstile_address(port
),
576 TURNSTILE_NULL
, TURNSTILE_SYNC_IPC
);
578 ipc_port_send_update_inheritor(port
, send_turnstile
,
579 TURNSTILE_DELAYED_UPDATE
);
581 wresult
= waitq_assert_wait64_leeway(
582 &send_turnstile
->ts_waitq
,
585 TIMEOUT_URGENCY_USER_NORMAL
,
590 turnstile_update_inheritor_complete(send_turnstile
,
591 TURNSTILE_INTERLOCK_NOT_HELD
);
593 if (wresult
== THREAD_WAITING
) {
594 wresult
= thread_block(THREAD_CONTINUE_NULL
);
595 counter(c_ipc_mqueue_send_block
++);
598 /* Call turnstile complete with interlock held */
600 turnstile_complete((uintptr_t)port
, port_send_turnstile_address(port
), NULL
, TURNSTILE_SYNC_IPC
);
603 /* Call cleanup after dropping the interlock */
607 case THREAD_AWAKENED
:
609 * we can proceed - inherited msgcount from waker
610 * or the message queue has been destroyed and the msgcount
611 * has been reset to zero (will detect in ipc_mqueue_post()).
615 case THREAD_TIMED_OUT
:
616 assert(option
& MACH_SEND_TIMEOUT
);
617 return MACH_SEND_TIMED_OUT
;
619 case THREAD_INTERRUPTED
:
620 return MACH_SEND_INTERRUPTED
;
623 /* mqueue is being destroyed */
624 return MACH_SEND_INVALID_DEST
;
626 panic("ipc_mqueue_send");
630 ipc_mqueue_post(mqueue
, kmsg
, option
);
631 return MACH_MSG_SUCCESS
;
635 * Routine: ipc_mqueue_override_send
637 * Set an override qos on the first message in the queue
638 * (if the queue is full). This is a send-possible override
639 * that will go away as soon as we drain a message from the
643 * The message queue is not locked.
644 * The caller holds a reference on the message queue.
647 ipc_mqueue_override_send(
649 mach_msg_priority_t override
)
651 boolean_t __unused full_queue_empty
= FALSE
;
654 assert(imq_valid(mqueue
));
655 assert(!imq_is_set(mqueue
));
657 if (imq_full(mqueue
)) {
658 ipc_kmsg_t first
= ipc_kmsg_queue_first(&mqueue
->imq_messages
);
660 if (first
&& ipc_kmsg_override_qos(&mqueue
->imq_messages
, first
, override
)) {
661 ipc_object_t object
= imq_to_object(mqueue
);
662 assert(io_otype(object
) == IOT_PORT
);
663 ipc_port_t port
= ip_object_to_port(object
);
664 if (ip_active(port
) &&
665 port
->ip_receiver_name
!= MACH_PORT_NULL
&&
666 is_active(port
->ip_receiver
) &&
667 ipc_mqueue_has_klist(mqueue
)) {
668 KNOTE(&mqueue
->imq_klist
, 0);
672 full_queue_empty
= TRUE
;
677 #if DEVELOPMENT || DEBUG
678 if (full_queue_empty
) {
679 ipc_port_t port
= ip_from_mq(mqueue
);
681 if (ip_active(port
) && !port
->ip_tempowner
&&
682 port
->ip_receiver_name
&& port
->ip_receiver
&&
683 port
->ip_receiver
!= ipc_space_kernel
) {
684 dst_pid
= task_pid(port
->ip_receiver
->is_task
);
691 * Routine: ipc_mqueue_release_msgcount
693 * Release a message queue reference in the case where we
697 * The message queue is locked.
698 * The message corresponding to this reference is off the queue.
699 * There is no need to pass reserved preposts because this will
700 * never prepost to anyone
703 ipc_mqueue_release_msgcount(ipc_mqueue_t port_mq
, ipc_mqueue_t set_mq
)
705 struct turnstile
*send_turnstile
= port_send_turnstile(ip_from_mq(port_mq
));
707 assert(imq_held(port_mq
));
708 assert(port_mq
->imq_msgcount
> 1 || ipc_kmsg_queue_empty(&port_mq
->imq_messages
));
710 port_mq
->imq_msgcount
--;
712 if (!imq_full(port_mq
) && port_mq
->imq_fullwaiters
&&
713 send_turnstile
!= TURNSTILE_NULL
) {
715 * boost the priority of the awoken thread
716 * (WAITQ_PROMOTE_PRIORITY) to ensure it uses
717 * the message queue slot we've just reserved.
719 * NOTE: this will never prepost
721 * The wakeup happens on a turnstile waitq
722 * which will wakeup the highest priority waiter.
723 * A potential downside of this would be starving low
724 * priority senders if there is a constant churn of
725 * high priority threads trying to send to this port.
727 if (waitq_wakeup64_one(&send_turnstile
->ts_waitq
,
730 WAITQ_PROMOTE_PRIORITY
) != KERN_SUCCESS
) {
731 port_mq
->imq_fullwaiters
= FALSE
;
733 /* gave away our slot - add reference back */
734 port_mq
->imq_msgcount
++;
738 if (ipc_kmsg_queue_empty(&port_mq
->imq_messages
)) {
739 /* no more msgs: invalidate the port's prepost object */
740 waitq_clear_prepost_locked(&port_mq
->imq_wait_queue
);
745 * Routine: ipc_mqueue_post
747 * Post a message to a waiting receiver or enqueue it. If a
748 * receiver is waiting, we can release our reserved space in
753 * If we need to queue, our space in the message queue is reserved.
759 mach_msg_option_t __unused option
)
761 uint64_t reserved_prepost
= 0;
762 boolean_t destroy_msg
= FALSE
;
764 ipc_kmsg_trace_send(kmsg
, option
);
767 * While the msg queue is locked, we have control of the
768 * kmsg, so the ref in it for the port is still good.
770 * Check for a receiver for the message.
772 imq_reserve_and_lock(mqueue
, &reserved_prepost
);
774 /* we may have raced with port destruction! */
775 if (!imq_valid(mqueue
)) {
781 struct waitq
*waitq
= &mqueue
->imq_wait_queue
;
784 mach_msg_size_t msize
;
786 receiver
= waitq_wakeup64_identify_locked(waitq
,
791 WAITQ_ALL_PRIORITIES
,
793 /* waitq still locked, thread locked */
795 if (receiver
== THREAD_NULL
) {
797 * no receivers; queue kmsg if space still reserved
798 * Reservations are cancelled when the port goes inactive.
799 * note that this will enqueue the message for any
800 * "peeking" receivers.
802 * Also, post the knote to wake up any threads waiting
803 * on that style of interface if this insertion is of
804 * note (first insertion, or adjusted override qos all
805 * the way to the head of the queue).
807 * This is just for ports. portset knotes are stay-active,
808 * and their threads get awakened through the !MACH_RCV_IN_PROGRESS
811 if (mqueue
->imq_msgcount
> 0) {
812 if (ipc_kmsg_enqueue_qos(&mqueue
->imq_messages
, kmsg
)) {
813 /* if the space is dead there is no point calling KNOTE */
814 ipc_object_t object
= imq_to_object(mqueue
);
815 assert(io_otype(object
) == IOT_PORT
);
816 ipc_port_t port
= ip_object_to_port(object
);
817 if (ip_active(port
) &&
818 port
->ip_receiver_name
!= MACH_PORT_NULL
&&
819 is_active(port
->ip_receiver
) &&
820 ipc_mqueue_has_klist(mqueue
)) {
821 KNOTE(&mqueue
->imq_klist
, 0);
828 * Otherwise, the message queue must belong to an inactive
829 * port, so just destroy the message and pretend it was posted.
836 * If a thread is attempting a "peek" into the message queue
837 * (MACH_PEEK_IN_PROGRESS), then we enqueue the message and set the
838 * thread running. A successful peek is essentially the same as
839 * message delivery since the peeking thread takes responsibility
840 * for delivering the message and (eventually) removing it from
841 * the mqueue. Only one thread can successfully use the peek
842 * facility on any given port, so we exit the waitq loop after
843 * encountering such a thread.
845 if (receiver
->ith_state
== MACH_PEEK_IN_PROGRESS
&& mqueue
->imq_msgcount
> 0) {
846 ipc_kmsg_enqueue_qos(&mqueue
->imq_messages
, kmsg
);
847 ipc_mqueue_peek_on_thread(mqueue
, receiver
->ith_option
, receiver
);
848 thread_unlock(receiver
);
850 break; /* Message was posted, so break out of loop */
854 * If the receiver waited with a facility not directly related
855 * to Mach messaging, then it isn't prepared to get handed the
856 * message directly. Just set it running, and go look for
857 * another thread that can.
859 if (receiver
->ith_state
!= MACH_RCV_IN_PROGRESS
) {
860 thread_unlock(receiver
);
867 * We found a waiting thread.
868 * If the message is too large or the scatter list is too small
869 * the thread we wake up will get that as its status.
871 msize
= ipc_kmsg_copyout_size(kmsg
, receiver
->map
);
872 if (receiver
->ith_rsize
<
873 (msize
+ REQUESTED_TRAILER_SIZE(thread_is_64bit_addr(receiver
), receiver
->ith_option
))) {
874 receiver
->ith_msize
= msize
;
875 receiver
->ith_state
= MACH_RCV_TOO_LARGE
;
877 receiver
->ith_state
= MACH_MSG_SUCCESS
;
881 * If there is no problem with the upcoming receive, or the
882 * receiver thread didn't specifically ask for special too
883 * large error condition, go ahead and select it anyway.
885 if ((receiver
->ith_state
== MACH_MSG_SUCCESS
) ||
886 !(receiver
->ith_option
& MACH_RCV_LARGE
)) {
887 receiver
->ith_kmsg
= kmsg
;
888 receiver
->ith_seqno
= mqueue
->imq_seqno
++;
890 mach_node_t node
= kmsg
->ikm_node
;
892 thread_unlock(receiver
);
895 /* we didn't need our reserved spot in the queue */
896 ipc_mqueue_release_msgcount(mqueue
, IMQ_NULL
);
899 if (MACH_NODE_VALID(node
) && FPORT_VALID(mqueue
->imq_fport
)) {
900 flipc_msg_ack(node
, mqueue
, TRUE
);
907 * Otherwise, this thread needs to be released to run
908 * and handle its error without getting the message. We
909 * need to go back and pick another one.
911 receiver
->ith_receiver_name
= mqueue
->imq_receiver_name
;
912 receiver
->ith_kmsg
= IKM_NULL
;
913 receiver
->ith_seqno
= 0;
914 thread_unlock(receiver
);
919 /* clear the waitq boost we may have been given */
920 waitq_clear_promotion_locked(&mqueue
->imq_wait_queue
, current_thread());
921 imq_release_and_unlock(mqueue
, reserved_prepost
);
923 ipc_kmsg_destroy(kmsg
);
926 current_task()->messages_sent
++;
932 ipc_mqueue_receive_results(wait_result_t saved_wait_result
)
934 thread_t self
= current_thread();
935 mach_msg_option_t option
= self
->ith_option
;
938 * why did we wake up?
940 switch (saved_wait_result
) {
941 case THREAD_TIMED_OUT
:
942 self
->ith_state
= MACH_RCV_TIMED_OUT
;
945 case THREAD_INTERRUPTED
:
946 self
->ith_state
= MACH_RCV_INTERRUPTED
;
950 /* something bad happened to the port/set */
951 self
->ith_state
= MACH_RCV_PORT_CHANGED
;
954 case THREAD_AWAKENED
:
956 * We do not need to go select a message, somebody
957 * handed us one (or a too-large indication).
959 switch (self
->ith_state
) {
960 case MACH_RCV_SCATTER_SMALL
:
961 case MACH_RCV_TOO_LARGE
:
963 * Somebody tried to give us a too large
964 * message. If we indicated that we cared,
965 * then they only gave us the indication,
966 * otherwise they gave us the indication
967 * AND the message anyway.
969 if (option
& MACH_RCV_LARGE
) {
973 case MACH_MSG_SUCCESS
:
974 case MACH_PEEK_READY
:
978 panic("ipc_mqueue_receive_results: strange ith_state");
982 panic("ipc_mqueue_receive_results: strange wait_result");
987 ipc_mqueue_receive_continue(
988 __unused
void *param
,
989 wait_result_t wresult
)
991 ipc_mqueue_receive_results(wresult
);
992 mach_msg_receive_continue(); /* hard-coded for now */
996 * Routine: ipc_mqueue_receive
998 * Receive a message from a message queue.
1001 * Our caller must hold a reference for the port or port set
1002 * to which this queue belongs, to keep the queue
1003 * from being deallocated.
1005 * The kmsg is returned with clean header fields
1006 * and with the circular bit turned off through the ith_kmsg
1007 * field of the thread's receive continuation state.
1009 * MACH_MSG_SUCCESS Message returned in ith_kmsg.
1010 * MACH_RCV_TOO_LARGE Message size returned in ith_msize.
1011 * MACH_RCV_TIMED_OUT No message obtained.
1012 * MACH_RCV_INTERRUPTED No message obtained.
1013 * MACH_RCV_PORT_DIED Port/set died; no message.
1014 * MACH_RCV_PORT_CHANGED Port moved into set; no msg.
1020 ipc_mqueue_t mqueue
,
1021 mach_msg_option_t option
,
1022 mach_msg_size_t max_size
,
1023 mach_msg_timeout_t rcv_timeout
,
1026 wait_result_t wresult
;
1027 thread_t self
= current_thread();
1030 wresult
= ipc_mqueue_receive_on_thread(mqueue
, option
, max_size
,
1031 rcv_timeout
, interruptible
,
1033 /* mqueue unlocked */
1034 if (wresult
== THREAD_NOT_WAITING
) {
1038 if (wresult
== THREAD_WAITING
) {
1039 counter((interruptible
== THREAD_ABORTSAFE
) ?
1040 c_ipc_mqueue_receive_block_user
++ :
1041 c_ipc_mqueue_receive_block_kernel
++);
1043 if (self
->ith_continuation
) {
1044 thread_block(ipc_mqueue_receive_continue
);
1048 wresult
= thread_block(THREAD_CONTINUE_NULL
);
1050 ipc_mqueue_receive_results(wresult
);
1054 mqueue_process_prepost_receive(void *ctx
, struct waitq
*waitq
,
1055 struct waitq_set
*wqset
)
1057 ipc_mqueue_t port_mq
, *pmq_ptr
;
1060 port_mq
= (ipc_mqueue_t
)waitq
;
1063 * If there are no messages on this queue, skip it and remove
1064 * it from the prepost list
1066 if (ipc_kmsg_queue_empty(&port_mq
->imq_messages
)) {
1067 return WQ_ITERATE_INVALIDATE_CONTINUE
;
1071 * There are messages waiting on this port.
1072 * Instruct the prepost iteration logic to break, but keep the
1075 pmq_ptr
= (ipc_mqueue_t
*)ctx
;
1079 return WQ_ITERATE_BREAK_KEEP_LOCKED
;
1083 * Routine: ipc_mqueue_receive_on_thread
1085 * Receive a message from a message queue using a specified thread.
1086 * If no message available, assert_wait on the appropriate waitq.
1089 * Assumes thread is self.
1090 * Called with mqueue locked.
1091 * Returns with mqueue unlocked.
1092 * May have assert-waited. Caller must block in those cases.
1095 ipc_mqueue_receive_on_thread(
1096 ipc_mqueue_t mqueue
,
1097 mach_msg_option_t option
,
1098 mach_msg_size_t max_size
,
1099 mach_msg_timeout_t rcv_timeout
,
1103 wait_result_t wresult
;
1105 struct turnstile
*rcv_turnstile
= TURNSTILE_NULL
;
1107 /* called with mqueue locked */
1109 /* no need to reserve anything: we never prepost to anyone */
1111 if (!imq_valid(mqueue
)) {
1112 /* someone raced us to destroy this mqueue/port! */
1115 * ipc_mqueue_receive_results updates the thread's ith_state
1116 * TODO: differentiate between rights being moved and
1117 * rights/ports being destroyed (21885327)
1119 return THREAD_RESTART
;
1122 if (imq_is_set(mqueue
)) {
1123 ipc_mqueue_t port_mq
= IMQ_NULL
;
1125 (void)waitq_set_iterate_preposts(&mqueue
->imq_set_queue
,
1127 mqueue_process_prepost_receive
);
1129 if (port_mq
!= IMQ_NULL
) {
1131 * We get here if there is at least one message
1132 * waiting on port_mq. We have instructed the prepost
1133 * iteration logic to leave both the port_mq and the
1134 * set mqueue locked.
1136 * TODO: previously, we would place this port at the
1137 * back of the prepost list...
1142 * Continue on to handling the message with just
1143 * the port mqueue locked.
1145 if (option
& MACH_PEEK_MSG
) {
1146 ipc_mqueue_peek_on_thread(port_mq
, option
, thread
);
1148 ipc_mqueue_select_on_thread(port_mq
, mqueue
, option
,
1152 imq_unlock(port_mq
);
1153 return THREAD_NOT_WAITING
;
1155 } else if (imq_is_queue(mqueue
) || imq_is_turnstile_proxy(mqueue
)) {
1156 ipc_kmsg_queue_t kmsgs
;
1159 * Receive on a single port. Just try to get the messages.
1161 kmsgs
= &mqueue
->imq_messages
;
1162 if (ipc_kmsg_queue_first(kmsgs
) != IKM_NULL
) {
1163 if (option
& MACH_PEEK_MSG
) {
1164 ipc_mqueue_peek_on_thread(mqueue
, option
, thread
);
1166 ipc_mqueue_select_on_thread(mqueue
, IMQ_NULL
, option
,
1170 return THREAD_NOT_WAITING
;
1173 panic("Unknown mqueue type 0x%x: likely memory corruption!\n",
1174 mqueue
->imq_wait_queue
.waitq_type
);
1178 * Looks like we'll have to block. The mqueue we will
1179 * block on (whether the set's or the local port's) is
1182 if (option
& MACH_RCV_TIMEOUT
) {
1183 if (rcv_timeout
== 0) {
1185 thread
->ith_state
= MACH_RCV_TIMED_OUT
;
1186 return THREAD_NOT_WAITING
;
1190 thread
->ith_option
= option
;
1191 thread
->ith_rsize
= max_size
;
1192 thread
->ith_msize
= 0;
1194 if (option
& MACH_PEEK_MSG
) {
1195 thread
->ith_state
= MACH_PEEK_IN_PROGRESS
;
1197 thread
->ith_state
= MACH_RCV_IN_PROGRESS
;
1200 if (option
& MACH_RCV_TIMEOUT
) {
1201 clock_interval_to_deadline(rcv_timeout
, 1000 * NSEC_PER_USEC
, &deadline
);
1207 * Threads waiting on a reply port (not portset)
1208 * will wait on its receive turnstile.
1210 * Donate waiting thread's turnstile and
1211 * setup inheritor for special reply port.
1212 * Based on the state of the special reply
1213 * port, the inheritor would be the send
1214 * turnstile of the connection port on which
1215 * the send of sync ipc would happen or
1216 * workloop's turnstile who would reply to
1217 * the sync ipc message.
1219 * Pass in mqueue wait in waitq_assert_wait to
1220 * support port set wakeup. The mqueue waitq of port
1221 * will be converted to to turnstile waitq
1222 * in waitq_assert_wait instead of global waitqs.
1224 if (imq_is_turnstile_proxy(mqueue
)) {
1225 ipc_port_t port
= ip_from_mq(mqueue
);
1226 rcv_turnstile
= turnstile_prepare((uintptr_t)port
,
1227 port_rcv_turnstile_address(port
),
1228 TURNSTILE_NULL
, TURNSTILE_SYNC_IPC
);
1230 ipc_port_recv_update_inheritor(port
, rcv_turnstile
,
1231 TURNSTILE_DELAYED_UPDATE
);
1234 thread_set_pending_block_hint(thread
, kThreadWaitPortReceive
);
1235 wresult
= waitq_assert_wait64_locked(&mqueue
->imq_wait_queue
,
1238 TIMEOUT_URGENCY_USER_NORMAL
,
1242 /* preposts should be detected above, not here */
1243 if (wresult
== THREAD_AWAKENED
) {
1244 panic("ipc_mqueue_receive_on_thread: sleep walking");
1249 /* Check if its a port mqueue and if it needs to call turnstile_update_inheritor_complete */
1250 if (rcv_turnstile
!= TURNSTILE_NULL
) {
1251 turnstile_update_inheritor_complete(rcv_turnstile
, TURNSTILE_INTERLOCK_NOT_HELD
);
1253 /* Its callers responsibility to call turnstile_complete to get the turnstile back */
1260 * Routine: ipc_mqueue_peek_on_thread
1262 * A receiver discovered that there was a message on the queue
1263 * before he had to block. Tell a thread about the message queue,
1264 * but don't pick off any messages.
1267 * at least one message on port_mq's message queue
1269 * Returns: (on thread->ith_state)
1270 * MACH_PEEK_READY ith_peekq contains a message queue
1273 ipc_mqueue_peek_on_thread(
1274 ipc_mqueue_t port_mq
,
1275 mach_msg_option_t option
,
1279 assert(option
& MACH_PEEK_MSG
);
1280 assert(ipc_kmsg_queue_first(&port_mq
->imq_messages
) != IKM_NULL
);
1283 * Take a reference on the mqueue's associated port:
1284 * the peeking thread will be responsible to release this reference
1285 * using ip_release_mq()
1287 ip_reference_mq(port_mq
);
1288 thread
->ith_peekq
= port_mq
;
1289 thread
->ith_state
= MACH_PEEK_READY
;
1293 * Routine: ipc_mqueue_select_on_thread
1295 * A receiver discovered that there was a message on the queue
1296 * before he had to block. Pick the message off the queue and
1297 * "post" it to thread.
1300 * thread not locked.
1301 * There is a message.
1302 * No need to reserve prepost objects - it will never prepost
1305 * MACH_MSG_SUCCESS Actually selected a message for ourselves.
1306 * MACH_RCV_TOO_LARGE May or may not have pull it, but it is large
1309 ipc_mqueue_select_on_thread(
1310 ipc_mqueue_t port_mq
,
1311 ipc_mqueue_t set_mq
,
1312 mach_msg_option_t option
,
1313 mach_msg_size_t max_size
,
1317 mach_msg_return_t mr
= MACH_MSG_SUCCESS
;
1318 mach_msg_size_t msize
;
1321 * Do some sanity checking of our ability to receive
1322 * before pulling the message off the queue.
1324 kmsg
= ipc_kmsg_queue_first(&port_mq
->imq_messages
);
1325 assert(kmsg
!= IKM_NULL
);
1328 * If we really can't receive it, but we had the
1329 * MACH_RCV_LARGE option set, then don't take it off
1330 * the queue, instead return the appropriate error
1331 * (and size needed).
1333 msize
= ipc_kmsg_copyout_size(kmsg
, thread
->map
);
1334 if (msize
+ REQUESTED_TRAILER_SIZE(thread_is_64bit_addr(thread
), option
) > max_size
) {
1335 mr
= MACH_RCV_TOO_LARGE
;
1336 if (option
& MACH_RCV_LARGE
) {
1337 thread
->ith_receiver_name
= port_mq
->imq_receiver_name
;
1338 thread
->ith_kmsg
= IKM_NULL
;
1339 thread
->ith_msize
= msize
;
1340 thread
->ith_seqno
= 0;
1341 thread
->ith_state
= mr
;
1346 ipc_kmsg_rmqueue(&port_mq
->imq_messages
, kmsg
);
1348 if (MACH_NODE_VALID(kmsg
->ikm_node
) && FPORT_VALID(port_mq
->imq_fport
)) {
1349 flipc_msg_ack(kmsg
->ikm_node
, port_mq
, TRUE
);
1352 ipc_mqueue_release_msgcount(port_mq
, set_mq
);
1353 thread
->ith_seqno
= port_mq
->imq_seqno
++;
1354 thread
->ith_kmsg
= kmsg
;
1355 thread
->ith_state
= mr
;
1357 current_task()->messages_received
++;
1362 * Routine: ipc_mqueue_peek_locked
1364 * Peek at a (non-set) message queue to see if it has a message
1365 * matching the sequence number provided (if zero, then the
1366 * first message in the queue) and return vital info about the
1370 * The ipc_mqueue_t is locked by callers.
1371 * Other locks may be held by callers, so this routine cannot block.
1372 * Caller holds reference on the message queue.
1375 ipc_mqueue_peek_locked(ipc_mqueue_t mq
,
1376 mach_port_seqno_t
* seqnop
,
1377 mach_msg_size_t
* msg_sizep
,
1378 mach_msg_id_t
* msg_idp
,
1379 mach_msg_max_trailer_t
* msg_trailerp
,
1382 ipc_kmsg_queue_t kmsgq
;
1384 mach_port_seqno_t seqno
, msgoff
;
1387 assert(!imq_is_set(mq
));
1390 if (seqnop
!= NULL
) {
1395 seqno
= mq
->imq_seqno
;
1397 } else if (seqno
>= mq
->imq_seqno
&&
1398 seqno
< mq
->imq_seqno
+ mq
->imq_msgcount
) {
1399 msgoff
= seqno
- mq
->imq_seqno
;
1404 /* look for the message that would match that seqno */
1405 kmsgq
= &mq
->imq_messages
;
1406 kmsg
= ipc_kmsg_queue_first(kmsgq
);
1407 while (msgoff
-- && kmsg
!= IKM_NULL
) {
1408 kmsg
= ipc_kmsg_queue_next(kmsgq
, kmsg
);
1410 if (kmsg
== IKM_NULL
) {
1414 /* found one - return the requested info */
1415 if (seqnop
!= NULL
) {
1418 if (msg_sizep
!= NULL
) {
1419 *msg_sizep
= kmsg
->ikm_header
->msgh_size
;
1421 if (msg_idp
!= NULL
) {
1422 *msg_idp
= kmsg
->ikm_header
->msgh_id
;
1424 if (msg_trailerp
!= NULL
) {
1425 memcpy(msg_trailerp
,
1426 (mach_msg_max_trailer_t
*)((vm_offset_t
)kmsg
->ikm_header
+
1427 round_msg(kmsg
->ikm_header
->msgh_size
)),
1428 sizeof(mach_msg_max_trailer_t
));
1430 if (kmsgp
!= NULL
) {
1442 * Routine: ipc_mqueue_peek
1444 * Peek at a (non-set) message queue to see if it has a message
1445 * matching the sequence number provided (if zero, then the
1446 * first message in the queue) and return vital info about the
1450 * The ipc_mqueue_t is unlocked.
1451 * Locks may be held by callers, so this routine cannot block.
1452 * Caller holds reference on the message queue.
1455 ipc_mqueue_peek(ipc_mqueue_t mq
,
1456 mach_port_seqno_t
* seqnop
,
1457 mach_msg_size_t
* msg_sizep
,
1458 mach_msg_id_t
* msg_idp
,
1459 mach_msg_max_trailer_t
* msg_trailerp
,
1466 res
= ipc_mqueue_peek_locked(mq
, seqnop
, msg_sizep
, msg_idp
,
1467 msg_trailerp
, kmsgp
);
1474 * Routine: ipc_mqueue_release_peek_ref
1476 * Release the reference on an mqueue's associated port which was
1477 * granted to a thread in ipc_mqueue_peek_on_thread (on the
1478 * MACH_PEEK_MSG thread wakeup path).
1481 * The ipc_mqueue_t should be locked on entry.
1482 * The ipc_mqueue_t will be _unlocked_ on return
1483 * (and potentially invalid!)
1487 ipc_mqueue_release_peek_ref(ipc_mqueue_t mq
)
1489 assert(!imq_is_set(mq
));
1490 assert(imq_held(mq
));
1493 * clear any preposts this mq may have generated
1494 * (which would cause subsequent immediate wakeups)
1496 waitq_clear_prepost_locked(&mq
->imq_wait_queue
);
1501 * release the port reference: we need to do this outside the lock
1502 * because we might be holding the last port reference!
1508 * peek at the contained port message queues, break prepost iteration as soon
1509 * as we spot a message on one of the message queues referenced by the set's
1510 * prepost list. No need to lock each message queue, as only the head of each
1511 * queue is checked. If a message wasn't there before we entered here, no need
1512 * to find it (if we do, great).
1515 mqueue_peek_iterator(void *ctx
, struct waitq
*waitq
,
1516 struct waitq_set
*wqset
)
1518 ipc_mqueue_t port_mq
= (ipc_mqueue_t
)waitq
;
1519 ipc_kmsg_queue_t kmsgs
= &port_mq
->imq_messages
;
1524 if (ipc_kmsg_queue_first(kmsgs
) != IKM_NULL
) {
1525 return WQ_ITERATE_BREAK
; /* break out of the prepost iteration */
1527 return WQ_ITERATE_CONTINUE
;
1531 * Routine: ipc_mqueue_set_peek
1533 * Peek at a message queue set to see if it has any ports
1537 * Locks may be held by callers, so this routine cannot block.
1538 * Caller holds reference on the message queue.
1541 ipc_mqueue_set_peek(ipc_mqueue_t mq
)
1548 * We may have raced with port destruction where the mqueue is marked
1549 * as invalid. In that case, even though we don't have messages, we
1550 * have an end-of-life event to deliver.
1552 if (!imq_is_valid(mq
)) {
1556 ret
= waitq_set_iterate_preposts(&mq
->imq_set_queue
, NULL
,
1557 mqueue_peek_iterator
);
1561 return ret
== WQ_ITERATE_BREAK
;
1565 * Routine: ipc_mqueue_set_gather_member_names
1567 * Discover all ports which are members of a given port set.
1568 * Because the waitq linkage mechanism was redesigned to save
1569 * significan amounts of memory, it no longer keeps back-pointers
1570 * from a port set to a port. Therefore, we must iterate over all
1571 * ports within a given IPC space and individually query them to
1572 * see if they are members of the given set. Port names of ports
1573 * found to be members of the given set will be gathered into the
1574 * provided 'names' array. Actual returned names are limited to
1575 * maxnames entries, but we keep counting the actual number of
1576 * members to let the caller decide to retry if necessary.
1579 * Locks may be held by callers, so this routine cannot block.
1580 * Caller holds reference on the message queue (via port set).
1583 ipc_mqueue_set_gather_member_names(
1585 ipc_mqueue_t set_mq
,
1586 ipc_entry_num_t maxnames
,
1587 mach_port_name_t
*names
,
1588 ipc_entry_num_t
*actualp
)
1591 ipc_entry_num_t tsize
;
1592 struct waitq_set
*wqset
;
1593 ipc_entry_num_t actual
= 0;
1595 assert(set_mq
!= IMQ_NULL
);
1596 wqset
= &set_mq
->imq_set_queue
;
1598 assert(space
!= IS_NULL
);
1599 is_read_lock(space
);
1600 if (!is_active(space
)) {
1601 is_read_unlock(space
);
1605 if (!waitq_set_is_valid(wqset
)) {
1606 is_read_unlock(space
);
1610 table
= space
->is_table
;
1611 tsize
= space
->is_table_size
;
1612 for (ipc_entry_num_t idx
= 0; idx
< tsize
; idx
++) {
1613 ipc_entry_t entry
= &table
[idx
];
1615 /* only receive rights can be members of port sets */
1616 if ((entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
) != MACH_PORT_TYPE_NONE
) {
1617 ipc_port_t port
= ip_object_to_port(entry
->ie_object
);
1618 ipc_mqueue_t mq
= &port
->ip_messages
;
1620 assert(IP_VALID(port
));
1621 if (ip_active(port
) &&
1622 waitq_member(&mq
->imq_wait_queue
, wqset
)) {
1623 if (actual
< maxnames
) {
1624 names
[actual
] = mq
->imq_receiver_name
;
1631 is_read_unlock(space
);
1639 * Routine: ipc_mqueue_destroy_locked
1641 * Destroy a (non-set) message queue.
1642 * Set any blocked senders running.
1643 * Destroy the kmsgs in the queue.
1646 * Receivers were removed when the receive right was "changed"
1649 ipc_mqueue_destroy_locked(ipc_mqueue_t mqueue
)
1651 ipc_kmsg_queue_t kmqueue
;
1653 boolean_t reap
= FALSE
;
1654 struct turnstile
*send_turnstile
= port_send_turnstile(ip_from_mq(mqueue
));
1656 assert(!imq_is_set(mqueue
));
1659 * rouse all blocked senders
1660 * (don't boost anyone - we're tearing this queue down)
1663 mqueue
->imq_fullwaiters
= FALSE
;
1665 if (send_turnstile
!= TURNSTILE_NULL
) {
1666 waitq_wakeup64_all(&send_turnstile
->ts_waitq
,
1669 WAITQ_ALL_PRIORITIES
);
1673 * Move messages from the specified queue to the per-thread
1674 * clean/drain queue while we have the mqueue lock.
1676 kmqueue
= &mqueue
->imq_messages
;
1677 while ((kmsg
= ipc_kmsg_dequeue(kmqueue
)) != IKM_NULL
) {
1679 if (MACH_NODE_VALID(kmsg
->ikm_node
) && FPORT_VALID(mqueue
->imq_fport
)) {
1680 flipc_msg_ack(kmsg
->ikm_node
, mqueue
, TRUE
);
1684 first
= ipc_kmsg_delayed_destroy(kmsg
);
1691 * Wipe out message count, both for messages about to be
1692 * reaped and for reserved space for (previously) woken senders.
1693 * This is the indication to them that their reserved space is gone
1694 * (the mqueue was destroyed).
1696 mqueue
->imq_msgcount
= 0;
1698 /* invalidate the waitq for subsequent mqueue operations */
1699 waitq_invalidate_locked(&mqueue
->imq_wait_queue
);
1701 /* clear out any preposting we may have done */
1702 waitq_clear_prepost_locked(&mqueue
->imq_wait_queue
);
1705 * assert that we are destroying / invalidating a queue that's
1706 * not a member of any other queue.
1708 assert(mqueue
->imq_preposts
== 0);
1709 assert(mqueue
->imq_in_pset
== 0);
1715 * Routine: ipc_mqueue_set_qlimit
1717 * Changes a message queue limit; the maximum number
1718 * of messages which may be queued.
1724 ipc_mqueue_set_qlimit(
1725 ipc_mqueue_t mqueue
,
1726 mach_port_msgcount_t qlimit
)
1728 assert(qlimit
<= MACH_PORT_QLIMIT_MAX
);
1730 /* wake up senders allowed by the new qlimit */
1732 if (qlimit
> mqueue
->imq_qlimit
) {
1733 mach_port_msgcount_t i
, wakeup
;
1734 struct turnstile
*send_turnstile
= port_send_turnstile(ip_from_mq(mqueue
));
1736 /* caution: wakeup, qlimit are unsigned */
1737 wakeup
= qlimit
- mqueue
->imq_qlimit
;
1739 for (i
= 0; i
< wakeup
; i
++) {
1741 * boost the priority of the awoken thread
1742 * (WAITQ_PROMOTE_PRIORITY) to ensure it uses
1743 * the message queue slot we've just reserved.
1745 * NOTE: this will never prepost
1747 if (send_turnstile
== TURNSTILE_NULL
||
1748 waitq_wakeup64_one(&send_turnstile
->ts_waitq
,
1751 WAITQ_PROMOTE_PRIORITY
) == KERN_NOT_WAITING
) {
1752 mqueue
->imq_fullwaiters
= FALSE
;
1755 mqueue
->imq_msgcount
++; /* give it to the awakened thread */
1758 mqueue
->imq_qlimit
= qlimit
;
1763 * Routine: ipc_mqueue_set_seqno
1765 * Changes an mqueue's sequence number.
1767 * Caller holds a reference to the queue's containing object.
1770 ipc_mqueue_set_seqno(
1771 ipc_mqueue_t mqueue
,
1772 mach_port_seqno_t seqno
)
1775 mqueue
->imq_seqno
= seqno
;
1781 * Routine: ipc_mqueue_copyin
1783 * Convert a name in a space to a message queue.
1785 * Nothing locked. If successful, the caller gets a ref for
1786 * for the object. This ref ensures the continued existence of
1789 * MACH_MSG_SUCCESS Found a message queue.
1790 * MACH_RCV_INVALID_NAME The space is dead.
1791 * MACH_RCV_INVALID_NAME The name doesn't denote a right.
1792 * MACH_RCV_INVALID_NAME
1793 * The denoted right is not receive or port set.
1794 * MACH_RCV_IN_SET Receive right is a member of a set.
1800 mach_port_name_t name
,
1801 ipc_mqueue_t
*mqueuep
,
1802 ipc_object_t
*objectp
)
1805 ipc_entry_bits_t bits
;
1806 ipc_object_t object
;
1807 ipc_mqueue_t mqueue
;
1809 is_read_lock(space
);
1810 if (!is_active(space
)) {
1811 is_read_unlock(space
);
1812 return MACH_RCV_INVALID_NAME
;
1815 entry
= ipc_entry_lookup(space
, name
);
1816 if (entry
== IE_NULL
) {
1817 is_read_unlock(space
);
1818 return MACH_RCV_INVALID_NAME
;
1821 bits
= entry
->ie_bits
;
1822 object
= entry
->ie_object
;
1824 if (bits
& MACH_PORT_TYPE_RECEIVE
) {
1825 ipc_port_t port
= ip_object_to_port(object
);
1827 assert(port
!= IP_NULL
);
1830 require_ip_active(port
);
1831 assert(port
->ip_receiver_name
== name
);
1832 assert(port
->ip_receiver
== space
);
1833 is_read_unlock(space
);
1834 mqueue
= &port
->ip_messages
;
1835 } else if (bits
& MACH_PORT_TYPE_PORT_SET
) {
1836 ipc_pset_t pset
= ips_object_to_pset(object
);
1838 assert(pset
!= IPS_NULL
);
1841 assert(ips_active(pset
));
1842 is_read_unlock(space
);
1844 mqueue
= &pset
->ips_messages
;
1846 is_read_unlock(space
);
1847 /* guard exception if we never held the receive right in this entry */
1848 if ((bits
& MACH_PORT_TYPE_EX_RECEIVE
) == 0) {
1849 mach_port_guard_exception(name
, 0, 0, kGUARD_EXC_RCV_INVALID_NAME
);
1851 return MACH_RCV_INVALID_NAME
;
1855 * At this point, the object is locked and active,
1856 * the space is unlocked, and mqueue is initialized.
1859 io_reference(object
);
1864 return MACH_MSG_SUCCESS
;
1868 imq_lock(ipc_mqueue_t mq
)
1870 ipc_object_t object
= imq_to_object(mq
);
1871 ipc_object_validate(object
);
1872 waitq_lock(&(mq
)->imq_wait_queue
);
1876 imq_lock_try(ipc_mqueue_t mq
)
1878 ipc_object_t object
= imq_to_object(mq
);
1879 ipc_object_validate(object
);
1880 return waitq_lock_try(&(mq
)->imq_wait_queue
);