Thank you for this thoughtful reply. There's a variety of options if I'm willing to poll, including shared memory or the filesystem idea you outline, but I hope to avoid polling for hygienic reasons. I also explored inotify but found it to be unreliable (https://github.com/travis-ci/travis-ci/issues/2342).
That's why I like inotify in blocking mode - the call to poll() is just to wake up the process (I think you could just blocking-read the inotify file handle? I haven't tried it directly). The point of using inotify is that you don't need to poll, because the kernel send your process reliable events instead over a file handle. The use of poll(2) is just a consequence of the interface using a file handle.
As, I originally said, though, there is certainly no one-size-fits-all solution, these are just a few of the available options, which may not be apropriate for your situation.
I like blocking inotify in principle - the problem is that it just didn't work! I think there is a gap in the Linux APIs in this area. Its multicast IPC mechanisms are just too heavyweight.