1 % -----------------------------------------------------------------------------
2 % $Id: PrelIOBase.lhs,v 1.6 1998/12/02 13:27:03 simonm 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 ( fail )
24 import PrelST ( ST(..), STret(..) )
25 import PrelMaybe ( Maybe(..) )
26 import PrelAddr ( Addr(..), nullAddr )
27 import PrelPack ( unpackCString )
28 import PrelArr ( MutableVar, readVar )
32 #define cat2(x,y) x/**/y
33 #define CCALL(fun) cat2(prim_,fun)
34 #define __CONCURRENT_HASKELL__
36 #define unpackCString primUnpackString
38 #define CCALL(fun) _ccall_ fun
39 #define ref_freeStdFileObject (``&freeStdFileObject''::Addr)
42 #ifndef __PARALLEL_HASKELL__
43 #define FILE_OBJECT ForeignObj
45 #define FILE_OBJECT Addr
49 %*********************************************************
51 \subsection{The @IO@ monad}
53 %*********************************************************
55 The IO Monad is just an instance of the ST monad, where the state is
56 the real world. We use the exception mechanism (in PrelException) to
57 implement IO exceptions.
61 newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
65 instance Functor IO where
66 map f x = x >>= (return . f)
68 instance Monad IO where
72 m >> k = m >>= \ _ -> k
73 return x = IO $ \ s -> (# s, x #)
77 -- not required but worth having around
78 fixIO :: (a -> IO a) -> IO a
79 fixIO m = stToIO (fixST (ioToST . m))
81 liftIO :: IO a -> State# RealWorld -> STret RealWorld a
82 liftIO (IO m) = \s -> case m s of (# s', r #) -> STret s' r
84 bindIO :: IO a -> (a -> IO b) -> IO b
85 bindIO (IO m) k = IO ( \ s ->
87 (# new_s, a #) -> unIO (k a) new_s
93 %*********************************************************
95 \subsection{Coercions to @ST@}
97 %*********************************************************
101 /* Hugs doesn't distinguish these types so no coercion required) */
103 stToIO :: ST RealWorld a -> IO a
104 stToIO (ST m) = (IO m)
106 ioToST :: IO a -> ST RealWorld a
107 ioToST (IO m) = (ST m)
111 %*********************************************************
113 \subsection{Utility functions}
115 %*********************************************************
117 I'm not sure why this little function is here...
120 --fputs :: Addr{-FILE*-} -> String -> IO Bool
122 userError :: String -> IOError
123 userError str = IOError Nothing (UserError Nothing) "" str
126 fputs stream (c : cs)
127 = CCALL(filePutc) stream c >>
132 %*********************************************************
134 \subsection{Unsafe @IO@ operations}
136 %*********************************************************
140 {-# NOINLINE unsafePerformIO #-}
141 unsafePerformIO :: IO a -> a
142 unsafePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
144 unsafeInterleaveIO :: IO a -> IO a
145 unsafeInterleaveIO = stToIO . unsafeInterleaveST . ioToST
149 %*********************************************************
151 \subsection{Type @IOError@}
153 %*********************************************************
155 A value @IOError@ encode errors occurred in the @IO@ monad.
156 An @IOError@ records a more specific error type, a descriptive
157 string and maybe the handle that was used when the error was
163 (Maybe Handle) -- the handle used by the action flagging the
165 IOErrorType -- what it was.
167 String -- error type specific information.
171 = AlreadyExists | HardwareFault
172 | IllegalOperation | InappropriateType
173 | Interrupted | InvalidArgument
174 | NoSuchThing | OtherError
175 | PermissionDenied | ProtocolError
176 | ResourceBusy | ResourceExhausted
177 | ResourceVanished | SystemError
178 | TimeExpired | UnsatisfiedConstraints
179 | UnsupportedOperation | UserError (Maybe Addr)
183 instance Show IOErrorType where
187 AlreadyExists -> "already exists"
188 HardwareFault -> "hardware fault"
189 IllegalOperation -> "illegal operation"
190 InappropriateType -> "inappropriate type"
191 Interrupted -> "interrupted"
192 InvalidArgument -> "invalid argument"
193 NoSuchThing -> "does not exist"
194 OtherError -> "failed"
195 PermissionDenied -> "permission denied"
196 ProtocolError -> "protocol error"
197 ResourceBusy -> "resource busy"
198 ResourceExhausted -> "resource exhausted"
199 ResourceVanished -> "resource vanished"
200 SystemError -> "system error"
201 TimeExpired -> "timeout"
202 UnsatisfiedConstraints -> "unsatisified constraints" -- ultra-precise!
203 UserError _ -> "failed"
208 Predicates on IOError; little effort made on these so far...
212 isAlreadyExistsError (IOError _ AlreadyExists _ _) = True
213 isAlreadyExistsError _ = False
215 isAlreadyInUseError (IOError _ ResourceBusy _ _) = True
216 isAlreadyInUseError _ = False
218 isFullError (IOError _ ResourceExhausted _ _) = True
219 isFullError _ = False
221 isEOFError (IOError _ EOF _ _) = True
224 isIllegalOperation (IOError _ IllegalOperation _ _) = True
225 isIllegalOperation _ = False
227 isPermissionError (IOError _ PermissionDenied _ _) = True
228 isPermissionError _ = False
230 isDoesNotExistError (IOError _ NoSuchThing _ _) = True
231 isDoesNotExistError _ = False
233 isUserError (IOError _ (UserError _) _ _) = True
234 isUserError _ = False
241 -- For now we give a fairly uninformative error message which just happens to
242 -- be like the ones that Hugs used to give.
243 instance Show IOError where
244 showsPrec p (IOError hdl iot loc s) = showString s . showChar '\n'
246 instance Show IOError where
247 showsPrec p (IOError hdl iot loc s) =
252 _ -> showString "Action: " . showString loc . showChar '\n') .
256 _ -> showString "Reason: " . showString s)
261 Just h -> showString "Handle: " . showsPrec p h
266 The @String@ part of an @IOError@ is platform-dependent. However, to
267 provide a uniform mechanism for distinguishing among errors within
268 these broad categories, each platform-specific standard shall specify
269 the exact strings to be used for particular errors. For errors not
270 explicitly mentioned in the standard, any descriptive string may be
274 constructErrorAndFail :: String -> IO a
275 constructErrorAndFail call_site
276 = constructError call_site >>= \ io_error ->
279 constructErrorAndFailWithInfo :: String -> String -> IO a
280 constructErrorAndFailWithInfo call_site reason
281 = constructErrorMsg call_site (Just reason) >>= \ io_error ->
286 This doesn't seem to be documented/spelled out anywhere,
289 The implementation of the IO prelude uses various C stubs
290 to do the actual interaction with the OS. The bandwidth
291 \tr{C<->Haskell} is somewhat limited, so the general strategy
292 for flaggging any errors (apart from possibly using the
293 return code of the external call), is to set the @ghc_errtype@
294 to a value that is one of the \tr{#define}s in @includes/error.h@.
295 @ghc_errstr@ holds a character string providing error-specific
296 information. Error constructing functions will then reach out
297 and grab these values when generating
300 constructError :: String -> IO IOError
301 constructError call_site = constructErrorMsg call_site Nothing
303 constructErrorMsg :: String -> Maybe String -> IO IOError
304 constructErrorMsg call_site reason =
305 CCALL(getErrType__) >>= \ errtype ->
306 CCALL(getErrStr__) >>= \ str ->
310 ERR_ALREADYEXISTS -> AlreadyExists
311 ERR_HARDWAREFAULT -> HardwareFault
312 ERR_ILLEGALOPERATION -> IllegalOperation
313 ERR_INAPPROPRIATETYPE -> InappropriateType
314 ERR_INTERRUPTED -> Interrupted
315 ERR_INVALIDARGUMENT -> InvalidArgument
316 ERR_NOSUCHTHING -> NoSuchThing
317 ERR_OTHERERROR -> OtherError
318 ERR_PERMISSIONDENIED -> PermissionDenied
319 ERR_PROTOCOLERROR -> ProtocolError
320 ERR_RESOURCEBUSY -> ResourceBusy
321 ERR_RESOURCEEXHAUSTED -> ResourceExhausted
322 ERR_RESOURCEVANISHED -> ResourceVanished
323 ERR_SYSTEMERROR -> SystemError
324 ERR_TIMEEXPIRED -> TimeExpired
325 ERR_UNSATISFIEDCONSTRAINTS -> UnsatisfiedConstraints
326 ERR_UNSUPPORTEDOPERATION -> UnsupportedOperation
333 OtherError -> "(error code: " ++ show errtype ++ ")"
339 return (IOError Nothing iot call_site msg)
342 File names are specified using @FilePath@, a OS-dependent
343 string that (hopefully, I guess) maps to an accessible file/object.
346 type FilePath = String
349 %*********************************************************
351 \subsection{Types @Handle@, @Handle__@}
353 %*********************************************************
355 The type for @Handle@ is defined rather than in @IOHandle@
356 module, as the @IOError@ type uses it..all operations over
357 a handles reside in @IOHandle@.
363 Sigh, the MVar ops in ConcBase depend on IO, the IO
364 representation here depend on MVars for handles (when
365 compiling in a concurrent way). Break the cycle by having
366 the definition of MVars go here:
369 data MVar a = MVar (MVar# RealWorld a)
372 Double sigh - ForeignObj is needed here too to break a cycle.
374 data ForeignObj = ForeignObj ForeignObj# -- another one
375 instance CCallable ForeignObj
376 instance CCallable ForeignObj#
377 #endif /* ndef __HUGS__ */
379 #if defined(__CONCURRENT_HASKELL__)
380 newtype Handle = Handle (MVar Handle__)
382 newtype Handle = Handle (MutableVar RealWorld Handle__)
386 A Handle is represented by (a reference to) a record
387 containing the state of the I/O port/device. We record
388 the following pieces of info:
390 * type (read,write,closed etc.)
391 * pointer to the external file object.
393 * user-friendly name (usually the
394 FilePath used when IO.openFile was called)
396 Note: when a Handle is garbage collected, we want to flush its buffer
397 and close the OS file handle, so as to free up a (precious) resource.
401 haFO__ :: FILE_OBJECT,
402 haType__ :: Handle__Type,
403 haBufferMode__ :: BufferMode,
404 haFilePath__ :: FilePath
408 Internally, we classify handles as being one
412 = ErrorHandle IOError
421 -- handle types are 'show'ed when printing error msgs, so
422 -- we provide a more user-friendly Show instance for it
423 -- than the derived one.
424 instance Show Handle__Type where
427 ErrorHandle iot -> showString "error " . showsPrec p iot
428 ClosedHandle -> showString "closed"
429 SemiClosedHandle -> showString "semi-closed"
430 ReadHandle -> showString "readable"
431 WriteHandle -> showString "writeable"
432 AppendHandle -> showString "writeable (append)"
433 ReadWriteHandle -> showString "read-writeable"
435 instance Show Handle where
436 showsPrec p (Handle h) =
438 #if defined(__CONCURRENT_HASKELL__)
440 hdl_ = unsafePerformIO (primTakeMVar h)
442 -- (Big) SIGH: unfolded defn of takeMVar to avoid
443 -- an (oh-so) unfortunate module loop with PrelConc.
444 hdl_ = unsafePerformIO (IO $ \ s# ->
445 case h of { MVar h# ->
446 case takeMVar# h# s# of { (# s2# , r #) ->
450 hdl_ = unsafePerformIO (stToIO (readVar h))
454 showHdl (haType__ hdl_)
455 (showString "loc=" . showString (haFilePath__ hdl_) . showChar ',' .
456 showString "type=" . showsPrec p (haType__ hdl_) . showChar ',' .
457 showString "buffering=" . showBufMode (haFO__ hdl_) (haBufferMode__ hdl_) . showString "}\n" )
459 showHdl :: Handle__Type -> ShowS -> ShowS
462 ClosedHandle -> showsPrec p ht . showString "}\n"
463 ErrorHandle _ -> showsPrec p ht . showString "}\n"
466 showBufMode :: FILE_OBJECT -> BufferMode -> ShowS
469 NoBuffering -> showString "none"
470 LineBuffering -> showString "line"
471 BlockBuffering (Just n) -> showString "block " . showParen True (showsPrec p n)
472 BlockBuffering Nothing -> showString "block " . showParen True (showsPrec p def)
475 def = unsafePerformIO (CCALL(getBufSize) fo)
477 mkBuffer__ :: FILE_OBJECT -> Int -> IO ()
478 mkBuffer__ fo sz_in_bytes = do
481 0 -> return nullAddr -- this has the effect of overwriting the pointer to the old buffer.
483 chunk <- CCALL(allocMemory__) sz_in_bytes
485 then fail (IOError Nothing ResourceExhausted "mkBuffer__" "not enough virtual memory")
487 CCALL(setBuf) fo chunk sz_in_bytes
491 %*********************************************************
493 \subsection[BufferMode]{Buffering modes}
495 %*********************************************************
497 Three kinds of buffering are supported: line-buffering,
498 block-buffering or no-buffering. These modes have the following
499 effects. For output, items are written out from the internal
500 buffer according to the buffer mode:
503 \item[line-buffering] the entire output buffer is written
504 out whenever a newline is output, the output buffer overflows,
505 a flush is issued, or the handle is closed.
507 \item[block-buffering] the entire output buffer is written out whenever
508 it overflows, a flush is issued, or the handle
511 \item[no-buffering] output is written immediately, and never stored
512 in the output buffer.
515 The output buffer is emptied as soon as it has been written out.
517 Similarly, input occurs according to the buffer mode for handle {\em hdl}.
519 \item[line-buffering] when the input buffer for {\em hdl} is not empty,
520 the next item is obtained from the buffer;
521 otherwise, when the input buffer is empty,
522 characters up to and including the next newline
523 character are read into the buffer. No characters
524 are available until the newline character is
526 \item[block-buffering] when the input buffer for {\em hdl} becomes empty,
527 the next block of data is read into this buffer.
528 \item[no-buffering] the next input item is read and returned.
531 For most implementations, physical files will normally be block-buffered
532 and terminals will normally be line-buffered. (the IO interface provides
533 operations for changing the default buffering of a handle tho.)
537 = NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
538 deriving (Eq, Ord, Show)
539 {- Read instance defined in IO. -}