SO_RCVLOWAT and SO_SNDLOWAT
Specify the minimum number of bytes in the buffer until the socket
layer will pass the data to the protocol (SO_SNDLOWAT) or the user
on receiving (SO_RCVLOWAT). These two values are initialized to 1.
On the transmit side: EPOLLET
Sets the Edge Triggered behavior for the associated file descriptor.
The default behavior for epoll is Level Triggered. See epoll(7) for
more detailed informa‐ tion about Edge and Level Triggered event
distribution architectures.Unless I'm missing something (and I could very well be missing something), I'm not seeing how that is any different than anything I tried...and I went through every socket option I could find, even if it seemed irrelevant.
Have you written code that actually performs this way? Or are you speculating? I really do wish I could do this with epoll, but I (and several others) just never were able to figure it out. And kqueue simply performed at least an order of magnitude better of any variation I could hack together with epoll.
However, because of what you have observed I wrote up a quick test, which confirms to my satisfaction that epoll_wait() respects SO_RCVLOWAT on TCP sockets: https://gist.github.com/keaston/d2473b8b996a34a5860b0744684f...
It seems likely that you must have been dealing with an old "enterprise" kernel in 2015 that hadn't had this fix backported to it?
My only guess is that I was botching something else when I was digging into this a few years ago.
I can't tell you how much I appreciate you putting that together. This seriously changes a lot of what I work on. Thank you.
The client code I wrote: https://gist.github.com/benwills/95ee844853d3b18588fb3df7d56...
The errors are just because you need to check for EAGAIN or EWOULDBLOCK when read() returns -1, and not bail out when that happens.
The way epoll() is written triggers so many syscalls that things like socket clients can get triggered for every single packet. Whereas kqueue coordinates with other socket options set on the descriptor, such as not returning until x bytes have been received and/or the server has closed the connection.
...not to mention how much more it's tied to across the IO subsystem.