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: SpaceSpace92 Space() 93 : m_pParent(NULL), 94 type(UNALLOCATED), 95 file_offset(0), 96 size(0), 97 data(0), 98 region_num(0) 99 { } 100 SpaceSpace101 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 ~SpaceSpace110 ~Space() 111 { } 112 syncSpace113 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. path()167 const sys::fs::Path& path() const 168 { return m_FilePath; } 169 170 // size - the real size of the mapped file. size()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 page_boundary(off_t 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 page_offset(off_t 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