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@
23 * @OSF_FREE_COPYRIGHT@
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/ipc_mqueue.c
57 * Functions to manipulate IPC message queues.
60 #include <mach/port.h>
61 #include <mach/message.h>
62 #include <mach/sync_policy.h>
64 #include <kern/assert.h>
65 #include <kern/counters.h>
66 #include <kern/sched_prim.h>
67 #include <kern/ipc_kobject.h>
68 #include <kern/misc_protos.h>
69 #include <kern/task.h>
70 #include <kern/thread.h>
71 #include <kern/wait_queue.h>
73 #include <ipc/ipc_mqueue.h>
74 #include <ipc/ipc_kmsg.h>
75 #include <ipc/ipc_port.h>
76 #include <ipc/ipc_pset.h>
77 #include <ipc/ipc_space.h>
81 int ipc_mqueue_full
; /* address is event for queue space */
82 int ipc_mqueue_rcv
; /* address is event for message arrival */
87 * Routine: ipc_mqueue_init
89 * Initialize a newly-allocated message queue.
97 wait_queue_sub_init(&mqueue
->imq_set_queue
, SYNC_POLICY_FIFO
);
99 wait_queue_init(&mqueue
->imq_wait_queue
, SYNC_POLICY_FIFO
);
100 ipc_kmsg_queue_init(&mqueue
->imq_messages
);
101 mqueue
->imq_seqno
= 0;
102 mqueue
->imq_msgcount
= 0;
103 mqueue
->imq_qlimit
= MACH_PORT_QLIMIT_DEFAULT
;
104 mqueue
->imq_fullwaiters
= FALSE
;
109 * Routine: ipc_mqueue_member
111 * Indicate whether the (port) mqueue is a member of
112 * this portset's mqueue. We do this by checking
113 * whether the portset mqueue's waitq is an member of
114 * the port's mqueue waitq.
116 * the portset's mqueue is not already a member
117 * this may block while allocating linkage structures.
122 ipc_mqueue_t port_mqueue
,
123 ipc_mqueue_t set_mqueue
)
125 wait_queue_t port_waitq
= &port_mqueue
->imq_wait_queue
;
126 wait_queue_t set_waitq
= &set_mqueue
->imq_wait_queue
;
128 return (wait_queue_member(port_waitq
, set_waitq
));
133 * Routine: ipc_mqueue_remove
135 * Remove the association between the queue and the specified
136 * subordinate message queue.
142 ipc_mqueue_t sub_mqueue
)
144 wait_queue_t mq_waitq
= &mqueue
->imq_wait_queue
;
145 wait_queue_sub_t sub_waitq
= &sub_mqueue
->imq_set_queue
;
147 if (wait_queue_member(mq_waitq
, sub_waitq
)) {
148 wait_queue_unlink(mq_waitq
, sub_waitq
);
151 return KERN_NOT_IN_SET
;
155 * Routine: ipc_mqueue_remove_one
157 * Find and remove one subqueue from the queue.
159 * Will return the set mqueue that was removed
162 ipc_mqueue_remove_one(
164 ipc_mqueue_t
*sub_queuep
)
166 wait_queue_t mq_waitq
= &mqueue
->imq_wait_queue
;
168 wait_queue_unlink_one(mq_waitq
, (wait_queue_sub_t
*)sub_queuep
);
174 * Routine: ipc_mqueue_add
176 * Associate the portset's mqueue with the port's mqueue.
177 * This has to be done so that posting the port will wakeup
178 * a portset waiter. If there are waiters on the portset
179 * mqueue and messages on the port mqueue, try to match them
186 ipc_mqueue_t port_mqueue
,
187 ipc_mqueue_t set_mqueue
)
189 wait_queue_t port_waitq
= &port_mqueue
->imq_wait_queue
;
190 wait_queue_sub_t set_waitq
= &set_mqueue
->imq_set_queue
;
191 ipc_kmsg_queue_t kmsgq
;
192 ipc_kmsg_t kmsg
, next
;
196 kr
= wait_queue_link(port_waitq
, set_waitq
);
197 if (kr
!= KERN_SUCCESS
)
201 * Now that the set has been added to the port, there may be
202 * messages queued on the port and threads waiting on the set
203 * waitq. Lets get them together.
206 imq_lock(port_mqueue
);
207 kmsgq
= &port_mqueue
->imq_messages
;
208 for (kmsg
= ipc_kmsg_queue_first(kmsgq
);
211 next
= ipc_kmsg_queue_next(kmsgq
, kmsg
);
216 th
= wait_queue_wakeup_identity_locked(port_waitq
,
220 /* waitq/mqueue still locked, thread locked */
222 if (th
== THREAD_NULL
)
226 * Found a receiver. see if they can handle the message
227 * correctly (the message is not too large for them, or
228 * they didn't care to be informed that the message was
229 * too large). If they can't handle it, take them off
230 * the list and let them go back and figure it out and
231 * just move onto the next.
234 kmsg
->ikm_header
.msgh_size
+
235 REQUESTED_TRAILER_SIZE(th
->ith_option
)) {
236 th
->ith_state
= MACH_RCV_TOO_LARGE
;
237 th
->ith_msize
= kmsg
->ikm_header
.msgh_size
;
238 if (th
->ith_option
& MACH_RCV_LARGE
) {
240 * let him go without message
242 th
->ith_kmsg
= IKM_NULL
;
245 continue; /* find another thread */
248 th
->ith_state
= MACH_MSG_SUCCESS
;
252 * This thread is going to take this message,
255 ipc_mqueue_release_msgcount(port_mqueue
);
256 ipc_kmsg_rmqueue(kmsgq
, kmsg
);
258 th
->ith_seqno
= port_mqueue
->imq_seqno
++;
260 break; /* go to next message */
265 imq_unlock(port_mqueue
);
271 * Routine: ipc_mqueue_changed
273 * Wake up receivers waiting in a message queue.
275 * The message queue is locked.
282 wait_queue_wakeup_all_locked(&mqueue
->imq_wait_queue
,
285 FALSE
); /* unlock waitq? */
292 * Routine: ipc_mqueue_send
294 * Send a message to a message queue. The message holds a reference
295 * for the destination port for this message queue in the
296 * msgh_remote_port field.
298 * If unsuccessful, the caller still has possession of
299 * the message and must do something with it. If successful,
300 * the message is queued, given to a receiver, or destroyed.
304 * MACH_MSG_SUCCESS The message was accepted.
305 * MACH_SEND_TIMED_OUT Caller still has message.
306 * MACH_SEND_INTERRUPTED Caller still has message.
312 mach_msg_option_t option
,
313 mach_msg_timeout_t timeout
)
315 int save_wait_result
;
320 * 1) We're under the queue limit.
321 * 2) Caller used the MACH_SEND_ALWAYS internal option.
322 * 3) Message is sent to a send-once right.
327 if (!imq_full(mqueue
) ||
328 (option
& MACH_SEND_ALWAYS
) ||
329 (MACH_MSGH_BITS_REMOTE(kmsg
->ikm_header
.msgh_bits
) ==
330 MACH_MSG_TYPE_PORT_SEND_ONCE
)) {
331 mqueue
->imq_msgcount
++;
337 * We have to wait for space to be granted to us.
339 if ((option
& MACH_SEND_TIMEOUT
) && (timeout
== 0)) {
342 return MACH_SEND_TIMED_OUT
;
344 mqueue
->imq_fullwaiters
= TRUE
;
345 (void)wait_queue_assert_wait_locked(&mqueue
->imq_wait_queue
,
349 /* wait/mqueue is unlocked */
352 if (option
& MACH_SEND_TIMEOUT
)
353 thread_set_timer(timeout
, 1000*NSEC_PER_USEC
);
355 counter(c_ipc_mqueue_send_block
++);
356 save_wait_result
= thread_block((void (*)(void)) 0);
358 switch (save_wait_result
) {
359 case THREAD_TIMED_OUT
:
360 assert(option
& MACH_SEND_TIMEOUT
);
361 return MACH_SEND_TIMED_OUT
;
363 case THREAD_AWAKENED
:
364 /* we can proceed - inherited msgcount from waker */
365 if (option
& MACH_SEND_TIMEOUT
)
366 thread_cancel_timer();
369 case THREAD_INTERRUPTED
:
370 if (option
& MACH_SEND_TIMEOUT
)
371 thread_cancel_timer();
372 return MACH_SEND_INTERRUPTED
;
376 panic("ipc_mqueue_send");
380 ipc_mqueue_post(mqueue
, kmsg
);
381 return MACH_MSG_SUCCESS
;
385 * Routine: ipc_mqueue_release_msgcount
387 * Release a message queue reference in the case where we
391 * The message queue is locked
394 ipc_mqueue_release_msgcount(
397 assert(imq_held(mqueue
));
398 assert(mqueue
->imq_msgcount
> 0);
400 mqueue
->imq_msgcount
--;
401 if (!imq_full(mqueue
) && mqueue
->imq_fullwaiters
) {
402 if (wait_queue_wakeup_one_locked(&mqueue
->imq_wait_queue
,
405 FALSE
) != KERN_SUCCESS
) {
406 mqueue
->imq_fullwaiters
= FALSE
;
408 mqueue
->imq_msgcount
++; /* gave it away */
414 * Routine: ipc_mqueue_post
416 * Post a message to a waiting receiver or enqueue it. If a
417 * receiver is waiting, we can release our reserved space in
421 * If we need to queue, our space in the message queue is reserved.
425 register ipc_mqueue_t mqueue
,
426 register ipc_kmsg_t kmsg
)
432 * While the msg queue is locked, we have control of the
433 * kmsg, so the ref in it for the port is still good.
435 * Check for a receiver for the message.
440 wait_queue_t waitq
= &mqueue
->imq_wait_queue
;
443 receiver
= wait_queue_wakeup_identity_locked(waitq
,
447 /* waitq still locked, thread locked */
449 if (receiver
== THREAD_NULL
) {
451 * no receivers; queue kmsg
453 assert(mqueue
->imq_msgcount
> 0);
454 ipc_kmsg_enqueue_macro(&mqueue
->imq_messages
, kmsg
);
459 * We found a waiting thread.
460 * If the message is too large or the scatter list is too small
461 * the thread we wake up will get that as its status.
463 if (receiver
->ith_msize
<
464 (kmsg
->ikm_header
.msgh_size
) +
465 REQUESTED_TRAILER_SIZE(receiver
->ith_option
)) {
466 receiver
->ith_msize
= kmsg
->ikm_header
.msgh_size
;
467 receiver
->ith_state
= MACH_RCV_TOO_LARGE
;
469 receiver
->ith_state
= MACH_MSG_SUCCESS
;
473 * If there is no problem with the upcoming receive, or the
474 * receiver thread didn't specifically ask for special too
475 * large error condition, go ahead and select it anyway.
477 if ((receiver
->ith_state
== MACH_MSG_SUCCESS
) ||
478 !(receiver
->ith_option
& MACH_RCV_LARGE
)) {
480 receiver
->ith_kmsg
= kmsg
;
481 receiver
->ith_seqno
= mqueue
->imq_seqno
++;
482 thread_unlock(receiver
);
484 /* we didn't need our reserved spot in the queue */
485 ipc_mqueue_release_msgcount(mqueue
);
490 * Otherwise, this thread needs to be released to run
491 * and handle its error without getting the message. We
492 * need to go back and pick another one.
494 receiver
->ith_kmsg
= IKM_NULL
;
495 receiver
->ith_seqno
= 0;
496 thread_unlock(receiver
);
502 current_task()->messages_sent
++;
508 ipc_mqueue_receive_results(void)
510 thread_t self
= current_thread();
511 mach_msg_option_t option
= self
->ith_option
;
512 kern_return_t saved_wait_result
= self
->wait_result
;
516 * why did we wake up?
518 switch (saved_wait_result
) {
519 case THREAD_TIMED_OUT
:
520 self
->ith_state
= MACH_RCV_TIMED_OUT
;
523 case THREAD_INTERRUPTED
:
524 if (option
& MACH_RCV_TIMEOUT
)
525 thread_cancel_timer();
526 self
->ith_state
= MACH_RCV_INTERRUPTED
;
530 /* something bad happened to the port/set */
531 if (option
& MACH_RCV_TIMEOUT
)
532 thread_cancel_timer();
533 self
->ith_state
= MACH_RCV_PORT_CHANGED
;
536 case THREAD_AWAKENED
:
538 * We do not need to go select a message, somebody
539 * handed us one (or a too-large indication).
541 if (option
& MACH_RCV_TIMEOUT
)
542 thread_cancel_timer();
544 mr
= MACH_MSG_SUCCESS
;
546 switch (self
->ith_state
) {
547 case MACH_RCV_SCATTER_SMALL
:
548 case MACH_RCV_TOO_LARGE
:
550 * Somebody tried to give us a too large
551 * message. If we indicated that we cared,
552 * then they only gave us the indication,
553 * otherwise they gave us the indication
554 * AND the message anyway.
556 if (option
& MACH_RCV_LARGE
) {
560 case MACH_MSG_SUCCESS
:
564 panic("ipc_mqueue_receive_results: strange ith_state");
568 panic("ipc_mqueue_receive_results: strange wait_result");
573 ipc_mqueue_receive_continue(void)
575 ipc_mqueue_receive_results();
576 mach_msg_receive_continue(); /* hard-coded for now */
580 * Routine: ipc_mqueue_receive
582 * Receive a message from a message queue.
584 * If continuation is non-zero, then we might discard
585 * our kernel stack when we block. We will continue
586 * after unblocking by executing continuation.
588 * If resume is true, then we are resuming a receive
589 * operation after a blocked receive discarded our stack.
591 * Our caller must hold a reference for the port or port set
592 * to which this queue belongs, to keep the queue
593 * from being deallocated.
595 * The kmsg is returned with clean header fields
596 * and with the circular bit turned off.
598 * MACH_MSG_SUCCESS Message returned in kmsgp.
599 * MACH_RCV_TOO_LARGE Message size returned in kmsgp.
600 * MACH_RCV_TIMED_OUT No message obtained.
601 * MACH_RCV_INTERRUPTED No message obtained.
602 * MACH_RCV_PORT_DIED Port/set died; no message.
603 * MACH_RCV_PORT_CHANGED Port moved into set; no msg.
610 mach_msg_option_t option
,
611 mach_msg_size_t max_size
,
612 mach_msg_timeout_t timeout
,
616 mach_msg_return_t mr
, mr2
;
617 ipc_kmsg_queue_t kmsgs
;
618 kern_return_t save_wait_result
;
621 mach_port_seqno_t
*seqnop
;
627 if (imq_is_set(mqueue
)) {
628 wait_queue_link_t wql
;
629 ipc_mqueue_t port_mq
;
632 q
= &mqueue
->imq_setlinks
;
635 * If we are waiting on a portset mqueue, we need to see if
636 * any of the member ports have work for us. If so, try to
637 * deliver one of those messages. By holding the portset's
638 * mqueue lock during the search, we tie up any attempts by
639 * mqueue_deliver or portset membership changes that may
640 * cross our path. But this is a lock order violation, so we
641 * have to do it "softly." If we don't find a message waiting
642 * for us, we will assert our intention to wait while still
643 * holding that lock. When we release the lock, the deliver/
644 * change will succeed and find us.
647 queue_iterate(q
, wql
, wait_queue_link_t
, wql_sublinks
) {
648 port_mq
= (ipc_mqueue_t
)wql
->wql_queue
;
649 kmsgs
= &port_mq
->imq_messages
;
651 if (!imq_lock_try(port_mq
)) {
657 goto search_set
; /* start again at beginning - SMP */
661 * If there is still a message to be had, we will
662 * try to select it (may not succeed because of size
663 * and options). In any case, we deliver those
664 * results back to the user.
666 * We also move the port's linkage to the tail of the
667 * list for this set (fairness). Future versions will
668 * sort by timestamp or priority.
670 if (ipc_kmsg_queue_first(kmsgs
) == IKM_NULL
) {
674 queue_remove(q
, wql
, wait_queue_link_t
, wql_sublinks
);
675 queue_enter(q
, wql
, wait_queue_link_t
, wql_sublinks
);
678 ipc_mqueue_select(port_mq
, option
, max_size
);
688 * Receive on a single port. Just try to get the messages.
690 kmsgs
= &mqueue
->imq_messages
;
691 if (ipc_kmsg_queue_first(kmsgs
) != IKM_NULL
) {
692 ipc_mqueue_select(mqueue
, option
, max_size
);
700 * Looks like we'll have to block. The mqueue we will
701 * block on (whether the set's or the local port's) is
704 self
= current_thread();
705 if (option
& MACH_RCV_TIMEOUT
) {
709 self
->ith_state
= MACH_RCV_TIMED_OUT
;
714 self
->ith_state
= MACH_RCV_IN_PROGRESS
;
715 self
->ith_option
= option
;
716 self
->ith_msize
= max_size
;
718 (void)wait_queue_assert_wait_locked(&mqueue
->imq_wait_queue
,
722 /* mqueue/waitq is unlocked */
725 if (option
& MACH_RCV_TIMEOUT
) {
726 thread_set_timer(timeout
, 1000*NSEC_PER_USEC
);
729 if (interruptible
== THREAD_ABORTSAFE
) {
730 counter(c_ipc_mqueue_receive_block_user
++);
732 counter(c_ipc_mqueue_receive_block_kernel
++);
735 #if defined (__i386__)
736 thread_block((void (*)(void))0);
738 if (self
->ith_continuation
) {
739 thread_block(ipc_mqueue_receive_continue
);
741 thread_block((void (*)(void))0);
745 ipc_mqueue_receive_results(); /* if we fell thru */
750 * Routine: ipc_mqueue_select
752 * A receiver discovered that there was a message on the queue
753 * before he had to block. Pick the message off the queue and
754 * "post" it to himself.
757 * There is a message.
759 * MACH_MSG_SUCCESS Actually selected a message for ourselves.
760 * MACH_RCV_TOO_LARGE May or may not have pull it, but it is large
765 mach_msg_option_t option
,
766 mach_msg_size_t max_size
)
768 thread_t self
= current_thread();
770 mach_port_seqno_t seqno
;
771 mach_msg_return_t mr
;
773 mr
= MACH_MSG_SUCCESS
;
777 * Do some sanity checking of our ability to receive
778 * before pulling the message off the queue.
780 kmsg
= ipc_kmsg_queue_first(&mqueue
->imq_messages
);
782 assert(kmsg
!= IKM_NULL
);
784 if (kmsg
->ikm_header
.msgh_size
+
785 REQUESTED_TRAILER_SIZE(option
) > max_size
) {
786 mr
= MACH_RCV_TOO_LARGE
;
790 * If we really can't receive it, but we had the
791 * MACH_RCV_LARGE option set, then don't take it off
792 * the queue, instead return the appropriate error
795 if ((mr
== MACH_RCV_TOO_LARGE
) && (option
& MACH_RCV_LARGE
)) {
796 self
->ith_kmsg
= IKM_NULL
;
797 self
->ith_msize
= kmsg
->ikm_header
.msgh_size
;
799 self
->ith_state
= mr
;
803 ipc_kmsg_rmqueue_first_macro(&mqueue
->imq_messages
, kmsg
);
804 ipc_mqueue_release_msgcount(mqueue
);
805 self
->ith_seqno
= mqueue
->imq_seqno
++;
806 self
->ith_kmsg
= kmsg
;
807 self
->ith_state
= mr
;
809 current_task()->messages_received
++;
814 * Routine: ipc_mqueue_destroy
816 * Destroy a message queue. Set any blocked senders running.
817 * Destroy the kmsgs in the queue.
820 * Receivers were removed when the receive right was "changed"
826 ipc_kmsg_queue_t kmqueue
;
834 * rouse all blocked senders
836 mqueue
->imq_fullwaiters
= FALSE
;
837 wait_queue_wakeup_all_locked(&mqueue
->imq_wait_queue
,
842 kmqueue
= &mqueue
->imq_messages
;
844 while ((kmsg
= ipc_kmsg_dequeue(kmqueue
)) != IKM_NULL
) {
848 ipc_kmsg_destroy_dest(kmsg
);
858 * Routine: ipc_mqueue_set_qlimit
860 * Changes a message queue limit; the maximum number
861 * of messages which may be queued.
867 ipc_mqueue_set_qlimit(
869 mach_port_msgcount_t qlimit
)
873 /* wake up senders allowed by the new qlimit */
876 if (qlimit
> mqueue
->imq_qlimit
) {
877 mach_port_msgcount_t i
, wakeup
;
879 /* caution: wakeup, qlimit are unsigned */
880 wakeup
= qlimit
- mqueue
->imq_qlimit
;
882 for (i
= 0; i
< wakeup
; i
++) {
883 if (wait_queue_wakeup_one_locked(&mqueue
->imq_wait_queue
,
886 FALSE
) == KERN_NOT_WAITING
) {
887 mqueue
->imq_fullwaiters
= FALSE
;
892 mqueue
->imq_qlimit
= qlimit
;
898 * Routine: ipc_mqueue_set_seqno
900 * Changes an mqueue's sequence number.
902 * Caller holds a reference to the queue's containing object.
905 ipc_mqueue_set_seqno(
907 mach_port_seqno_t seqno
)
913 mqueue
->imq_seqno
= seqno
;
920 * Routine: ipc_mqueue_copyin
922 * Convert a name in a space to a message queue.
924 * Nothing locked. If successful, the caller gets a ref for
925 * for the object. This ref ensures the continued existence of
928 * MACH_MSG_SUCCESS Found a message queue.
929 * MACH_RCV_INVALID_NAME The space is dead.
930 * MACH_RCV_INVALID_NAME The name doesn't denote a right.
931 * MACH_RCV_INVALID_NAME
932 * The denoted right is not receive or port set.
933 * MACH_RCV_IN_SET Receive right is a member of a set.
939 mach_port_name_t name
,
940 ipc_mqueue_t
*mqueuep
,
941 ipc_object_t
*objectp
)
948 if (!space
->is_active
) {
949 is_read_unlock(space
);
950 return MACH_RCV_INVALID_NAME
;
953 entry
= ipc_entry_lookup(space
, name
);
954 if (entry
== IE_NULL
) {
955 is_read_unlock(space
);
956 return MACH_RCV_INVALID_NAME
;
959 object
= entry
->ie_object
;
961 if (entry
->ie_bits
& MACH_PORT_TYPE_RECEIVE
) {
965 port
= (ipc_port_t
) object
;
966 assert(port
!= IP_NULL
);
969 assert(ip_active(port
));
970 assert(port
->ip_receiver_name
== name
);
971 assert(port
->ip_receiver
== space
);
972 is_read_unlock(space
);
973 mqueue
= &port
->ip_messages
;
975 } else if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_SET
) {
978 pset
= (ipc_pset_t
) object
;
979 assert(pset
!= IPS_NULL
);
982 assert(ips_active(pset
));
983 assert(pset
->ips_local_name
== name
);
984 is_read_unlock(space
);
986 mqueue
= &pset
->ips_messages
;
988 is_read_unlock(space
);
989 return MACH_RCV_INVALID_NAME
;
993 * At this point, the object is locked and active,
994 * the space is unlocked, and mqueue is initialized.
997 io_reference(object
);
1002 return MACH_MSG_SUCCESS
;