1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: fnd_Interlocked.h 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: 24961 $ 14 *---------------------------------------------------------------------------*/ 15 16 /* @file 17 @brief 排他制御された変数を扱うクラスの宣言 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 @brief 排他制御された変数を扱うクラステンプレートです。 49 50 テンプレート引数 T は POD である必要があります。 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 // AtomicUpdateConditional 用関数オブジェクトの定義 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 @brief コンストラクタです。 146 147 @param[in] v 初期値 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 @brief バリア変数を取得します。 165 166 @return バリア変数を返します。 167 */ 168 T Read() const { return *this; } 169 170 /* 171 @brief バリア変数を排他制御なしで変更します。 172 173 @param[in] v 変更後の値 174 */ 175 void WriteNotAtomic (T v) { m_v = v; } 176 177 /* 178 @brief 関数オブジェクトを排他制御下で実行します。 179 180 @param[in] updater 関数オブジェクト 181 182 @return 関数オブジェクトの実行の結果を返します。 183 */ 184 template <class Updater> 185 bool AtomicUpdateConditional(Updater& updater) { return Interlocked::AtomicUpdate(&m_v, updater); } 186 187 /* 188 @brief バリア変数と comparand を比較し、等しければバリア変数を value に変更します。 189 190 @param[in] comparand 比較する値 191 @param[in] value 等しい場合に設定する値 192 193 @return 比較、代入を行う直前でのバリア変数を返します。 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 @brief バリア変数と comparand を比較し、等しければバリア変数を value に変更します。 204 205 @param[in] comparand 比較する値 206 @param[in] value 等しい場合に設定する値 207 208 @return value への変更が成功すれば 0 を返し、失敗すれば 1 を返します。 209 */ 210 int CompareAndSwapWeak(T comparand, T value) 211 { 212 return Interlocked::CompareAndSwapWeak(&m_v, comparand, value); 213 } 214 215 /* 216 @brief バリア変数と cmpValue が等しくなるまで待ち、等しくなれば内部を newValue に変更します。 217 218 @param[in] comparand 比較する値 219 @param[in] newValue 等しい場合に設定する値 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 // 演算子のオーバーロード 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