00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef CNTM_ATOMICUTILS_H
00015 #define CNTM_ATOMICUTILS_H
00016 #include <cstddef>
00017 #include <Cntm/Utils/IntTypes.h>
00018
00019 #if !defined(__linux__)
00020 #error Atomic operations not support this OS.
00021 #endif
00022
00023 #if !defined(__GNUC__)
00024 #error Atomic operations not support this compiler.
00025 #endif
00026
00027 #if !(defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__arm))
00028 #error Atomic operations not support this processor.
00029 #endif
00030
00031 namespace Cntm
00032 {
00033 namespace SpecUtils
00034 {
00035
00036 #if defined(__i386__)
00037
00038
00039
00040
00041 typedef int AtomicIntType;
00042
00043
00044
00045
00046 template <typename T>
00047 static inline T* AtomicSwapPtr(T*volatile* Variable, T* NewValue)
00048 {
00049 asm volatile(
00050 "xchgl %0,%1"
00051 :"=r" (NewValue)
00052 :"m" (*Variable), "0" (NewValue)
00053 :"memory");
00054 return NewValue;
00055 }
00056
00057
00058
00059
00060 static inline AtomicIntType AtomicGet(volatile const AtomicIntType* Variable)
00061 {
00062 return *Variable;
00063 }
00064
00065
00066
00067
00068 static inline void AtomicSet(volatile AtomicIntType* Variable, AtomicIntType val)
00069 {
00070 *Variable = val;
00071 }
00072
00073
00074
00075
00076 static inline void AtomicInc(volatile AtomicIntType* Variable)
00077 {
00078 asm volatile(
00079 "lock ; " "incl %0"
00080 :"=m" (*Variable)
00081 :"m" (*Variable));
00082 }
00083
00084
00085
00086
00087 static inline void AtomicDec(volatile AtomicIntType* Variable)
00088 {
00089 asm volatile(
00090 "lock ; " "decl %0"
00091 :"=m" (*Variable)
00092 :"m" (*Variable));
00093 }
00094
00095
00096
00097
00098 static inline bool AtomicIncAndTest(volatile AtomicIntType* Variable)
00099 {
00100 unsigned char res;
00101
00102 asm volatile(
00103 "lock ; " "incl %0; sete %1"
00104 :"=m" (*Variable), "=qm" (res)
00105 :"m" (*Variable) : "memory");
00106 return res != 0;
00107 }
00108
00109
00110
00111
00112 static inline bool AtomicDecAndTest(volatile AtomicIntType* Variable)
00113 {
00114 unsigned char res;
00115
00116 asm volatile(
00117 "lock ; " "decl %0; sete %1"
00118 :"=m" (*Variable), "=qm" (res)
00119 :"m" (*Variable) : "memory");
00120 return res != 0;
00121 }
00122
00123 #endif // defined(__i386__)
00124
00125 #if defined(__x86_64__)
00126
00127
00128
00129
00130 typedef int AtomicIntType;
00131
00132
00133
00134
00135 template <typename T>
00136 static inline T* AtomicSwapPtr(T*volatile* Variable, T* NewValue)
00137 {
00138 asm volatile(
00139 "xchgq %0,%1"
00140 :"=r" (NewValue)
00141 :"m" (*Variable), "0" (NewValue)
00142 :"memory");
00143 return NewValue;
00144 }
00145
00146
00147
00148
00149 static inline AtomicIntType AtomicGet(volatile const AtomicIntType* Variable)
00150 {
00151 return *Variable;
00152 }
00153
00154
00155
00156
00157 static inline void AtomicSet(volatile AtomicIntType* Variable, AtomicIntType val)
00158 {
00159 *Variable = val;
00160 }
00161
00162
00163
00164
00165 static inline void AtomicInc(volatile AtomicIntType* Variable)
00166 {
00167 asm volatile(
00168 "lock ; " "incl %0"
00169 :"=m" (*Variable)
00170 :"m" (*Variable));
00171 }
00172
00173
00174
00175
00176 static inline void AtomicDec(volatile AtomicIntType* Variable)
00177 {
00178 asm volatile(
00179 "lock ; " "decl %0"
00180 :"=m" (*Variable)
00181 :"m" (*Variable));
00182 }
00183
00184
00185
00186
00187 static inline bool AtomicIncAndTest(volatile AtomicIntType* Variable)
00188 {
00189 unsigned char res;
00190
00191 asm volatile(
00192 "lock ; " "incl %0; sete %1"
00193 :"=m" (*Variable), "=qm" (res)
00194 :"m" (*Variable) : "memory");
00195 return res != 0;
00196 }
00197
00198
00199
00200
00201 static inline bool AtomicDecAndTest(volatile AtomicIntType* Variable)
00202 {
00203 unsigned char res;
00204
00205 asm volatile(
00206 "lock ; " "decl %0; sete %1"
00207 :"=m" (*Variable), "=qm" (res)
00208 :"m" (*Variable) : "memory");
00209 return res != 0;
00210 }
00211
00212 #endif // defined(__x86_64__)
00213
00214 #if defined(__arm__) || defined(__arm)
00215
00216
00217
00218
00219 typedef int AtomicIntType;
00220
00221
00222
00223
00224 template < typename T >
00225 static inline T* AtomicSwapPtr(T*volatile* Variable, T* NewValue)
00226 {
00227 T* res;
00228 asm volatile(
00229 "swp %0, %2, [%1]"
00230 : "=&r" (res)
00231 : "r" (Variable), "r" (NewValue));
00232 return res;
00233 }
00234
00235
00236
00237
00238 static inline AtomicIntType AtomicGet(volatile const AtomicIntType* Variable)
00239 {
00240 return *Variable;
00241 }
00242
00243
00244
00245
00246 static inline void AtomicSet(volatile AtomicIntType* Variable, AtomicIntType val)
00247 {
00248 *Variable = val;
00249 }
00250
00251
00252
00253
00254 static inline bool AtomicIncAndTest(volatile AtomicIntType* Variable)
00255 {
00256 int a, b, c;
00257
00258 asm volatile (
00259 "0:\n"
00260 "ldr %0, [%3]\n"
00261 "add %1, %0, %4\n"
00262 "swp %2, %1, [%3]\n"
00263 "cmp %0, %2\n"
00264 "swpne %1, %2, [%3]\n"
00265 "bne 0b"
00266 : "=&r" (a), "=&r" (b), "=&r" (c)
00267 : "r" (Variable), "r" (1)
00268 : "cc", "memory");
00269
00270 return b == 0;
00271 }
00272
00273
00274
00275
00276 static inline bool AtomicDecAndTest(volatile AtomicIntType* Variable)
00277 {
00278 int a, b, c;
00279
00280 asm volatile (
00281 "0:\n"
00282 "ldr %0, [%3]\n"
00283 "add %1, %0, %4\n"
00284 "swp %2, %1, [%3]\n"
00285 "cmp %0, %2\n"
00286 "swpne %1, %2, [%3]\n"
00287 "bne 0b"
00288 : "=&r" (a), "=&r" (b), "=&r" (c)
00289 : "r" (Variable), "r" (-1)
00290 : "cc", "memory");
00291
00292 return b == 0;
00293 }
00294
00295
00296
00297
00298 static inline void AtomicInc(volatile AtomicIntType* Variable)
00299 {
00300 AtomicIncAndTest(Variable);
00301 }
00302
00303
00304
00305
00306 static inline void AtomicDec(volatile AtomicIntType* Variable)
00307 {
00308 AtomicDecAndTest(Variable);
00309 }
00310
00311 #endif // defined(__arm__) || defined(__arm)
00312
00313
00314
00315
00316
00317
00318
00319 class AtomicVariable
00320 {
00321 public:
00322
00323 typedef AtomicIntType Type;
00324
00325
00326
00327
00328 AtomicVariable(Type Init = 0) { var = Init; }
00329
00330
00331
00332
00333 Type Value() volatile const { return AtomicGet(&var); }
00334
00335
00336
00337
00338 void SetValue(Type Value) { AtomicSet(&var, Value); }
00339
00340
00341
00342
00343 void Inc() { AtomicInc(&var); }
00344
00345
00346
00347
00348 void Dec() { AtomicDec(&var); }
00349
00350
00351
00352
00353 bool IncAndTest() { return AtomicIncAndTest(&var); }
00354
00355
00356
00357
00358 bool DecAndTest() { return AtomicDecAndTest(&var); }
00359
00360 private:
00361
00362
00363
00364
00365 volatile Type var;
00366 };
00367
00368 }
00369 }
00370
00371 #endif //CNTM_ATOMICUTILS_H