module Data.CompactMap.MemoryMap
( Protection(..)
, Flag(..)
, mmap
, alignSize
, mremap
, munmap
, getPageSize
) where
import Control.Monad
import GHC.IOBase
import Foreign.C
import Foreign
import Data.Bits
import Numeric
import Data.List
import Data.Char
foreign import ccall unsafe "mmap" c_mmap :: Ptr a -> CSize -> CInt -> CInt -> CInt -> CInt -> IO (Ptr a)
foreign import ccall unsafe "munmap" c_munmap :: Ptr a -> CSize -> IO CInt
foreign import ccall unsafe "mremap" c_mremap :: Ptr a -> CSize -> CSize -> CInt -> IO (Ptr a)
foreign import ccall unsafe "getpagesize" c_getpagesize :: IO CInt
getPageSize :: IO Int
getPageSize = liftM fromIntegral c_getpagesize
data Protection
= Execute
| Read
| Write
protToBit Read = 0x1
protToBit Write = 0x2
protToBit Execute = 0x4
data Flag
= Fixed
| Shared
| Private
| Anonymous
| NoReserve
flagToBit Fixed = 0x10
flagToBit Shared = 0x01
flagToBit Private = 0x02
flagToBit Anonymous = 0x20
flagToBit NoReserve = 0x04000
errPtr :: Ptr a
errPtr = nullPtr `plusPtr` (1)
mmap :: Int -> [Protection] -> [Flag] -> IO (Ptr a)
mmap size prot flags
= do let cprot = foldr (.|.) 0 (map protToBit prot)
cflags = foldr (.|.) 0 (map flagToBit flags)
throwErrnoIf (== errPtr) "mmap" (c_mmap nullPtr (fromIntegral size) cprot cflags (1) 0)
alignSize :: Int -> IO Int
alignSize size
= do page <- getPageSize
return $ if size <= 0 then page
else (size `div` page) * page + if size `mod` page == 0 then 0 else page
mremap :: Ptr a -> Int -> Int -> IO (Ptr a)
mremap ptr oldSize newSize
= throwErrnoIf (== errPtr) "mremap" (c_mremap ptr (fromIntegral oldSize) (fromIntegral newSize) 1)
munmap :: Ptr a -> Int -> IO ()
munmap ptr size
= throwErrnoIfMinus1_ "munmap" $ c_munmap ptr (fromIntegral size)