
On Thu, Mar 25, 2010 at 5:36 PM, Simon Marlow
Nice, I hadn't noticed that you can now code this up in the library since we added 'blocked'. Unfortunately this isn't cheap: 'blocked' is currently an out-of-line call to the RTS, so if we want to start using it for important things like finally and bracket, then we should put some effort into optimising it.
I'd also be amenable to having block/unblock count nesting levels instead, I don't think it would be too hard to implement and it wouldn't require any changes at the library level.
Yes counting the nesting level like Twan proposed will definitely solve the modularity problem. I do think we need to optimize the block and unblock operations in such a way that they don't need to use IORefs to save the counting level. The version Twan posted requires 2 reads and 2 writes for a block and unblock. While I haven't profiled it I think it's not very efficient.
Incedentally, I've been using the term "mask" rather than "block" in this context, as "block" is far too overloaded. It would be nice to change the terminology in the library too, leaving the old functions around for backwards compatibility of course.
Indeed "block" is to overloaded. I've been using block and unblock a lot in concurrent-extra[1] and because this package deals with threads that can "block" it sometimes is confusing whether a block refers to thread blocking or asynchronous exceptions blocking. So I'm all for deprecating 'block' in favor of 'mask'. However what do we call 'unblock'? 'unmask' maybe? However when we have: mask $ mask $ unmask x and these operations have the counting nesting levels semantics, asynchronous exception will not be unmasked in 'x'. However I don't currently know of a nicer alternative. BTW I also use the 'blockedApply' function in the Control.Concurrent.Thread.forkIO function of concurrent-extra: http://code.haskell.org/concurrent-extra/Control/Concurrent/Thread.hs forkIO ∷ IO α → IO (ThreadId α) forkIO = fork Conc.forkIO fork ∷ (IO () → IO Conc.ThreadId) → IO α → IO (ThreadId α) fork doFork act = do stop ← newEmptyMVar fmap (ThreadId stop) $ blockedApply act $ \a → doFork $ try a >>= putMVar stop Here I use it to ensure that the forked IO computation keeps the same blocked status as the parent thread. So that this forkIO has the same semantics as the standard forkIO. regards, Bas [1] http://hackage.haskell.org/package/concurrent-extra