• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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