[project @ 2005-09-01 10:49:07 by ross]
[haskell-directory.git] / GHC / IOBase.lhs
index 84a2d84..f0ce8de 100644 (file)
@@ -1,5 +1,5 @@
 \begin{code}
-{-# OPTIONS -fno-implicit-prelude #-}
+{-# OPTIONS_GHC -fno-implicit-prelude #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  GHC.IOBase
 --
 -----------------------------------------------------------------------------
 
-module GHC.IOBase where
-
+-- #hide
+module GHC.IOBase(
+    IO(..), unIO, failIO, liftIO, bindIO, thenIO, returnIO, 
+    unsafePerformIO, unsafeInterleaveIO,
+  
+       -- To and from from ST
+    stToIO, ioToST, unsafeIOToST,
+
+       -- References
+    IORef(..), newIORef, readIORef, writeIORef, 
+    IOArray(..), newIOArray, readIOArray, writeIOArray, unsafeReadIOArray, unsafeWriteIOArray,
+    MVar(..),
+
+       -- Handles, file descriptors,
+    FilePath,  
+    Handle(..), Handle__(..), HandleType(..), IOMode(..), FD, 
+    isReadableHandleType, isWritableHandleType, isReadWriteHandleType, showHandle,
+  
+       -- Buffers
+    Buffer(..), RawBuffer, BufferState(..), BufferList(..), BufferMode(..),
+    bufferIsWritable, bufferEmpty, bufferFull, 
+
+       -- Exceptions
+    Exception(..), ArithException(..), AsyncException(..), ArrayException(..),
+    stackOverflow, heapOverflow, throw, throwIO, ioException, 
+    IOError, IOException(..), IOErrorType(..), ioError, userError,
+    ExitCode(..) 
+  ) where
+       
 import GHC.ST
 import GHC.Arr -- to derive Ix class
 import GHC.Enum -- to derive Enum class
 import GHC.STRef
 import GHC.Base
-import GHC.Num -- To get fromInteger etc, needed because of -fno-implicit-prelude
+--  import GHC.Num     -- To get fromInteger etc, needed because of -fno-implicit-prelude
 import Data.Maybe  ( Maybe(..) )
 import GHC.Show
 import GHC.List
@@ -112,13 +139,22 @@ returnIO x = IO (\ s -> (# s, x #))
 -- ---------------------------------------------------------------------------
 -- Coercions between IO and ST
 
---stToIO        :: (forall s. ST s a) -> IO a
+-- | A monad transformer embedding strict state transformers in the 'IO'
+-- monad.  The 'RealWorld' parameter indicates that the internal state
+-- used by the 'ST' computation is a special one supplied by the 'IO'
+-- monad, and thus distinct from those used by invocations of 'runST'.
 stToIO       :: ST RealWorld a -> IO a
 stToIO (ST m) = IO m
 
 ioToST       :: IO a -> ST RealWorld a
 ioToST (IO m) = (ST m)
 
+-- This relies on IO and ST having the same representation modulo the
+-- constraint on the type of the state
+--
+unsafeIOToST        :: IO a -> ST s a
+unsafeIOToST (IO io) = ST $ \ s -> (unsafeCoerce# io) s
+
 -- ---------------------------------------------------------------------------
 -- Unsafe IO operations
 
@@ -164,7 +200,7 @@ It is less well known that
 >     
 >     main = do
 >            writeIORef test [42]
->            bang \<- readIORef test
+>            bang <- readIORef test
 >            print (bang :: [Char])
 
 This program will core dump.  This problem with polymorphic references
@@ -178,13 +214,19 @@ help of 'unsafePerformIO'.  So be careful!
 unsafePerformIO        :: IO a -> a
 unsafePerformIO (IO m) = case m realWorld# of (# _, r #)   -> r
 
+-- Why do we NOINLINE unsafePerformIO?  See the comment with
+-- GHC.ST.runST.  Essentially the issue is that the IO computation
+-- inside unsafePerformIO must be atomic: it must either all run, or
+-- not at all.  If we let the compiler see the application of the IO
+-- to realWorld#, it might float out part of the IO.
+
 {-|
 'unsafeInterleaveIO' allows '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'.
 -}
-{-# NOINLINE unsafeInterleaveIO #-}
+{-# INLINE unsafeInterleaveIO #-}
 unsafeInterleaveIO :: IO a -> IO a
 unsafeInterleaveIO (IO m)
   = IO ( \ s -> let
@@ -192,6 +234,10 @@ unsafeInterleaveIO (IO m)
                in
                (# s, r #))
 
+-- We believe that INLINE on unsafeInterleaveIO is safe, because the
+-- state from this IO thread is passed explicitly to the interleaved
+-- IO, so it cannot be floated out and shared.
+
 -- ---------------------------------------------------------------------------
 -- Handle type
 
@@ -247,6 +293,15 @@ instance Eq (MVar a) where
 -- enough information to identify the handle for debugging.  A handle is
 -- equal according to '==' only to itself; no attempt
 -- is made to compare the internal state of different handles for equality.
+--
+-- GHC note: a 'Handle' will be automatically closed when the garbage
+-- collector detects that it has become unreferenced by the program.
+-- However, relying on this behaviour is not generally recommended:
+-- the garbage collector is unpredictable.  If possible, use explicit
+-- an explicit 'hClose' to close 'Handle's when they are no longer
+-- required.  GHC does not currently attempt to free up file
+-- descriptors when they have run out, it is your responsibility to
+-- ensure that this doesn't happen.
 
 data Handle 
   = FileHandle                         -- A normal handle to a file
@@ -368,6 +423,9 @@ isWritableHandleType WriteHandle     = True
 isWritableHandleType ReadWriteHandle = True
 isWritableHandleType _              = False
 
+isReadWriteHandleType ReadWriteHandle{} = True
+isReadWriteHandleType _                 = False
+
 -- | File and directory names are values of type 'String', whose precise
 -- meaning is operating system dependent. Files can be opened, yielding a
 -- handle which can then be used to operate on the contents of that file.
@@ -396,7 +454,7 @@ type FilePath = String
 -- but not less frequently, than specified above.
 -- The output buffer is emptied as soon as it has been written out.
 --
--- Similarly, input occurs according to the buffer mode for handle {\em hdl}.
+-- Similarly, input occurs according to the buffer mode for the handle:
 --
 --  * /line-buffering/: when the buffer for the handle is not empty,
 --    the next item is obtained from the buffer; otherwise, when the
@@ -408,8 +466,8 @@ type FilePath = String
 --    the next block of data is read into the buffer.
 --
 --  * /no-buffering/: the next input item is read and returned.
---    The 'hLookAhead' operation implies that even a no-buffered handle
---    may require a one-character buffer.
+--    The 'System.IO.hLookAhead' operation implies that even a no-buffered
+--    handle may require a one-character buffer.
 --
 -- The default buffering mode when a handle is opened is
 -- implementation-dependent and may depend on the file system object
@@ -518,7 +576,8 @@ showHandle file = showString "{handle: " . showString file . showString "}"
 -- |The type of exceptions.  Every kind of system-generated exception
 -- has a constructor in the 'Exception' type, and values of other
 -- types may be injected into 'Exception' by coercing them to
--- 'Dynamic' (see the section on Dynamic Exceptions: "Control.Exception\#DynamicExceptions").
+-- 'Data.Dynamic.Dynamic' (see the section on Dynamic Exceptions:
+-- "Control.Exception\#DynamicExceptions").
 data Exception
   = ArithException     ArithException
        -- ^Exceptions raised by arithmetic
@@ -537,8 +596,12 @@ data Exception
        -- ^Asynchronous exceptions (see section on Asynchronous Exceptions: "Control.Exception\#AsynchronousExceptions").
   | BlockedOnDeadMVar
        -- ^The current thread was executing a call to
-       -- 'takeMVar' that could never return, because there are no other
-       -- references to this 'MVar'.
+       -- 'Control.Concurrent.MVar.takeMVar' that could never return,
+       -- because there are no other references to this 'MVar'.
+  | BlockedIndefinitely
+       -- ^The current thread was waiting to retry an atomic memory transaction
+       -- that could never become possible to complete because there are no other
+       -- threads referring to any of teh TVars involved.
   | Deadlock
        -- ^There are no runnable threads, so the program is
        -- deadlocked.  The 'Deadlock' exception is
@@ -676,6 +739,7 @@ instance Show Exception where
   showsPrec _ (DynException _err)        = showString "unknown exception"
   showsPrec _ (AsyncException e)        = shows e
   showsPrec _ (BlockedOnDeadMVar)       = showString "thread blocked indefinitely"
+  showsPrec _ (BlockedIndefinitely)     = showString "thread blocked indefinitely"
   showsPrec _ (NonTermination)           = showString "<<loop>>"
   showsPrec _ (Deadlock)                 = showString "<<deadlock>>"
 
@@ -701,18 +765,17 @@ instance Eq Exception where
 -- -----------------------------------------------------------------------------
 -- The ExitCode type
 
--- The `ExitCode' type defines the exit codes that a program
--- can return.  `ExitSuccess' indicates successful termination;
--- and `ExitFailure code' indicates program failure
--- with value `code'.  The exact interpretation of `code'
--- is operating-system dependent.  In particular, some values of 
--- `code' may be prohibited (e.g. 0 on a POSIX-compliant system).
-
 -- We need it here because it is used in ExitException in the
 -- Exception datatype (above).
 
-data ExitCode = ExitSuccess | ExitFailure Int 
-                deriving (Eq, Ord, Read, Show)
+data ExitCode
+  = ExitSuccess        -- ^ indicates successful termination;
+  | ExitFailure Int
+               -- ^ indicates program failure with an exit code.
+               -- The exact interpretation of the code is
+               -- operating-system dependent.  In particular, some values
+               -- may be prohibited (e.g. 0 on a POSIX-compliant system).
+  deriving (Eq, Ord, Read, Show)
 
 -- --------------------------------------------------------------------------
 -- Primitive throw
@@ -743,13 +806,18 @@ throwIO err       =  IO $ raiseIO# err
 ioException    :: IOException -> IO a
 ioException err =  IO $ raiseIO# (IOException err)
 
+-- | Raise an 'IOError' in the 'IO' monad.
 ioError         :: IOError -> IO a 
 ioError                =  ioException
 
 -- ---------------------------------------------------------------------------
 -- IOError type
 
--- | The Haskell 98 type for exceptions in the @IO@ monad.
+-- | The Haskell 98 type for exceptions in the 'IO' monad.
+-- Any I\/O operation may raise an 'IOError' instead of returning a result.
+-- For a more general type of exception, including also those that arise
+-- in pure code, see 'Control.Exception.Exception'.
+--
 -- In Haskell 98, this is an opaque type.
 type IOError = IOException
 
@@ -771,6 +839,7 @@ instance Eq IOException where
   (IOError h1 e1 loc1 str1 fn1) == (IOError h2 e2 loc2 str2 fn2) = 
     e1==e2 && str1==str2 && h1==h2 && loc1==loc2 && fn1==fn2
 
+-- | An abstract type that contains a value for each variant of 'IOError'.
 data IOErrorType
   -- Haskell 98:
   = AlreadyExists
@@ -826,6 +895,14 @@ instance Show IOErrorType where
       UnsupportedOperation -> "unsupported operation"
       DynIOError{}      -> "unknown IO error"
 
+-- | Construct an 'IOError' value with a string describing the error.
+-- The 'fail' method of the 'IO' instance of the 'Monad' class raises a
+-- 'userError', thus:
+--
+-- > instance Monad IO where 
+-- >   ...
+-- >   fail s = ioError (userError s)
+--
 userError       :: String  -> IOError
 userError str  =  IOError Nothing UserError "" str Nothing