gwnavruntime/kernel/HeapPT/HeapPT_PageTable.h Source File

HeapPT_PageTable.h
Go to the documentation of this file.
1 /*
2 * Copyright 2015 Autodesk, Inc. All rights reserved.
3 * Use of this software is subject to the terms of the Autodesk license agreement and any attachments or Appendices thereto provided at the time of installation or download,
4 * or which otherwise accompanies this software in either electronic or hard copy form, or which is signed by you and accepted by Autodesk.
5 */
6 
7 /**************************************************************************
8 
9 Filename : HeapPT_PageTable.h
10 Content : Allocator page table for mapping the address space.
11  :
12 Created : July 14, 2008
13 Authors : Michael Antonov, Boris Rayskiy, Maxim Shemanarev
14 
15 **************************************************************************/
16 
17 #ifndef INC_KY_Kernel_HeapPT_PageTable_H
18 #define INC_KY_Kernel_HeapPT_PageTable_H
19 
22 
23 namespace Kaim { namespace HeapPT {
24 
25 using namespace Heap;
26 
27 #ifdef KY_64BIT_POINTERS
28 
29 #define Heap_Lv1_PageSize (UPInt(1) << Heap_Lv1_PageShift)
30 #define Heap_Lv2_PageSize (UPInt(1) << Heap_Lv2_PageShift)
31 #define Heap_Lv3_PageSize (UPInt(1) << Heap_Lv3_PageShift)
32 #define Heap_Lv4_PageSize (UPInt(1) << Heap_Lv4_PageShift)
33 #define Heap_Lv5_PageSize (UPInt(1) << Heap_Lv5_PageShift)
34 
35 #define Heap_Lv1_PageMask ((UPInt(1) << Heap_Lv1_PageShift) - 1)
36 #define Heap_Lv2_PageMask ((UPInt(1) << Heap_Lv2_PageShift) - 1)
37 #define Heap_Lv3_PageMask ((UPInt(1) << Heap_Lv3_PageShift) - 1)
38 #define Heap_Lv4_PageMask ((UPInt(1) << Heap_Lv4_PageShift) - 1)
39 #define Heap_Lv5_PageMask ((UPInt(1) << Heap_Lv5_PageShift) - 1)
40 
41 #endif
42 
43 
44 //------------------------------------------------------------------------
45 template<class T, UPInt N> class HeapHeader
46 {
47  T* pTable;
48  UPInt RefCount;
49 
50 public:
51 
52  HeapHeader() : pTable(0), RefCount(0) {}
53 
54  T* GetTable() const { return pTable; }
55  T* GetTable(UPInt i) const { return &pTable[i]; }
56  //T* GetTableSafe(UPInt i) const { return pTable ? &pTable[i] : 0; } // DBG
57 
58 
59 #ifndef KY_64BIT_POINTERS
60 
61  bool HasTable() const { return pTable != 0; }
62 
63 #else
64 
65  KY_INLINE bool HasTable(UPInt address) const;
66 
67 #endif
68 
69  bool AddRef(Starter* starter)
70  {
71  if (!pTable)
72  {
73  // For potential ref counting in the pointer: We must ensure
74  // the alignment provides enough capacity for ref counting.
75  //-------------------
76  pTable = (T*)starter->Alloc(sizeof(T) * N, sizeof(void*) * N);
77  if (!pTable)
78  return false;
79 
80  // We must initialize the table to 0 since that is the correct value
81  // of headers that indexing relies on.
82  memset(pTable, 0, sizeof(T) * N);
83  }
84  RefCount++;
85  return true;
86  }
87 
88  void Release(Starter* starter)
89  {
90  if (--RefCount == 0)
91  {
92  starter->Free((UByte*)pTable, sizeof(T) * N, sizeof(void*) * N);
93  pTable = 0;
94  }
95  }
96 };
97 
98 
99 //------------------------------------------------------------------------
100 struct DebugNode;
101 struct HeapHeader1
102 {
103  HeapSegment* pSegment;
104 #ifdef KY_MEMORY_ENABLE_DEBUG_INFO
105  DebugNode* pDebugNode;
106 #endif
107 };
108 
109 #ifndef KY_64BIT_POINTERS
110 
111 // Allocator header of level 2.
112 // Describes 1M memory block, using table containing 256 Lv1 headers.
113 //------------------------------------------------------------------------
114 typedef HeapHeader<HeapHeader1, Heap_Lv1_TableSize> HeapHeader2;
115 typedef HeapHeader2 HeapHeaderRoot;
116 
117 #else
118 
119 // Allocator header of level 2-5. For details see Types.h
120 //________________________________________________________________________
121 typedef HeapHeader<HeapHeader1, Heap_Lv1_TableSize> HeapHeader2;
122 typedef HeapHeader<HeapHeader2, Heap_Lv2_TableSize> HeapHeader3;
123 typedef HeapHeader<HeapHeader3, Heap_Lv3_TableSize> HeapHeader4;
124 typedef HeapHeader<HeapHeader4, Heap_Lv4_TableSize> HeapHeader5;
125 
126 typedef HeapHeader5 HeapHeaderRoot;
127 
128 
129 template<class T, UPInt N>
130 inline bool HeapHeader<T,N>::HasTable(UPInt address) const
131 {
132  UPInt i4 = (address & Heap_Lv5_PageMask) >> Heap_Lv4_PageShift;
133  UPInt i3 = (address & Heap_Lv4_PageMask) >> Heap_Lv3_PageShift;
134  UPInt i2 = (address & Heap_Lv3_PageMask) >> Heap_Lv2_PageShift;
135  //UPInt i1 = (address & Heap_Lv2_PageMask) >> Heap_Lv1_PageShift; // DBG
136 
137  HeapHeader4* table4 = this->GetTable();
138  if (table4)
139  {
140  HeapHeader3* table3 = table4[i4].GetTable();
141  if (table3)
142  {
143  HeapHeader2* table2 = table3[i3].GetTable();
144  if (table2)
145  {
146  HeapHeader1* table1 = table2[i2].GetTable();
147  if (table1)
148  {
149  return true;
150  }
151  }
152  }
153  }
154  return false;
155 }
156 
157 #endif
158 
159 
160 // ***** PageTable
161 //
162 // Root Page Table.
163 // Root interface implementing a page table that spans an address space,
164 // implemented differently for 32 and 64-bit system. The interface supports
165 // mapping and un-mapping address ranges, such that after a memory range is
166 // mapped, a Header class is allocated that corresponds to every BlockSize.
167 //
168 // Internally the headers for mapped ranges are managed with reference counts.
169 //------------------------------------------------------------------------
170 class PageTable
171 {
172 public:
173  PageTable();
174 
175  // Init creates a single global instance in static memory
176  // and assigns GlobalPageTable.
177  static void Init();
178 
179  // Set/Get the bootstrapping starter allocator.
180  void SetStarter(Starter* s) { pStarter = s; }
181  Starter* GetStarter() { return pStarter; }
182 
183  // Looks up Header1 address based on the global page table.
184  // DOESN'T DO ERROR CHECKS - these are not necessary within internal addressing
185  // in allocator (only needed for externally passed addresses).
186  KY_INLINE HeapSegment* GetSegment(UPInt address) const
187  {
188 
189 #ifndef KY_64BIT_POINTERS
190 
191  UPInt rootIndex = address >> Heap_Root_PageShift;
192  const HeapHeaderRoot* rootHeader = RootTable + rootIndex;
193  UPInt i1 = (address & Heap_Lv2_PageMask) >> Heap_Lv1_PageShift;
194  return rootHeader->GetTable()[i1].pSegment;
195 
196 #else
197 
198  UPInt i5 = address >> Heap_Lv5_PageShift;
199  UPInt i4 = (address & Heap_Lv5_PageMask) >> Heap_Lv4_PageShift;
200  UPInt i3 = (address & Heap_Lv4_PageMask) >> Heap_Lv3_PageShift;
201  UPInt i2 = (address & Heap_Lv3_PageMask) >> Heap_Lv2_PageShift;
202  UPInt i1 = (address & Heap_Lv2_PageMask) >> Heap_Lv1_PageShift;
203 
204  const HeapHeaderRoot* rootHeader = RootTable + i5;
205 
206  return rootHeader->
207  GetTable(i4)->
208  GetTable(i3)->
209  GetTable(i2)->
210  GetTable(i1)->pSegment;
211 #endif
212 
213  }
214 
215 
216  // Obtains a pointer to header with page table validity check.
217  KY_INLINE HeapSegment* GetSegmentSafe(UPInt address) const
218  {
219 
220 #ifndef KY_64BIT_POINTERS
221 
222  UPInt rootIndex = address >> Heap_Root_PageShift;
223  UPInt i1 = (address & Heap_Lv2_PageMask) >> Heap_Lv1_PageShift;
224  const HeapHeaderRoot* rootHeader = RootTable + rootIndex;
225 
226  return rootHeader->HasTable() ? (rootHeader->GetTable()[i1].pSegment) : 0;
227 
228 #else
229 
230  UPInt i5 = address >> Heap_Lv5_PageShift;
231  UPInt i4 = (address & Heap_Lv5_PageMask) >> Heap_Lv4_PageShift;
232  UPInt i3 = (address & Heap_Lv4_PageMask) >> Heap_Lv3_PageShift;
233  UPInt i2 = (address & Heap_Lv3_PageMask) >> Heap_Lv2_PageShift;
234  UPInt i1 = (address & Heap_Lv2_PageMask) >> Heap_Lv1_PageShift;
235 
236  const HeapHeaderRoot* table5 = RootTable + i5;
237  if (table5)
238  {
239  const HeapHeader4* table4 = table5->GetTable(i4);
240  if (table4)
241  {
242  const HeapHeader3* table3 = table4->GetTable(i3);
243  if (table3)
244  {
245  const HeapHeader2* table2 = table3->GetTable(i2);
246  if (table2)
247  {
248  const HeapHeader1* table1 = table2->GetTable(i1);
249  if (table1)
250  {
251  return table1->pSegment;
252  }
253  }
254  }
255  }
256  }
257 
258  return NULL;
259 
260 #endif
261 
262  }
263 
264  // Maps an address range by allocating all of the headers for it.
265  // Input:
266  // address - start address of the heap segment.
267  // size - Heap size in bytes.
268  // Returns true if headers of Lv2 are successfully mapped, false
269  // if allocation failed.
270  bool MapRange(void* address, UPInt size);
271 
272  // Unmaps a memory range mapped by MapRange.
273  void UnmapRange(void* address, UPInt size);
274 
275  // Remaps a memory range mapped by MapRange.
276  bool RemapRange(void* address, UPInt newSize, UPInt oldSize);
277 
278  // Helper function used to assign a range of segment pointers,
279  // used for mapping and external nested heap assignments.
280  void SetSegmentInRange(UPInt address, UPInt size, HeapSegment* seg);
281 
282 #ifdef KY_MEMORY_ENABLE_DEBUG_INFO
283  void SetDebugNode(UPInt address, DebugNode* page);
284  DebugNode* GetDebugNode(UPInt address) const;
285  DebugNode* FindDebugNode(UPInt address) const;
286 #endif
287 
288  void VisitMem(MemVisitor* visitor)
289  {
290  pStarter->VisitMem(visitor);
291  }
292 
293 private:
294  // Bootstrapping starter allocator used for pages needed for
295  // Map/Unmap implementation.
296  Starter* pStarter;
297 
298  // Root page table. We could make it static or allocate it in the future;
299  // however, we can't grab it from page allocator as the later one has fixed
300  // size while this table contains the remaining number of entries.
301  HeapHeaderRoot RootTable[Heap_Root_TableSize];
302 };
303 
304 extern PageTable* GlobalPageTable;
305 
306 }} // Kaim::Heap
307 
308 #endif
Definition: gamekitcrowddispersion.h:20