Roman Cheplyaka | 28 Jul 16:02 2013

Is withAsync absolutely safe?

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?

Roman
Bertram Felgenhauer | 28 Jul 18:11 2013

Re: Is withAsync absolutely safe?

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
(Continue reading)

Roman Cheplyaka | 29 Jul 09:34 2013

Re: Is withAsync absolutely safe?

* Bertram Felgenhauer <bertram.felgenhauer <at> googlemail.com> [2013-07-28 18:11:54+0200]
> 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
(Continue reading)


Gmane