Dryad/DryadVertex/VertexHost/system/classlib/include/Interlocked.h

151 lines
4.2 KiB
C++

/*
Copyright (c) Microsoft Corporation
All rights reserved.
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
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <windows.h>
// The Interlocked64 APIs are only available on Windows Server 2003
// and later. Even though the Interlocked64 operation are declared in
// winbase.h, they are not in kernel32, so the application breaks at
// runtime.
// Also, AMD64 machines do not have InterlockedCompareExchange64() in
// kernel32, since the function is an intrinsic, so it must be called
// directly.
//
// This file defines Interlocked64 operations on 32 bit platforms.
// On 64 bit platforms (AMD or IA64), the inlined functions
// call the intrinsic functions.
namespace Interlocked
{
#if defined(_M_AMD64) || defined(_M_IA64)
LONGLONG inline CompareExchange64(LONGLONG volatile* destination,
LONGLONG comparand,
LONGLONG exchange)
{
return ::InterlockedCompareExchange64(destination, comparand, exchange);
}
LONGLONG inline Increment64(LONGLONG volatile *Addend)
{
return ::InterlockedIncrement64(Addend);
}
LONGLONG inline Decrement64(LONGLONG volatile *Addend)
{
return InterlockedDecrement64(Addend);
}
LONGLONG inline Exchange64(LONGLONG volatile *Target, LONGLONG Value)
{
return ::InterlockedExchange64(Target, Value);
}
LONGLONG inline ExchangeAdd64(LONGLONG volatile *Addend, LONGLONG Value)
{
return ::InterlockedExchangeAdd64(Addend, Value);
}
LONGLONG inline Read64(LONGLONG volatile *target)
{
return *target;
}
#else
LONGLONG inline __cdecl CompareExchange64(LONGLONG volatile* destination,
LONGLONG comparand,
LONGLONG exchange)
{
__asm
{
mov esi, [destination]
mov ebx, dword ptr [comparand]
mov ecx, dword ptr [comparand + 4]
mov eax, dword ptr [exchange]
mov edx, dword ptr [exchange + 4]
lock cmpxchg8b [esi]
};
}
// Copied from winbase.h
LONGLONG inline Increment64(LONGLONG volatile *Addend)
{
LONGLONG Old;
do {
Old = *Addend;
} while (CompareExchange64(Addend, Old + 1, Old) != Old);
return Old + 1;
}
// Copied from winbase.h
LONGLONG inline Decrement64(LONGLONG volatile *Addend)
{
LONGLONG Old;
do {
Old = *Addend;
} while (CompareExchange64(Addend, Old - 1, Old) != Old);
return Old - 1;
}
// Copied from winbase.h
LONGLONG inline Exchange64(LONGLONG volatile *Target, LONGLONG Value)
{
LONGLONG Old;
do {
Old = *Target;
} while (CompareExchange64(Target, Value, Old) != Old);
return Old;
}
// Copied from winbase.h
LONGLONG inline ExchangeAdd64(LONGLONG volatile *Addend,
LONGLONG Value)
{
LONGLONG Old;
do {
Old = *Addend;
} while (CompareExchange64(Addend, Old + Value, Old) != Old);
return Old;
}
LONGLONG inline Read64(LONGLONG volatile *target)
{
// As far as I know, this is the only way to atomically read a
// 64 bit value on a 32 bit platform.
// InterlockedCompareExchange64 reads the target value
// atomically. If the value is 0, it sets the value to 0 and
// returns 0 (no-op) If the value is non-zero, it does not
// change the value and returns old value.
return CompareExchange64(target, 0, 0);
}
#endif
};