Unfortunately, there is a lot of weird interaction between all these processes. It's often badly (or not at all) documented, and what plugs where is extremely unclear. It's very messy, and it doesn't stand still long enough for someone to fix it. They just pile half-done stuff over more half-done stuff.
It's really unfortunate because the Linux kernel is, pragmatically, probably the best there is. It may not excel in specific niches (e.g. security), but overall, it does a lot of things better than, or at least about as well as BSDs, on systems where not even NetBSD boots.
One problem with message passing as such is that messages are like function calls, but you can't put a breakpoint into the system and see a call stack!
If we call a function f on object a, which calls b.g(), a breakpoint in b.g() tells us that something called a.f() which then called b.g(). If we send a message f to a, which then sends a message g to b, a breakpoint in b on the receipt of message g tells us diddly squat! The g message came in for some reason, evidently from a. Well, why did a do that? Who knows; a has gone off and is doing something else.