Comment by eqvinox
1 day ago
> epoll/kqueue are replacements for their deprecated counterparts poll and select.
Neither poll nor select are deprecated. They're just not good fits for particular use patterns. But even select() is fine if you just need to watch 2 FDs in a CLI tool.
In fact, due to its footguns, I'd highly advise against epoll (particularly edge triggering) unless you really need it.
> But even select() is fine if you just need to watch 2 FDs in a CLI tool.
Only if those fds are below ~1024 or whatever. (If you're going to use one of the legacy interfaces, at least poll() doesn't have arbitrary limits on the numeric value of the fd.)
The Winsock version doesn't have this limitation. It's a very weak select() because it only works on network sockets, but it doesn't care about numeric values of file descriptors. As on POSIX, file descriptors are added and removed to the select set using macros, and these work on a vector or linked list (I forgot) instead of a bitset.
1024 is the default fd limit anyway, isn't it?
...because of select, and how it became essentially impossible to ensure that a process wasn't using it anywhere, indirectly or incidentally.
select() is at least kind of deprecated, in that its own man page says not to use it in new code.
I don't see it in the man page?
https://man.freebsd.org/cgi/man.cgi?select
The man page also suggests how you might increase the FD limit if needed. I still use select for a small number of FDs where overhead isn't a real concern, and select is a good fit.
https://man7.org/linux/man-pages/man2/select.2.html
In anything new you should use poll not select.
They're basically identical apis but poll doesn't have a hard limit and works with high number fds.
2 replies →
or better yet, go with libevent (https://libevent.org, almost) always better than ’naked’ calls to low level routines, and cross-platform to boot.
lubuv, libevent introduce a layer of abstraction, their own approach to buffer mgmt, etc. If poll() works, better stay with poll(). It is universally portable, things stay pretty clean and simple as a result.
Right now I am working on JavaScript bindings for a project and doing it the node.js way (or Deno) is definitely a no-no. That would be one more layer in the architecture, if not two. Once you have more layers, you also have more layer interactions and that never stops.
I mean, complexity begets complexity
https://github.com/gritzko/librdx/blob/master/js/README.md
Having more than 1000 conns per a thread is a very specific usecase.
Very specific, but very common, such as a web server, forward proxy, reverse proxy, load balancer, etc. Used in high millions of instances. I'd say a toy CLI tool is a very specific usecase for a lot less people than the above.
What's the footgun with edge triggering?
The edge in epoll edge triggering is going from has data to doesn't have data.
So the obvious loop using level triggering switched to edge will eventually lock up.
You'll read 4092bbytesbwhen there is 4093 bytes leaving 1 behind and then never get a signal again.
This is a blatant application bug, not an epoll issue, unless you prove otherwise.
select() is great for embedded daemons and user space signals handling, and so on.
Just don't try to solve the 10,000x problem with it, by putting it on the Internet.
Or, if you do, build it out properly.
Or use epoll or kqueue.