Final bikeshedding call: Fixing Control.Exception.bracket

Edward Kmett ekmett at gmail.com
Sun Nov 23 20:23:22 UTC 2014


This is predicated on a lot of assumptions though:

* That nobody else has closed over a reference to the handle in a way that
prevents the GC from freeing it.

* That file handles are the only resources we are concerned with.

* That eventual clean up is okay when things go wrong.

These often hold, and at least we can say they hold for file handles for
all but the most resource constrained of users, but I think ultimately
there is a fundamental tension between real actual finalization guarantees
and having killThread return in a timely manner when its target goes off
the reservation.

With files we can get into situations where just bracketing "badly" still
just works. With other resources though its a fair bit more hazardous.

Whether that warrants a change in the default form of bracket is another
matter.

-Edward

On Sun, Nov 23, 2014 at 1:57 PM, Simon Marlow <marlowsd at gmail.com> wrote:

> On 23/11/14 17:46, John Lato wrote:
>
>>
>>
>> On Sun Nov 23 2014 at 7:09:10 AM Simon Marlow <marlowsd at gmail.com
>> <mailto:marlowsd at gmail.com>> wrote:
>>
>>     On 21/11/14 17:22, Gregory Collins wrote:
>>      > New post from Yuras provides food for thought:
>>      >
>>     https://github.com/Yuras/io-__region/wiki/Handling-%28async%
>> __29-exceptions-in-haskell:-__pushing-bracket-to-the-limits
>>     <https://github.com/Yuras/io-region/wiki/Handling-%28async%
>> 29-exceptions-in-haskell:-pushing-bracket-to-the-limits>
>>      >
>>      > In particular he points out a case for which uninterruptibleMask
>> will
>>      > cause unkillable threads: let's say hClose blocks flushing the
>>     output to
>>      > a file, but the write fails because of a hardware error and blocks
>>      > forever. (Alternatively, imagine the file is on NFS and you get a
>>     cable
>>      > cut between the two machines). The thread executing hClose in the
>>      > cleanup action becomes unkillable.
>>
>>     Yes, and furthermore hClose is not "buggy": even if it is interrupted
>> by
>>     an async exception, the file descriptor will still be closed by the
>>     finalizer.  This is not something you want to do a lot, of course, but
>>     as a backup plan for the rare case of an async exception killing the
>>     cleanup action it's fine.
>>
>>
>> This is not entirely correct.  If another thread is holding the MVar
>> when hClose is called, and it is blocked in takeMVar, if an async
>> exception arrives takeMVar will be interrupted and the file descriptor
>> will never be closed.  Arguably that situation shouldn't happen except
>> in poorly-designed programs, but I can provide at least one example
>> where it appears to be a viable architecture, and I'm not convinced it
>> would never happen in practice.
>>
>
> Handles have a finalizer that closes the Handle sometime after its last
> use, so it's not possible to leak a Handle permanently.  There's an
> unpredictable delay before it gets closed, which is why we don't rely on
> this to close our Handles normally, but I'm arguing it's fine to rely on
> this to close Handles in the rare case where hClose is interrupted.
>
>      So arguably uninterruptibleMask is not what we want for hClose.
>>
>>
>> Is there any way to fix the issue I describe besides preventing async
>> exceptions from arising while blocked on the MVar?  Although I do agree
>> we don't want to put uninterruptibleMask inside hClose (long ramble at
>> http://johnlato.blogspot.ca/2014/11/exception-handling-and-cleanup.html)
>>
>
> In the absence of a finalizer, besides uninterruptibleMask the only
> alternative that springs to mind is to fork a thread to finish the cleanup
> when an async exception strikes; which is actually not a bad solution as
> long as you don't rely on the resource being released in the original
> thread.
>
> Cheers,
> Simon
>
>  John
>>
>>
>>     Cheers,
>>     Simon
>>
>>
>>      > G
>>      >
>>      > On Thu, Nov 20, 2014 at 7:24 AM, Simon Marlow <marlowsd at gmail.com
>>     <mailto:marlowsd at gmail.com>
>>      > <mailto:marlowsd at gmail.com <mailto:marlowsd at gmail.com>>> wrote:
>>      >
>>      >     On 19/11/2014 23:07, Ganesh Sittampalam wrote:
>>      >
>>      >         On 13/11/2014 10:44, Simon Marlow wrote:
>>      >
>>      >             On 13/11/2014 07:47, Merijn Verstraaten wrote:
>>      >
>>      >
>>      >                 A new version would look like:
>>      >
>>      >                 bracket before after thing =
>>      >                      mask $ \restore -> do
>>      >                        let atomicAfter = uninterruptibleMask .
>> after
>>      >                        a <- before
>>      >                        r <- restore (thing a) `onException`
>>     atomicAfter a
>>      >                        _ <- atomicAfter a
>>      >                        return r
>>      >
>>      >                 Slightly different versions are possible and the
>>     other
>>      >                 relevant
>>      >                 bracketing functions mentioned in this thread can
>> be
>>      >                 treated similarly.
>>      >
>>      >
>>      >             Since we would need this for catch too, the sensible
>>     thing
>>      >             to do (if we
>>      >             decide to go ahead with this) would be to change the
>>      >             implementation of
>>      >             catch in the RTS from masking the exception handler to
>>      >             uninterruptibleMask.  That would mean that at least for
>>      >             catch there
>>      >             would be no additional overhead, and it would make the
>>      >             modifications to
>>      >             the other operations simpler in some cases.
>>      >
>>      >
>>      >         If this isn't done in the RTS, is there a possibility of
>>     an async
>>      >         exception slipping in between the exception handler
>>     starting and the
>>      >         uninterruptibleMask starting?
>>      >
>>      >
>>      >     No, because the exception handler is masked.
>>      >
>>      >     Cheers,
>>      >     Simon
>>      >
>>      >     ___________________________________________________
>>      >     Libraries mailing list
>>      > Libraries at haskell.org <mailto:Libraries at haskell.org>
>>     <mailto:Libraries at haskell.org <mailto:Libraries at haskell.org>>
>>      > http://www.haskell.org/____mailman/listinfo/libraries
>>     <http://www.haskell.org/__mailman/listinfo/libraries>
>>      >     <http://www.haskell.org/__mailman/listinfo/libraries
>>     <http://www.haskell.org/mailman/listinfo/libraries>>
>>      >
>>      >
>>      >
>>      >
>>      > --
>>      > Gregory Collins <greg at gregorycollins.net
>>     <mailto:greg at gregorycollins.net> <mailto:greg at gregorycollins.__net
>>     <mailto:greg at gregorycollins.net>>>
>>
>>     _________________________________________________
>>     Libraries mailing list
>>     Libraries at haskell.org <mailto:Libraries at haskell.org>
>>     http://www.haskell.org/__mailman/listinfo/libraries
>>     <http://www.haskell.org/mailman/listinfo/libraries>
>>
>>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://www.haskell.org/mailman/listinfo/libraries
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/libraries/attachments/20141123/7deba875/attachment-0001.html>


More information about the Libraries mailing list