hSelect will cause all your Haskell
threads to block until the hSelect returns,
much like any call to a foreign function.

You don't need to. Concurrent Haskell will let you do
I/O on multiple file handles concurrently by forking threads,
and if you need to assign a timeout, then this can be done
using a combination of threadDelay (see
Section 3.3) and asynchronous exceptions
(see Section 5.12.7).