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 (readHandle, writeHandle, newHandle, getBMode__, getHandleFd )
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
77 -- default is no buffering.
78 fdToHandle :: Fd -> IO Handle
79 fdToHandle fd@(FD# fd#) = do
80 -- first find out what kind of file desc. this is..
81 flags <- _ccall_ fcntl fd (``F_GETFL''::Int) 0
87 wH = (int2Word# flags# `and#` (case ``O_WRONLY'' of { W# x -> x}))
88 `neWord#` int2Word# 0#
89 aH = (int2Word# flags# `and#` (case ``O_APPEND'' of { W# x -> x}))
90 `neWord#` int2Word# 0#
91 rwH = (int2Word# flags# `and#` (case ``O_RDWR'' of { W# x -> x }))
92 `neWord#` int2Word# 0#
94 (handle_t, flush_on_close)
95 | wH && aH = (AppendHandle, 1)
96 | wH = (WriteHandle, 1)
97 | rwH = (ReadWriteHandle, 1)
98 | otherwise = (ReadHandle, 0)
100 fo <- _ccall_ openFd fd flags flush_on_close
101 if fo /= nullAddr then do
103 A distinction is made here between std{Input,Output,Error} Fds
104 and all others. The standard descriptors have a finaliser
105 that will not close the underlying fd, the others have one
108 Delaying the closing of the standard descriptors until the process
109 exits is necessary since the RTS is likely to require these after
110 (or as a result of) program termination.
112 #ifndef __PARALLEL_HASKELL__
114 (if fd == stdInput || fd == stdOutput || fd == stdError then
115 makeForeignObj fo (``&freeStdFile''::Addr)
117 makeForeignObj fo (``&freeFileObject''::Addr))
119 (bm, bf_size) <- getBMode__ fo
120 mkBuffer__ fo bf_size
121 newHandle (Handle__ fo handle_t bm fd_str)
127 fd_str = "<file descriptor: " ++ show (I# fd#) ++ ">"
129 fdRead :: Fd -> ByteCount -> IO (String, ByteCount)
130 fdRead fd 0 = return ("", 0)
131 fdRead fd nbytes = do
132 bytes <- allocChars nbytes
133 rc <- _ccall_ read fd bytes nbytes
135 -1 -> syserr "fdRead"
136 0 -> fail (IOError Nothing EOF "fdRead" "EOF")
137 n | n == nbytes -> do
139 return (unpackPS (unsafeByteArrayToPS buf n), n)
141 -- Let go of the excessively long ByteArray# by copying to a
142 -- shorter one. Maybe we need a new primitive, shrinkCharArray#?
143 bytes' <- allocChars n
144 _casm_ ``do {I_ i; for(i = 0; i < %2; i++) ((B_)%0)[i] = ((B_)%1)[i];
145 } while(0);'' bytes' bytes n
147 return (unpackPS (unsafeByteArrayToPS buf n), n)
149 fdWrite :: Fd -> String -> IO ByteCount
151 buf <- stToIO (psToByteArrayST str)
152 rc <- _ccall_ write fd buf (length str)
155 else syserr "fdWrite"
157 data FdOption = AppendOnWrite
161 queryFdOption :: Fd -> FdOption -> IO Bool
162 queryFdOption fd CloseOnExec =
163 _ccall_ fcntl fd (``F_GETFD''::Int) 0 >>= \ (I# flags#) ->
164 if flags# /=# -1# then
165 return ((int2Word# flags# `and#` fd_cloexec#) `neWord#` int2Word# 0#)
167 syserr "queryFdOption"
169 fd_cloexec# = case (``FD_CLOEXEC'') of { W# x -> x }
170 queryFdOption fd other =
171 _ccall_ fcntl fd (``F_GETFL''::Int) 0 >>= \ (I# flags#) ->
172 if flags# >=# 0# then
173 return ((int2Word# flags# `and#` opt#) `neWord#` int2Word# 0#)
175 syserr "queryFdOption"
179 AppendOnWrite -> ``O_APPEND''
180 NonBlockingRead -> ``O_NONBLOCK'' ) of { W# x -> x }
182 setFdOption :: Fd -> FdOption -> Bool -> IO ()
183 setFdOption fd CloseOnExec val = do
184 flags <- _ccall_ fcntl fd (``F_GETFD''::Int) 0
185 if flags /= -1 then do
187 _casm_ ``%r = fcntl(%0, F_SETFD, %1 | FD_CLOEXEC);'' fd flags
189 _casm_ ``%r = fcntl(%0, F_SETFD, %1 & ~FD_CLOEXEC);'' fd flags)
195 fail = syserr "setFdOption"
197 setFdOption fd other val = do
198 flags <- _ccall_ fcntl fd (``F_GETFL''::Int) 0
199 if flags >= 0 then do
201 _casm_ ``%r = fcntl(%0, F_SETFL, %1 | %2);'' fd flags opt
203 _casm_ ``%r = fcntl(%0, F_SETFL, %1 & ~(%2));'' fd flags opt)
209 fail = syserr "setFdOption"
212 AppendOnWrite -> (``O_APPEND''::Word)
213 NonBlockingRead -> (``O_NONBLOCK''::Word)
215 data LockRequest = ReadLock
219 type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)
221 getLock :: Fd -> FileLock -> IO (Maybe (ProcessID, FileLock))
223 flock <- lock2Bytes lock
224 rc <- _ccall_ fcntl fd (``F_GETLK''::Int) flock
227 result <- bytes2ProcessIDAndLock flock
228 return (maybeResult result)
229 else syserr "getLock"
231 maybeResult (_, (Unlock, _, _, _)) = Nothing
232 maybeResult x = Just x
234 setLock :: Fd -> FileLock -> IO ()
236 flock <- lock2Bytes lock
237 minusone_error (_ccall_ fcntl fd (``F_SETLK''::Int) flock) "setLock"
239 waitToSetLock :: Fd -> FileLock -> IO ()
240 waitToSetLock fd lock = do
241 flock <- lock2Bytes lock
242 minusone_error (_ccall_ fcntl fd (``F_SETLKW''::Int) flock) "waitToSetLock"
244 fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset
245 fdSeek fd mode offset = do
246 rc <- _ccall_ lseek fd offset (mode2Int mode)
253 Local utility functions
257 -- Convert a Haskell SeekMode to an int
259 mode2Int :: SeekMode -> Int
260 mode2Int AbsoluteSeek = ``SEEK_SET''
261 mode2Int RelativeSeek = ``SEEK_CUR''
262 mode2Int SeekFromEnd = ``SEEK_END''
264 -- Convert a Haskell FileLock to an flock structure
265 lockRequest2Int :: LockRequest -> Int
266 lockRequest2Int kind =
268 ReadLock -> ``F_RDLCK''
269 WriteLock -> ``F_WRLCK''
270 Unlock -> ``F_UNLCK''
272 lock2Bytes :: FileLock -> IO (MutableByteArray RealWorld ())
273 lock2Bytes (kind, mode, start, len) = do
274 bytes <- allocChars ``sizeof(struct flock)''
275 _casm_ ``do { struct flock *fl = (struct flock *)%0;
281 bytes (lockRequest2Int kind) (mode2Int mode) start len
285 bytes2ProcessIDAndLock :: MutableByteArray s () -> IO (ProcessID, FileLock)
286 bytes2ProcessIDAndLock bytes = do
287 ltype <- _casm_ ``%r = ((struct flock *)%0)->l_type;'' bytes
288 lwhence <- _casm_ ``%r = ((struct flock *)%0)->l_whence;'' bytes
289 lstart <- _casm_ ``%r = ((struct flock *)%0)->l_start;'' bytes
290 llen <- _casm_ ``%r = ((struct flock *)%0)->l_len;'' bytes
291 lpid <- _casm_ ``%r = ((struct flock *)%0)->l_pid;'' bytes
292 return (lpid, (kind ltype, mode lwhence, lstart, llen))
294 kind :: Int -> LockRequest
296 | x == ``F_RDLCK'' = ReadLock
297 | x == ``F_WRLCK'' = WriteLock
298 | x == ``F_UNLCK'' = Unlock
300 mode :: Int -> SeekMode
302 | x == ``SEEK_SET'' = AbsoluteSeek
303 | x == ``SEEK_CUR'' = RelativeSeek
304 | x == ``SEEK_END'' = SeekFromEnd