/* Copyright 2012 10gen Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Implementation of the AtomicIntrinsics::* operations for Windows systems. */ #pragma once #include #include "mongo/platform/windows_basic.h" #if defined(_MSC_VER) && (_WINNT_VERSION < 0x502) #include #pragma intrinsic(_InterlockedCompareExchange64) __inline __int64 _InterlockedExchange64(__int64 volatile * Target,__int64 Value) { __int64 ret = *Target; _InterlockedCompareExchange64(Target,Value,*Target); return ret; } __inline __int64 _InterlockedExchangeAdd64(__int64 volatile * Addend,__int64 Value) { __int64 ret; if(Value == 0) return *Addend; ret = *Addend; _InterlockedCompareExchange64(Addend,*Addend+Value,*Addend); return ret; } #define InterlockedCompareExchange64 _InterlockedCompareExchange64 #define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 #define InterlockedExchange64 _InterlockedExchange64 #endif namespace mongo { /** * Default instantiation of AtomicIntrinsics<>, for unsupported types. */ template class AtomicIntrinsics { private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; /** * Instantiation of AtomicIntrinsics<> for 32-bit word sizes (i.e., unsigned). */ template class AtomicIntrinsics::type> { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { return InterlockedCompareExchange(reinterpret_cast(dest), LONG(newValue), LONG(expected)); } static T swap(volatile T* dest, T newValue) { return InterlockedExchange(reinterpret_cast(dest), LONG(newValue)); } static T load(volatile const T* value) { MemoryBarrier(); T result = *value; MemoryBarrier(); return result; } static void store(volatile T* dest, T newValue) { MemoryBarrier(); *dest = newValue; MemoryBarrier(); } static T fetchAndAdd(volatile T* dest, T increment) { return InterlockedExchangeAdd(reinterpret_cast(dest), LONG(increment)); } private: AtomicIntrinsics(); ~AtomicIntrinsics(); }; /** * Instantiation of AtomicIntrinsics<> for 64-bit word sizes. */ template class AtomicIntrinsics::type> { public: static T compareAndSwap(volatile T* dest, T expected, T newValue) { return _InterlockedCompareExchange64(reinterpret_cast(dest), LONGLONG(newValue), LONGLONG(expected)); } static T swap(volatile T* dest, T newValue) { return _InterlockedExchange64(reinterpret_cast(dest), LONGLONG(newValue)); } static T load(volatile const T* value) { return LoadStoreImpl::load(value); } static void store(volatile T* dest, T newValue) { LoadStoreImpl::store(dest, newValue); } static T fetchAndAdd(volatile T* dest, T increment) { return _InterlockedExchangeAdd64(reinterpret_cast(dest), LONGLONG(increment)); } private: AtomicIntrinsics(); ~AtomicIntrinsics(); // 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 class LoadStoreImpl{}; // Implementation on 64-bit systems. template class LoadStoreImpl::type> { public: static U load(volatile const U* value) { MemoryBarrier(); U result = *value; MemoryBarrier(); return result; } static void store(volatile U* dest, U newValue) { MemoryBarrier(); *dest = newValue; MemoryBarrier(); } }; // Implementation on 32-bit systems. template class LoadStoreImpl::type> { public: static U load(volatile const U* value) { return AtomicIntrinsics::compareAndSwap(const_cast(value), U(0), U(0)); } static void store(volatile U* dest, U newValue) { AtomicIntrinsics::swap(dest, newValue); } }; }; } // namespace mongo