1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: fnd_UnitHeap.h
4
5 Copyright (C)2009 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 34147 $
14 *---------------------------------------------------------------------------*/
15
16 /*! @file
17 @brief ユニットヒープに関するAPIの宣言
18
19 */
20
21 #ifndef NN_FND_FND_UNIT_HEAP_H_
22 #define NN_FND_FND_UNIT_HEAP_H_
23
24 #include <nn/fnd/fnd_HeapBase.h>
25 #include <nn/util/util_TypeTraits.h>
26 #include <nn/util/util_StaticAssert.h>
27 #include <nn/fnd/fnd_Allocator.h>
28 #include <nn/Assert.h>
29 #include <nn/os.h>
30
31
32 #ifdef __cplusplus
33
34 namespace nn { namespace fnd {
35
36 /*!
37 @brief ユニットヒープのベースクラスです。
38
39 このクラスのインスタンスを直接作成することはできません。
40 */
41 class UnitHeapBase : public HeapBase
42 {
43 public:
44
45 /*!
46 @brief 指定したユニットサイズとアラインメントのブロックを指定数を管理できるだけのヒープメモリのサイズを取得します。
47
48 @param[in] unit ユニットのサイズを指定します。
49 @param[in] numUnit 確保したいブロックの数。
50 @param[in] alignment ユニットのアラインメント。
51 */
52 static size_t GetRequiredHeapSize(size_t unit, size_t numUnit, s32 alignment = DEFAULT_ALIGNMENT);
53
54 protected:
55
UnitHeapBase()56 UnitHeapBase() : m_FreeNode(0) {}
57
58 UnitHeapBase(size_t unit, uptr addr, size_t size, s32 alignment = DEFAULT_ALIGNMENT, bit32 option = 0) : m_FreeNode(0) { Initialize(unit, addr, size, alignment, option); }
59
60 template <class MemoryBlock>
61 explicit UnitHeapBase(size_t unit, const MemoryBlock& block, s32 alignment = DEFAULT_ALIGNMENT, bit32 option = 0) : m_FreeNode(0) { Initialize(unit, block.GetAddress(), block.GetSize(), alignment, option); }
62
63 void Initialize(size_t unit, uptr addr, size_t size, s32 alignment = DEFAULT_ALIGNMENT, bit32 option = 0);
64
65 void Invalidate();
66
67 void Finalize();
68
69 virtual ~UnitHeapBase();
70
71 void* Allocate();
72
73 void Free(void* p);
74
75 virtual void FreeV(void* p);
76
GetUnitSize()77 size_t GetUnitSize() const { return m_Unit; }
78
GetAllocatableCount()79 size_t GetAllocatableCount() const { return m_Size / m_Unit - m_Count; }
80
GetAllocatedCount()81 size_t GetAllocatedCount() const { return m_Count; }
82
GetStartAddress()83 virtual void* GetStartAddress() const { return reinterpret_cast<void*>(m_Addr); }
84
GetTotalSize()85 virtual size_t GetTotalSize() const { return m_Size; }
86
87 virtual void Dump() const;
88
89 virtual bool HasAddress(const void* addr) const;
90
91 private:
92
93 struct Node
94 {
95 Node* next;
96 };
97
98 size_t m_Unit;
99 uptr m_Addr;
100 size_t m_Size;
101 Node* m_FreeNode;
102 s32 m_Alignment;
103 size_t m_Count;
104
105 };
106
Finalize()107 inline void UnitHeapBase::Finalize()
108 {
109 if (m_FreeNode == 0)
110 {
111 return;
112 }
113 NN_TASSERT_(m_Count == 0);
114 this->m_FreeNode = 0;
115 }
116
~UnitHeapBase()117 inline UnitHeapBase::~UnitHeapBase()
118 {
119 Finalize();
120 }
121
Invalidate()122 inline void UnitHeapBase::Invalidate()
123 {
124 this->m_FreeNode = 0;
125 }
126
Allocate()127 inline void* UnitHeapBase::Allocate()
128 {
129 void* ret = reinterpret_cast<void*&>(m_FreeNode);
130 if (ret)
131 {
132 this->m_FreeNode = m_FreeNode->next;
133 ++this->m_Count;
134
135 // フィルオプション
136 DebugFillMemory(reinterpret_cast<uptr>(ret), m_Unit, HEAP_FILL_TYPE_ALLOC);
137 FillMemoryZero(reinterpret_cast<uptr>(ret), m_Unit);
138 }
139
140 return ret;
141 }
142
HasAddress(const void * addr)143 inline bool UnitHeapBase::HasAddress(const void* addr) const
144 {
145 return m_Addr <= reinterpret_cast<uptr>(addr)
146 && reinterpret_cast<uptr>(addr) < (m_Addr+m_Size);
147 }
148
Free(void * p)149 inline void UnitHeapBase::Free(void* p)
150 {
151 NN_TASSERT_(HasAddress(p));
152
153 DebugFillMemory(reinterpret_cast<uptr>(p), m_Unit, HEAP_FILL_TYPE_FREE);
154
155 reinterpret_cast<Node*&>(p)->next = m_FreeNode;
156 this->m_FreeNode = reinterpret_cast<Node*&>(p);
157 --this->m_Count;
158 }
159
FreeV(void * p)160 inline void UnitHeapBase::FreeV(void* p)
161 {
162 Free(p);
163 }
164
165 /*!
166 @brief ユニットヒープのためのクラステンプレートです。
167
168 このクラステンプレートを実体化したクラスでは、
169 指定したロックポリシーによって、排他制御が行われます。
170 ロックポリシーは @ref nn::os::LockPolicy クラスの内部で宣言される
171 クラスもしくはクラステンプレートを実体化したクラスを指定することができます。
172 上述のクラス以外を LockPolicy に指定した場合の動作・互換性は保障されません。
173
174 ロックされるのは、ヒープ内の操作に対してのみであり、
175 ヒープの階層化に対する操作などを行う場合は、適切な排他処理などが別途必要となります。
176
177 @tparam LockPolicy ヒープに対する操作を行うときのロックポリシーを指定します。
178 */
179 template <class LockPolicy>
180 class UnitHeapTemplate : public UnitHeapBase, private LockPolicy::LockObject
181 {
182 private:
183 typedef UnitHeapBase Base;
184 typedef typename LockPolicy::LockObject LockObject;
185 typedef typename LockPolicy::ScopedLock ScopedLock;
186 public:
187
188 /*!
189 @brief 指定したユニットサイズとアラインメントのブロックを指定数を管理できるだけのヒープメモリのサイズを取得します。
190
191 @param[in] unit ユニットのサイズを指定します。
192 @param[in] numUnit 確保したいブロックの数。
193 @param[in] alignment ユニットのアラインメント。
194 */
195 static size_t GetRequiredHeapSize(size_t unit, size_t numUnit, s32 alignment = DEFAULT_ALIGNMENT)
196 {
197 return Base::GetRequiredHeapSize(unit, numUnit, alignment);
198 }
199
200 /*!
201 @brief コンストラクタです。初期化は行いません。
202 */
UnitHeapTemplate()203 UnitHeapTemplate() {}
204
205 /*!
206 @brief コンストラクタです。指定したパラメータを用いてユニットヒープの初期化を行います。
207
208 @param[in] unit ユニットのサイズを指定します。
209 @param[in] addr ユニットヒープで使うメモリの先頭アドレスを指定します。
210 @param[in] size ユニットヒープで使うメモリのサイズを指定します。
211 @param[in] alignment ユニットのアラインメントを指定します。
212 @param[in] option オプションを指定します。未実装です。
213 */
214 UnitHeapTemplate(size_t unit, uptr addr, size_t size, s32 alignment = DEFAULT_ALIGNMENT, bit32 option = 0)
215 {
216 Initialize(unit, addr, size, alignment, option);
217 }
218
219 /*!
220 @brief コンストラクタです。指定したパラメータを用いてユニットヒープの初期化を行います。
221
222 @param[in] unit ユニットのサイズを指定します。
223 @param[in] block フレームヒープに割り当てるメモリブロックを指定します。
224 @param[in] alignment ユニットのアラインメントを指定します。
225 @param[in] option オプションを指定します。未実装です。
226 */
227 template <class MemoryBlock>
228 explicit UnitHeapTemplate(size_t unit, const MemoryBlock& block, s32 alignment = DEFAULT_ALIGNMENT, bit32 option = 0)
229 {
230 Initialize(unit, block.GetAddress(), block.GetSize(), alignment, option);
231 }
232
233 /*!
234 @brief ヒープ内にユニットヒープを作成します。
235
236 この関数で作成したヒープは @ref HeapBase::Destroy により破壊してください。
237 ExpHeap自身をaddrとsizeで指定した領域内に作成します。
238 このため、指定した領域の大きさから sizeof(ExpHeap) の大きさだけ少ない領域をヒープとして割り当てます。
239
240 placementによりExpHeapオブジェクト自身の配置場所を指定します。
241 placementに HEAP_INFOPLACEMENT_HEAD を指定すると領域の先頭(addr から addr+sizeof(ExpHeap) までの領域)にExpHeapオブジェクト自身を配置します。
242 placementに HEAP_INFOPLACEMENT_TAIL を指定すると領域の末尾(addr+size-sizeof(ExpHeap) から addr+size までの領域)にExpHeapオブジェクト自身を配置します。
243
244 @param[in] parent addr を領域内に持つ親のヒープを指定します。
245 @param[in] unit ユニットのサイズを指定します。
246 @param[in] addr ユニットヒープで使うメモリの先頭アドレスを指定します。
247 @param[in] size ユニットヒープで使うメモリのサイズを指定します。
248 @param[in] alignment ユニットのアラインメントを指定します。
249 @param[in] option オプションを指定します。未実装です。
250 @param[in] placement 管理領域(UnitHeapオブジェクト)の配置場所を指定します。
251 */
252 static UnitHeapTemplate* Create(HeapBase* parent, size_t unit, void* addr, size_t size, s32 alignment = DEFAULT_ALIGNMENT, bit32 option = 0, bit32 placement = HEAP_INFOPLACEMENT_HEAD);
253
254 /*!
255 @brief 指定したパラメータを用いてユニットヒープの初期化を行います。
256 初期化無しのコンストラクタを使ってオブジェクトを生成した場合に用います。
257
258 @param[in] unit ユニットのサイズを指定します。
259 @param[in] addr ユニットヒープで使うメモリの先頭アドレスを指定します。このアドレスは alignment パラメータの値でアラインメントされている必要があります。
260 @param[in] size ユニットヒープで使うメモリのサイズを指定します。
261 @param[in] alignment ユニットのアラインメントを指定します。
262 @param[in] option オプションを指定します。未実装です。
263 */
264 void Initialize(size_t unit, uptr addr, size_t size, s32 alignment = DEFAULT_ALIGNMENT, bit32 option = 0)
265 {
266 Base::Initialize(unit, addr, size, alignment, option);
267 LockObject::Initialize();
268 }
269
270 /*!
271 @brief ヒープオブジェクトを無効化します。
272 この関数を呼んだ後は @ref Finalize 以外の操作をヒープに対して行うことができなくなります。
273 */
Invalidate()274 void Invalidate() { Base::Invalidate(); }
275
276 /*!
277 @brief ヒープオブジェクトの終了処理をします。
278 この関数はデストラクタの中で暗黙的に呼ばれるため、明示的に呼ぶ必要はありません。
279
280 ヒープの中に未解放のブロックが存在した場合、アプリケーションは強制終了します。
281 意図して未解放のままこの関数を呼ぶ際は、その前に、明示的に @ref Invalidate 関数を呼んでください。
282 */
Finalize()283 void Finalize()
284 {
285 LockObject::Finalize();
286 Base::Finalize();
287 }
288
289 /*!
290 @brief デストラクタです。
291
292 破棄時の注意は @ref Finalize を参照してください。
293 */
~UnitHeapTemplate()294 virtual ~UnitHeapTemplate() {}
295
296 /*!
297 @brief ヒープからユニットに基づいてメモリを確保します。
298
299 @return 確保に成功した場合は、メモリへのポインタを返します。
300 確保に失敗した場合は、0 を返します。
301 */
Allocate()302 void* Allocate()
303 {
304 ScopedLock lk(*this);
305 return Base::Allocate();
306 }
307
308 /*!
309 @brief このヒープから確保したメモリを解放します。
310
311 @param[in] p メモリへのポインタを指定します。
312 */
Free(void * p)313 void Free(void* p)
314 {
315 ScopedLock lk(*this);
316 Base::Free(p);
317 }
318
319 /*!
320 @brief このヒープから確保したメモリを解放します。
321
322 仮想メンバ関数であるため、HeapBaseから解放できます。
323
324 @param[in] p メモリへのポインタを指定します。
325 */
FreeV(void * p)326 virtual void FreeV(void* p) { Free(p); }
327
328
329 /*!
330 @brief このユニットヒープのユニットサイズを取得します。
331
332 @return ユニットサイズを返します。
333 */
GetUnitSize()334 size_t GetUnitSize() const { return Base::GetUnitSize(); }
335
336 /*!
337 @brief 現在このヒープから確保できるユニットの数を取得します。
338
339 @return 確保できるユニットの数を返します。
340 */
GetAllocatableCount()341 size_t GetAllocatableCount() const
342 {
343 ScopedLock lk(*this);
344 return Base::GetAllocatableCount();
345 }
346
347 /*!
348 @brief 現在このヒープから確保されているユニットの数を取得します。
349
350 @return 確保されているユニットの数を返します。
351 */
GetAllocatedCount()352 size_t GetAllocatedCount() const {
353 ScopedLock lk(*this);
354 return Base::GetAllocatedCount();
355 }
356
357 /*!
358 @brief ユニットヒープのメモリ領域の開始アドレスを取得します。
359
360 @return ユニットヒープのメモリ領域の開始アドレスをを返します。
361 */
GetStartAddress()362 virtual void* GetStartAddress() const { return Base::GetStartAddress(); }
363
364 /*!
365 @brief ユニットヒープに割り当てられているメモリサイズを取得します。
366
367 @return ユニットヒープに割り当てられているメモリサイズを返します。
368 */
GetTotalSize()369 virtual size_t GetTotalSize() const { return Base::GetTotalSize(); }
370
371 /*!
372 @brief ヒープ内部の情報を表示します。(デバッグ用)
373
374 @return 無し。
375 */
Dump()376 virtual void Dump() const
377 {
378 ScopedLock lk(*this);
379 Base::Dump();
380 }
381
382 /*!
383 @brief 指定したアドレスがヒープに含まれているか調べます。
384
385 @param[in] addr 調べたいアドレスを指定します。
386
387 @return ヒープに含まれていれば true を返し、含まれていなければ false を返します。
388 */
HasAddress(const void * addr)389 virtual bool HasAddress(const void* addr) const { return Base::HasAddress(addr); }
390
391 class Allocator;
392
393 };
394
395 /*!
396 @brief ユニットヒープ用のアロケータクラスです。
397 */
398 template <class LockPolicy>
399 class UnitHeapTemplate<LockPolicy>::Allocator : public IAllocator
400 {
401 public:
402
403 /*!
404 @brief ユニットヒープを指定してアロケータを初期化するコンストラクタです。
405
406 @param[in] ユニットヒープを指定します。
407 */
Allocator(UnitHeapTemplate<LockPolicy> & heap)408 Allocator(UnitHeapTemplate<LockPolicy>& heap) : m_Heap(&heap) {}
409
410 /*!
411 @brief 初期化をしないコンストラクタです。
412 */
Allocator()413 Allocator() : m_Heap(0) {}
414
415 /*!
416 @brief 初期化されていないアロケータを初期化します。
417
418 @param[in] ユニットヒープを指定します。
419 */
Initialize(UnitHeapTemplate<LockPolicy> & heap)420 void Initialize(UnitHeapTemplate<LockPolicy>& heap) { m_Heap = &heap; }
421
422 /*!
423 @brief アロケータにセットされているユニットヒープを返します。
424 @return アロケータにセットされているユニットヒープ
425 */
GetHeap()426 UnitHeapTemplate<LockPolicy>* GetHeap() { return m_Heap; }
427
428 /*!
429 @brief アロケータにセットされているユニットヒープを返します。
430 @return アロケータにセットされているユニットヒープ
431 */
GetHeap()432 const UnitHeapTemplate<LockPolicy>* GetHeap() const { return m_Heap; }
433
434 /*!
435 @brief 指定したサイズとアラインメントでメモリ領域を確保します。
436
437 @param[in] size 確保するメモリのサイズ
438 @param[in] alignment 確保するメモリのアラインメント
439
440 @return 確保したメモリ領域の先頭へのポインタ
441 */
442 virtual void* Allocate(size_t size, s32 alignment);
443
444 /*!
445 @brief メモリ領域を解放します。
446 @param[in] p 確保されているメモリ領域の先頭へのポインタ
447 */
448 virtual void Free(void* p);
449
450 private:
451 UnitHeapTemplate<LockPolicy>* m_Heap;
452 };
453
454 template <class LockPolicy>
Allocate(size_t size,s32 alignment)455 inline void* UnitHeapTemplate<LockPolicy>::Allocator::Allocate(size_t size, s32 alignment)
456 {
457 if (size == m_Heap->m_Unit && alignment >= 0 && m_Heap->m_Alignment % alignment == 0)
458 {
459 return m_Heap->Allocate();
460 }
461 else
462 {
463 return 0;
464 }
465 }
466
467 template <class LockPolicy>
Free(void * p)468 inline void UnitHeapTemplate<LockPolicy>::Allocator::Free(void* p)
469 {
470 m_Heap->Free(p);
471 }
472
473 /*!
474 @brief ロック操作をしないスレッドアンセーフなユニットヒープを表す型です。
475 */
476 typedef UnitHeapTemplate<nn::os::LockPolicy::NoLock> UnitHeap;
477
478 /*!
479 @brief ヒープごとに用意されるクリティカルセクションで保護された、スレッドセーフなユニットヒープを表す型です。
480 */
481 typedef UnitHeapTemplate<nn::os::LockPolicy::Object<nn::os::CriticalSection> > ThreadSafeUnitHeap;
482
483 template <class LockPolicy>
Create(HeapBase * parent,size_t unit,void * addr,size_t size,s32 alignment,bit32 option,bit32 placement)484 UnitHeapTemplate<LockPolicy>* UnitHeapTemplate<LockPolicy>::Create(HeapBase* parent, size_t unit, void* addr, size_t size, s32 alignment, bit32 option, bit32 placement)
485 {
486 UnitHeapTemplate* heap;
487 if ( parent->FindHeap(addr) != parent ) return 0;
488
489 if ( placement == HEAP_INFOPLACEMENT_HEAD )
490 {
491 heap = new (addr) UnitHeapTemplate(unit, reinterpret_cast<uptr>(addr)+sizeof(UnitHeapTemplate), static_cast<size_t>(size - sizeof(UnitHeapTemplate)), alignment, option);
492 }
493 else if ( placement == HEAP_INFOPLACEMENT_TAIL )
494 {
495 void* placeaddr = reinterpret_cast<void*>(reinterpret_cast<uptr>(addr)+static_cast<size_t>(size - sizeof(UnitHeapTemplate)));
496 heap = new (placeaddr) UnitHeapTemplate(unit, reinterpret_cast<uptr>(addr), static_cast<size_t>(size - sizeof(UnitHeapTemplate)), alignment, option);
497 }
498 else
499 {
500 return 0;
501 }
502
503 heap->SetParent(parent);
504 return heap;
505 }
506
507 }}
508
509 #endif
510
511 #endif
512