Message passing is Minix's native form of IPC. Together with memory grants, they are the only low-level IPC directly understood by the micro-kernel. POSIX-style IPC is implemented on top of them at a higher level of abstraction.
The messages are fixed-length 64 bytes of data. To transfer more effectively bigger amounts of data memory grants are used. Messages are composed of :
All available messages are enumerated at minix/include/minix/ipc.h.
A endpoint identifies a process uniquely among the operating system. It is composed of the process slot number concatenated with a generation number.
The reason behind this generation number is that a process slot may be recycled when a process dies, so unrelated processes may sequentially share the same process slot number, which would cause problems when delivering messages to a process which happened to share the same process slot than a unrelated predecessor.
A thorough explanation of endpoints is available at minix/include/minix/endpoint.h.
Message types identifies what kind of message is a particular message. They are enumerated at minix/include/minix/com.h
A special kind of messages is notifications : notifications allows one to notify a process about something (for example, a hard disk interrupt meant for the disk driver). They take priority over normal messages when a process tries to RECEIVE one. Due to their construction, they are not stored in the receive buffer and their payload is generated on-the-fly by the micro-kernel.
Messages have a 56 bytes fixed payload. Each message type has its own payload format, which are described at minix/include/minix/ipc.h.
You can transfer more than 56 bytes per message using grants (minix/include/minix/safecopies.h). Grants are pointers to an allocated data block exported by the granter.
Case 1: A needs to send more than 56 bytes to B
The grantee receives the read only grant via message and maps it to memory in the target process. The target process can now read and process the payload transferred via grant. After processing the payload, the granter needs to be informed to revoke the grant.
Case 2: A requests more than 56 bytes from B
The grantee receives the read write grant via message and maps it to memory in the target process. The target process can now write to the memory transferred via grant. After writing, the grantee maps back the the memory to the grant address and send it back via message to the granter. The granter needs to revoke the grant.
Case 3: A needs to send more than 56 bytes and expects to return more than 56 bytes
The granter creates a grant for an already allocated memory. The grantee receives the read write grant via message and maps it to memory in the target process. The target process can now write to the memory transferred via grant. After writing, the grantee maps back the the memory to the grant address and send it back via message to the granter.
The micro-kernel handles the delivery of messages. There are three basic primitives :
There are also NOTIFY, SENDNB (non-blocking SEND) and SENDA (asynchronous SEND) for specific purposes.
Each endpoint has a 1 message receive buffer inside the micro-kernel.
To prevent deadlocks (by error or by malicious processes), processes are limited by what kind of primitives they may use and to whom they may send messages to. Also, the order of messages and protocols built upon them are carefully designed to prevent them.