MemoryArea.h revision 5460a1f25d9ddecb5c70667267d66d51af177a99
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)
25namespace mcldtest
26{
27  class MemoryAreaTest;
28} // namespace of mcldtest
29
30#endif
31namespace mcld
32{
33
34class MemoryRegion;
35class 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 */
53class MemoryArea : private Uncopyable
54{
55#if defined(ENABLE_UNITTEST)
56friend class mcldtest::MemoryAreaTest;
57#endif
58public:
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
76private:
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
130public:
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
207private:
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
213private:
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
246private:
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