diff options
author | José Fonseca <[email protected]> | 2015-01-20 23:36:50 +0000 |
---|---|---|
committer | Jose Fonseca <[email protected]> | 2015-01-30 15:24:34 +0000 |
commit | fbc3e030e658c2c6d44bac084c3166d1fb737c7e (patch) | |
tree | cba809e1780162a9ed33626d0f02af72be5fe13d | |
parent | d7f2dfb67ee9c50f221d35c840d3427e8f184209 (diff) |
util/u_atomic: Provide a _InterlockedCompareExchange8 for older MSVC.
Fixes build with Windows SDK 7.0.7600.
Tested with u_atomic_test, both on x86 and x86_64.
Reviewed-by: Roland Scheidegger <[email protected]>
-rw-r--r-- | src/util/u_atomic.h | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/src/util/u_atomic.h b/src/util/u_atomic.h index a528e01bc98..cf7fff3f35b 100644 --- a/src/util/u_atomic.h +++ b/src/util/u_atomic.h @@ -84,7 +84,35 @@ #include <intrin.h> #include <assert.h> -#pragma intrinsic(_InterlockedCompareExchange8) +#if _MSC_VER < 1600 + +/* Implement _InterlockedCompareExchange8 in terms of InterlockedCompareExchange16 */ +static __inline +char _InterlockedCompareExchange8(char volatile *Destination8, char Exchange8, char Comparand8) +{ + INT_PTR DestinationAddr = (INT_PTR)Destination8; + short volatile *Destination16 = (short volatile *)(DestinationAddr & ~1); + const short Shift8 = (DestinationAddr & 1) * 8; + const short Mask8 = 0xff << Shift8; + short Initial16 = *Destination16; + char Initial8 = Initial16 >> Shift8; + while (Initial8 == Comparand8) { + /* initial *Destination8 matches, so try exchange it while keeping the + * neighboring byte untouched */ + short Exchange16 = (Initial16 & ~Mask8) | ((short)Exchange8 << Shift8); + short Comparand16 = Initial16; + short Initial16 = InterlockedCompareExchange16(Destination16, Exchange16, Comparand16); + if (Initial16 == Comparand16) { + /* succeeded */ + return Comparand8; + } + /* something changed, retry with the new initial value */ + Initial8 = Initial16 >> Shift8; + } + return Initial8; +} + +#endif /* _MSC_VER < 1600 */ /* MSVC supports decltype keyword, but it's only supported on C++ and doesn't * quite work here; and if a C++-only solution is worthwhile, then it would be |