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