Proposal: add new forms of unsafePerformIO and unsafeInterleaveIO

Duncan Coutts duncan.coutts at worc.ox.ac.uk
Thu Feb 14 05:54:37 EST 2008


This proposal is to add two new variations on unsafePerformIO and one
new form of unsafeInterleaveIO to the System.IO.Unsafe module in the
base library (which already exports unsafePerformIO and
unsafeInterleaveIO).

The additions are documented and portable to non-ghc.

Summary and documentation below, see patch attached to the ticket for
code details. http://hackage.haskell.org/trac/ghc/ticket/2095

Suggested timescale: ~2 weeks, ends Friday 29th February

Summary
      * unsafeDupablePerformIO and unsafeDupableInterleaveIO When GHC
        added SMP support the previous unsafePerform/InterleaveIO got
        renamed to these two functions and new
        unsafePerform/InterleaveIO functions were added that provide
        protection against duplication in a multi-threaded context. This
        protection comes at some cost so there are cases where it is ok
        to uses these weaker forms if duplicating the IO action is safe.
        These are already defined and documented in GHC.IOBase, this
        patch just exports them.
      * unsafeInlinePerformIO This is an even less safe form of
        unsafePerformIO. It is used in the Data.ByteString
        implementation and is very occasionally needed in other
        projects. If it is needed it is better that it be supplied in a
        portable form from a standard module with a sensible name and
        with full documentation.

Haddock Documentation

This version of 'unsafePerformIO' is slightly more efficient, because it
omits the check that the IO is only being performed by a single thread.
Hence, when you write 'unsafeDupablePerformIO', there is a possibility
that the IO action may be performed multiple times (on a
multiprocessor), and you should therefore ensure that it gives the same
results each time.

unsafeDupablePerformIO :: IO a -> a

        TODO: Actually, unsafeDupableInterleaveIO is not yet documented,
        that will have to be fixed.
        
unsafeDupableInterleaveIO :: IO a -> IO a

This variant of 'unsafePerformIO' is quite /mind-bogglingly unsafe/. It
unstitches the dependency chain that holds the IO monad together and
breaks all your ordinary intuitions about IO, sequencing and side
effects. Avoid it unless you really know what you are doing.

It is only safe for operations which are genuinely pure (not just
externally pure) for example reading from an immutable foreign data
structure. In particular, you should do no memory allocation inside an
'unsafeInlinePerformIO' block. This is because an allocation is a
constant and is likely to be floated out and shared. More generally, any
part of any IO action that does not depend on a function argument is
likely to be floated to the top level and have its result shared.

It is more efficient because in addition to the checks that
'unsafeDupablePerformIO' omits, we also inline. Additionally we do not
pretend that the body is lazy which allows the strictness analyser to
see the strictness in the body. In turn this allows some re-ordering of
operations and any corresponding side-effects.

With GHC it compiles to essentially no code and it exposes the body to
further inlining.

unsafeInlinePerformIO :: IO a -> a



More information about the Libraries mailing list