/*---------------------------------------------------------------------------* Project: Horizon File: fnd_Interlocked.h Copyright (C)2009 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 24961 $ *---------------------------------------------------------------------------*/ /* @file @brief 排他制御された変数を扱うクラスの宣言 */ #ifndef NN_FND_FND_INTERLOCKED_H_ #define NN_FND_FND_INTERLOCKED_H_ #ifdef __cplusplus #include #if defined(NN_PROCESSOR_ARM_V4) || defined(NN_PROCESSOR_ARM_V5) #include namespace nn { namespace fnd { using ARMv4::Interlocked; } } #elif defined(NN_PROCESSOR_ARM_V6) #include namespace nn { namespace fnd { using ARMv6::Interlocked; } } #else #error processor not selected #endif namespace nn { namespace fnd { /* @brief 排他制御された変数を扱うクラステンプレートです。 テンプレート引数 T は POD である必要があります。 */ template class InterlockedVariable { private: template struct StorageSelecter; template struct StorageSelecter::type> { typedef s64 Type; }; template struct StorageSelecter::type> { typedef s32 Type; }; template struct StorageSelecter::type> { typedef s16 Type; }; template struct StorageSelecter::type> { typedef s8 Type; }; private: volatile T m_v; //!< バリア変数 // AtomicUpdateConditional 用関数オブジェクトの定義 template struct ConvertFunc { Converter& m_converter; ConvertFunc(Converter converter) : m_converter(converter) {} bool operator()(T& x) { x = m_converter(x); return true; } }; #define NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(F, op) \ struct F \ { \ T m_operand; \ template F(const U& operand) : m_operand(operand) {} \ bool operator()(T& x) { x op m_operand; return true; } \ }; NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(AssignFunc, =) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(PlusFunc, +=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(MinusFunc, -=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(OrFunc, |=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(AndFunc, &=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC(XorFunc, ^=) #undef NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_FUNC #define NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(F, preop, postop) \ struct F \ { \ T result; \ bool operator()(T& x) { result = preop x postop; return true; } \ }; NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PreIncFunc, ++, ) NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PreDecFunc, --, ) NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PostIncFunc, , ++) NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC(PostDecFunc, , --) #undef NN_UTIL_INTERLOCKED_DEFINE_UNARY_FUNC struct CompareAndSwapFunc { T m_comparand; T m_value; T m_result; bool operator()(T& x) { m_result = x; if (x == m_comparand) { x = m_value; return true; } else { return false; } } CompareAndSwapFunc(T comparand, T value) : m_comparand(comparand), m_value(value) {} }; public: /* @brief コンストラクタです。 @param[in] v 初期値 */ InterlockedVariable() : m_v() {} InterlockedVariable(T v) : m_v(v) {} operator T() const { typename StorageSelecter::Type x = reinterpret_cast::Type&>(m_v); return reinterpret_cast(x); } T operator ->() { typename StorageSelecter::Type x = reinterpret_cast::Type&>(m_v); return reinterpret_cast(x); } /* @brief バリア変数を取得します。 @return バリア変数を返します。 */ T Read() const { return *this; } /* @brief バリア変数を排他制御なしで変更します。 @param[in] v 変更後の値 */ void WriteNotAtomic (T v) { m_v = v; } /* @brief 関数オブジェクトを排他制御下で実行します。 @param[in] updater 関数オブジェクト @return 関数オブジェクトの実行の結果を返します。 */ template bool AtomicUpdateConditional(Updater& updater) { return Interlocked::AtomicUpdate(&m_v, updater); } /* @brief バリア変数と comparand を比較し、等しければバリア変数を value に変更します。 @param[in] comparand 比較する値 @param[in] value 等しい場合に設定する値 @return 比較、代入を行う直前でのバリア変数を返します。 */ T CompareAndSwap(T comparand, T value) { CompareAndSwapFunc f(comparand, value); AtomicUpdateConditional(f); return f.m_result; } /* @brief バリア変数と comparand を比較し、等しければバリア変数を value に変更します。 @param[in] comparand 比較する値 @param[in] value 等しい場合に設定する値 @return value への変更が成功すれば 0 を返し、失敗すれば 1 を返します。 */ int CompareAndSwapWeak(T comparand, T value) { return Interlocked::CompareAndSwapWeak(&m_v, comparand, value); } /* @brief バリア変数と cmpValue が等しくなるまで待ち、等しくなれば内部を newValue に変更します。 @param[in] comparand 比較する値 @param[in] newValue 等しい場合に設定する値 */ void CompareAndSpinWaitAndSwap(T cmpValue, T newValue) { for(;;) { if( m_v == cmpValue ) { if( CompareAndSwapWeak(cmpValue, newValue) == 0 ) { break; } } } } // 演算子のオーバーロード #define NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(F, op) \ template \ void operator op(V v) { F f(v); AtomicUpdateConditional(f); } NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(AssignFunc, =) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(PlusFunc, +=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(MinusFunc, -=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(OrFunc, |=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(AndFunc, &=) NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR(XorFunc, ^=) #undef NN_UTIL_INTERLOCKED_DEFINE_ASSIGN_OPERATOR #define NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(F, op, premarker) \ InterlockedVariable operator op(premarker) { F f; AtomicUpdateConditional(f); return f.result; } \ NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PreIncFunc, ++, ) NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PreDecFunc, --, ) NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PostIncFunc, ++, int) NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR(PostDecFunc, --, int) #undef NN_UTIL_INTERLOCKED_DEFINE_UNARY_OPERATOR }; }} #endif // __cplusplus #endif // NN_UTIL_INTERLOCKED_H_