base: Kill out-of-date Notes
[ghc.git] / libraries / base / GHC / IO / Unsafe.hs
1 {-# LANGUAGE Unsafe #-}
2 {-# LANGUAGE NoImplicitPrelude
3 , MagicHash
4 , UnboxedTuples
5 #-}
6 {-# OPTIONS_HADDOCK hide #-}
7
8 -----------------------------------------------------------------------------
9 -- |
10 -- Module : GHC.IO.Unsafe
11 -- Copyright : (c) The University of Glasgow 1994-2002
12 -- License : see libraries/base/LICENSE
13 --
14 -- Maintainer : cvs-ghc@haskell.org
15 -- Stability : internal
16 -- Portability : non-portable (GHC Extensions)
17 --
18 -- Unsafe IO operations
19 --
20 -----------------------------------------------------------------------------
21
22 module GHC.IO.Unsafe (
23 unsafePerformIO, unsafeInterleaveIO,
24 unsafeDupablePerformIO, unsafeDupableInterleaveIO,
25 noDuplicate,
26 ) where
27
28 import GHC.Base
29
30
31 {-|
32 This is the \"back door\" into the 'IO' monad, allowing
33 'IO' computation to be performed at any time. For
34 this to be safe, the 'IO' computation should be
35 free of side effects and independent of its environment.
36
37 If the I\/O computation wrapped in 'unsafePerformIO' performs side
38 effects, then the relative order in which those side effects take
39 place (relative to the main I\/O trunk, or other calls to
40 'unsafePerformIO') is indeterminate. Furthermore, when using
41 'unsafePerformIO' to cause side-effects, you should take the following
42 precautions to ensure the side effects are performed as many times as
43 you expect them to be. Note that these precautions are necessary for
44 GHC, but may not be sufficient, and other compilers may require
45 different precautions:
46
47 * Use @{\-\# NOINLINE foo \#-\}@ as a pragma on any function @foo@
48 that calls 'unsafePerformIO'. If the call is inlined,
49 the I\/O may be performed more than once.
50
51 * Use the compiler flag @-fno-cse@ to prevent common sub-expression
52 elimination being performed on the module, which might combine
53 two side effects that were meant to be separate. A good example
54 is using multiple global variables (like @test@ in the example below).
55
56 * Make sure that the either you switch off let-floating (@-fno-full-laziness@), or that the
57 call to 'unsafePerformIO' cannot float outside a lambda. For example,
58 if you say:
59 @
60 f x = unsafePerformIO (newIORef [])
61 @
62 you may get only one reference cell shared between all calls to @f@.
63 Better would be
64 @
65 f x = unsafePerformIO (newIORef [x])
66 @
67 because now it can't float outside the lambda.
68
69 It is less well known that
70 'unsafePerformIO' is not type safe. For example:
71
72 > test :: IORef [a]
73 > test = unsafePerformIO $ newIORef []
74 >
75 > main = do
76 > writeIORef test [42]
77 > bang <- readIORef test
78 > print (bang :: [Char])
79
80 This program will core dump. This problem with polymorphic references
81 is well known in the ML community, and does not arise with normal
82 monadic use of references. There is no easy way to make it impossible
83 once you use 'unsafePerformIO'. Indeed, it is
84 possible to write @coerce :: a -> b@ with the
85 help of 'unsafePerformIO'. So be careful!
86 -}
87 unsafePerformIO :: IO a -> a
88 unsafePerformIO m = unsafeDupablePerformIO (noDuplicate >> m)
89
90 {-|
91 This version of 'unsafePerformIO' is more efficient
92 because it omits the check that the IO is only being performed by a
93 single thread. Hence, when you use 'unsafeDupablePerformIO',
94 there is a possibility that the IO action may be performed multiple
95 times (on a multiprocessor), and you should therefore ensure that
96 it gives the same results each time. It may even happen that one
97 of the duplicated IO actions is only run partially, and then interrupted
98 in the middle without an exception being raised. Therefore, functions
99 like 'bracket' cannot be used safely within 'unsafeDupablePerformIO'.
100
101 @since 4.4.0.0
102 -}
103 unsafeDupablePerformIO :: IO a -> a
104 unsafeDupablePerformIO (IO m) = case runRW# m of (# _, a #) -> a
105
106 {-|
107 'unsafeInterleaveIO' allows 'IO' computation to be deferred lazily.
108 When passed a value of type @IO a@, the 'IO' will only be performed
109 when the value of the @a@ is demanded. This is used to implement lazy
110 file reading, see 'System.IO.hGetContents'.
111 -}
112 {-# INLINE unsafeInterleaveIO #-}
113 unsafeInterleaveIO :: IO a -> IO a
114 unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m)
115
116 -- We used to believe that INLINE on unsafeInterleaveIO was safe,
117 -- because the state from this IO thread is passed explicitly to the
118 -- interleaved IO, so it cannot be floated out and shared.
119 --
120 -- HOWEVER, if the compiler figures out that r is used strictly here,
121 -- then it will eliminate the thunk and the side effects in m will no
122 -- longer be shared in the way the programmer was probably expecting,
123 -- but can be performed many times. In #5943, this broke our
124 -- definition of fixIO, which contains
125 --
126 -- ans <- unsafeInterleaveIO (takeMVar m)
127 --
128 -- after inlining, we lose the sharing of the takeMVar, so the second
129 -- time 'ans' was demanded we got a deadlock. We could fix this with
130 -- a readMVar, but it seems wrong for unsafeInterleaveIO to sometimes
131 -- share and sometimes not (plus it probably breaks the noDuplicate).
132 -- So now, we do not inline unsafeDupableInterleaveIO.
133
134 {-# NOINLINE unsafeDupableInterleaveIO #-}
135 unsafeDupableInterleaveIO :: IO a -> IO a
136 unsafeDupableInterleaveIO (IO m)
137 = IO ( \ s -> let
138 r = case m s of (# _, res #) -> res
139 in
140 (# s, r #))
141
142 {-|
143 Ensures that the suspensions under evaluation by the current thread
144 are unique; that is, the current thread is not evaluating anything
145 that is also under evaluation by another thread that has also executed
146 'noDuplicate'.
147
148 This operation is used in the definition of 'unsafePerformIO' to
149 prevent the IO action from being executed multiple times, which is usually
150 undesirable.
151 -}
152 noDuplicate :: IO ()
153 noDuplicate = IO $ \s -> case noDuplicate# s of s' -> (# s', () #)