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 #ifndef NN_FND_ARMV6_FND_INTERLOCKED_H_ 17 #define NN_FND_ARMV6_FND_INTERLOCKED_H_ 18 19 #ifdef __cplusplus 20 21 #include <nn/types.h> 22 #include <nn/util/util_TypeTraits.h> 23 24 namespace nn { 25 namespace fnd { 26 namespace ARMv6 27 { 28 namespace detail 29 { 30 template <typename T> 31 struct LoadStoreRegEx 32 { LoadRegExLoadStoreRegEx33 static T LoadRegEx (volatile T* ptr) { return __ldrex(ptr); } StoreRegExLoadStoreRegEx34 static int StoreRegEx(T val, volatile T* ptr) { return __strex(val, ptr); } 35 }; 36 template <> 37 struct LoadStoreRegEx<s64> 38 { 39 static s64 LoadRegEx (volatile s64* ptr) { return __ldrexd(ptr); } 40 static int StoreRegEx(s64 val, volatile s64* ptr) { return __strexd(val, ptr); } 41 }; 42 } 43 44 class Interlocked 45 { 46 private: 47 48 template <typename T, typename = void> struct AtomicStorageSelecter; 49 50 template <typename T> struct AtomicStorageSelecter<T, typename nn::util::enable_if<sizeof(T) == sizeof(s64)>::type> 51 { 52 typedef s64 Type; 53 }; 54 55 template <typename T> struct AtomicStorageSelecter<T, typename nn::util::enable_if<sizeof(T) == sizeof(s32)>::type> 56 { 57 typedef s32 Type; 58 }; 59 60 template <typename T> struct AtomicStorageSelecter<T, typename nn::util::enable_if<sizeof(T) == sizeof(s16)>::type> 61 { 62 typedef s16 Type; 63 }; 64 65 template <typename T> struct AtomicStorageSelecter<T, typename nn::util::enable_if<sizeof(T) == sizeof(s8)>::type> 66 { 67 typedef s8 Type; 68 }; 69 70 public: 71 static s32 CompareAndSwap(s32* pTarget, s32 comp, s32 swap); 72 static s32 Swap(s32* pTarget, s32 value); 73 static s32 Increment(s32* pTarget); 74 static s32 Decrement(s32* pTarget); 75 static s32 Add(s32* pTarget, s32 value); 76 static s32 Substract(s32* pTarget, s32 value); 77 static s32 BitwiseOr(s32* pTarget, s32 value); 78 static s32 BitwiseAnd(s32* pTarget, s32 value); 79 static s32 BitwiseXor(s32* pTarget, s32 value); 80 static s32 BitwiseNot(s32* pTarget); 81 static s64 Read(s64* pTarget) { return *pTarget; } 82 static u64 CompareAndSwap(u64* pTarget, const u64& comp, u64 swap); 83 84 template <typename T> 85 static T* CompareAndSwap(T** pTarget, T* comp, T* swap) 86 { 87 return reinterpret_cast<T*>( 88 CompareAndSwap( reinterpret_cast<s32*>(pTarget), 89 reinterpret_cast<s32>(comp), 90 reinterpret_cast<s32>(swap) )); 91 } 92 93 template <typename T> 94 static T* Swap(T** pTarget, T* value) 95 { 96 return reinterpret_cast<T*>( 97 Swap( reinterpret_cast<s32*>(pTarget), 98 reinterpret_cast<s32>(value) )); 99 } 100 101 template <typename T, typename UpdateFunc> 102 static bool AtomicUpdate(volatile T* p, UpdateFunc& update, typename nn::util::enable_if<sizeof(T) <= sizeof(s64)>::type* = 0) 103 { 104 typedef typename AtomicStorageSelecter<T>::Type Storage; 105 typedef detail::LoadStoreRegEx<Storage> LoadStore; 106 107 // Use a union to guarantee that T can be used as a POD 108 union U 109 { 110 T v; 111 Storage n; 112 }; 113 114 U x; 115 116 for(;;) 117 { 118 x.n = LoadStore::LoadRegEx(reinterpret_cast<volatile Storage*&>(p)); 119 120 if (!update(x.v)) 121 { 122 __clrex(); 123 return false; 124 } 125 126 if ( LoadStore::StoreRegEx(x.n, reinterpret_cast<volatile Storage*&>(p)) == 0 ) 127 { 128 return true; 129 } 130 } 131 } 132 133 template <typename T> 134 static int CompareAndSwapWeak(volatile T* p, T compValue, T setValue, typename nn::util::enable_if<sizeof(T) <= sizeof(s64)>::type* = 0) 135 { 136 typedef typename AtomicStorageSelecter<T>::Type Storage; 137 typedef detail::LoadStoreRegEx<Storage> LoadStore; 138 139 // Use a union to guarantee that T can be used as a POD 140 union U 141 { 142 T v; 143 Storage n; 144 }; 145 146 U x; 147 148 x.n = LoadStore::LoadRegEx(reinterpret_cast<volatile Storage*&>(p)); 149 150 int ret = 1; 151 152 if( x.v != compValue ) 153 { 154 LoadStore::StoreRegEx(x.n, reinterpret_cast<volatile Storage*&>(p)); 155 } 156 else 157 { 158 x.v = setValue; 159 ret = LoadStore::StoreRegEx(x.n, reinterpret_cast<volatile Storage*&>(p)); 160 } 161 162 return ret; 163 } 164 }; 165 } 166 } 167 } 168 169 170 #endif // __cplusplus 171 172 #endif // NN_UTIL_MPCORE_INTERLOCKED_H_ 173