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