Next: Message Receive, Previous: Memory, Up: Messaging Interface
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_TIMEOUTMACH_SEND_TIMED_OUT. A zero timeout is legitimate.
MACH_SEND_NOTIFYMACH_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
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_INTERRUPTmach_msg call will return
MACH_SEND_INTERRUPTED if a software interrupt aborts the call.
Otherwise, the send operation will be retried.
MACH_SEND_CANCELThis 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_SMALLMACH_SEND_NO_BUFFERMACH_SEND_INVALID_DATAMACH_SEND_INVALID_HEADERmsgh_bits value was invalid.
MACH_SEND_INVALID_DESTmsgh_remote_port value was invalid.
MACH_SEND_INVALID_REPLYmsgh_local_port value was invalid.
MACH_SEND_INVALID_NOTIFYMACH_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_MEMORYMACH_SEND_INVALID_RIGHTMACH_SEND_INVALID_TYPEMACH_SEND_MSG_TOO_SMALLThese return codes imply that the message was returned to the caller with a pseudo-receive operation:
MACH_SEND_TIMED_OUTMACH_SEND_INTERRUPTEDMACH_SEND_INVALID_NOTIFYMACH_SEND_NOTIFY, the notify argument did not denote a
valid receive right.
MACH_SEND_NO_NOTIFYMACH_SEND_NOTIFY_IN_PROGRESSThese return codes imply that the message was queued:
MACH_SEND_WILL_NOTIFYMACH_MSG_SUCCESSSome 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.
[1] 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.