
On Wed, Sep 3, 2014 at 4:21 AM, John Lato
On Tue, Sep 2, 2014 at 12:26 PM, Leon Smith
wrote: On Tue, Sep 2, 2014 at 1:31 PM, Felipe Lessa
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.
If you wanted to go this route, you could use an MVar (Maybe (Int,Fd)), where the Int is a count of interested threads. Instead of using readMVar before threadWaitRead, you would use modifyMVar to atomically increment the counter and retrieve the fd. Then, after threadWaitRead returns, decrement the counter. You'd need to make sure that you never close an fd when the counter is greater than 0. This would work better with a TMVar, because then the close operation could block until the counter has changed.
I think the semantics should probably be for a concurrent close to immediately close the descriptor, with exceptions raised in any threads that are blocked on the descriptor. It seems that any sort of use-case along these lines is going to result in an exception eventually... so you might as well make it prompt. So I still don't see any lock-based solution for my intended semantics.
threadWaitReadMVar fd = (atomically . fst) =<< withMVar fd
threadWaitReadSTM
This should work even in the presence of async exceptions, barring bugs in withMVar and threadWaitReadSTM. You can implement your registerWaitRead using forkIO and MVars, but I think the only reason to do so would be for compatibility with older ghcs. It's probably more sensible to just copy the definition of threadWaitReadSTM in that case, unless you want to target pre-STM compiler versions.
I think you are right; I suppose an async exception could result in interest registered in the descriptor without ever waiting on it, but this really isn't a big deal, especially as the callback will be removed from the IO manager once the descriptor becomes readable or the descriptor is closed. And it shouldn't prevent the higher-level inotify "descriptor" from being garbage-collected either, as the IO manager doesn't know anything about that, so the finalizer can still close the descriptor. Best, Leon