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