This is, IIRC, similar to the underying message passing system in Minix (If I am wrong, well, it' s been a few years since I've had a copy of OS:D&I), AmigaExec (again, this is from memory) and QNX. My impression is that this design works very efficiently for between local threads, or in a system with no hardware protection, but runs into shared memory issues when used for IPC between processes (or between machines); passing a pointer across memory spaces won't work. You would have to either,
- use this mechanism only for thread-local IPC, and have a separate IPC mechansm for non-local messages; or,
- have a shared memory space in all processes for IPC messaging; or,
- have the kernel IPC system copy the message from the sending process's memory space to that of the recipient.
The first option the most efficient, but means that you would have at least two separate IPC mechanisms. The second is reasonably effiecent, but involves juggling paging so that every process maps the IPC common area the same way, and introduces the risk of a process scribbling over an important system memory area; furthermore, it would not be usable for remote IPC. The last approach has the most overhead, but is the most flexible, and is reasonably secure.
Another objection is that tying the message passing mechanism directly to threading leads to a loss of flexibility; a system based on mailboxes or message ports, in which more than one thread can read a mbox and a thread can have more than one mbox, is more general, and separates the message abstraction from the threads themselves. One advantage of this is that it solves the problem of how to determine where to send a given message to; rather than having to get the thread ID, there would simply be a mbox assigned ahead of time to receive those messages; the sending thread need not know about the receiver, and vis versa. Furthermore, it means that if a thread as to be halted and restarted, the mbox for the service it provides doesn't get trashed.
As for the issue of a thread deadlocking on messages from a specific sender, well, most implementations of message passing don't queue separately based on sender; those which do, general use a polling rather than waiting message receiver function to avoid the problem you mention (that is to say, a call to kreceive() would immediately return false if there are no messages from the recipient, rather than waiting until a message arrives). Or at least that's the impression I have of it.
C&CW.