{-# LANGUAGE ForeignFunctionInterface #-} -------------------------------------------------------------------- -- | -- Module : System.IO.Posix.MMap -- Copyright : (c) Galois, Inc. 2007 -- License : BSD3 -- -- Maintainer: Don Stewart -- Stability : provisional -- Portability: non-portable -- posix only -- -- mmap a file or device into memory as a strict ByteString. -- module System.IO.Posix.MMap ( -- $mmap_intro -- $mmap_unmap -- * Memory mapped files unsafeMMapFile -- :: FilePath -> IO ByteString -- $mmap_intro -- -- 'unsafeMMapFile' mmaps a file or device into memory as a strict -- 'ByteString'. The file is not actually copied strictly into memory, -- but instead pages from the file will be loaded into the address -- space on demand. -- -- We can consider mmap as lazy IO pushed into the virtual memory -- subsystem. -- -- The file is mapped using MAP_SHARED: modifications to the file -- will be immediately shared with any other process accessing the -- file. This has no effect from the Haskell point of view, since -- ByteStrings are treated as immutable values. -- -- However, if the file is written to by any other process on the -- system while it is in use in Haskell, those changes will be -- immediately reflected on the Haskell side, destroying referential -- transparency. -- -- It is only safe to mmap a file if you know you are the sole user. -- -- For more details about mmap, and its consequences, see: -- -- * -- -- * -- -- $mmap_unmap -- -- When the entire file is out of scope, the Haskell storage manager -- will call munmap to free the file, using a finaliser. Until then, as -- much of the file as you access will be allocated. -- -- Note that the Haskell storage manager doesn't know how large a -- resource is associated with an mmapped file. If you allocate many -- such files, the garbage collector will only see the 'ForeignPtr's -- that have been allocated, not the corresponding ByteArrays. The -- result will be that the GC runs less often that you hoped, as it -- looks like only a few bytes have been allocated on the Haskell heap. -- -- Use of 'performGC' or 'finalizeForeignPtr' when you know that -- the object is going out of scope can ensure that resources are -- released appropriately. -- ) where import System.IO.Posix.MMap.Internal -- import System.IO -- import qualified System.IO as IO import Foreign.Ptr import Control.Exception import Data.ByteString import System.Posix -- | The 'unsafeMMapFile' function maps a file or device into memory, -- returning a strict 'ByteString' that accesses the mapped file. -- If the mmap fails for some reason, an error is thrown. -- -- Memory mapped files will behave as if they were read lazily -- -- pages from the file will be loaded into memory on demand. -- -- The storage manager is used to free the mapped memory. When -- the garbage collector notices there are no further references to the -- mapped memory, a call to munmap is made. It is not necessary to do -- this yourself. In tight memory situations, it may be profitable to -- use 'performGC' or 'finalizeForeignPtr' to force an unmap. -- -- Note: this operation may break referential transparency! If -- any other process on the system changes the file when it is mapped -- into Haskell, the contents of your 'ByteString' will change. -- unsafeMMapFile :: FilePath -> IO ByteString unsafeMMapFile f = do fd <- openFd f ReadOnly Nothing defaultFileFlags always (closeFd fd) $ do stat <- getFdStatus fd let size = fromIntegral (fileSize stat) if size <= 0 then return empty -- BSD mmap won't accept a length of zero else do ptr <- c_mmap size (fromIntegral fd) if ptr == nullPtr then error "System.IO.Posix.MMap.mmapFile: unable to mmap file" else unsafePackMMapPtr ptr size where always = flip finally