Home | History | Annotate | Download | only in Support
      1 //===- MemoryArea.h -------------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #ifndef MCLD_MEMORY_AREA_H
     10 #define MCLD_MEMORY_AREA_H
     11 #ifdef ENABLE_UNITTEST
     12 #include <gtest.h>
     13 #endif
     14 
     15 #include "mcld/ADT/Uncopyable.h"
     16 #include "mcld/Support/FileSystem.h"
     17 #include "mcld/Support/Path.h"
     18 #include <llvm/ADT/ilist.h>
     19 #include <llvm/ADT/ilist_node.h>
     20 #include <fcntl.h>
     21 #include <string>
     22 #include <list>
     23 
     24 #if defined(ENABLE_UNITTEST)
     25 namespace mcldtest
     26 {
     27   class MemoryAreaTest;
     28 } // namespace of mcldtest
     29 
     30 #endif
     31 namespace mcld
     32 {
     33 
     34 class MemoryRegion;
     35 class RegionFactory;
     36 
     37 /** \class MemoryArea
     38  *  \brief MemoryArea is used to manage distinct MemoryRegions of address space.
     39  *
     40  *  Good linkers must well manipulate memory mapped I/O and dynamic memory.
     41  *  In MCLinker, MemoryArea is the decision-maker to use memory mapped I/O or
     42  *  dynamic memory. When a client requests MemoryArea for a piece of memory
     43  *  to hold a part of a file, MemoryArea is going to see whether the requested
     44  *  part of the file is already in any existing memory which is requested
     45  *  before. If it is, MemoryArea creates a new MemoryRegion within the memory
     46  *  requested before. Otherwise, MemoryArea uses memory mapped I/O or dynamic
     47  *  memory to load the file.
     48  *
     49  *  If the part a file being loaded is larger than 3/4 pages, MemoryArea uses
     50  *  memory mapped I/O to load the file. Otherwise, MemoryArea uses dynamic
     51  *  memory to read the content of file into the memory space.
     52  */
     53 class MemoryArea : private Uncopyable
     54 {
     55 #if defined(ENABLE_UNITTEST)
     56 friend class mcldtest::MemoryAreaTest;
     57 #endif
     58 public:
     59   enum IOState
     60   {
     61     GoodBit    = 0,
     62     BadBit     = 1L << 0,
     63     EOFBit     = 1L << 1,
     64     FailBit    = 1L << 2,
     65     IOStateEnd = 1L << 16
     66   };
     67 
     68   enum AccessMode
     69   {
     70     ReadOnly = O_RDONLY,
     71     WriteOnly = O_WRONLY,
     72     ReadWrite = O_RDWR,
     73     AccessMask = O_ACCMODE
     74   };
     75 
     76 private:
     77   typedef sys::fs::detail::Address Address;
     78 
     79   friend class MemoryRegion;
     80   friend class RegionFactory;
     81   struct Space : public llvm::ilist_node<Space>
     82   {
     83   public:
     84     enum Type
     85     {
     86       ALLOCATED_ARRAY,
     87       MMAPED,
     88       UNALLOCATED
     89     };
     90 
     91   public:
     92     Space()
     93     : m_pParent(NULL),
     94       type(UNALLOCATED),
     95       file_offset(0),
     96       size(0),
     97       data(0),
     98       region_num(0)
     99     { }
    100 
    101     Space(MemoryArea* pParent, size_t pOffset, size_t pLength)
    102     : m_pParent(pParent),
    103       type(UNALLOCATED),
    104       file_offset(pOffset),
    105       size(pLength),
    106       data(0),
    107       region_num(0)
    108     { }
    109 
    110     ~Space()
    111     { }
    112 
    113     void sync()
    114     { m_pParent->write(*this); }
    115 
    116   private:
    117     MemoryArea* m_pParent;
    118 
    119   public:
    120     Type type;
    121     size_t file_offset;
    122     size_t size;
    123     sys::fs::detail::Address data;
    124     size_t region_num;
    125   };
    126 
    127   friend class Space;
    128   typedef llvm::iplist<Space> SpaceList;
    129 
    130 public:
    131   // constructor
    132   // @param pRegionFactory the factory to manage MemoryRegions
    133   MemoryArea(RegionFactory& pRegionFactory);
    134 
    135   // destructor
    136   ~MemoryArea();
    137 
    138   // request - create a MemoryRegion within a sufficient space
    139   // find an existing space to hold the MemoryRegion.
    140   // if MemoryArea does not find such space, then it creates a new space and
    141   // assign a MemoryRegion into the space.
    142   MemoryRegion* request(size_t pOffset, size_t pLength);
    143 
    144   // release - release a MemoryRegion.
    145   // release a MemoryRegion does not cause
    146   void release(MemoryRegion* pRegion);
    147 
    148   // clean - release all MemoryRegion and unmap all spaces.
    149   void clean();
    150 
    151   // sync - sync all MemoryRegion
    152   void sync();
    153 
    154   // map - open the file pPath and mapped it onto MemoryArea
    155   // @param flags see man 2 open
    156   void map(const sys::fs::Path& pPath, int flags);
    157 
    158   // map - open the file pPath and mapped it onto MemoryArea
    159   // @param flags see man 2 open
    160   // @param mode see man 2 open
    161   void map(const sys::fs::Path& pPath, int flags, int mode);
    162 
    163   // unmap - close the opened file and unmap the MemoryArea
    164   void unmap();
    165 
    166   // path - the path of the mapped file.
    167   const sys::fs::Path& path() const
    168   { return m_FilePath; }
    169 
    170   // size - the real size of the mapped file.
    171   size_t size() const
    172   { return m_FileSize; }
    173 
    174   // isMapped - check if MemoryArea is mapped to a file
    175   bool isMapped() const;
    176 
    177   // isGood - check if the state of the opened area is good for read/write
    178   // operations
    179   bool isGood() const;
    180 
    181   // isBad - check if an error causes the loss of integrity of the memory space
    182   bool isBad() const;
    183 
    184   // isFailed - check if an error related to the internal logic of the operation
    185   // itself occurs
    186   bool isFailed() const;
    187 
    188   // isEOF - check if we reach the end of the file
    189   bool isEOF() const;
    190 
    191   // isReadable - check if the memory area is readable
    192   bool isReadable() const;
    193 
    194   // isWriteable - check if the memory area is writable
    195   bool isWritable() const;
    196 
    197   // rdstate - get error state flags
    198   // Returns the current internal error state flags of the stream
    199   int rdstate() const;
    200 
    201   // setState - set error state flag
    202   void setState(IOState pState);
    203 
    204   // clear - set error state flag
    205   void clear(IOState pState = GoodBit);
    206 
    207 private:
    208   // readToBuffer - read data from the file behind this MemorySpace and store
    209   // those bytes in pBuf. Return the number of byte read or -1 on error.
    210   ssize_t readToBuffer(sys::fs::detail::Address pBuf,
    211                        size_t pSize, size_t pOffset);
    212 
    213 private:
    214   // find - first fit search
    215   Space* find(size_t pOffset, size_t pLength);
    216 
    217   // release a Space, but does not remove it from space list
    218   void release(Space* pSpace);
    219 
    220   // read - read data from mapped file into virtual memroy of pSpace. Return
    221   // false on error.
    222   bool read(Space& pSpace);
    223 
    224   // write - write back the virtual memory of pSpace into mapped file.
    225   void write(const Space& pSpace);
    226 
    227   // truncate - truncate the file size to length.
    228   void truncate(size_t pLength);
    229 
    230   // policy - decide whehter to use dynamic memory or memory mapped I/O
    231   Space::Type policy(off_t pOffset, size_t pLength);
    232 
    233   // the size of one page
    234   static const off_t PageSize = 4096;
    235 
    236   // page_boundary - Given a file size, return the size to read integral pages.
    237   // return the first page boundary after pFileOffset
    238   static off_t page_boundary(off_t pFileOffset)
    239   { return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
    240 
    241   // Given a file offset, return the page offset.
    242   // return the first page boundary before pFileOffset
    243   static off_t page_offset(off_t pFileOffset)
    244   { return pFileOffset & ~ (PageSize - 1); }
    245 
    246 private:
    247   RegionFactory& m_RegionFactory;
    248   sys::fs::Path m_FilePath;
    249   int m_FileDescriptor;
    250   size_t m_FileSize;
    251   int m_AccessFlags;
    252   int m_State;
    253 
    254   SpaceList m_SpaceList;
    255 };
    256 
    257 } // namespace of mcld
    258 
    259 #endif
    260 
    261