Message Passing in MINIX
Message Passing Properties
Minix uses the concept of a message to support communication between processes. This is used universally througout Minix whenever one process needs to access another.
Minix user processes can only send/receive messages to system processes, not to other user processes.
Minix system processes can send messages to other system processes and reply to user process messages subject to certain restrictions.
The following message passing functions are implemented by the kernel:
- send
- receive
- sendrec (send/receive)
- notify
- echo
The first three use the rendezvous style message passing. So sendrec in a user process will block the user if the destination system process is currently doing something other than trying to receive an new request message.
The _syscall function used by user level programs actually uses the sendrec (send/receive) function to send a request and receive a reply.
The notify type message does not use the rendezvous. That is, it does not get blocked if the destination is not yet ready to receive the notification.
The echo is used by the kernel process for passing a message from a process to itself.
Message Format
A message consists of: the process ID of the sending process, an identifier telling the process what sort of message it is, and then a union for holding the actual message structure. The code snippet from the file /usr/src/include/minix/ipc.h
shows the message structure :
typedef struct {
endpoint_t m_source; /* who sent the message */
int m_type; /* what kind of message is it */
union {
mess_1 m_m1;
mess_2 m_m2;
mess_3 m_m3;
mess_4 m_m4;
mess_5 m_m5;
mess_7 m_m7;
mess_8 m_m8;
mess_6 m_m6;
mess_9 m_m9;
mess_10 m_m10;
} m_u;
} message __aligned(16);
MINIX 3 has 10 message types (mess_1 to mess_10) as we can see from the message structure above. Each of these message types are unique. The code below from the same file shows the different message types :
typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1;
typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;
short m2s1;} mess_2;
typedef struct {int m3i1, m3i2; char *m3p1; char m3ca1[M3_LONG_STRING];} mess_3;
typedef struct {long m4l1, m4l2, m4l3, m4l4, m4l5;} mess_4;
typedef struct {short m5s1, m5s2; int m5i1, m5i2; long m5l1, m5l2, m5l3;}mess_5;
typedef struct {long m6l1, m6l2, m6l3; short m6s1, m6s2, m6s3; char m6c1, m6c2;
char *m6p1, *m6p2;} mess_6;
typedef struct {int m7i1, m7i2, m7i3, m7i4, m7i5; char *m7p1, *m7p2;} mess_7;
typedef struct {int m8i1, m8i2; char *m8p1, *m8p2, *m8p3, *m8p4;} mess_8;
typedef struct {long m9l1, m9l2, m9l3, m9l4, m9l5;
short m9s1, m9s2, m9s3, m9s4; } mess_9;
typedef struct {int m10i1, m10i2, m10i3, m10i4;
long m10l1, m10l2, m10l3; } mess_10;