2011-07-13 20:08:05 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS kernel-mode tests
|
|
|
|
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
|
|
|
* PURPOSE: Kernel-Mode Test Suite Interlocked function test
|
|
|
|
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
|
|
|
|
*/
|
|
|
|
|
2012-05-01 09:13:19 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
|
2011-07-13 20:08:05 +00:00
|
|
|
/* missing prototypes >:| */
|
|
|
|
__declspec(dllimport) long __fastcall InterlockedCompareExchange(volatile long *, long, long);
|
|
|
|
__declspec(dllimport) __int64 __fastcall ExInterlockedCompareExchange64(volatile __int64 *, __int64 *, __int64 *, void *);
|
|
|
|
__declspec(dllimport) __int64 __fastcall ExfInterlockedCompareExchange64(volatile __int64 *, __int64 *, __int64 *);
|
|
|
|
__declspec(dllimport) long __fastcall InterlockedExchange(volatile long *, long);
|
|
|
|
__declspec(dllimport) unsigned long __stdcall ExInterlockedExchangeUlong(unsigned long *, unsigned long, void *);
|
|
|
|
__declspec(dllimport) long __fastcall InterlockedExchangeAdd(volatile long *, long);
|
2012-05-01 09:13:19 +00:00
|
|
|
#ifdef _X86_
|
|
|
|
__declspec(dllimport) unsigned long __stdcall ExInterlockedAddUlong(unsigned long *, unsigned long, unsigned long *);
|
|
|
|
#endif
|
2011-07-13 20:08:05 +00:00
|
|
|
__declspec(dllimport) unsigned long __stdcall Exi386InterlockedExchangeUlong(unsigned long *, unsigned long);
|
|
|
|
__declspec(dllimport) long __fastcall InterlockedIncrement(long *);
|
|
|
|
__declspec(dllimport) long __fastcall InterlockedDecrement(long *);
|
|
|
|
__declspec(dllimport) int __stdcall ExInterlockedIncrementLong(long *, void *);
|
|
|
|
__declspec(dllimport) int __stdcall ExInterlockedDecrementLong(long *, void *);
|
|
|
|
__declspec(dllimport) int __stdcall Exi386InterlockedIncrementLong(long *);
|
|
|
|
__declspec(dllimport) int __stdcall Exi386InterlockedDecrementLong(long *);
|
|
|
|
|
|
|
|
#include <kmt_test.h>
|
|
|
|
|
|
|
|
/* TODO: There are quite some changes needed for other architectures!
|
|
|
|
ExInterlockedAddLargeInteger, ExInterlockedAddUlong are the only two
|
|
|
|
functions actually exported by my win7/x64 kernel! */
|
|
|
|
|
|
|
|
/* TODO: stress-testing */
|
|
|
|
|
|
|
|
static KSPIN_LOCK SpinLock;
|
|
|
|
|
2011-07-22 12:01:48 +00:00
|
|
|
#ifdef _M_IX86
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
unsigned long esi, edi, ebx, ebp, esp;
|
|
|
|
} PROCESSOR_STATE;
|
|
|
|
#elif defined(_M_AMD64)
|
2011-07-13 21:17:55 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
2011-07-22 12:01:48 +00:00
|
|
|
unsigned long long rsi, rdi, rbx, rbp, rsp, r12, r13, r14, r15;
|
|
|
|
} PROCESSOR_STATE;
|
|
|
|
#else
|
|
|
|
// dummy
|
|
|
|
typedef int PROCESSOR_STATE;
|
|
|
|
#endif
|
2011-07-13 21:17:55 +00:00
|
|
|
|
2012-08-26 12:06:45 +00:00
|
|
|
/* TODO: these need to be rewritten in proper assembly to account for registers
|
|
|
|
* saved by the caller */
|
2011-07-13 21:17:55 +00:00
|
|
|
#if defined(_MSC_VER) && defined(_M_IX86)
|
|
|
|
#define SaveState(State) do \
|
|
|
|
{ \
|
|
|
|
__asm lea ecx, [State] \
|
|
|
|
__asm mov [ecx], esi \
|
|
|
|
__asm mov [ecx+4], edi \
|
|
|
|
__asm mov [ecx+8], ebx \
|
|
|
|
__asm mov [ecx+12], ebp \
|
|
|
|
__asm mov [ecx+16], esp \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CheckState(OldState, NewState) do \
|
|
|
|
{ \
|
2012-03-15 11:46:30 +00:00
|
|
|
/* TODO: MSVC uses esi and saves it before, so this is okay */ \
|
|
|
|
/*ok_eq_hex((OldState)->esi, (NewState)->esi);*/ \
|
2011-07-13 21:17:55 +00:00
|
|
|
ok_eq_hex((OldState)->edi, (NewState)->edi); \
|
|
|
|
ok_eq_hex((OldState)->ebx, (NewState)->ebx); \
|
|
|
|
ok_eq_hex((OldState)->ebp, (NewState)->ebp); \
|
|
|
|
ok_eq_hex((OldState)->esp, (NewState)->esp); \
|
|
|
|
} while (0)
|
|
|
|
|
2011-07-22 12:01:48 +00:00
|
|
|
#elif defined(__GNUC__) && defined(_M_IX86)
|
|
|
|
#define SaveState(State) \
|
|
|
|
asm volatile( \
|
2012-08-26 12:06:45 +00:00
|
|
|
"movl\t%%esi, (%%ecx)\n\t" \
|
|
|
|
"movl\t%%edi, 4(%%ecx)\n\t" \
|
|
|
|
"movl\t%%ebx, 8(%%ecx)\n\t" \
|
|
|
|
"movl\t%%ebp, 12(%%ecx)\n\t" \
|
|
|
|
"movl\t%%esp, 16(%%ecx)" \
|
2011-07-22 12:01:48 +00:00
|
|
|
: : "c" (&State) : "memory" \
|
|
|
|
);
|
|
|
|
|
|
|
|
#define CheckState(OldState, NewState) do \
|
|
|
|
{ \
|
2012-08-26 12:06:45 +00:00
|
|
|
/* TODO: GCC 4.7 uses esi and saves it before, so this is okay */ \
|
|
|
|
/*ok_eq_hex((OldState)->esi, (NewState)->esi);*/ \
|
2011-07-22 12:01:48 +00:00
|
|
|
ok_eq_hex((OldState)->edi, (NewState)->edi); \
|
2012-08-26 12:06:45 +00:00
|
|
|
/* TODO: GCC 4.4 uses ebx and saves it before, so this is okay */ \
|
2012-03-15 11:46:30 +00:00
|
|
|
/*ok_eq_hex((OldState)->ebx, (NewState)->ebx);*/ \
|
2011-07-22 12:01:48 +00:00
|
|
|
ok_eq_hex((OldState)->ebp, (NewState)->ebp); \
|
|
|
|
ok_eq_hex((OldState)->esp, (NewState)->esp); \
|
|
|
|
} while (0)
|
|
|
|
#elif defined(__GNUC__) && defined(_M_AMD64)
|
|
|
|
#define SaveState(State) \
|
|
|
|
asm volatile( \
|
2012-08-26 12:06:45 +00:00
|
|
|
"mov\t%%rsi, (%%rcx)\n\t" \
|
|
|
|
"mov\t%%rdi, 8(%%rcx)\n\t" \
|
|
|
|
"mov\t%%rbx, 16(%%rcx)\n\t" \
|
|
|
|
"mov\t%%rbp, 24(%%rcx)\n\t" \
|
|
|
|
"mov\t%%rsp, 32(%%rcx)\n\t" \
|
|
|
|
"mov\t%%r12, 40(%%rcx)\n\t" \
|
|
|
|
"mov\t%%r13, 48(%%rcx)\n\t" \
|
|
|
|
"mov\t%%r14, 56(%%rcx)\n\t" \
|
|
|
|
"mov\t%%r15, 64(%%rcx)" \
|
2011-07-22 12:01:48 +00:00
|
|
|
: : "c" (&State) : "memory" \
|
|
|
|
);
|
|
|
|
|
|
|
|
#define CheckState(OldState, NewState) do \
|
|
|
|
{ \
|
|
|
|
ok_eq_hex((OldState)->rsi, (NewState)->rsi); \
|
|
|
|
ok_eq_hex((OldState)->rdi, (NewState)->rdi); \
|
|
|
|
ok_eq_hex((OldState)->rbx, (NewState)->rbx); \
|
|
|
|
ok_eq_hex((OldState)->rbp, (NewState)->rbp); \
|
|
|
|
ok_eq_hex((OldState)->rsp, (NewState)->rsp); \
|
|
|
|
ok_eq_hex((OldState)->r12, (NewState)->r12); \
|
|
|
|
ok_eq_hex((OldState)->r13, (NewState)->r13); \
|
|
|
|
ok_eq_hex((OldState)->r14, (NewState)->r14); \
|
|
|
|
ok_eq_hex((OldState)->r15, (NewState)->r15); \
|
|
|
|
} while (0)
|
2011-07-13 21:17:55 +00:00
|
|
|
#else
|
|
|
|
#define SaveState(State)
|
2012-05-01 09:13:19 +00:00
|
|
|
#define CheckState(OldState, NewState) do \
|
|
|
|
{ \
|
|
|
|
(void)OldState; \
|
|
|
|
(void)NewState; \
|
|
|
|
} while (0)
|
2011-07-13 21:17:55 +00:00
|
|
|
#endif
|
|
|
|
|
2011-07-13 20:08:05 +00:00
|
|
|
static
|
|
|
|
LARGE_INTEGER
|
|
|
|
Large(
|
|
|
|
ULONGLONG Value)
|
|
|
|
{
|
|
|
|
LARGE_INTEGER Ret;
|
|
|
|
Ret.QuadPart = Value;
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CheckInterlockedCmpXchg(Function, Type, Print, Val, Cmp, Xchg, \
|
2011-08-19 19:03:46 +00:00
|
|
|
ExpectedValue, ExpectedRet) do \
|
2011-07-13 20:08:05 +00:00
|
|
|
{ \
|
|
|
|
Type Ret##Type = 0; \
|
|
|
|
Type Value##Type = Val; \
|
|
|
|
Status = STATUS_SUCCESS; \
|
|
|
|
_SEH2_TRY { \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(OldState); \
|
2011-08-19 19:03:46 +00:00
|
|
|
Ret##Type = Function(&Value##Type, Xchg, Cmp); \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(NewState); \
|
|
|
|
CheckState(&OldState, &NewState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
|
|
|
|
Status = _SEH2_GetExceptionCode(); \
|
|
|
|
} _SEH2_END; \
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS); \
|
|
|
|
ok_eq_print(Ret##Type, ExpectedRet, Print); \
|
|
|
|
ok_eq_print(Value##Type, ExpectedValue, Print); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CheckInterlockedCmpXchgI(Function, Type, Print, Val, Cmp, Xchg, \
|
|
|
|
ExpectedValue, ExpectedRet, ...) do \
|
|
|
|
{ \
|
|
|
|
Type Ret##Type = 0; \
|
|
|
|
Type Value##Type = Val; \
|
|
|
|
Type Compare##Type = Cmp; \
|
|
|
|
Type Exchange##Type = Xchg; \
|
|
|
|
Status = STATUS_SUCCESS; \
|
|
|
|
_SEH2_TRY { \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(OldState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
Ret##Type = Function(&Value##Type, &Exchange##Type, \
|
|
|
|
&Compare##Type, ##__VA_ARGS__); \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(NewState); \
|
|
|
|
CheckState(&OldState, &NewState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
|
|
|
|
Status = _SEH2_GetExceptionCode(); \
|
|
|
|
} _SEH2_END; \
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS); \
|
|
|
|
ok_eq_print(Ret##Type, ExpectedRet, Print); \
|
|
|
|
ok_eq_print(Value##Type, ExpectedValue, Print); \
|
|
|
|
ok_eq_print(Exchange##Type, Xchg, Print); \
|
|
|
|
ok_eq_print(Compare##Type, Cmp, Print); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define CheckInterlockedOp(Function, Type, Print, Val, Op, \
|
|
|
|
ExpectedValue, ExpectedRet, ...) do \
|
|
|
|
{ \
|
|
|
|
Type Ret##Type = 0; \
|
|
|
|
Type Value##Type = Val; \
|
|
|
|
Status = STATUS_SUCCESS; \
|
|
|
|
_SEH2_TRY { \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(OldState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__); \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(NewState); \
|
|
|
|
CheckState(&OldState, &NewState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
|
|
|
|
Status = _SEH2_GetExceptionCode(); \
|
|
|
|
} _SEH2_END; \
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS); \
|
|
|
|
ok_eq_print(Ret##Type, ExpectedRet, Print); \
|
|
|
|
ok_eq_print(Value##Type, ExpectedValue, Print); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CheckInterlockedOpNoArg(Function, Type, Print, Val, \
|
|
|
|
ExpectedValue, ExpectedRet, ...) do \
|
|
|
|
{ \
|
|
|
|
Type Ret##Type = 0; \
|
|
|
|
Type Value##Type = Val; \
|
|
|
|
Status = STATUS_SUCCESS; \
|
|
|
|
_SEH2_TRY { \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(OldState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
Ret##Type = Function(&Value##Type, ##__VA_ARGS__); \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(NewState); \
|
|
|
|
CheckState(&OldState, &NewState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
|
|
|
|
Status = _SEH2_GetExceptionCode(); \
|
|
|
|
} _SEH2_END; \
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS); \
|
|
|
|
ok_eq_print(Ret##Type, ExpectedRet, Print); \
|
|
|
|
ok_eq_print(Value##Type, ExpectedValue, Print); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CheckInterlockedOpLarge(Function, Type, Print, Val, Op, \
|
|
|
|
ExpectedValue, ExpectedRet, ...) do \
|
|
|
|
{ \
|
|
|
|
Type Ret##Type = Large(0); \
|
|
|
|
Type Value##Type = Val; \
|
|
|
|
Status = STATUS_SUCCESS; \
|
|
|
|
_SEH2_TRY { \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(OldState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__); \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(NewState); \
|
|
|
|
CheckState(&OldState, &NewState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
|
|
|
|
Status = _SEH2_GetExceptionCode(); \
|
|
|
|
} _SEH2_END; \
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS); \
|
|
|
|
ok_eq_print(Ret##Type.QuadPart, ExpectedRet, Print); \
|
|
|
|
ok_eq_print(Value##Type.QuadPart, ExpectedValue, Print); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define CheckInterlockedOpLargeNoRet(Function, Type, Print, Val, Op, \
|
2011-08-19 19:03:46 +00:00
|
|
|
ExpectedValue) do \
|
2011-07-13 20:08:05 +00:00
|
|
|
{ \
|
|
|
|
Type Value##Type = Val; \
|
|
|
|
Status = STATUS_SUCCESS; \
|
|
|
|
_SEH2_TRY { \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(OldState); \
|
2011-08-19 19:03:46 +00:00
|
|
|
Function(&Value##Type, Op); \
|
2011-07-13 21:17:55 +00:00
|
|
|
SaveState(NewState); \
|
|
|
|
CheckState(&OldState, &NewState); \
|
2011-07-13 20:08:05 +00:00
|
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
|
|
|
|
Status = _SEH2_GetExceptionCode(); \
|
|
|
|
} _SEH2_END; \
|
|
|
|
ok_eq_hex(Status, STATUS_SUCCESS); \
|
|
|
|
ok_eq_print(Value##Type.QuadPart, ExpectedValue, Print); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* TODO: missing in wdm.h! */
|
|
|
|
#define InterlockedCompareExchangeAcquire InterlockedCompareExchange
|
|
|
|
#define InterlockedCompareExchangeRelease InterlockedCompareExchange
|
|
|
|
#define InterlockedIncrementAcquire InterlockedIncrement
|
|
|
|
#define InterlockedIncrementRelease InterlockedIncrement
|
|
|
|
#define InterlockedDecrementAcquire InterlockedDecrement
|
|
|
|
#define InterlockedDecrementRelease InterlockedDecrement
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
TestInterlockedFunctional(VOID)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PKSPIN_LOCK pSpinLock = &SpinLock;
|
2011-07-13 21:17:55 +00:00
|
|
|
PROCESSOR_STATE OldState, NewState;
|
2011-07-13 20:08:05 +00:00
|
|
|
|
2011-07-22 11:33:17 +00:00
|
|
|
/* on x86, most of these are supported intrinsically and don't need a spinlock! */
|
2011-07-13 20:08:05 +00:00
|
|
|
#if defined _M_IX86 || defined _M_AMD64
|
|
|
|
pSpinLock = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* CompareExchange */
|
|
|
|
/* macro version */
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 6, 8, 5L, 5L);
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 5, 9, 9L, 5L);
|
|
|
|
/* these only exist as macros on x86 */
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchangeAcquire, LONG, "%ld", 16, 9, 12, 16L, 16L);
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchangeAcquire, LONG, "%ld", 16, 16, 4, 4L, 16L);
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchangeRelease, LONG, "%ld", 27, 123, 38, 27L, 27L);
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchangeRelease, LONG, "%ld", 27, 27, 39, 39L, 27L);
|
2011-07-22 12:01:48 +00:00
|
|
|
/* exported function */
|
|
|
|
#undef InterlockedCompareExchange
|
|
|
|
#ifdef _M_IX86
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 6, 8, 5L, 5L);
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchange, LONG, "%ld", 5, 5, 9, 9L, 5L);
|
|
|
|
#endif
|
2011-07-13 20:08:05 +00:00
|
|
|
/* only exists as a macro */
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchangePointer, PVOID, "%p", (PVOID)117, (PVOID)711, (PVOID)12, (PVOID)117, (PVOID)117);
|
|
|
|
CheckInterlockedCmpXchg(InterlockedCompareExchangePointer, PVOID, "%p", (PVOID)117, (PVOID)117, (PVOID)228, (PVOID)228, (PVOID)117);
|
|
|
|
/* macro version */
|
|
|
|
CheckInterlockedCmpXchgI(ExInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 4LL, 20LL, 17LL, 17LL, pSpinLock);
|
|
|
|
CheckInterlockedCmpXchgI(ExInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 17LL, 21LL, 21LL, 17LL, pSpinLock);
|
2011-07-22 12:01:48 +00:00
|
|
|
#ifdef _M_IX86
|
2011-07-13 20:08:05 +00:00
|
|
|
/* exported function */
|
|
|
|
CheckInterlockedCmpXchgI((ExInterlockedCompareExchange64), LONGLONG, "%I64d", 17, 4LL, 20LL, 17LL, 17LL, pSpinLock);
|
|
|
|
CheckInterlockedCmpXchgI((ExInterlockedCompareExchange64), LONGLONG, "%I64d", 17, 17LL, 21LL, 21LL, 17LL, pSpinLock);
|
|
|
|
/* fastcall version */
|
|
|
|
CheckInterlockedCmpXchgI(ExfInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 4LL, 20LL, 17LL, 17LL);
|
|
|
|
CheckInterlockedCmpXchgI(ExfInterlockedCompareExchange64, LONGLONG, "%I64d", 17, 17LL, 21LL, 21LL, 17LL);
|
2011-07-22 12:01:48 +00:00
|
|
|
#endif
|
2011-07-13 20:08:05 +00:00
|
|
|
|
|
|
|
/* Exchange */
|
|
|
|
CheckInterlockedOp(InterlockedExchange, LONG, "%ld", 5, 8, 8L, 5L);
|
2011-08-19 19:03:46 +00:00
|
|
|
CheckInterlockedOpNoArg(InterlockedExchangePointer, PVOID, "%p", (PVOID)700, (PVOID)93, (PVOID)700, (PVOID)93);
|
2011-07-13 20:08:05 +00:00
|
|
|
#undef InterlockedExchange
|
2011-07-22 12:01:48 +00:00
|
|
|
#ifdef _M_IX86
|
2011-07-13 20:08:05 +00:00
|
|
|
CheckInterlockedOp(InterlockedExchange, LONG, "%ld", 5, 8, 8L, 5L);
|
|
|
|
CheckInterlockedOp(ExInterlockedExchangeUlong, ULONG, "%lu", 212, 121, 121LU, 212LU, pSpinLock);
|
|
|
|
CheckInterlockedOp((ExInterlockedExchangeUlong), ULONG, "%lu", 212, 121, 121LU, 212LU, pSpinLock);
|
|
|
|
CheckInterlockedOp(Exi386InterlockedExchangeUlong, ULONG, "%lu", 212, 121, 121LU, 212LU);
|
|
|
|
CheckInterlockedOp(Exfi386InterlockedExchangeUlong, ULONG, "%lu", 212, 121, 121LU, 212LU);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* ExchangeAdd */
|
|
|
|
/* TODO: ExInterlockedExchangeAddLargeInteger? */
|
|
|
|
CheckInterlockedOp(InterlockedExchangeAdd, LONG, "%ld", 312, 7, 319L, 312L);
|
|
|
|
#undef InterlockedExchangeAdd
|
2011-07-22 12:01:48 +00:00
|
|
|
#ifdef _M_IX86
|
2011-07-13 20:08:05 +00:00
|
|
|
CheckInterlockedOp(InterlockedExchangeAdd, LONG, "%ld", 312, 7, 319L, 312L);
|
2011-07-22 12:01:48 +00:00
|
|
|
#endif
|
2011-07-13 20:08:05 +00:00
|
|
|
|
|
|
|
/* Add */
|
|
|
|
/* these DO need a valid spinlock even on x86 */
|
|
|
|
CheckInterlockedOpLarge(ExInterlockedAddLargeInteger, LARGE_INTEGER, "%I64d", Large(23), Large(7), 30LL, 23LL, &SpinLock);
|
|
|
|
CheckInterlockedOpLargeNoRet(ExInterlockedAddLargeStatistic, LARGE_INTEGER, "%I64d", Large(15), 17LL, 32LL);
|
|
|
|
CheckInterlockedOp(ExInterlockedAddUlong, ULONG, "%lu", 239, 44, 283LU, 239LU, &SpinLock);
|
|
|
|
#undef ExInterlockedAddUlong
|
|
|
|
CheckInterlockedOp(ExInterlockedAddUlong, ULONG, "%lu", 239, 44, 283LU, 239LU, &SpinLock);
|
|
|
|
|
|
|
|
/* Increment */
|
|
|
|
CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", 2341L, 2342L, 2342L);
|
|
|
|
CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)MINLONG);
|
2011-07-22 12:01:48 +00:00
|
|
|
CheckInterlockedOpNoArg(InterlockedIncrementAcquire, LONG, "%ld", 2341L, 2342L, 2342L);
|
|
|
|
CheckInterlockedOpNoArg(InterlockedIncrementRelease, LONG, "%ld", 2341L, 2342L, 2342L);
|
2011-07-13 20:08:05 +00:00
|
|
|
#undef InterlockedIncrement
|
2011-07-22 12:01:48 +00:00
|
|
|
#ifdef _M_IX86
|
2011-07-13 20:08:05 +00:00
|
|
|
CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", 2341L, 2342L, 2342L);
|
|
|
|
CheckInterlockedOpNoArg(InterlockedIncrement, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)MINLONG);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", -2L, -1L, (LONG)ResultNegative, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", -1L, 0L, (LONG)ResultZero, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", 0L, 1L, (LONG)ResultPositive, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedIncrementLong, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)ResultNegative, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", -2L, -1L, (LONG)ResultNegative, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", -1L, 0L, (LONG)ResultZero, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", 0L, 1L, (LONG)ResultPositive, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedIncrementLong), LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)ResultNegative, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", -2L, -1L, (LONG)ResultNegative);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", -1L, 0L, (LONG)ResultZero);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", 0L, 1L, (LONG)ResultPositive);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedIncrementLong, LONG, "%ld", (LONG)MAXLONG, (LONG)MINLONG, (LONG)ResultNegative);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Decrement */
|
|
|
|
CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", 1745L, 1744L, 1744L);
|
|
|
|
CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)MAXLONG);
|
2011-07-22 12:01:48 +00:00
|
|
|
CheckInterlockedOpNoArg(InterlockedDecrementAcquire, LONG, "%ld", 1745L, 1744L, 1744L);
|
|
|
|
CheckInterlockedOpNoArg(InterlockedDecrementRelease, LONG, "%ld", 1745L, 1744L, 1744L);
|
2011-07-13 20:08:05 +00:00
|
|
|
#undef InterlockedDecrement
|
2011-07-22 12:01:48 +00:00
|
|
|
#ifdef _M_IX86
|
2011-07-13 20:08:05 +00:00
|
|
|
CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", 1745L, 1744L, 1744L);
|
|
|
|
CheckInterlockedOpNoArg(InterlockedDecrement, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)MAXLONG);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)ResultPositive, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", 0L, -1L, (LONG)ResultNegative, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", 1L, 0L, (LONG)ResultZero, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(ExInterlockedDecrementLong, LONG, "%ld", 2L, 1L, (LONG)ResultPositive, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)ResultPositive, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", 0L, -1L, (LONG)ResultNegative, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", 1L, 0L, (LONG)ResultZero, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg((ExInterlockedDecrementLong), LONG, "%ld", 2L, 1L, (LONG)ResultPositive, pSpinLock);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", (LONG)MINLONG, (LONG)MAXLONG, (LONG)ResultPositive);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", 0L, -1L, (LONG)ResultNegative);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", 1L, 0L, (LONG)ResultZero);
|
|
|
|
CheckInterlockedOpNoArg(Exi386InterlockedDecrementLong, LONG, "%ld", 2L, 1L, (LONG)ResultPositive);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* And, Or, Xor */
|
|
|
|
CheckInterlockedOp(InterlockedAnd, LONG, "0x%lx", 0x1234L, 0x1111L, 0x1010L, 0x1234L);
|
|
|
|
CheckInterlockedOp(InterlockedOr, LONG, "0x%lx", 0x1234L, 0x1111L, 0x1335L, 0x1234L);
|
|
|
|
CheckInterlockedOp(InterlockedXor, LONG, "0x%lx", 0x1234L, 0x1111L, 0x0325L, 0x1234L);
|
|
|
|
#ifdef _WIN64
|
|
|
|
CheckInterlockedOp(InterlockedXor64, LONGLONG, "0x%I64x", 0x200001234LL, 0x100001111LL, 0x300000325LL, 0x200001234LL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
START_TEST(ExInterlocked)
|
|
|
|
{
|
|
|
|
KIRQL Irql;
|
|
|
|
KeInitializeSpinLock(&SpinLock);
|
|
|
|
|
|
|
|
/* functional testing */
|
|
|
|
TestInterlockedFunctional();
|
|
|
|
KeRaiseIrql(HIGH_LEVEL, &Irql);
|
|
|
|
TestInterlockedFunctional();
|
|
|
|
KeLowerIrql(Irql);
|
|
|
|
}
|