• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- Space.cpp ----------------------------------------------------------===//
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 #include <mcld/Support/Space.h>
10 #include <mcld/Support/FileHandle.h>
11 #include <mcld/Support/MsgHandling.h>
12 #include <cstdlib>
13 #include <unistd.h>
14 
15 using namespace mcld;
16 
17 //===----------------------------------------------------------------------===//
18 // constant data
19 static const off_t PageSize = getpagesize();
20 
21 //===----------------------------------------------------------------------===//
22 // Non-member functions
23 //===----------------------------------------------------------------------===//
24 //
25 // low address      A page             high address
26 // |--------------------|------------------|
27 // ^ page_offset        ^ pFileOffset      ^ page_boundary
28 //
29 // Given a file offset, return the page offset.
30 // return the first page boundary \b before pFileOffset
page_offset(off_t pFileOffset)31 inline static off_t page_offset(off_t pFileOffset)
32 { return pFileOffset & ~ (PageSize - 1); }
33 
34 // page_boundary - Given a file size, return the size to read integral pages.
35 // return the first page boundary \b after pFileOffset
page_boundary(off_t pFileOffset)36 inline static off_t page_boundary(off_t pFileOffset)
37 { return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
38 
policy(off_t pOffset,size_t pLength)39 inline static Space::Type policy(off_t pOffset, size_t pLength)
40 {
41   const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
42   if (pLength < threshold)
43     return Space::ALLOCATED_ARRAY;
44   else
45     return Space::MMAPED;
46 }
47 
48 //===----------------------------------------------------------------------===//
49 // Space
50 //===----------------------------------------------------------------------===//
Space()51 Space::Space()
52   : m_Data(NULL), m_StartOffset(0), m_Size(0),
53     m_RegionCount(0), m_Type(UNALLOCATED) {
54 }
55 
Space(Space::Type pType,void * pMemBuffer,size_t pSize)56 Space::Space(Space::Type pType, void* pMemBuffer, size_t pSize)
57   : m_Data(static_cast<Address>(pMemBuffer)), m_StartOffset(0), m_Size(pSize),
58     m_RegionCount(0), m_Type(pType)
59 {
60 }
61 
~Space()62 Space::~Space()
63 {
64   // do nothing. m_Data is deleted by @ref releaseSpace
65 }
66 
Create(void * pMemBuffer,size_t pSize)67 Space* Space::Create(void* pMemBuffer, size_t pSize)
68 {
69   Space* result = new Space(EXTERNAL, pMemBuffer, pSize);
70   return result;
71 }
72 
Create(FileHandle & pHandler,size_t pStart,size_t pSize)73 Space* Space::Create(FileHandle& pHandler, size_t pStart, size_t pSize)
74 {
75   Type type;
76   void* memory = NULL;
77   Space* result = NULL;
78   size_t start = 0, size = 0, total_offset;
79   switch(type = policy(pStart, pSize)) {
80     case ALLOCATED_ARRAY: {
81       // adjust total_offset, start and size
82       total_offset = pStart + pSize;
83       start = pStart;
84       if (total_offset > pHandler.size()) {
85         if (pHandler.isWritable()) {
86           size = pSize;
87           pHandler.truncate(total_offset);
88         }
89         else if (pHandler.size() > start)
90           size = pHandler.size() - start;
91         else {
92           // create a space out of a read-only file.
93           fatal(diag::err_cannot_read_small_file) << pHandler.path()
94                                                   << pHandler.size()
95                                                   << start << size;
96         }
97       }
98       else
99         size = pSize;
100 
101       // malloc
102       memory = (void*)malloc(size);
103       if (!pHandler.read(memory, start, size))
104         error(diag::err_cannot_read_file) << pHandler.path() << start << size;
105 
106       break;
107     }
108     case MMAPED: {
109       // adjust total_offset, start and size
110       total_offset = page_boundary(pStart + pSize);
111       start = page_offset(pStart);
112       if (total_offset > pHandler.size()) {
113         if (pHandler.isWritable()) {
114           size = page_boundary((pStart - start) + pSize);
115           pHandler.truncate(total_offset);
116         }
117         else if (pHandler.size() > start)
118           size = pHandler.size() - start;
119         else {
120           // create a space out of a read-only file.
121           fatal(diag::err_cannot_read_small_file) << pHandler.path()
122                                                   << pHandler.size()
123                                                   << start << size;
124         }
125       }
126       else
127         size = page_boundary((pStart - start) + pSize);
128 
129       // mmap
130       if (!pHandler.mmap(memory, start, size))
131         error(diag::err_cannot_mmap_file) << pHandler.path() << start << size;
132 
133       break;
134     }
135     default:
136       break;
137   } // end of switch
138 
139   result = new Space(type, memory, size);
140   result->setStart(start);
141   return result;
142 }
143 
Destroy(Space * & pSpace)144 void Space::Destroy(Space*& pSpace)
145 {
146   delete pSpace;
147   pSpace = NULL;
148 }
149 
Release(Space * pSpace,FileHandle & pHandler)150 void Space::Release(Space* pSpace, FileHandle& pHandler)
151 {
152   if (NULL == pSpace)
153     return;
154 
155   switch(pSpace->type()) {
156     case ALLOCATED_ARRAY:
157       free(pSpace->memory());
158       break;
159     case MMAPED:
160       if (!pHandler.munmap(pSpace->memory(), pSpace->size()))
161         error(diag::err_cannot_munmap_file) << pHandler.path();
162       break;
163     default: // external and unallocated memory buffers
164       break;
165   } // end of switch
166 }
167 
Sync(Space * pSpace,FileHandle & pHandler)168 void Space::Sync(Space* pSpace, FileHandle& pHandler)
169 {
170   if (NULL == pSpace || !pHandler.isWritable())
171     return;
172 
173   switch(pSpace->type()) {
174     case Space::ALLOCATED_ARRAY: {
175       if (!pHandler.write(pSpace->memory(),
176                           pSpace->start(),
177                           pSpace->size())) {
178         error(diag::err_cannot_write_file) << pHandler.path()
179                                            << pSpace->start()
180                                            << pSpace->size();
181       }
182       return;
183     }
184     case Space::MMAPED:
185     default: {
186       // system will eventually write bakc the memory after
187       // calling ::munmap
188       return;
189     }
190   } // end of switch
191 }
192 
193