summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/IO/Unsafe.hs
diff options
context:
space:
mode:
authorDavid Feuer <david.feuer@gmail.com>2017-03-22 17:25:03 -0400
committerDavid Feuer <David.Feuer@gmail.com>2017-03-22 17:29:26 -0400
commit30d68d630c1685bb81ec4afdaf6d483ba8aafd38 (patch)
tree0a99cd62c6f131a6e086fede441d6262debaee11 /libraries/base/GHC/IO/Unsafe.hs
parentacd85ce97accb8fac10b1191c30da9bfd507c857 (diff)
downloadhaskell-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.hs16
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