The send operation queues a message to a port. The message carries a copy of the caller's data. After the send, the caller can freely modify the message buffer or the out-of-line memory regions and the message contents will remain unchanged.
Message delivery is reliable and sequenced. Messages are not lost, and messages sent to a port, from a single thread, are received in the order in which they were sent.
If the destination port's queue is full, then several things can happen.
If the message is sent to a send-once right (
carries a send-once right), then the kernel ignores the queue limit and
delivers the message. Otherwise the caller blocks until there is room
in the queue, unless the
MACH_SEND_NOTIFY options are used. If a port has several blocked
senders, then any of them may queue the next message when space in the
queue becomes available, with the proviso that a blocked sender will not
be indefinitely starved.
These options modify
not also specified, they are ignored.
MACH_SEND_TIMED_OUT. A zero timeout is legitimate.
MACH_SEND_WILL_NOTIFYis returned, and a msg-accepted notification is requested. If
MACH_SEND_TIMEOUTis also specified, then
MACH_SEND_NOTIFYdoesn't take effect until the timeout interval elapses.
MACH_SEND_NOTIFY, a task can forcibly queue to a send right
one message at a time. A msg-accepted notification is sent to the
notify port when another message can be forcibly queued. If an attempt
is made to use
MACH_SEND_NOTIFY before then, the call returns a
The msg-accepted notification carries the name of the send right. If
the send right is deallocated before the msg-accepted notification is
generated, then the msg-accepted notification carries the value
MACH_PORT_NULL. If the destination port is destroyed before the
notification is generated, then a send-once notification is generated
mach_msgcall will return
MACH_SEND_INTERRUPTEDif a software interrupt aborts the call. Otherwise, the send operation will be retried.
This option is typically used to cancel a dead-name request made with
MACH_RCV_NOTIFY option. It should only be used as an optimization.
The send operation can generate the following return codes. These return codes imply that the call did nothing:
msgh_bitsvalue was invalid.
msgh_remote_portvalue was invalid.
msgh_local_portvalue was invalid.
MACH_SEND_CANCEL, the notify argument did not denote a valid receive right.
These return codes imply that some or all of the message was destroyed:
These return codes imply that the message was returned to the caller with a pseudo-receive operation:
MACH_SEND_NOTIFY, the notify argument did not denote a valid receive right.
These return codes imply that the message was queued:
Some return codes, like
MACH_SEND_TIMED_OUT, imply that the
message was almost sent, but could not be queued. In these situations,
the kernel tries to return the message contents to the caller with a
pseudo-receive operation. This prevents the loss of port rights or
memory which only exist in the message. For example, a receive right
which was moved into the message, or out-of-line memory sent with the
The pseudo-receive operation is very similar to a normal receive operation. The pseudo-receive handles the port rights in the message header as if they were in the message body. They are not reversed. After the pseudo-receive, the message is ready to be resent. If the message is not resent, note that out-of-line memory regions may have moved and some port rights may have changed names.
The pseudo-receive operation may encounter resource shortages. This is
similar to a
MACH_RCV_BODY_ERROR return code from a receive
operation. When this happens, the normal send return codes are
augmented with the
MACH_MSG_VM_KERNEL bits to
indicate the nature of the resource shortage.
The queueing of a message carrying receive rights may create a circular loop of receive rights and messages, which can never be received. For example, a message carrying a receive right can be sent to that receive right. This situation is not an error, but the kernel will garbage-collect such loops, destroying the messages and ports involved.
 If MACH_SEND_TIMEOUT is used without MACH_SEND_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.