1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_Default.cpp
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: 28141 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/Result.h>
17 #include <nn/os.h>
18 
19 namespace nn { namespace os {
20 
21 #if NN_PLATFORM_HAS_MMU
22     namespace
23     {
24         template <typename T>
RoundUp(T x,int r)25         T RoundUp(T x, int r)
26         {
27             return (x + (r - 1)) & ~(r - 1);
28         }
29 
30 
31         class DefaultAutoStackManager : public nn::os::Thread::AutoStackManager
32         {
33         private:
34             static const size_t DESTRUCTOR_STACK_SIZE = 512;
35 
36         private:
37             nn::os::Mutex                               m_DestructorMutex;         //!< スタック領域解放処理用同期オブジェクト
38             bool                                        m_Initialized;
39             NN_PADDING3;
40             NN_PADDING4;
41             nn::os::StackBuffer<DESTRUCTOR_STACK_SIZE>  m_DestructorStack;
42 
43         public:
DefaultAutoStackManager()44             DefaultAutoStackManager() : m_Initialized(false)
45             {
46             }
47 
~DefaultAutoStackManager()48             ~DefaultAutoStackManager()
49             {
50                 if ( m_Initialized )
51                 {
52                     m_DestructorMutex.Finalize();
53                     m_Initialized = false;
54                 }
55             }
56 
Construct(size_t stackSize)57             virtual void* Construct(size_t stackSize)
58             {
59                 if ( !m_Initialized )
60                 {
61                     Initialize();
62                 }
63 
64                 nnosStackMemoryBlock stackBlock;
65                 nnosStackMemoryBlockAllocate(&stackBlock, stackSize);
66 
67                 uptr stackBottom = nnosStackMemoryBlockGetStackBottom(&stackBlock);
68                 stackBottom -= RoundUp(sizeof(nnosStackMemoryBlock), 8);
69 
70                 nnosStackMemoryBlock* pBlockOnStack = reinterpret_cast<nnosStackMemoryBlock*>(stackBottom);
71 
72                 nnosStackMemoryBlockInitialize(pBlockOnStack);
73                 nn::os::detail::Switch(
74                     reinterpret_cast<nn::os::StackMemoryBlock*>(pBlockOnStack),
75                     reinterpret_cast<nn::os::StackMemoryBlock*>(&stackBlock) );
76 
77                 return reinterpret_cast<void*>(stackBottom);
78             }
79 
Destruct(void * pStackBottom,bool isError)80             virtual void Destruct(void* pStackBottom, bool isError)
81             {
82                 if( isError )
83                 {
84                     FreeStack(reinterpret_cast<nnosStackMemoryBlock*>(pStackBottom));
85                 }
86                 else
87                 {
88                     // 複数スレッドで同時にスタック領域解放処理が発生しないようにロックします。
89                     m_DestructorMutex.Lock();
90 
91                     // スレッド用スタックを破棄します。
92                     InvokeOnOtherStack(m_DestructorStack.GetStackBottom(), &FreeStack, pStackBottom, __return_address());
93                 }
94             }
95 
96         private:
Initialize(void)97             void Initialize(void)
98             {
99                 m_DestructorMutex.Initialize(false);
100                 m_Initialized = true;
101             }
102 
FreeStack(void * pStackBottom)103             static void FreeStack(void* pStackBottom)
104             {
105                 nnosStackMemoryBlock* pBlockOnStack = reinterpret_cast<nnosStackMemoryBlock*>(pStackBottom);
106                 nnosStackMemoryBlockFree(pBlockOnStack);
107             }
108 
InvokeOnOtherStack(uptr stackBottom NN_IS_UNUSED_VAR,void (* f)(void *)NN_IS_UNUSED_VAR,void * param NN_IS_UNUSED_VAR,uptr returnAddr NN_IS_UNUSED_VAR)109             static asm void InvokeOnOtherStack(
110                 uptr    stackBottom NN_IS_UNUSED_VAR,
111                 void (*f)(void*)    NN_IS_UNUSED_VAR,
112                 void*   param       NN_IS_UNUSED_VAR,
113                 uptr    returnAddr  NN_IS_UNUSED_VAR)
114             {
115                 ARM
116 
117                 // r0: stackBottom
118                 // r1: f
119                 // r2: param
120                 // r3: returnAddr
121 
122                 mov     sp, r0
123                 mov     r0, r2
124                 mov     lr, r3
125 
126                 // r0: param
127                 // r1: f
128                 // lr: returnAddr
129 
130                 bx      r1
131             }
132         };
133 
134         DefaultAutoStackManager s_AutoStackManager;
135     }
136 #endif  // if NN_PLATFORM_HAS_MMU
137 
138 
SetDefaultAutoStackManager()139 void SetDefaultAutoStackManager()
140 {
141 #if NN_PLATFORM_HAS_MMU
142     nn::os::Thread::SetAutoStackManager(&s_AutoStackManager);
143 #endif  // if NN_PLATFORM_HAS_MMU
144 }
145 
146 
147 
148 }}
149