Go to the first, previous, next, last section, table of contents.


Message Send

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 (msgh_remote_port 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_TIMEOUT or 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 MACH_SEND_MSG. If MACH_SEND_MSG is not also specified, they are ignored.

MACH_SEND_TIMEOUT
The timeout argument should specify a maximum time (in milliseconds) for the call to block before giving up.(5) If the message can't be queued before the timeout interval elapses, then the call returns MACH_SEND_TIMED_OUT. A zero timeout is legitimate.
MACH_SEND_NOTIFY
The notify argument should specify a receive right for a notify port. If the send were to block, then instead the message is queued, MACH_SEND_WILL_NOTIFY is returned, and a msg-accepted notification is requested. If MACH_SEND_TIMEOUT is also specified, then MACH_SEND_NOTIFY doesn't take effect until the timeout interval elapses. With 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 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 MACH_SEND_NOTIFY_IN_PROGRESS error. 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 instead.
MACH_SEND_INTERRUPT
If specified, the mach_msg call will return MACH_SEND_INTERRUPTED if a software interrupt aborts the call. Otherwise, the send operation will be retried.
MACH_SEND_CANCEL
The notify argument should specify a receive right for a notify port. If the send operation removes the destination port right from the caller, and the removed right had a dead-name request registered for it, and notify is the notify port for the dead-name request, then the dead-name request may be silently canceled (instead of resulting in a port-deleted notification). This option is typically used to cancel a dead-name request made with the 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:

MACH_SEND_MSG_TOO_SMALL
The specified send_size was smaller than the minimum size for a message.
MACH_SEND_NO_BUFFER
A resource shortage prevented the kernel from allocating a message buffer.
MACH_SEND_INVALID_DATA
The supplied message buffer was not readable.
MACH_SEND_INVALID_HEADER
The msgh_bits value was invalid.
MACH_SEND_INVALID_DEST
The msgh_remote_port value was invalid.
MACH_SEND_INVALID_REPLY
The msgh_local_port value was invalid.
MACH_SEND_INVALID_NOTIFY
When using 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:

MACH_SEND_INVALID_MEMORY
The message body specified out-of-line data that was not readable.
MACH_SEND_INVALID_RIGHT
The message body specified a port right which the caller didn't possess.
MACH_SEND_INVALID_TYPE
A type descriptor was invalid.
MACH_SEND_MSG_TOO_SMALL
The last data item in the message ran over the end of the message.

These return codes imply that the message was returned to the caller with a pseudo-receive operation:

MACH_SEND_TIMED_OUT
The timeout interval expired.
MACH_SEND_INTERRUPTED
A software interrupt occurred.
MACH_SEND_INVALID_NOTIFY
When using MACH_SEND_NOTIFY, the notify argument did not denote a valid receive right.
MACH_SEND_NO_NOTIFY
A resource shortage prevented the kernel from setting up a msg-accepted notification.
MACH_SEND_NOTIFY_IN_PROGRESS
A msg-accepted notification was already requested, and hasn't yet been generated.

These return codes imply that the message was queued:

MACH_SEND_WILL_NOTIFY
The message was forcibly queued, and a msg-accepted notification was requested.
MACH_MSG_SUCCESS
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 deallocate bit.

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_IPC_SPACE, MACH_MSG_VM_SPACE, MACH_MSG_IPC_KERNEL, and 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.


Go to the first, previous, next, last section, table of contents.