You might want to take a look at rn by Dan Kegel (the c10k guy): http://www.kegel.com/rn/. It has plain-old-c interface around multiple select-like syscalls such as poll/epoll/sigio. There are significant performance difference between them at high fd counts and the best interfaces (epoll/kqueue) are non-portable.
The rn api is epoll-ish: you only add/remove individual fds instead of passing the whole list around like for select. Good old select with a FD_SET is limited at compile time to a number of sockets and copies the entire list from user-to-kernel space at every call. Using epoll you have separate syscalls to add/remove individual FDs which are fast even when you are waiting on 100K idle sockets.
All modern linux systems should support epoll. If you don't care about portability you can use it directly.