diff options
author | David Feuer <david.feuer@gmail.com> | 2017-03-22 17:25:03 -0400 |
---|---|---|
committer | David Feuer <David.Feuer@gmail.com> | 2017-03-22 17:29:26 -0400 |
commit | 30d68d630c1685bb81ec4afdaf6d483ba8aafd38 (patch) | |
tree | 0a99cd62c6f131a6e086fede441d6262debaee11 /libraries/base/GHC/IO/Unsafe.hs | |
parent | acd85ce97accb8fac10b1191c30da9bfd507c857 (diff) | |
download | haskell-30d68d630c1685bb81ec4afdaf6d483ba8aafd38.tar.gz |
Make unsafeInterleaveST less unsafe
* Make `unsafeInterleaveST` use `noDuplicate#` like
`unsafeInterleaveIO` does to prevent the suspended action from
being run in two threads.
* In order to accomplish this without `unsafeCoerce#`, generalize
the type of `noDuplicate#`.
* Add `unsafeDupableInterleaveST` to get the old behavior.
* Document unsafe `ST` functions and clean up some related
documentation.
Fixes #13457
Reviewers: austin, hvr, bgamari, ekmett
Reviewed By: bgamari
Subscribers: rwbarton, thomie
Differential Revision: https://phabricator.haskell.org/D3370
Diffstat (limited to 'libraries/base/GHC/IO/Unsafe.hs')
-rw-r--r-- | libraries/base/GHC/IO/Unsafe.hs | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/libraries/base/GHC/IO/Unsafe.hs b/libraries/base/GHC/IO/Unsafe.hs index 752353515e..c1c07ae2df 100644 --- a/libraries/base/GHC/IO/Unsafe.hs +++ b/libraries/base/GHC/IO/Unsafe.hs @@ -104,7 +104,7 @@ unsafeDupablePerformIO :: IO a -> a unsafeDupablePerformIO (IO m) = case runRW# m of (# _, a #) -> a {-| -'unsafeInterleaveIO' allows 'IO' computation to be deferred lazily. +'unsafeInterleaveIO' allows an 'IO' computation to be deferred lazily. When passed a value of type @IO a@, the 'IO' will only be performed when the value of the @a@ is demanded. This is used to implement lazy file reading, see 'System.IO.hGetContents'. @@ -113,6 +113,9 @@ file reading, see 'System.IO.hGetContents'. unsafeInterleaveIO :: IO a -> IO a unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m) +-- Note [unsafeDupableInterleaveIO should not be inlined] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- -- We used to believe that INLINE on unsafeInterleaveIO was safe, -- because the state from this IO thread is passed explicitly to the -- interleaved IO, so it cannot be floated out and shared. @@ -131,7 +134,18 @@ unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m) -- share and sometimes not (plus it probably breaks the noDuplicate). -- So now, we do not inline unsafeDupableInterleaveIO. +{-| +'unsafeDupableInterleaveIO' allows an 'IO' computation to be deferred lazily. +When passed a value of type @IO a@, the 'IO' will only be performed +when the value of the @a@ is demanded. + +The computation may be performed multiple times by different threads, +possibly at the same time. To ensure that the computation is performed +only once, use 'unsafeInterleaveIO' instead. +-} + {-# NOINLINE unsafeDupableInterleaveIO #-} +-- See Note [unsafeDupableInterleaveIO should not be inlined] unsafeDupableInterleaveIO :: IO a -> IO a unsafeDupableInterleaveIO (IO m) = IO ( \ s -> let |