1 % -----------------------------------------------------------------------------
2 % $Id: PrelIOBase.lhs,v 1.13 1999/09/19 19:12:41 sof Exp $
4 % (c) The AQUA Project, Glasgow University, 1994-1998
7 \section[PrelIOBase]{Module @PrelIOBase@}
9 Definitions for the @IO@ monad and its friends. Everything is exported
10 concretely; the @IO@ module itself exports abstractly.
13 {-# OPTIONS -fno-implicit-prelude -#include "cbits/stgio.h" #-}
14 #include "cbits/error.h"
16 #ifndef __HUGS__ /* Hugs just includes this in PreludeBuiltin so no header needed */
17 module PrelIOBase where
19 import {-# SOURCE #-} PrelErr ( error )
23 import {-# SOURCE #-} PrelException ( ioError )
24 import PrelST ( ST(..), STret(..) )
25 import PrelMaybe ( Maybe(..) )
26 import PrelAddr ( Addr(..), nullAddr )
27 import PrelPack ( unpackCString )
30 #if !defined(__CONCURRENT_HASKELL__)
31 import PrelArr ( MutableVar, readVar )
36 #define __CONCURRENT_HASKELL__
38 #define unpackCString primUnpackString
41 #ifndef __PARALLEL_HASKELL__
42 #define FILE_OBJECT ForeignObj
44 #define FILE_OBJECT Addr
48 %*********************************************************
50 \subsection{The @IO@ monad}
52 %*********************************************************
54 The IO Monad is just an instance of the ST monad, where the state is
55 the real world. We use the exception mechanism (in PrelException) to
56 implement IO exceptions.
60 newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
62 unIO :: IO a -> (State# RealWorld -> (# State# RealWorld, a #))
65 instance Functor IO where
66 fmap f x = x >>= (return . f)
68 instance Monad IO where
72 m >> k = m >>= \ _ -> k
73 return x = IO $ \ s -> (# s, x #)
76 fail s = error s -- not ioError?
78 -- not required but worth having around
79 fixIO :: (a -> IO a) -> IO a
80 fixIO m = stToIO (fixST (ioToST . m))
82 liftIO :: IO a -> State# RealWorld -> STret RealWorld a
83 liftIO (IO m) = \s -> case m s of (# s', r #) -> STret s' r
85 bindIO :: IO a -> (a -> IO b) -> IO b
86 bindIO (IO m) k = IO ( \ s ->
88 (# new_s, a #) -> unIO (k a) new_s
94 %*********************************************************
96 \subsection{Coercions to @ST@}
98 %*********************************************************
102 /* Hugs doesn't distinguish these types so no coercion required) */
104 stToIO :: ST RealWorld a -> IO a
105 stToIO (ST m) = (IO m)
107 ioToST :: IO a -> ST RealWorld a
108 ioToST (IO m) = (ST m)
112 %*********************************************************
114 \subsection{Unsafe @IO@ operations}
116 %*********************************************************
120 {-# NOINLINE unsafePerformIO #-}
121 unsafePerformIO :: IO a -> a
122 unsafePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
124 unsafeInterleaveIO :: IO a -> IO a
125 unsafeInterleaveIO = stToIO . unsafeInterleaveST . ioToST
129 %*********************************************************
131 \subsection{Type @IOError@}
133 %*********************************************************
135 A value @IOError@ encode errors occurred in the @IO@ monad.
136 An @IOError@ records a more specific error type, a descriptive
137 string and maybe the handle that was used when the error was
143 (Maybe Handle) -- the handle used by the action flagging the
145 IOErrorType -- what it was.
147 String -- error type specific information.
151 = AlreadyExists | HardwareFault
152 | IllegalOperation | InappropriateType
153 | Interrupted | InvalidArgument
154 | NoSuchThing | OtherError
155 | PermissionDenied | ProtocolError
156 | ResourceBusy | ResourceExhausted
157 | ResourceVanished | SystemError
158 | TimeExpired | UnsatisfiedConstraints
159 | UnsupportedOperation | UserError
162 | ComError Int -- HRESULT
166 instance Show IOErrorType where
170 AlreadyExists -> "already exists"
171 HardwareFault -> "hardware fault"
172 IllegalOperation -> "illegal operation"
173 InappropriateType -> "inappropriate type"
174 Interrupted -> "interrupted"
175 InvalidArgument -> "invalid argument"
176 NoSuchThing -> "does not exist"
177 OtherError -> "failed"
178 PermissionDenied -> "permission denied"
179 ProtocolError -> "protocol error"
180 ResourceBusy -> "resource busy"
181 ResourceExhausted -> "resource exhausted"
182 ResourceVanished -> "resource vanished"
183 SystemError -> "system error"
184 TimeExpired -> "timeout"
185 UnsatisfiedConstraints -> "unsatisified constraints" -- ultra-precise!
186 UserError -> "failed"
187 UnsupportedOperation -> "unsupported operation"
190 ComError _ -> "COM error"
195 userError :: String -> IOError
196 userError str = IOError Nothing UserError "" str
199 Predicates on IOError; little effort made on these so far...
203 isAlreadyExistsError :: IOError -> Bool
204 isAlreadyExistsError (IOError _ AlreadyExists _ _) = True
205 isAlreadyExistsError _ = False
207 isAlreadyInUseError :: IOError -> Bool
208 isAlreadyInUseError (IOError _ ResourceBusy _ _) = True
209 isAlreadyInUseError _ = False
211 isFullError :: IOError -> Bool
212 isFullError (IOError _ ResourceExhausted _ _) = True
213 isFullError _ = False
215 isEOFError :: IOError -> Bool
216 isEOFError (IOError _ EOF _ _) = True
219 isIllegalOperation :: IOError -> Bool
220 isIllegalOperation (IOError _ IllegalOperation _ _) = True
221 isIllegalOperation _ = False
223 isPermissionError :: IOError -> Bool
224 isPermissionError (IOError _ PermissionDenied _ _) = True
225 isPermissionError _ = False
227 isDoesNotExistError :: IOError -> Bool
228 isDoesNotExistError (IOError _ NoSuchThing _ _) = True
229 isDoesNotExistError _ = False
231 isUserError :: IOError -> Bool
232 isUserError (IOError _ UserError _ _) = True
233 isUserError _ = False
240 -- For now we give a fairly uninformative error message which just happens to
241 -- be like the ones that Hugs used to give.
242 instance Show IOError where
243 showsPrec p (IOError hdl iot loc s) = showString s . showChar '\n'
245 instance Show IOError where
246 showsPrec p (IOError hdl iot loc s) =
251 _ -> showString "Action: " . showString loc . showChar '\n') .
255 _ -> showString "Reason: " . showString s)
260 Just h -> showString "Handle: " . showsPrec p h
265 The @String@ part of an @IOError@ is platform-dependent. However, to
266 provide a uniform mechanism for distinguishing among errors within
267 these broad categories, each platform-specific standard shall specify
268 the exact strings to be used for particular errors. For errors not
269 explicitly mentioned in the standard, any descriptive string may be
273 constructErrorAndFail :: String -> IO a
274 constructErrorAndFail call_site
275 = constructError call_site >>= \ io_error ->
278 constructErrorAndFailWithInfo :: String -> String -> IO a
279 constructErrorAndFailWithInfo call_site reason
280 = constructErrorMsg call_site (Just reason) >>= \ io_error ->
285 This doesn't seem to be documented/spelled out anywhere,
288 The implementation of the IO prelude uses various C stubs
289 to do the actual interaction with the OS. The bandwidth
290 \tr{C<->Haskell} is somewhat limited, so the general strategy
291 for flaggging any errors (apart from possibly using the
292 return code of the external call), is to set the @ghc_errtype@
293 to a value that is one of the \tr{#define}s in @includes/error.h@.
294 @ghc_errstr@ holds a character string providing error-specific
295 information. Error constructing functions will then reach out
296 and grab these values when generating
299 constructError :: String -> IO IOError
300 constructError call_site = constructErrorMsg call_site Nothing
302 constructErrorMsg :: String -> Maybe String -> IO IOError
303 constructErrorMsg call_site reason =
304 getErrType__ >>= \ errtype ->
305 getErrStr__ >>= \ str ->
308 case (errtype::Int) of
309 ERR_ALREADYEXISTS -> AlreadyExists
310 ERR_HARDWAREFAULT -> HardwareFault
311 ERR_ILLEGALOPERATION -> IllegalOperation
312 ERR_INAPPROPRIATETYPE -> InappropriateType
313 ERR_INTERRUPTED -> Interrupted
314 ERR_INVALIDARGUMENT -> InvalidArgument
315 ERR_NOSUCHTHING -> NoSuchThing
316 ERR_OTHERERROR -> OtherError
317 ERR_PERMISSIONDENIED -> PermissionDenied
318 ERR_PROTOCOLERROR -> ProtocolError
319 ERR_RESOURCEBUSY -> ResourceBusy
320 ERR_RESOURCEEXHAUSTED -> ResourceExhausted
321 ERR_RESOURCEVANISHED -> ResourceVanished
322 ERR_SYSTEMERROR -> SystemError
323 ERR_TIMEEXPIRED -> TimeExpired
324 ERR_UNSATISFIEDCONSTRAINTS -> UnsatisfiedConstraints
325 ERR_UNSUPPORTEDOPERATION -> UnsupportedOperation
332 OtherError -> "(error code: " ++ show errtype ++ ")"
338 return (IOError Nothing iot call_site msg)
341 File names are specified using @FilePath@, a OS-dependent
342 string that (hopefully, I guess) maps to an accessible file/object.
345 type FilePath = String
348 %*********************************************************
350 \subsection{Types @Handle@, @Handle__@}
352 %*********************************************************
354 The type for @Handle@ is defined rather than in @IOHandle@
355 module, as the @IOError@ type uses it..all operations over
356 a handles reside in @IOHandle@.
362 Sigh, the MVar ops in ConcBase depend on IO, the IO
363 representation here depend on MVars for handles (when
364 compiling in a concurrent way). Break the cycle by having
365 the definition of MVars go here:
368 data MVar a = MVar (MVar# RealWorld a)
371 Double sigh - ForeignObj is needed here too to break a cycle.
373 data ForeignObj = ForeignObj ForeignObj# -- another one
374 instance CCallable ForeignObj
375 instance CCallable ForeignObj#
376 #endif /* ndef __HUGS__ */
378 #if defined(__CONCURRENT_HASKELL__)
379 newtype Handle = Handle (MVar Handle__)
381 newtype Handle = Handle (MutableVar RealWorld Handle__)
385 A Handle is represented by (a reference to) a record
386 containing the state of the I/O port/device. We record
387 the following pieces of info:
389 * type (read,write,closed etc.)
390 * pointer to the external file object.
392 * user-friendly name (usually the
393 FilePath used when IO.openFile was called)
395 Note: when a Handle is garbage collected, we want to flush its buffer
396 and close the OS file handle, so as to free up a (precious) resource.
400 haFO__ :: FILE_OBJECT,
401 haType__ :: Handle__Type,
402 haBufferMode__ :: BufferMode,
403 haFilePath__ :: FilePath
407 Internally, we classify handles as being one
411 = ErrorHandle IOError
420 -- handle types are 'show'ed when printing error msgs, so
421 -- we provide a more user-friendly Show instance for it
422 -- than the derived one.
423 instance Show Handle__Type where
426 ErrorHandle iot -> showString "error " . showsPrec p iot
427 ClosedHandle -> showString "closed"
428 SemiClosedHandle -> showString "semi-closed"
429 ReadHandle -> showString "readable"
430 WriteHandle -> showString "writeable"
431 AppendHandle -> showString "writeable (append)"
432 ReadWriteHandle -> showString "read-writeable"
434 instance Show Handle where
435 showsPrec p (Handle h) =
437 #if defined(__CONCURRENT_HASKELL__)
439 hdl_ = unsafePerformIO (primTakeMVar h)
441 -- (Big) SIGH: unfolded defn of takeMVar to avoid
442 -- an (oh-so) unfortunate module loop with PrelConc.
443 hdl_ = unsafePerformIO (IO $ \ s# ->
444 case h of { MVar h# ->
445 case takeMVar# h# s# of { (# s2# , r #) ->
449 hdl_ = unsafePerformIO (stToIO (readVar h))
453 showHdl (haType__ hdl_)
454 (showString "loc=" . showString (haFilePath__ hdl_) . showChar ',' .
455 showString "type=" . showsPrec p (haType__ hdl_) . showChar ',' .
456 showString "buffering=" . showBufMode (haFO__ hdl_) (haBufferMode__ hdl_) . showString "}\n" )
458 showHdl :: Handle__Type -> ShowS -> ShowS
461 ClosedHandle -> showsPrec p ht . showString "}\n"
462 ErrorHandle _ -> showsPrec p ht . showString "}\n"
465 showBufMode :: FILE_OBJECT -> BufferMode -> ShowS
468 NoBuffering -> showString "none"
469 LineBuffering -> showString "line"
470 BlockBuffering (Just n) -> showString "block " . showParen True (showsPrec p n)
471 BlockBuffering Nothing -> showString "block " . showParen True (showsPrec p def)
474 def = unsafePerformIO (getBufSize fo)
476 mkBuffer__ :: FILE_OBJECT -> Int -> IO ()
477 mkBuffer__ fo sz_in_bytes = do
480 0 -> return nullAddr -- this has the effect of overwriting the pointer to the old buffer.
482 chunk <- allocMemory__ sz_in_bytes
484 then ioError (IOError Nothing ResourceExhausted "mkBuffer__" "not enough virtual memory")
486 setBuf fo chunk sz_in_bytes
490 %*********************************************************
492 \subsection[BufferMode]{Buffering modes}
494 %*********************************************************
496 Three kinds of buffering are supported: line-buffering,
497 block-buffering or no-buffering. These modes have the following
498 effects. For output, items are written out from the internal
499 buffer according to the buffer mode:
502 \item[line-buffering] the entire output buffer is written
503 out whenever a newline is output, the output buffer overflows,
504 a flush is issued, or the handle is closed.
506 \item[block-buffering] the entire output buffer is written out whenever
507 it overflows, a flush is issued, or the handle
510 \item[no-buffering] output is written immediately, and never stored
511 in the output buffer.
514 The output buffer is emptied as soon as it has been written out.
516 Similarly, input occurs according to the buffer mode for handle {\em hdl}.
518 \item[line-buffering] when the input buffer for {\em hdl} is not empty,
519 the next item is obtained from the buffer;
520 otherwise, when the input buffer is empty,
521 characters up to and including the next newline
522 character are read into the buffer. No characters
523 are available until the newline character is
525 \item[block-buffering] when the input buffer for {\em hdl} becomes empty,
526 the next block of data is read into this buffer.
527 \item[no-buffering] the next input item is read and returned.
530 For most implementations, physical files will normally be block-buffered
531 and terminals will normally be line-buffered. (the IO interface provides
532 operations for changing the default buffering of a handle tho.)
536 = NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
537 deriving (Eq, Ord, Show)
538 {- Read instance defined in IO. -}
542 Foreign import declarations to helper routines:
545 foreign import "libHS_cbits" "getErrStr__" unsafe getErrStr__ :: IO Addr
546 foreign import "libHS_cbits" "getErrNo__" unsafe getErrNo__ :: IO Int
547 foreign import "libHS_cbits" "getErrType__" unsafe getErrType__ :: IO Int
549 foreign import "libHS_cbits" "allocMemory__" unsafe
550 allocMemory__ :: Int -> IO Addr
551 foreign import "libHS_cbits" "getBufSize" unsafe
552 getBufSize :: FILE_OBJECT -> IO Int
553 foreign import "libHS_cbits" "setBuf" unsafe
554 setBuf :: FILE_OBJECT -> Addr -> Int -> IO ()