[Haskell-cafe] addFinalizer in GHC 7.10

Edward Kmett ekmett at gmail.com
Tue Jan 30 22:25:17 UTC 2018


Yes, this can happen even if you're opaque and don't export stuff.

You could attach the finalizer to an (unpacked) IORef that holds the Bool
that says whether you've been finalized. An IORef holds onto a MutVar#
under the hood, and so it also maintains the same sort of stable presence
Weak# offered above. Similarly you _could_ just stuff the info in an MVar
or ForeignPtr. Each of those has support for attaching a finalizer directly
to the heap allocated part that lives in # and therefore isn't vulnerable
to being inlined or unpacked.

There probably should be able to be similar options for attaching the
finalizer to a MutableByteArray#, even if the combinators don't exist right
now, etc.

I'd personally go with an IORef and then atomicModifyIORef during the
"close" and "finalize" operations to extract and set the flag in one
operation. That way there isn't any communication overhead, but IORef,
ForeignPtr, MVar, etc. could all work.

-Edward

On Tue, Jan 30, 2018 at 5:09 PM, Viktor Dukhovni <ietf-dane at dukhovni.org>
wrote:

>
>
> > On Jan 30, 2018, at 4:50 PM, Edward Kmett <ekmett at gmail.com> wrote:
> >
> > It would be much, much safer to attach the finalizer to something that
> has a "presence" all its own, like Weak# () as is done in ForeignPtr. This
> would result in something like:
> >
> > data Socket = Socket !CInt (Weak# ())
> >
> > Then when it gets unpacked into another data constructor, then the Weak#
> () still exists. This isn't free, it comes at the cost that your sockets
> take a couple of words each (plus finalizer space), but the approach you
> are taking now isn't free either as it isn't really sound. ;)
> >
> > tl;dr don't attach finalizers to regular Haskell data types if you can
> help it
>
> THanks, good to know.  I gather the unpacking can/will happen even if
> Socket internals are [made] opaque to other modules?
>
> And of course in this case, in addition to avoiding
> running the finalizer too early, it is critical that each socket be closed
> at most once.  Therefore, to support finalization, and make the API safe
> for multiple close (as seems to be the case with System.IO Handle's for
> example) there's a need for additional mutable state in the Socket, to
> keep track of whether it has or has not yet been closed.
>
> I am curious as to what your suggestion would be as to how to best keep
> track of such state.
>
>    1. Employ a separate MVar to keep track of socket state, and update
>       it on close to ensure at most once close.
>
>    2. Wrap the file descriptor in an IORef, and set it to an invalid
>       value (-1 on Unix, INVALID_SOCKET on Windows) on close.  This
>       avoids misuse not only with close, but also with attempts at
>       read/write/... I/O after close.  However it does not avoid
>       (far less likely I think) races to close the socket from
>       multiple threads.
>
>    3. Move the state to a wrapper structure managed in FFI code
>       so that all socket operations are via a foreign pointer to
>       a C-structure in which the file descriptor is invalidated on
>       close.
>
>    4.  Other suggestions...
>
> --
>         Viktor.
>
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20180130/27e11aaf/attachment.html>


More information about the Haskell-Cafe mailing list