2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
4 \section[PosixIO]{Haskell 1.3 POSIX Input/Output Primitives}
7 {-# OPTIONS -#include "../std/cbits/stgio.h" #-}
29 handleToFd, fdToHandle,
35 import PrelHandle (filePtr, readHandle, writeHandle, newHandle)
37 import PackedString ( unpackPS, unsafeByteArrayToPS, psToByteArrayST )
42 import PosixFiles ( stdInput, stdOutput, stdError )
45 createPipe :: IO (Fd, Fd)
47 bytes <- allocChars ``(2*sizeof(int))''
48 rc <- _casm_ ``%r = pipe((int *)%0);'' bytes
51 rd <- _casm_ ``%r = ((int *)%0)[0];'' bytes
52 wd <- _casm_ ``%r = ((int *)%0)[1];'' bytes
59 _ccall_ dup fd >>= \ fd2@(I# fd2#) ->
65 dupTo :: Fd -> Fd -> IO ()
66 dupTo fd1 fd2 = minusone_error (_ccall_ dup2 fd1 fd2) "dupTo"
68 fdClose :: Fd -> IO ()
69 fdClose fd = minusone_error (_ccall_ close fd) "fdClose"
71 handleToFd :: Handle -> IO Fd
75 ErrorHandle ioError -> writeHandle h h_ >> fail ioError
76 ClosedHandle -> writeHandle h h_ >>
77 fail (IOError Nothing IllegalOperation
79 SemiClosedHandle _ _ -> writeHandle h h_ >>
80 fail (IOError Nothing IllegalOperation
81 "handle is semi-closed")
83 let file = filePtr h_ in
84 _casm_ `` %r=fileno((FILE *)%0); '' file >>= \ fd@(FD# fd#) ->
86 if fd# /=# (negateInt# 1#) then
91 -- default is no buffering.
92 fdToHandle :: Fd -> IO Handle
93 fdToHandle fd@(FD# fd#) =
94 _ccall_ fcntl fd (``F_GETFL''::Int) 0 >>= \ flags@(I# flags#) ->
97 wH = (int2Word# flags# `and#` (case ``O_WRONLY'' of { W# x -> x}))
98 `neWord#` int2Word# 0#
99 aH = (int2Word# flags# `and#` (case ``O_APPEND'' of { W# x -> x}))
100 `neWord#` int2Word# 0#
101 rwH = (int2Word# flags# `and#` (case ``O_RDWR'' of { W# x -> x }))
102 `neWord#` int2Word# 0#
106 then ("a",AppendHandle)
107 else ("w",WriteHandle)
109 ("r+",ReadWriteHandle)
113 _ccall_ openFd fd ft >>= \ file_struct@(A# ptr#) ->
114 if file_struct /= (``NULL''::Addr) then
116 A distinction is made here between std{Input,Output,Error} Fds
117 and all others. The standard descriptors have a finaliser
118 that will not close the underlying fd, the others have one
121 Delaying the closing of the standard descriptors until the process
122 exits is necessary since the RTS is likely to require these after
123 (or as a result of) program termination.
125 #ifndef __PARALLEL_HASKELL__
126 (if fd == stdInput || fd == stdOutput || fd == stdError then
127 makeForeignObj file_struct (``&freeStdFile''::Addr)
129 makeForeignObj file_struct (``&freeFile''::Addr)) >>= \ fp ->
130 newHandle (handle_t fp Nothing False)
132 newHandle (handle_t file_struct Nothing False)
139 fdRead :: Fd -> ByteCount -> IO (String, ByteCount)
140 fdRead fd 0 = return ("", 0)
141 fdRead fd nbytes = do
142 bytes <- allocChars nbytes
143 rc <- _ccall_ read fd bytes nbytes
145 -1 -> syserr "fdRead"
146 0 -> fail (IOError Nothing EOF "EOF")
147 n | n == nbytes -> do
149 return (unpackPS (unsafeByteArrayToPS buf n), n)
151 -- Let go of the excessively long ByteArray# by copying to a
152 -- shorter one. Maybe we need a new primitive, shrinkCharArray#?
153 bytes' <- allocChars n
154 _casm_ ``do {I_ i; for(i = 0; i < %2; i++) ((B_)%0)[i] = ((B_)%1)[i];
155 } while(0);'' bytes' bytes n
157 return (unpackPS (unsafeByteArrayToPS buf n), n)
159 fdWrite :: Fd -> String -> IO ByteCount
161 buf <- stToIO (psToByteArrayST str)
162 rc <- _ccall_ write fd buf (length str)
165 else syserr "fdWrite"
167 data FdOption = AppendOnWrite
171 queryFdOption :: Fd -> FdOption -> IO Bool
172 queryFdOption fd CloseOnExec =
173 _ccall_ fcntl fd (``F_GETFD''::Int) 0 >>= \ (I# flags#) ->
174 if flags# /=# -1# then
175 return ((int2Word# flags# `and#` fd_cloexec#) `neWord#` int2Word# 0#)
177 syserr "queryFdOption"
179 fd_cloexec# = case (``FD_CLOEXEC'') of { W# x -> x }
180 queryFdOption fd other =
181 _ccall_ fcntl fd (``F_GETFL''::Int) 0 >>= \ (I# flags#) ->
182 if flags# >=# 0# then
183 return ((int2Word# flags# `and#` opt#) `neWord#` int2Word# 0#)
185 syserr "queryFdOption"
189 AppendOnWrite -> ``O_APPEND''
190 NonBlockingRead -> ``O_NONBLOCK'' ) of { W# x -> x }
192 setFdOption :: Fd -> FdOption -> Bool -> IO ()
193 setFdOption fd CloseOnExec val = do
194 flags <- _ccall_ fcntl fd (``F_GETFD''::Int) 0
195 if flags /= -1 then do
197 _casm_ ``%r = fcntl(%0, F_SETFD, %1 | FD_CLOEXEC);'' fd flags
199 _casm_ ``%r = fcntl(%0, F_SETFD, %1 & ~FD_CLOEXEC);'' fd flags)
205 fail = syserr "setFdOption"
207 setFdOption fd other val = do
208 flags <- _ccall_ fcntl fd (``F_GETFL''::Int) 0
209 if flags >= 0 then do
211 _casm_ ``%r = fcntl(%0, F_SETFL, %1 | %2);'' fd flags opt
213 _casm_ ``%r = fcntl(%0, F_SETFL, %1 & ~(%2));'' fd flags opt)
219 fail = syserr "setFdOption"
222 AppendOnWrite -> (``O_APPEND''::Word)
223 NonBlockingRead -> (``O_NONBLOCK''::Word)
225 data LockRequest = ReadLock
229 type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)
231 getLock :: Fd -> FileLock -> IO (Maybe (ProcessID, FileLock))
233 flock <- lock2Bytes lock
234 rc <- _ccall_ fcntl fd (``F_GETLK''::Int) flock
237 result <- bytes2ProcessIDAndLock flock
238 return (maybeResult result)
239 else syserr "getLock"
241 maybeResult (_, (Unlock, _, _, _)) = Nothing
242 maybeResult x = Just x
244 setLock :: Fd -> FileLock -> IO ()
246 flock <- lock2Bytes lock
247 minusone_error (_ccall_ fcntl fd (``F_SETLK''::Int) flock) "setLock"
249 waitToSetLock :: Fd -> FileLock -> IO ()
250 waitToSetLock fd lock = do
251 flock <- lock2Bytes lock
252 minusone_error (_ccall_ fcntl fd (``F_SETLKW''::Int) flock) "waitToSetLock"
254 fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset
255 fdSeek fd mode offset = do
256 rc <- _ccall_ lseek fd offset (mode2Int mode)
263 Local utility functions
267 -- Convert a Haskell SeekMode to an int
269 mode2Int :: SeekMode -> Int
270 mode2Int AbsoluteSeek = ``SEEK_SET''
271 mode2Int RelativeSeek = ``SEEK_CUR''
272 mode2Int SeekFromEnd = ``SEEK_END''
274 -- Convert a Haskell FileLock to an flock structure
275 lockRequest2Int :: LockRequest -> Int
276 lockRequest2Int kind =
278 ReadLock -> ``F_RDLCK''
279 WriteLock -> ``F_WRLCK''
280 Unlock -> ``F_UNLCK''
282 lock2Bytes :: FileLock -> IO (MutableByteArray RealWorld ())
283 lock2Bytes (kind, mode, start, len) = do
284 bytes <- allocChars ``sizeof(struct flock)''
285 _casm_ ``do { struct flock *fl = (struct flock *)%0;
291 bytes (lockRequest2Int kind) (mode2Int mode) start len
295 bytes2ProcessIDAndLock :: MutableByteArray s () -> IO (ProcessID, FileLock)
296 bytes2ProcessIDAndLock bytes = do
297 ltype <- _casm_ ``%r = ((struct flock *)%0)->l_type;'' bytes
298 lwhence <- _casm_ ``%r = ((struct flock *)%0)->l_whence;'' bytes
299 lstart <- _casm_ ``%r = ((struct flock *)%0)->l_start;'' bytes
300 llen <- _casm_ ``%r = ((struct flock *)%0)->l_len;'' bytes
301 lpid <- _casm_ ``%r = ((struct flock *)%0)->l_pid;'' bytes
302 return (lpid, (kind ltype, mode lwhence, lstart, llen))
304 kind :: Int -> LockRequest
306 | x == ``F_RDLCK'' = ReadLock
307 | x == ``F_WRLCK'' = WriteLock
308 | x == ``F_UNLCK'' = Unlock
309 mode :: Int -> SeekMode
311 | x == ``SEEK_SET'' = AbsoluteSeek
312 | x == ``SEEK_CUR'' = RelativeSeek
313 | x == ``SEEK_END'' = SeekFromEnd