On Tue, Sep 2, 2014 at 1:31 PM, Felipe Lessa <felipe.lessa@gmail.com> wrote:
I don't see how one could allow concurrent readers and "closers" without
leaving this small opening.  The best workaround I can think of is to
create a blocking close operation that waits for readers using a semaphore.

Well yes,  I can't think of a simple lock-based solution to this problem,  because you don't want to hold any kind of lock while you are blocked on the file descriptor.     It would be solvable though if we had a thread-safe

threadWaitReadMVar :: MVar Fd -> IO ()

You should be able to implement this relatively easily if you dig deeper into the IO manager itself,  but we already have threadWaitReadSTM.    (For different reasons, which doesn't cover this use case.)   How many variations on this theme are we going to need.

We could implement threadWaitReadMVar if we had a non-blocking way of registering interest in a file descriptor,  and then later actually blocking on it.   So let's say something like

registerWaitRead :: Fd -> IO (IO ())

threadWaitReadMVar fd = join $ withMVar fd registerWaitRead

Which,  ignoring asynchronous exceptions for the moment,  should be adequate for the task.    I suppose that means you could instead do

threadWaitReadMVar fd = (atomically . fst) =<< withMVar fd threadWaitReadSTM

Which seems like an odd use of STM,  but that also does seem like a solution.   So I guess the earlier part of this email (as well as eariler emails)  is in fact wrong,  that threadWaitReadSTM does cover this use case.     And STM might also offer a nicer way of making multiple reads from the inotify binding thread-safe as well.

I suppose that leaves the question that if linux-inotify adopted this approach,  what should be done (if anything) about GHC 7.0 through 7.6.    Perhaps it would be possible to implement something like registerWaitRead using the lower-level semi-internal interface to the IO manager,   or perhaps I should just require GHC 7.8.

Best,
Leon