summaryrefslogtreecommitdiff
path: root/src/mongo/platform
diff options
context:
space:
mode:
authorAndrew Morrow <acm@10gen.com>2013-02-20 19:50:22 -0500
committerAndrew Morrow <acm@10gen.com>2013-02-26 11:49:04 -0500
commit7e3abac147af2eecc3b199c905be47b5120b4ee9 (patch)
treeaae3145eee4b74f0197fe1c7d52db99ab4a562e8 /src/mongo/platform
parent5bbdfa31eba4680f8aee37300db852706b9289cb (diff)
downloadmongo-7e3abac147af2eecc3b199c905be47b5120b4ee9.tar.gz
SERVER-8488 Re-enable support for Windows XP.
The strategy here is to use the one available 64-bit intrinsic for Windows XP, which is _InterlockedCompareExchange64, and then hand-roll our own implementations of the other primitives in terms of _InterlockedCompareExchange64.
Diffstat (limited to 'src/mongo/platform')
-rw-r--r--src/mongo/platform/atomic_intrinsics_win32.h85
1 files changed, 77 insertions, 8 deletions
diff --git a/src/mongo/platform/atomic_intrinsics_win32.h b/src/mongo/platform/atomic_intrinsics_win32.h
index c10c01a21c1..91ecc8fce2c 100644
--- a/src/mongo/platform/atomic_intrinsics_win32.h
+++ b/src/mongo/platform/atomic_intrinsics_win32.h
@@ -23,6 +23,9 @@
#include "mongo/platform/windows_basic.h"
+#include <intrin.h>
+#pragma intrinsic(_InterlockedCompareExchange64)
+
namespace mongo {
/**
@@ -84,16 +87,14 @@ namespace mongo {
template <typename T>
class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG)>::type> {
public:
+ static const bool kHaveInterlocked64 = (_WIN32_WINNT >= _WIN32_WINNT_VISTA);
static T compareAndSwap(volatile T* dest, T expected, T newValue) {
- return InterlockedCompareExchange64(reinterpret_cast<volatile LONGLONG*>(dest),
- LONGLONG(newValue),
- LONGLONG(expected));
+ return InterlockedImpl<kHaveInterlocked64>::compareAndSwap(dest, expected, newValue);
}
static T swap(volatile T* dest, T newValue) {
- return InterlockedExchange64(reinterpret_cast<volatile LONGLONG*>(dest),
- LONGLONG(newValue));
+ return InterlockedImpl<kHaveInterlocked64>::swap(dest, newValue);
}
static T load(volatile const T* value) {
@@ -105,19 +106,87 @@ namespace mongo {
}
static T fetchAndAdd(volatile T* dest, T increment) {
- return InterlockedExchangeAdd64(reinterpret_cast<volatile LONGLONG*>(dest),
- LONGLONG(increment));
+ return InterlockedImpl<kHaveInterlocked64>::fetchAndAdd(dest, increment);
}
private:
AtomicIntrinsics();
~AtomicIntrinsics();
+ template <bool>
+ struct InterlockedImpl;
+
+ // Implementation of 64-bit Interlocked operations via Windows API calls.
+ template<>
+ struct InterlockedImpl<true> {
+ static T compareAndSwap(volatile T* dest, T expected, T newValue) {
+ return InterlockedCompareExchange64(
+ reinterpret_cast<volatile LONGLONG*>(dest),
+ LONGLONG(newValue),
+ LONGLONG(expected));
+ }
+
+ static T swap(volatile T* dest, T newValue) {
+ return InterlockedExchange64(
+ reinterpret_cast<volatile LONGLONG*>(dest),
+ LONGLONG(newValue));
+ }
+
+ static T fetchAndAdd(volatile T* dest, T increment) {
+ return InterlockedExchangeAdd64(
+ reinterpret_cast<volatile LONGLONG*>(dest),
+ LONGLONG(increment));
+ }
+ };
+
+ // Implementation of 64-bit Interlocked operations for systems where the API does not
+ // yet provide the Interlocked...64 operations.
+ template<>
+ struct InterlockedImpl<false> {
+ static T compareAndSwap(volatile T* dest, T expected, T newValue) {
+ // NOTE: We must use the compiler intrinsic here: WinXP does not offer
+ // InterlockedCompareExchange64 as an API call.
+ return _InterlockedCompareExchange64(
+ reinterpret_cast<volatile LONGLONG*>(dest),
+ LONGLONG(newValue),
+ LONGLONG(expected));
+ }
+
+ static T swap(volatile T* dest, T newValue) {
+ // NOTE: You may be tempted to replace this with
+ // 'InterlockedExchange64'. Resist! It will compile just fine despite not being
+ // listed in the docs as available on XP, but the compiler may replace it with
+ // calls to the non-intrinsic 'InterlockedCompareExchange64', which does not
+ // exist on XP. We work around this by rolling our own synthetic in terms of
+ // compareAndSwap which we have explicitly formulated in terms of the compiler
+ // provided _InterlockedCompareExchange64 intrinsic.
+ T currentValue = *dest;
+ while (true) {
+ const T result = compareAndSwap(dest, currentValue, newValue);
+ if (result == currentValue)
+ return result;
+ currentValue = result;
+ }
+ }
+
+ static T fetchAndAdd(volatile T* dest, T increment) {
+ // NOTE: See note for 'swap' on why we roll this ourselves.
+ T currentValue = *dest;
+ while (true) {
+ const T incremented = currentValue + increment;
+ const T result = compareAndSwap(dest, currentValue, incremented);
+ if (result == currentValue)
+ return result;
+ currentValue = result;
+ }
+ }
+ };
+
// On 32-bit IA-32 systems, 64-bit load and store must be implemented in terms of
// Interlocked operations, but on 64-bit systems they support a simpler, native
// implementation. The LoadStoreImpl type represents the abstract implementation of
// loading and storing 64-bit values.
- template <typename T, typename _IsTTooBig=void>
+ template <typename U, typename _IsTTooBig=void>
class LoadStoreImpl{};
// Implementation on 64-bit systems.