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