2 % (c) The GRASP/AQUA Project, Glasgow University, 1995
4 \section[LibPosixIO]{Haskell 1.3 POSIX Input/Output Primitives}
31 createPipe :: IO (Channel, Channel)
33 allocChars ``(2*sizeof(int))'' `thenStrictlyST` \ bytes ->
34 _casm_ ``%r = pipe((int *)%0);'' bytes `thenPrimIO` \ rc ->
36 _casm_ ``%r = ((int *)%0)[0];'' bytes `thenPrimIO` \ wd ->
37 _casm_ ``%r = ((int *)%0)[1];'' bytes `thenPrimIO` \ rd ->
42 dupChannel :: Channel -> IO Channel
44 _ccall_ dup fd `thenPrimIO` \ fd2 ->
50 dupChannelTo :: Channel -> Channel -> IO ()
51 dupChannelTo fd1 fd2 =
52 _ccall_ dup2 fd1 fd2 `thenPrimIO` \ rc ->
58 closeChannel :: Channel -> IO ()
60 _ccall_ close fd `thenPrimIO` \ rc ->
66 readChannel :: Channel -> ByteCount -> IO (String, ByteCount)
67 readChannel fd 0 = return ("", 0)
68 readChannel fd nbytes =
69 allocChars nbytes `thenStrictlyST` \ bytes ->
70 _ccall_ read fd bytes nbytes `thenPrimIO` \ rc ->
72 -1 -> syserr "readChannel"
75 freeze bytes `thenStrictlyST` \ buf ->
76 return (_unpackPS (_unsafeByteArrayToPS buf n), n)
78 -- Let go of the excessively long ByteArray# by copying to a shorter one.
79 -- Maybe we need a new primitive, shrinkCharArray#?
80 allocChars n `thenPrimIO` \ bytes' ->
81 _casm_ ``do {I_ i; for(i = 0; i < %2; i++) ((B_)%0)[i] = ((B_)%1)[i];
82 } while(0);'' bytes' bytes n `thenPrimIO` \ () ->
83 freeze bytes' `thenStrictlyST` \ buf ->
84 return (_unpackPS (_unsafeByteArrayToPS buf n), n)
86 writeChannel :: Channel -> String -> IO ByteCount
88 _packBytesForCST str `thenPrimIO` \ buf ->
89 _ccall_ write fd buf (length str) `thenPrimIO` \ rc ->
95 data ChannelOption = AppendOnWrite
99 queryChannelOption :: ChannelOption -> Channel -> IO Bool
100 queryChannelOption CloseOnExec fd =
101 _ccall_ fcntl fd (``F_GETFD''::Int) 0 `thenPrimIO` \ (I# flags#) ->
102 if flags# /=# -1# then
103 return ((int2Word# flags# `and#` fd_cloexec#) `neWord#` int2Word# 0#)
105 syserr "queryChannelOption"
107 fd_cloexec# = case (``FD_CLOEXEC'') of { W# x -> x }
108 queryChannelOption other fd =
109 _ccall_ fcntl fd (``F_GETFL''::Int) 0 `thenPrimIO` \ (I# flags#) ->
110 if flags# >=# 0# then
111 return ((int2Word# flags# `and#` opt#) `neWord#` int2Word# 0#)
113 syserr "queryChannelOption"
117 AppendOnWrite -> ``O_APPEND''
118 NonBlockingRead -> ``O_NONBLOCK'' ) of { W# x -> x }
120 setChannelOption :: ChannelOption -> Bool -> Channel -> IO ()
121 setChannelOption CloseOnExec val fd =
122 _ccall_ fcntl fd (``F_GETFD''::Int) 0 `thenPrimIO` \ flags ->
125 _casm_ ``%r = fcntl(%0, F_SETFD, %1 | FD_CLOEXEC);'' fd flags
127 _casm_ ``%r = fcntl(%0, F_SETFD, %1 & ~FD_CLOEXEC);'' fd flags)
136 fail = syserr "setChannelOption"
137 setChannelOption other val fd =
138 _ccall_ fcntl fd (``F_GETFL''::Int) 0 `thenPrimIO` \ flags ->
141 _casm_ ``%r = fcntl(%0, F_SETFL, %1 | %2);'' fd flags opt
143 _casm_ ``%r = fcntl(%0, F_SETFL, %1 & ~(%2));'' fd flags opt)
152 fail = syserr "setChannelOption"
155 AppendOnWrite -> (``O_APPEND''::_Word)
156 NonBlockingRead -> (``O_NONBLOCK''::_Word)
158 data LockRequest = ReadLock
162 type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)
164 getLock :: Channel -> FileLock -> IO (Maybe (ProcessID, FileLock))
166 lock2Bytes lock >>= \ flock ->
167 _ccall_ fcntl fd (``F_GETLK''::Int) flock `thenPrimIO` \ rc ->
169 bytes2ProcessIDAndLock flock `thenPrimIO` \ result ->
170 return (maybeResult result)
174 maybeResult (_, (Unlock, _, _, _)) = Nothing
175 maybeResult x = Just x
177 setLock :: Channel -> FileLock -> IO ()
179 lock2Bytes lock >>= \ flock ->
180 _ccall_ fcntl fd (``F_SETLK''::Int) flock `thenPrimIO` \ rc ->
186 waitToSetLock :: Channel -> FileLock -> IO ()
187 waitToSetLock fd lock =
188 lock2Bytes lock >>= \ flock ->
189 _ccall_ fcntl fd (``F_SETLKW''::Int) flock `thenPrimIO` \ rc ->
193 syserr "waitToSetLock"
195 seekChannel :: Channel -> SeekMode -> FileOffset -> IO FileOffset
196 seekChannel fd mode offset =
197 _ccall_ lseek fd offset (mode2Int mode) `thenPrimIO` \ rc ->
205 Local utility functions
209 -- Convert a Haskell SeekMode to an int
211 mode2Int :: SeekMode -> Int
212 mode2Int AbsoluteSeek = ``SEEK_SET''
213 mode2Int RelativeSeek = ``SEEK_CUR''
214 mode2Int SeekFromEnd = ``SEEK_END''
216 -- Convert a Haskell FileLock to an flock structure
218 lock2Bytes :: FileLock -> IO (_MutableByteArray _RealWorld ())
219 lock2Bytes (kind, mode, start, len) =
220 allocChars ``sizeof(struct flock)'' `thenStrictlyST` \ bytes ->
221 _casm_ ``do { struct flock *fl = (struct flock *)%0;
222 fl->l_type = %1; fl->l_whence = %2; fl->l_start = %3; fl->l_len = %4;
223 } while(0);'' bytes ltype (mode2Int mode) start len
229 ReadLock -> ``F_RDLCK''
230 WriteLock -> ``F_WRLCK''
231 Unlock -> ``F_UNLCK''
233 bytes2ProcessIDAndLock :: _MutableByteArray s () -> PrimIO (ProcessID, FileLock)
234 bytes2ProcessIDAndLock bytes =
235 _casm_ ``%r = ((struct flock *)%0)->l_type;'' bytes
236 `thenPrimIO` \ ltype ->
237 _casm_ ``%r = ((struct flock *)%0)->l_whence;'' bytes
238 `thenPrimIO` \ lwhence ->
239 _casm_ ``%r = ((struct flock *)%0)->l_start;'' bytes
240 `thenPrimIO` \ lstart ->
241 _casm_ ``%r = ((struct flock *)%0)->l_len;'' bytes
242 `thenPrimIO` \ llen ->
243 _casm_ ``%r = ((struct flock *)%0)->l_pid;'' bytes
244 `thenPrimIO` \ lpid ->
245 returnPrimIO (lpid, (kind ltype, mode lwhence, lstart, llen))
247 kind :: Int -> LockRequest
249 | x == ``F_RDLCK'' = ReadLock
250 | x == ``F_WRLCK'' = WriteLock
251 | x == ``F_UNLCK'' = Unlock
252 mode :: Int -> SeekMode
254 | x == ``SEEK_SET'' = AbsoluteSeek
255 | x == ``SEEK_CUR'' = RelativeSeek
256 | x == ``SEEK_END'' = SeekFromEnd