You can.
This ISSET() over the set without ISSET() - all ISSET() from the array. But you still have to touch all long in the fd_set.__fds_bits .
#include<sys/select.h> #include<stdio.h> int main(void) { fd_set fds; FD_ZERO(&fds); //Fill the set. FD_SET(6, &fds);FD_SET(20, &fds);FD_SET(33, &fds);FD_SET(200, &fds); int i; unsigned long *m = (unsigned long *)__FDS_BITS(&fds); int fd=0; for (i = 0; i < sizeof (fd_set) / sizeof (unsigned long); ++i) //can use int, long or long long. Using long because internal structure is long. { fd=sizeof (unsigned long)*i*8; while(m[i]!=0) { fd+=__builtin_ctzl(m[i]); //Get Number of trailing zero bits in long. printf("FD=%d\n",fd); /*Found FD*/ m[i]>>=(__builtin_ctzl(m[i]))+1; ++fd; } } return 0; }
This works fine for me using gcc (SUSE Linux) 4.6.2
Background
on my system, fd_set looks like this (extraction and simplified /usr/include/sys/select.h ):
typedef struct { __fd_mask __fds_bits[__FD_SETSIZE/__NFDBITS]; }
with __fd_mask being typedef to long int .
__FD_SETSIZE/__NFDBITS seems 16 on my system.
So this array is bits (__FD_SETSIZE/__NFDBITS)*sizeof(__fd_mask)*8 .
With __NFDBITS = 8*sizeof(__fd_mask) you see that there is a __FD_SETSIZE bit in this.
Looking at the definitions of actual macros in /usr/include/bits/select.h shows that __fd_bits are used to store fds. When fd n , the nth bit in __fd_bits set to 1.
i386 (among others ) processors have one operation for counting the final zero bits of a number. With this number of __fd_bits zeros, you can easily shift the __fd_bits record by that sum + 1, and you will find the next true bit.
Compared to the input data set cycle of your fd_set, you need a minimum of __FD_SETSIZE/__NFDBITS=16 cycles if you do not optimize the use of the return value of select.
But make sure your processor and compiler support the operation for the selected loop type. When it defaults to NOT using a bit operation, but a complex implementation can get worse.
If this is actually better than a loop, then known fds should be proven.
MaPePeR
source share