Next: Atomicity, Previous: Message Send, Up: Messaging Interface
The receive operation dequeues a message from a port. The receiving task acquires the port rights and out-of-line memory regions carried in the message.
The rcv_name
argument specifies a port or port set from which to
receive. If a port is specified, the caller must possess the receive
right for the port and the port must not be a member of a port set. If
no message is present, then the call blocks, subject to the
MACH_RCV_TIMEOUT
option.
If a port set is specified, the call will receive a message sent to any
of the member ports. It is permissible for the port set to have no
member ports, and ports may be added and removed while a receive from
the port set is in progress. The received message can come from any of
the member ports which have messages, with the proviso that a member
port with messages will not be indefinitely starved. The
msgh_local_port
field in the received message header specifies
from which port in the port set the message came.
The rcv_size
argument specifies the size of the caller's message
buffer. The mach_msg
call will not receive a message larger than
rcv_size
. Messages that are too large are destroyed, unless the
MACH_RCV_LARGE
option is used.
The destination and reply ports are reversed in a received message
header. The msgh_local_port
field names the destination port,
from which the message was received, and the msgh_remote_port
field names the reply port right. The bits in msgh_bits
are also
reversed. The MACH_MSGH_BITS_LOCAL
bits have the value
MACH_MSG_TYPE_PORT_SEND
if the message was sent to a send right,
and the value MACH_MSG_TYPE_PORT_SEND_ONCE
if was sent to a
send-once right. The MACH_MSGH_BITS_REMOTE
bits describe the
reply port right.
A received message can contain port rights and out-of-line memory. The
msgh_local_port
field does not receive a port right; the act of
receiving the message destroys the send or send-once right for the
destination port. The msgh_remote_port field does name a received port
right, the reply port right, and the message body can carry port rights
and memory if MACH_MSGH_BITS_COMPLEX
is present in msgh_bits.
Received port rights and memory should be consumed or deallocated in
some fashion.
In almost all cases, msgh_local_port
will specify the name of a
receive right, either rcv_name
or if rcv_name
is a port
set, a member of rcv_name
. If other threads are concurrently
manipulating the receive right, the situation is more complicated. If
the receive right is renamed during the call, then
msgh_local_port
specifies the right's new name. If the caller
loses the receive right after the message was dequeued from it, then
mach_msg
will proceed instead of returning
MACH_RCV_PORT_DIED
. If the receive right was destroyed, then
msgh_local_port
specifies MACH_PORT_DEAD
. If the receive
right still exists, but isn't held by the caller, then
msgh_local_port
specifies MACH_PORT_NULL
.
Received messages are stamped with a sequence number, taken from the
port from which the message was received. (Messages received from a
port set are stamped with a sequence number from the appropriate member
port.) Newly created ports start with a zero sequence number, and the
sequence number is reset to zero whenever the port's receive right moves
between tasks. When a message is dequeued from the port, it is stamped
with the port's sequence number and the port's sequence number is then
incremented. The dequeue and increment operations are atomic, so that
multiple threads receiving messages from a port can use the
msgh_seqno
field to reconstruct the original order of the
messages.
These options modify MACH_RCV_MSG
. If MACH_RCV_MSG
is not
also specified, they are ignored.
MACH_RCV_TIMEOUT
MACH_RCV_TIMED_OUT
. A zero timeout is legitimate.
MACH_RCV_NOTIFY
MACH_RCV_INTERRUPT
mach_msg
call will return
MACH_RCV_INTERRUPTED
if a software interrupt aborts the call.
Otherwise, the receive operation will be retried.
MACH_RCV_LARGE
rcv_size
, then the message remains
queued instead of being destroyed. The call returns
MACH_RCV_TOO_LARGE
and the actual size of the message is returned
in the msgh_size
field of the message header.
The receive operation can generate the following return codes. These return codes imply that the call did not dequeue a message:
MACH_RCV_INVALID_NAME
rcv_name
was invalid.
MACH_RCV_IN_SET
MACH_RCV_TIMED_OUT
MACH_RCV_INTERRUPTED
MACH_RCV_PORT_DIED
rcv_name
.
MACH_RCV_PORT_CHANGED
rcv_name
specified a receive right which was moved into a port
set during the call.
MACH_RCV_TOO_LARGE
MACH_RCV_LARGE
, and the message was larger than
rcv_size
. The message is left queued, and its actual size is
returned in the msgh_size
field of the message buffer.
These return codes imply that a message was dequeued and destroyed:
MACH_RCV_HEADER_ERROR
MACH_RCV_INVALID_NOTIFY
MACH_RCV_NOTIFY
, the notify argument did not denote a
valid receive right.
MACH_RCV_TOO_LARGE
MACH_RCV_LARGE
, a message larger than
rcv_size
was dequeued and destroyed.
In these situations, when a message is dequeued and then destroyed, the
reply port and all port rights and memory in the message body are
destroyed. However, the caller receives the message's header, with all
fields correct, including the destination port but excepting the reply
port, which is MACH_PORT_NULL
.
These return codes imply that a message was received:
MACH_RCV_BODY_ERROR
MACH_RCV_INVALID_DATA
MACH_MSG_SUCCESS
Resource shortages can occur after a message is dequeued, while
transferring port rights and out-of-line memory regions to the receiving
task. The mach_msg
call returns MACH_RCV_HEADER_ERROR
or
MACH_RCV_BODY_ERROR
in this situation. These return codes always
carry extra bits (bitwise-ored) that indicate the nature of the resource
shortage:
MACH_MSG_IPC_SPACE
MACH_MSG_VM_SPACE
MACH_MSG_IPC_KERNEL
MACH_MSG_VM_KERNEL
If a resource shortage prevents the reception of a port right, the port
right is destroyed and the caller sees the name MACH_PORT_NULL
.
If a resource shortage prevents the reception of an out-of-line memory
region, the region is destroyed and the caller receives a zero address.
In addition, the msgt_size
(msgtl_size
) field in the
data's type descriptor is changed to zero. If a resource shortage
prevents the reception of out-of-line memory carrying port rights, then
the port rights are always destroyed if the memory region can not be
received. A task never receives port rights or memory regions that it
isn't told about.
[1] If MACH_RCV_TIMEOUT is used without MACH_RCV_INTERRUPT, then the timeout duration might not be accurate. When the call is interrupted and automatically retried, the original timeout is used. If interrupts occur frequently enough, the timeout interval might never expire.