Next: Atomicity, Previous: Message Send, Up: Messaging Interface [Contents][Index]
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
.
Servers usually associate some state with a receive right. To that
end, they might use a hash table to look up the state for the port a
message was sent to. To optimize this, a task may associate an opaque
payload with a receive right using the
mach_port_set_protected_payload
function. Once this is done,
the kernel will set the msgh_protected_payload
field to
payload when delivering a message to this right and indicate
this by setting the local part of msgh_bits
to
MACH_MSG_TYPE_PROTECTED_PAYLOAD
.
The support for protected payloads was added to GNU Mach. To preserve
binary compatibility, the msgh_local_port
and
msgh_local_port
share the same location. This makes it
possible to add the payload information without increasing the size of
mach_msg_header_t
. This is an implementation detail. Which
field is valid is determined by the local part of the
msgh_bits
. Existing software is not affected. When a receive
right is transferred to another task, its payload is cleared.
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
The timeout argument should specify a maximum time (in milliseconds) for
the call to block before giving up.6 If no message arrives before the
timeout interval elapses, then the call returns
MACH_RCV_TIMED_OUT
. A zero timeout is legitimate.
MACH_RCV_NOTIFY
The notify argument should specify a receive right for a notify port. If receiving the reply port creates a new port right in the caller, then the notify port is used to request a dead-name notification for the new port right.
MACH_RCV_INTERRUPT
If specified, the 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
If the message is larger than 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
The specified rcv_name
was invalid.
MACH_RCV_IN_SET
The specified port was a member of a port set.
MACH_RCV_TIMED_OUT
The timeout interval expired.
MACH_RCV_INTERRUPTED
A software interrupt occurred.
MACH_RCV_PORT_DIED
The caller lost the rights specified by 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
When using 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
A resource shortage prevented the reception of the port rights in the message header.
MACH_RCV_INVALID_NOTIFY
When using MACH_RCV_NOTIFY
, the notify argument did not denote a
valid receive right.
MACH_RCV_TOO_LARGE
When not using 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
A resource shortage prevented the reception of a port right or out-of-line memory region in the message body. The message header, including the reply port, is correct. The kernel attempts to transfer all port rights and memory regions in the body, and only destroys those that can’t be transferred.
MACH_RCV_INVALID_DATA
The specified message buffer was not writable. The calling task did successfully receive the port rights and out-of-line memory regions in the message.
MACH_MSG_SUCCESS
A message was received.
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
There was no room in the task’s IPC name space for another port name.
MACH_MSG_VM_SPACE
There was no room in the task’s VM address space for an out-of-line memory region.
MACH_MSG_IPC_KERNEL
A kernel resource shortage prevented the reception of a port right.
MACH_MSG_VM_KERNEL
A kernel resource shortage prevented the reception of an out-of-line memory region.
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.
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.
Next: Atomicity, Previous: Message Send, Up: Messaging Interface [Contents][Index]