00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "../../num/basic_types.h"
00044
00045 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00046 # pragma warning(push)
00047 # pragma warning(disable: 4035)
00048 #endif
00049
00050 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC && (LASS_ADDRESS_SIZE == 64)
00051 # define LASS_UTIL_IMPL_ATOMIC_MSVC_X64
00052 # include <intrin.h>
00053 # pragma intrinsic(_InterlockedCompareExchange)
00054 # pragma intrinsic(_InterlockedCompareExchange16)
00055 # pragma intrinsic(_InterlockedCompareExchange64)
00056 # pragma intrinsic(_InterlockedIncrement)
00057 # pragma intrinsic(_InterlockedIncrement16)
00058 # pragma intrinsic(_InterlockedIncrement64)
00059 # pragma intrinsic(_InterlockedDecrement)
00060 # pragma intrinsic(_InterlockedDecrement16)
00061 # pragma intrinsic(_InterlockedDecrement64)
00062 # pragma intrinsic(__ll_rshift)
00063
00064 extern "C"
00065 {
00066 lass::num::Tuint8 lass_cas8(volatile lass::num::Tuint8*, lass::num::Tuint8, lass::num::Tuint8);
00067 void lass_inc8(volatile lass::num::Tuint8*);
00068 void lass_dec8(volatile lass::num::Tuint8*);
00069 bool lass_dcas8(volatile lass::num::Tuint8*, lass::num::Tuint8, lass::num::Tuint8, lass::num::Tuint8, lass::num::Tuint8);
00070 bool lass_dcas16(volatile lass::num::Tuint16*, lass::num::Tuint16, lass::num::Tuint16, lass::num::Tuint16, lass::num::Tuint16);
00071 bool lass_dcas32(volatile lass::num::Tuint32*, lass::num::Tuint32, lass::num::Tuint32, lass::num::Tuint32, lass::num::Tuint32);
00072 }
00073
00074 #endif
00075
00076 namespace lass
00077 {
00078 namespace util
00079 {
00080
00081 namespace impl
00082 {
00083
00084
00085
00086
00087 template <int byteSize> struct AtomicOperations;
00088
00089
00090
00091
00092 template <>
00093 struct AtomicOperations<1>
00094 {
00095 template <typename T> inline
00096 static T LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
00097 {
00098 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00099 __asm__ __volatile__(
00100 "lock; cmpxchgb %2, %0;"
00101 : "=m"(dest), "=a"(expectedValue)
00102 : "q"(newValue), "1"(expectedValue), "m"(dest)
00103 : "cc", "memory");
00104 return expectedValue;
00105 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00106 __asm
00107 {
00108 mov al, expectedValue
00109 mov dl, newValue
00110 mov edi, dest
00111 lock cmpxchg [edi], dl
00112 }
00113
00114 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00115 return lass_cas8(reinterpret_cast<volatile num::Tuint8*>(&dest),
00116 *reinterpret_cast<num::Tuint8*>(&newValue), *reinterpret_cast<num::Tuint8*>(&expectedValue));
00117 #else
00118 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00119 #endif
00120 }
00121
00122 template <typename T1, typename T2> inline
00123 static bool LASS_CALL compareAndSwap(
00124 volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
00125 {
00126 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00127 bool result;
00128 __asm__ __volatile__(
00129 "movb %%bl, %%ah;"
00130 "movb %%cl, %%dh;"
00131 "lock; cmpxchgw %%dx, %0;"
00132 "sete %1;"
00133 : "=m"(reinterpret_cast<volatile num::Tuint16&>(dest1)), "=q"(result)
00134 : "a"(expected1), "d"(new1), "b"(expected2), "c"(new2),
00135 "m"(reinterpret_cast<volatile num::Tuint16&>(dest1))
00136 : "cc", "memory");
00137 return result;
00138 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00139 __asm
00140 {
00141 mov al, expected1
00142 mov dl, new1
00143 mov ah, expected2
00144 mov dh, new2
00145 mov edi, dest1
00146 lock cmpxchg [edi], dx
00147 mov eax, 0
00148 sete al
00149 }
00150
00151 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00152 return lass_dcas8(
00153 reinterpret_cast<volatile num::Tuint8*>(&dest1),
00154 *reinterpret_cast<num::Tuint8*>(&new1), *reinterpret_cast<num::Tuint8*>(&new2),
00155 *reinterpret_cast<num::Tuint8*>(&expected1), *reinterpret_cast<num::Tuint8*>(&expected2));
00156 #else
00157 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00158 #endif
00159 }
00160
00161 template <typename T> inline
00162 static void LASS_CALL increment(volatile T& value)
00163 {
00164 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00165 __asm__ __volatile__(
00166 "lock; incb %0;"
00167 : "=m"(value)
00168 : "m"(value)
00169 : "cc", "memory");
00170 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00171 __asm
00172 {
00173 mov edi, value
00174 lock inc byte ptr [edi]
00175 }
00176 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00177 lass_inc8(reinterpret_cast<volatile num::Tuint8*>(&value));
00178 #else
00179 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00180 #endif
00181 }
00182
00183 template <typename T> inline
00184 static void LASS_CALL decrement(volatile T& value)
00185 {
00186 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00187 __asm__ __volatile__(
00188 "lock; decb %0;"
00189 : "=m"(value)
00190 : "m"(value)
00191 : "cc", "memory");
00192 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00193 __asm
00194 {
00195 mov edi, value
00196 lock dec byte ptr [edi]
00197 }
00198 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00199 lass_dec8(reinterpret_cast<volatile num::Tuint8*>(&value));
00200 #else
00201 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00202 #endif
00203 }
00204 };
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 template <>
00215 struct AtomicOperations<2>
00216 {
00217 template <typename T> inline
00218 static T LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
00219 {
00220 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00221 __asm__ __volatile__(
00222 "lock; cmpxchgw %2, %0;"
00223 : "=m"(dest), "=a"(expectedValue)
00224 : "q"(newValue), "1"(expectedValue), "m"(dest)
00225 : "cc", "memory");
00226 return expectedValue;
00227 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00228 __asm
00229 {
00230 mov ax, expectedValue
00231 mov dx, newValue
00232 mov edi, dest
00233 lock cmpxchg [edi], dx
00234 }
00235
00236
00237 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00238 return _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(&dest),
00239 *reinterpret_cast<short*>(&newValue), *reinterpret_cast<short*>(&expectedValue));
00240 #else
00241 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00242 #endif
00243 }
00244
00245 template <typename T1, typename T2> inline
00246 static bool LASS_CALL compareAndSwap(
00247 volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
00248 {
00249 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00250 bool result;
00251 __asm__ __volatile__(
00252 "shll $16, %%eax;"
00253 "shll $16, %%edx;"
00254 "movw %4, %%ax;"
00255 "movw %5, %%dx;"
00256 "lock; cmpxchgl %%edx, %0;"
00257 "sete %1;"
00258 : "=m"(reinterpret_cast<volatile num::Tuint32&>(dest1)), "=q"(result)
00259 : "a"(expected2), "d"(new2), "g"(expected1), "g"(new1),
00260 "m"(reinterpret_cast<volatile num::Tuint32&>(dest1))
00261 : "cc", "memory");
00262 return result;
00263 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00264 __asm
00265 {
00266 mov ax, expected2
00267 mov dx, new2
00268 shl eax, 16
00269 shl edx, 16
00270 mov ax, expected1
00271 mov dx, new1
00272 mov edi, dest1
00273 lock cmpxchg [edi], edx
00274 mov eax, 0
00275 sete al
00276 }
00277
00278 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00279 return lass_dcas16(
00280 reinterpret_cast<volatile num::Tuint16*>(&dest1),
00281 *reinterpret_cast<num::Tuint16*>(&new1), *reinterpret_cast<num::Tuint16*>(&new2),
00282 *reinterpret_cast<num::Tuint16*>(&expected1), *reinterpret_cast<num::Tuint16*>(&expected2));
00283 #else
00284 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00285 #endif
00286 }
00287
00288 template <typename T> inline
00289 static void LASS_CALL increment(volatile T& value)
00290 {
00291 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00292 __asm__ __volatile__(
00293 "lock; incw %0;"
00294 : "=m"(value)
00295 : "m"(value)
00296 : "cc", "memory");
00297 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00298 __asm
00299 {
00300 mov edi, value
00301 lock inc word ptr [edi]
00302 }
00303 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00304 _InterlockedIncrement16(reinterpret_cast<volatile short*>(&value));
00305 #else
00306 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00307 #endif
00308 }
00309
00310 template <typename T> inline
00311 static void LASS_CALL decrement(volatile T& value)
00312 {
00313 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00314 __asm__ __volatile__(
00315 "lock; decw %0;"
00316 : "=m"(value)
00317 : "m"(value)
00318 : "cc", "memory");
00319 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00320 __asm
00321 {
00322 mov edi, value
00323 lock dec word ptr [edi]
00324 }
00325 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00326 _InterlockedDecrement16(reinterpret_cast<volatile short*>(&value));
00327 #else
00328 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00329 #endif
00330 }
00331 };
00332
00333
00334
00335
00336
00337
00338
00339
00340 template <>
00341 struct AtomicOperations<4>
00342 {
00343 template <typename T> inline
00344 static T LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
00345 {
00346 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00347 __asm__ __volatile__(
00348 "lock; cmpxchgl %2, %0;"
00349 : "=m"(dest), "=a"(expectedValue)
00350 : "q"(newValue), "1"(expectedValue), "m"(dest)
00351 : "cc", "memory");
00352 return expectedValue;
00353 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00354 __asm
00355 {
00356 mov eax, expectedValue
00357 mov edx, newValue
00358 mov edi, dest
00359 lock cmpxchg [edi], edx
00360 }
00361
00362 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00363 return _InterlockedCompareExchange(reinterpret_cast<volatile long*>(&dest),
00364 *reinterpret_cast<long*>(&newValue), *reinterpret_cast<long*>(&expectedValue));
00365 #else
00366 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00367 #endif
00368 }
00369
00370 template <typename T1, typename T2> inline
00371 static bool LASS_CALL compareAndSwap(
00372 volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
00373 {
00374 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00375 bool result;
00376
00377
00378
00379
00380 # ifdef __PIC__
00381 __asm__ __volatile__(
00382 "pushl %%ebx;"
00383 "movl %4,%%ebx;"
00384 "lock; cmpxchg8b %0;"
00385 "sete %1;"
00386 "pop %%ebx;"
00387 : "=m"(dest1), "=q"(result)
00388 : "a"(expected1), "d"(expected2), "m"(new1), "c"(new2), "m"(dest1)
00389 : "cc", "memory");
00390 # else
00391 __asm__ __volatile__(
00392 "lock; cmpxchg8b %0;"
00393 "sete %1;"
00394 : "=m"(dest1), "=q"(result)
00395 : "a"(expected1), "d"(expected2), "b"(new1), "c"(new2), "m"(dest1)
00396 : "cc", "memory");
00397 # endif
00398 return result;
00399 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00400 __asm
00401 {
00402 mov eax, expected1
00403 mov edx, expected2
00404 mov ebx, new1
00405 mov ecx, new2
00406 mov edi, dest1
00407 lock cmpxchg8b [edi]
00408 mov eax, 0
00409 sete al
00410 }
00411
00412 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00413 return lass_dcas32(
00414 reinterpret_cast<volatile num::Tuint32*>(&dest1),
00415 *reinterpret_cast<num::Tuint32*>(&new1), *reinterpret_cast<num::Tuint32*>(&new2),
00416 *reinterpret_cast<num::Tuint32*>(&expected1), *reinterpret_cast<num::Tuint32*>(&expected2));
00417 #else
00418 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00419 #endif
00420 }
00421
00422 template <typename T> inline
00423 static void LASS_CALL increment(volatile T& value)
00424 {
00425 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00426 __asm__ __volatile__(
00427 "lock; incl %0;"
00428 : "=m"(value)
00429 : "m"(value)
00430 : "cc", "memory");
00431 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00432 __asm
00433 {
00434 mov edi, value
00435 lock inc dword ptr [edi]
00436 }
00437 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00438 _InterlockedIncrement(reinterpret_cast<volatile long*>(&value));
00439 #else
00440 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00441 #endif
00442 }
00443
00444 template <typename T> inline
00445 static void LASS_CALL decrement(volatile T& value)
00446 {
00447 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00448 __asm__ __volatile__(
00449 "lock; decl %0;"
00450 : "=m"(value)
00451 : "m"(value)
00452 : "cc", "memory");
00453 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00454 __asm
00455 {
00456 mov edi, value
00457 lock dec dword ptr [edi]
00458 }
00459 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00460 _InterlockedDecrement(reinterpret_cast<volatile long*>(&value));
00461 #else
00462 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00463 #endif
00464 }
00465 };
00466
00467
00468
00469
00470
00471
00472
00473
00474 template <>
00475 struct AtomicOperations<8>
00476 {
00477 template <typename T> inline
00478 static T LASS_CALL compareAndSwap(volatile T& dest, T expectedValue, T newValue)
00479 {
00480 #if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC) && (LASS_ADDRESS_SIZE == 32)
00481
00482
00483
00484 # ifdef __PIC__
00485 __asm__ __volatile__(
00486 "pushl %%ebx;"
00487 "movl %5,%%ebx;"
00488 "lock; cmpxchg8b %0;"
00489 "pop %%ebx;"
00490 : "=m"(dest), "=A"(expectedValue)
00491 : "m"(dest),
00492 "a"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[0]),
00493 "d"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[1]),
00494 "m"(reinterpret_cast<volatile num::Tuint32*>((void*)&newValue)[0]),
00495 "c"(reinterpret_cast<volatile num::Tuint32*>((void*)&newValue)[1])
00496 : "cc", "memory");
00497 # else
00498 __asm__ __volatile__(
00499 "lock; cmpxchg8b %0;"
00500 : "=m"(dest), "=A"(expectedValue)
00501 : "m"(dest),
00502 "a"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[0]),
00503 "d"(reinterpret_cast<volatile num::Tuint32*>((void*)&expectedValue)[1]),
00504 "b"(reinterpret_cast<volatile num::Tuint32*>((void*)&newValue)[0]),
00505 "c"(reinterpret_cast<volatile num::Tuint32*>((void*)&newValue)[1])
00506 : "cc", "memory");
00507 # endif
00508 return expectedValue;
00509 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_GCC) && (LASS_ADDRESS_SIZE == 64)
00510 __asm__ __volatile__(
00511 "lock; cmpxchgq %2, %0;"
00512 : "=m"(dest), "=a"(expectedValue)
00513 : "q"(newValue), "1"(expectedValue), "m"(dest)
00514 : "cc", "memory");
00515 return expectedValue;
00516 #elif defined(LASS_HAVE_INLINE_ASSEMBLY_MSVC) && (LASS_ADDRESS_SIZE == 32)
00517 __asm
00518 {
00519 lea esi, expectedValue
00520 lea edi, newValue
00521 mov eax, [esi]
00522 mov edx, 4[esi]
00523 mov ebx, [edi]
00524 mov ecx, 4[edi]
00525 mov edi, dest
00526 lock cmpxchg8b [edi]
00527 }
00528
00529 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00530 return _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(&dest),
00531 *reinterpret_cast<__int64*>(&newValue), *reinterpret_cast<__int64*>(&expectedValue));
00532 #else
00533 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00534 #endif
00535 }
00536
00537
00538
00539
00540
00541
00542
00543 template <typename T> inline
00544 static void LASS_CALL increment(volatile T& value)
00545 {
00546 #if (LASS_ADDRESS_SIZE == 32)
00547
00548 T old, fresh;
00549 do
00550 {
00551 old = value;
00552 fresh = old + 1;
00553 }
00554 while (!atomicCompareAndSwap(value, old, fresh));
00555 #elif (LASS_ADDRESS_SIZE == 64) && defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00556 __asm__ __volatile__(
00557 "lock; incq %0;"
00558 : "=m"(value)
00559 : "m"(value)
00560 : "cc", "memory");
00561 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00562 _InterlockedIncrement64(reinterpret_cast<volatile __int64*>(&value));
00563 #else
00564 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00565 #endif
00566 }
00567
00568 template <typename T> inline
00569 static void LASS_CALL decrement(volatile T& value)
00570 {
00571 #if (LASS_ADDRESS_SIZE == 32)
00572
00573 T old, fresh;
00574 do
00575 {
00576 old = value;
00577 fresh = old - 1;
00578 }
00579 while (!atomicCompareAndSwap(value, old, fresh));
00580 #elif (LASS_ADDRESS_SIZE == 64) && defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00581 __asm__ __volatile__(
00582 "lock; decq %0;"
00583 : "=m"(value)
00584 : "m"(value)
00585 : "cc", "memory");
00586 #elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00587 _InterlockedDecrement64(reinterpret_cast<volatile __int64*>(&value));
00588 #else
00589 # error [LASS BUILD MSG] lass/util/impl/atomic_impl.h: missing implementation
00590 #endif
00591 }
00592 };
00593
00594
00595
00596 }
00597 }
00598 }
00599
00600 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00601 # pragma warning(pop)
00602 #endif
00603
00604