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