4 ms·
> People tend to forget that it's the value of the fds you pass to select() which can't exceed FD_SETSIZE Is that true? I have a memory of working on systems w
by wiml 5y ago
> People tend to forget that it's the value of the fds you pass to select() which can't exceed FD_SETSIZE
Is that true? I have a memory of working on systems where you can pass larger arrays in if you want, you just have to allocate your own bitvectors instead of using the convenient struct. A quick look at the linux kernel makes me think that this is true for Linux; the kernel doesn't appear to reference FD_SETSIZE in its implementation.
- TheDong 5y agoIf you read the man page bugs section: https://man7.org/linux/man-pages/man2/select.2.html https://man7.org/linux/man-pages/man2/select.2.html "The Linux kernel imposes no fixed limit, but the glibc implementation makes fd_set a fixed-size type, with FD_SETSIZE defined as 1024" Everyone using select, with very few exceptions, is using glibc. That limitation does appear to exist in glibc if you look at the source code. The source code requires you to pass a glibc defined 'fd_set' type https://man7.org/linux/man-pages/man2/select.2.html https://man7.org/linux/man-pages/man2/select.2.html That struct is defined here: https://github.com/bminor/glibc/blob/595c22ecd8e87a27fd19270ed30fdbae9ad25426/misc/sys/select.h#L58-L70 https://github.com/bminor/glibc/blob/595c22ecd8e87a27fd19270... It does seem to have the limits described by the blogpost.
- ksherlock 5y agoThe glibc/musl select library call doesn't verify nfds is < FD_SETSIZE so you could create your own fd_set as large as you want it. glibc: https://github.com/bminor/glibc/blob/master/sysdeps/unix/sysv/linux/select.c https://github.com/bminor/glibc/blob/master/sysdeps/unix/sys... musl: https://git.musl-libc.org/cgit/musl/tree/src/select/select.c https://git.musl-libc.org/cgit/musl/tree/src/select/select.c *BSD allows you to define your own FD_SETSIZE before including system headers.
- toast0 5y agoOn FreeBSD's select(2) man page, the NOTES section has the much friendlier > The default size of FD_SETSIZE is currently 1024. In order to accommodate programs which might potentially use a larger number of open files with select(), it is possible to increase this size by having the program define FD_SETSIZE before the inclusion of any header which includes <sys/types.h>. Although, if you link to a library which uses select and doesn't check that fds it uses are valid with the FD_SETSIZE it was compiled with, you're still in for a bad time, as suggested in the article. And still, probably use something better than select.
- Joker_vD 5y agoYep, and if you pass an fd >= 1024, it will corrupt the stack by using FD_SET and your program will crash. I've seen that in production, was solved by forcing glibc to use epoll.
- anonymousiam 5y agoFrom what I recall (without looking it up, and relying on wetware memory that's 20 years old), there is a set of macros that are used to initialize, add, and remove descriptors to a file descriptor set. FD_SETSIZE defines the maximum number of descriptors that the set can hold. I could be wrong, but I seem to recall that the implementation uses both an array and a bit-mask. The array holds the descriptors and the bit-mask identifies which array elements are "active".
- wiml 5y agoThe argument is just an array of unsigned longs, each bit of which represents one file descriptor — there's no magic in there. The add/remove macros just do the typical shift-and-mask style bit twiddling. You can pass a bigger or smaller array than the one in fd_set if you want; TTBOMK the kernel doesn't care. It just looks at the numfds argument to know how large an array you passed in.
- jlokier 5y agoSome platforms (but not Linux) let you define FD_SETSIZE before including C headers to override the default. The fd_set structure will be made correspondingly larger. On these platforms it should work fine, though there may still be an undocumented kernel limit. Some really old platforms with select() don't even define fd_set or FD_SETSIZE, and you're on your own :-) Linux added the poll() syscall in 2.1.23, and Linux select() had a kernel-side limit of 256 fds up to 2.1.26, when it raised the kernel-side limit to 5120/10752 depending on architecture. It was 2.5 years until the kernel-side limit was removed, by which point everyone would have had poll() in Glibc. So if you are going to the effort of writing portable select() except using the trick of defining your own, larger arrays, and using poll() when it's available, on Linux don't bother. You'll hit a kernel limit anyway on those very old systems which don't have poll().