
Roman Cheplyaka wrote:
Can withAsync guarantee that its child will be terminated if the thread executing withAsync gets an exception?
To remind, here's an implementation of withAsync:
withAsyncUsing :: (IO () -> IO ThreadId) -> IO a -> (Async a -> IO b) -> IO b -- The bracket version works, but is slow. We can do better by -- hand-coding it: withAsyncUsing doFork = \action inner -> do var <- newEmptyTMVarIO mask $ \restore -> do t <- doFork $ try (restore action) >>= atomically . putTMVar var let a = Async t (readTMVar var) r <- restore (inner a) `catchAll` \e -> do cancel a; throwIO e cancel a return r
I am interested in the case when an exception arrives which transfers control to 'cancel', and then another exception arrives to the same thread. Even though 'catchAll' (which is a type-restricted synonym for catch) masks the exception handler, 'throwTo' inside 'cancel' is interruptible (as stated by the documentation).
Will this scenario lead to a thread leakage?
Yes. I guess that 'cancel' should use 'uninterruptibleMask_', but it's a hard call to make (if an async action becomes unresponsive, do we want to risk not being able to deliver any exceptions to the controlling thread just because it wants to terminate the async action?) Best regards, Bertram