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