patomic.cxx (6417B)
1 /* 2 * 3 * C++ Portable Types Library (PTypes) 4 * Version 2.1.1 Released 27-Jun-2007 5 * 6 * Copyright (C) 2001-2007 Hovik Melikyan 7 * 8 * http://www.melikyan.com/ptypes/ 9 * 10 */ 11 12 #ifdef WIN32 13 # include <windows.h> 14 #endif 15 16 #include "ptypes.h" 17 #include "pasync.h" // for pmemlock* 18 19 #include <assert.h> 20 21 namespace ptypes { 22 23 24 #ifdef PTYPES_ST 25 // single-threaded version 26 27 28 int __PFASTCALL pexchange(int* target, int value) 29 { 30 int r = *target; 31 *target = value; 32 return r; 33 } 34 35 36 void* __PFASTCALL pexchange(void** target, void* value) 37 { 38 void* r = *target; 39 *target = value; 40 return r; 41 } 42 43 44 int __PFASTCALL pincrement(int* target) 45 { 46 return ++(*target); 47 } 48 49 50 int __PFASTCALL pdecrement(int* target) 51 { 52 return --(*target); 53 } 54 55 56 #else 57 // multi-threaded version 58 59 #if defined(__GNUC__) && (defined(__i386__) || defined(__I386__)) 60 # define GCC_i386 61 #elif defined(__GNUC__) && defined(__ppc__) 62 # define GCC_PPC 63 #elif defined(_MSC_VER) && defined(_M_IX86) 64 # define MSC_i386 65 #elif defined(_MSC_VER) && (defined(_M_IA64) || defined(_WIN64)) 66 # define MSC_x64 67 #elif defined(__BORLANDC__) && defined(_M_IX86) 68 # define BCC_i386 69 #elif defined(__GNUC__) && defined(__sparc__) && !defined(__arch64__) 70 # define GCC_sparc 71 #endif 72 73 74 #if defined(MSC_i386) || defined(BCC_i386) 75 76 // 77 // atomic operations for Microsoft C or Borland C on Windows 78 // 79 80 #if defined(_MSC_VER) 81 # pragma warning (disable: 4035) 82 #elif defined(__BORLANDC__) 83 # pragma warn -rvl 84 #endif 85 86 // !!! NOTE 87 // the following functions implement atomic exchange/inc/dec on 88 // windows. they are dangerous in that they rely on the calling 89 // conventions of MSVC and BCC. the first one passes the first 90 // two arguments in ECX and EDX, and the second one - in EAX and 91 // EDX. 92 93 int __PFASTCALL pincrement(int* v) 94 { 95 return InterlockedIncrement((LONG*)v); 96 } 97 98 99 int __PFASTCALL pdecrement(int* v) 100 { 101 return InterlockedDecrement((LONG*)v); 102 } 103 104 105 int __PFASTCALL pexchange(int* a, int b) 106 { 107 return InterlockedExchange((LONG*)a,b); 108 } 109 110 111 void* __PFASTCALL pexchange(void** a, void* b) 112 { 113 #ifdef _WIN64 114 return InterlockedExchange64( a,b); 115 #else 116 return (void*)InterlockedExchange((LONG*)a,(LONG)b); 117 #endif 118 } 119 120 121 #elif defined(GCC_i386) 122 123 // 124 // GNU C compiler on any i386 platform (actually 486+ for xadd) 125 // 126 127 int pexchange(int* target, int value) 128 { 129 __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target)); 130 return value; 131 } 132 133 134 void* pexchange(void** target, void* value) 135 { 136 __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target)); 137 return value; 138 } 139 140 141 int pincrement(int* target) 142 { 143 int temp = 1; 144 __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target)); 145 return temp + 1; 146 } 147 148 149 int pdecrement(int* target) 150 { 151 int temp = -1; 152 __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target)); 153 return temp - 1; 154 } 155 156 157 #elif defined(GCC_PPC) 158 159 // 160 // GNU C compiler on any PPC platform 161 // 162 163 int pexchange(int* target, int value) 164 { 165 int temp; 166 __asm__ __volatile ( 167 "1: lwarx %0,0,%1\n\ 168 stwcx. %2,0,%1\n\ 169 bne- 1b\n\ 170 isync" 171 : "=&r" (temp) 172 : "r" (target), "r" (value) 173 : "cc", "memory" 174 ); 175 return temp; 176 } 177 178 179 void* pexchange(void** target, void* value) 180 { 181 void* temp; 182 __asm__ __volatile ( 183 "1: lwarx %0,0,%1\n\ 184 stwcx. %2,0,%1\n\ 185 bne- 1b\n\ 186 isync" 187 : "=&r" (temp) 188 : "r" (target), "r" (value) 189 : "cc", "memory" 190 ); 191 return temp; 192 } 193 194 195 int pincrement(int* target) 196 { 197 int temp; 198 __asm__ __volatile ( 199 "1: lwarx %0,0,%1\n\ 200 addic %0,%0,1\n\ 201 stwcx. %0,0,%1\n\ 202 bne- 1b\n\ 203 isync" 204 : "=&r" (temp) 205 : "r" (target) 206 : "cc", "memory" 207 ); 208 return temp; 209 } 210 211 212 int pdecrement(int* target) 213 { 214 int temp; 215 __asm__ __volatile ( 216 "1: lwarx %0,0,%1\n\ 217 addic %0,%0,-1\n\ 218 stwcx. %0,0,%1\n\ 219 bne- 1b\n\ 220 isync" 221 : "=&r" (temp) 222 : "r" (target) 223 : "cc", "memory" 224 ); 225 return temp; 226 } 227 228 229 #elif defined GCC_sparc 230 231 // 232 // GNU C compiler on SPARC in 32-bit mode (pointers are 32-bit) 233 // 234 235 // assembly routines defined in patomic.sparc.s 236 // we currently don't use CAS in the library, but let it be there 237 extern "C" { 238 int __patomic_add(volatile int* __mem, int __val); 239 int __patomic_swap(volatile int* __mem, int __val); 240 int __patomic_cas(volatile int* __mem, int __expected, int __newval); 241 } 242 243 #define __patomic_swap_p(mem,val) \ 244 (void*)(__patomic_swap((int*)(mem), (int)(val))) 245 246 247 int pexchange(int* target, int value) 248 { 249 return __patomic_swap(target, value); 250 } 251 252 253 void* pexchange(void** target, void* value) 254 { 255 return __patomic_swap_p(target, value); 256 } 257 258 259 int pincrement(int* target) 260 { 261 return __patomic_add(target, 1); 262 } 263 264 265 int pdecrement(int* target) 266 { 267 return __patomic_add(target, -1); 268 } 269 270 #elif defined __EMSCRIPTEN__ 271 #include <emscripten/threading.h> 272 int pexchange(int* target, int value) 273 { 274 return emscripten_atomic_exchange_u32(target, value); 275 } 276 277 278 void* pexchange(void** target, void* value) 279 { 280 return (void*)emscripten_atomic_exchange_u32(*target, (uint32_t)value); 281 } 282 283 284 int pincrement(int* target) 285 { 286 return emscripten_atomic_add_u32(target, 1); 287 } 288 289 290 int pdecrement(int* target) 291 { 292 return emscripten_atomic_add_u32(target, -1); 293 } 294 295 #elif defined MSC_x64 296 297 int pexchange(int* target, int value) 298 { 299 assert( sizeof(target) == sizeof(volatile LONG*) ); 300 301 return InterlockedExchange((volatile LONG*)target,value); 302 } 303 304 305 void* pexchange(void** target, void* value) 306 { 307 return InterlockedExchangePointer(target,value); 308 } 309 310 int pincrement(int* target) 311 { 312 assert( sizeof(target) == sizeof(volatile LONG*) ); 313 return InterlockedIncrement((volatile LONG*)target); 314 } 315 316 317 int pdecrement(int* target) 318 { 319 assert( sizeof(target) == sizeof(volatile LONG*) ); 320 return InterlockedDecrement((volatile LONG*)target); 321 } 322 323 324 #else 325 326 // 327 // other platforms: mutex locking 328 // 329 330 int pexchange(int* target, int value) 331 { 332 pmemlock* m = pgetmemlock(target); 333 pmementer(m); 334 int r = *target; 335 *target = value; 336 pmemleave(m); 337 return r; 338 } 339 340 341 void* pexchange(void** target, void* value) 342 { 343 pmemlock* m = pgetmemlock(target); 344 pmementer(m); 345 void* r = *target; 346 *target = value; 347 pmemleave(m); 348 return r; 349 } 350 351 int pincrement(int* target) 352 { 353 assert( NULL != _mtxtable ); 354 pmemlock* m = pgetmemlock(target); 355 pmementer(m); 356 int r = ++(*target); 357 pmemleave(m); 358 return r; 359 } 360 361 362 int pdecrement(int* target) 363 { 364 pmemlock* m = pgetmemlock(target); 365 pmementer(m); 366 int r = --(*target); 367 pmemleave(m); 368 return r; 369 } 370 371 #endif 372 373 374 #endif 375 376 377 }