1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_ThreadLocalStorage.cpp
4 
5   Copyright (C)2009-2012 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: 47384 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/os/os_ThreadLocalStorage.h>
17 #include <nn/os/os_Result.h>
18 #include <nn/os/os_Private.h>
19 #include <nn/os/os_ErrorHandlerSelect.h>
20 #include <nn/assert.h>
21 #include <nn/hw/ARM/reg_access.h>
22 //---------------------------------------------------------------------------
23 
24 using namespace nn;
25 using nn::Result;
26 
27 namespace nn{ namespace os{
28 
29     namespace
30     {
31 #if defined(NN_PROCESSOR_ARM_V6)
32         NN_STATIC_ASSERT(TLS_NUM == 16);
33 
34         typedef ThreadLocalRegion ThreadLocalBuffer;
35 
GetThreadLocalBuffer()36         inline ThreadLocalBuffer* GetThreadLocalBuffer()
37         {
38             return GetThreadLocalRegion();
39         }
40 #elif defined(NN_PROCESSOR_ARM_V5)
41         struct ThreadLocalBuffer
42         {
43             uptr tls[TLS_NUM];
44         };
45 
46         ThreadLocalBuffer s_ThreadLocalBuffers[nn::os::CTR::ARM946ES::NUM_THREAD_INDEX];
47 
48         inline ThreadLocalBuffer* GetThreadLocalBuffer()
49         {
50             return s_ThreadLocalBuffers + nn::os::CTR::ARM946ES::GetThreadIndex();
51         }
52 #endif
53 
54         u16 sTLSMap = 0;   // Manages TLS allocation status with bits 0 to 15
55 
56         /* Please see man pages for details
57 
58 
59 
60         */
IsMappedIndex(s32 index)61         inline bool IsMappedIndex(s32 index)
62         {
63             if( (index < 0) || (TLS_NUM <= index) )
64             {
65                 return false;
66             }
67 
68             return ((sTLSMap >> index) & 1) == 1;
69         }
70 
71         /* Please see man pages for details
72 
73 
74 
75         */
SearchFreeTLSIndex()76         s32 SearchFreeTLSIndex()
77         {
78 
79             for(int i = 0; i < TLS_NUM; ++i)
80             {
81                 if(!IsMappedIndex(i))
82                 {
83                     return i;
84                 }
85             }
86             return -1;
87         }
88 
89         /* Please see man pages for details
90 
91 
92 
93         */
AllocateTLSIndex()94         s32 AllocateTLSIndex()
95         {
96             s32 index = SearchFreeTLSIndex();
97             if(index >= 0 && index < TLS_NUM)
98             {
99                 sTLSMap |= (1 << index);
100             }
101             return index;
102         }
103 
104         /* Please see man pages for details
105 
106 
107 
108         */
FreeTLSIndex(int index)109         s32 FreeTLSIndex(int index)
110         {
111             if(!IsMappedIndex(index))
112             {
113                 return -1;
114             }
115             return sTLSMap &= ~(1 << index);
116         }
117 
118     } // Namespace
119 
120 
121 
ThreadLocalStorage()122 ThreadLocalStorage::ThreadLocalStorage()
123 {
124     Initialize();
125 }
126 
~ThreadLocalStorage()127 ThreadLocalStorage::~ThreadLocalStorage()
128 {
129     if( IsMappedIndex(m_Index) )
130     {
131         Finalize();
132     }
133 }
134 
Initialize()135 void ThreadLocalStorage::Initialize()
136 {
137     this->m_Index = AllocateTLSIndex();
138     NN_TASSERTMSG_(m_Index >= 0, "Out of Thread Local Storage Slot.");
139     if ( m_Index < 0 )
140     {
141         NN_OS_ERROR_IF_FAILED(ResultExceedTlsLimit());
142     }
143 }
144 
Finalize()145 void ThreadLocalStorage::Finalize()
146 {
147     NN_TASSERT_(m_Index >= 0 && m_Index < TLS_NUM);
148     NN_TASSERT_(IsMappedIndex(m_Index));
149 
150     FreeTLSIndex(m_Index);
151 }
152 
GetValue() const153 uptr ThreadLocalStorage::GetValue() const
154 {
155     NN_TASSERT_(m_Index >= 0 && m_Index < TLS_NUM);
156     NN_TASSERT_(IsMappedIndex(m_Index));
157 
158     return GetThreadLocalBuffer()->tls[m_Index];
159 }
160 
SetValue(uptr value)161 void ThreadLocalStorage::SetValue(uptr value)
162 {
163     NN_TASSERT_(m_Index >= 0 && m_Index < TLS_NUM);
164     NN_TASSERT_(IsMappedIndex(m_Index));
165     NN_TASSERT_(IsMappedIndex(m_Index));
166 
167     GetThreadLocalBuffer()->tls[m_Index] = value;
168 }
169 
SetValueTo(void * pTo,uptr value)170 void ThreadLocalStorage::SetValueTo(void* pTo, uptr value)
171 {
172     ThreadLocalBuffer* pTlb = reinterpret_cast<ThreadLocalBuffer*>(pTo);
173     pTlb->tls[m_Index] = value;
174 }
175 
ClearAllSlots()176 void ThreadLocalStorage::ClearAllSlots()
177 {
178     ThreadLocalBuffer& tlr = *GetThreadLocalBuffer();
179 
180     for( int i = 0; i < TLS_NUM; ++i )
181     {
182         tlr.tls[i] = 0;
183     }
184 }
185 
186 }} // namespace nn::os
187 
188