1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fnd_Interlocked.h
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: 46347 $
14  *---------------------------------------------------------------------------*/
15 
16 /*
17 
18 */
19 
20 #ifndef NN_FND_FND_INTERLOCKED_H_
21 #define NN_FND_FND_INTERLOCKED_H_
22 
23 #ifdef __cplusplus
24 
25 #include <nn/types.h>
26 
27 #if     defined(NN_PROCESSOR_ARM_V4) || defined(NN_PROCESSOR_ARM_V5)
28     #include <nn/fnd/ARMv4/fnd_Interlocked.h>
29     namespace nn {
30         namespace fnd {
31             using ARMv4::Interlocked;
32         }
33     }
34 #elif   defined(NN_PROCESSOR_ARM_V6)
35     #include <nn/fnd/ARMv6/fnd_Interlocked.h>
36     namespace nn {
37         namespace fnd {
38             using ARMv6::Interlocked;
39         }
40     }
41 #else
42     #error processor not selected
43 #endif
44 
45 namespace nn { namespace fnd {
46 
47 /*
48 
49 
50 
51 */
52 template <typename T>
53 class InterlockedVariable
54 {
55 private:
56     template <typename U, typename = void> struct StorageSelecter;
57 
58     template <typename U> struct StorageSelecter<U, typename nn::util::enable_if<sizeof(U) == sizeof(s64)>::type>
59     {
60         typedef s64 Type;
61     };
62 
63     template <typename U> struct StorageSelecter<U, typename nn::util::enable_if<sizeof(U) == sizeof(s32)>::type>
64     {
65         typedef s32 Type;
66     };
67 
68     template <typename U> struct StorageSelecter<U, typename nn::util::enable_if<sizeof(U) == sizeof(s16)>::type>
69     {
70         typedef s16 Type;
71     };
72 
73     template <typename U> struct StorageSelecter<U, typename nn::util::enable_if<sizeof(U) == sizeof(s8)>::type>
74     {
75         typedef s8 Type;
76     };
77 
78 private:
79     volatile T m_v; //
80 
81     // Definitions for AtomicUpdateConditional function object
82 
83     template <class Converter>
84     struct ConvertFunc
85     {
86         Converter& m_converter;
87         ConvertFunc(Converter converter) : m_converter(converter) {}
88         bool operator()(T& x) { x = m_converter(x); return true; }
89     };
90 
91 #define NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(F, op)                       \
92     struct F                                                                \
93     {                                                                       \
94         T m_operand;                                                        \
95         template <typename U> F(const U& operand) : m_operand(operand) {}   \
96         bool operator()(T& x) { x op m_operand; return true; }              \
97     };
98 
99     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(AssignFunc, =)
100     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(PlusFunc, +=)
101     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(MinusFunc, -=)
102     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(OrFunc, |=)
103     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(AndFunc, &=)
104     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(XorFunc, ^=)
105 
106 #undef NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC
107 
108 #define NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(F, preop, postop) \
109     struct F                                                    \
110     {                                                           \
111         T result;                                               \
112         bool operator()(T& x) { result = preop x postop; return true; }   \
113     };
114 
115     NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PreIncFunc,  ++,   )
116     NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PreDecFunc,  --,   )
117     NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PostIncFunc,   , ++)
118     NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PostDecFunc,   , --)
119 
120 #undef NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC
121 
122     struct CompareAndSwapFunc
123     {
124         T m_comparand;
125         T m_value;
126         T m_result;
127         bool operator()(T& x)
128         {
129             m_result = x;
130             if (x == m_comparand)
131             {
132                 x = m_value;
133                 return true;
134             }
135             else
136             {
137                 return false;
138             }
139         }
140         CompareAndSwapFunc(T comparand, T value) : m_comparand(comparand), m_value(value) {}
141     };
142 
143 public:
144     /*
145 
146 
147 
148     */
149     InterlockedVariable() : m_v() {}
150     InterlockedVariable(T v) : m_v(v) {}
151 
152     operator T() const
153     {
154         typename StorageSelecter<T>::Type x = reinterpret_cast<const volatile typename StorageSelecter<T>::Type&>(m_v);
155         return reinterpret_cast<T&>(x);
156     }
157     T operator ->()
158     {
159         typename StorageSelecter<T>::Type x = reinterpret_cast<const volatile typename StorageSelecter<T>::Type&>(m_v);
160         return reinterpret_cast<T&>(x);
161     }
162 
163     /*
164 
165 
166 
167     */
168     T Read() const { return *this; }
169 
170     /*
171 
172 
173 
174     */
175     void WriteNotAtomic (T v) { m_v = v; }
176 
177     /*
178 
179 
180 
181 
182 
183     */
184     template <class Updater>
185     bool AtomicUpdateConditional(Updater& updater) { return Interlocked::AtomicUpdate(&m_v, updater); }
186 
187     /*
188 
189 
190 
191 
192 
193 
194     */
195     T CompareAndSwap(T comparand, T value)
196     {
197         CompareAndSwapFunc f(comparand, value);
198         AtomicUpdateConditional(f);
199         return f.m_result;
200     }
201 
202     /*
203 
204 
205 
206 
207 
208 
209     */
210     int CompareAndSwapWeak(T comparand, T value)
211     {
212         return Interlocked::CompareAndSwapWeak(&m_v, comparand, value);
213     }
214 
215     /*
216 
217 
218 
219 
220     */
221     void CompareAndSpinWaitAndSwap(T cmpValue, T newValue)
222     {
223         for(;;)
224         {
225             if( m_v == cmpValue )
226             {
227                 if( CompareAndSwapWeak(cmpValue, newValue) == 0 )
228                 {
229                     break;
230                 }
231             }
232         }
233     }
234 
235     // Overloaded operators
236 
237 #define NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(F, op)                                       \
238     template <typename V>                                                                       \
239     void operator op(V v) { F f(v); AtomicUpdateConditional(f); }
240 
241     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(AssignFunc, =)
242     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(PlusFunc, +=)
243     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(MinusFunc, -=)
244     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(OrFunc, |=)
245     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(AndFunc, &=)
246     NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(XorFunc, ^=)
247 
248 #undef NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR
249 
250 #define NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(F, op, premarker)                                     \
251     InterlockedVariable operator op(premarker) { F f; AtomicUpdateConditional(f); return f.result; }    \
252 
253     NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PreIncFunc,  ++,    )
254     NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PreDecFunc,  --,    )
255     NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PostIncFunc, ++, int)
256     NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PostDecFunc, --, int)
257 
258 #undef NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR
259 };
260 
261 }}
262 
263 #endif // __cplusplus
264 
265 #endif  // NN_UTIL_INTERLOCKED_H_
266