libwinpr-interlocked: added unit tests for interlocked access

This commit is contained in:
Marc-André Moreau 2012-10-01 21:58:24 -04:00
parent a80eeabc48
commit eb54da8eb5
6 changed files with 304 additions and 30 deletions

View File

@ -57,7 +57,7 @@ typedef struct LIST_ENTRY64
} LIST_ENTRY64; } LIST_ENTRY64;
typedef LIST_ENTRY64 *PLIST_ENTRY64; typedef LIST_ENTRY64 *PLIST_ENTRY64;
#ifdef _AMD64_ #ifdef _WIN64
typedef struct _SLIST_ENTRY *PSLIST_ENTRY; typedef struct _SLIST_ENTRY *PSLIST_ENTRY;
typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY
@ -65,24 +65,46 @@ typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY
PSLIST_ENTRY Next; PSLIST_ENTRY Next;
} SLIST_ENTRY; } SLIST_ENTRY;
#else /* _AMD64_ */ #else /* _WIN64 */
#define SLIST_ENTRY SINGLE_LIST_ENTRY #define SLIST_ENTRY SINGLE_LIST_ENTRY
#define _SLIST_ENTRY _SINGLE_LIST_ENTRY #define _SLIST_ENTRY _SINGLE_LIST_ENTRY
#define PSLIST_ENTRY PSINGLE_LIST_ENTRY #define PSLIST_ENTRY PSINGLE_LIST_ENTRY
#endif /* _AMD64_ */ #endif /* _WIN64 */
#if defined(_AMD64_) #ifdef _WIN64
typedef struct DECLSPEC_ALIGN(16) _SLIST_HEADER typedef union DECLSPEC_ALIGN(16) _SLIST_HEADER
{ {
ULONGLONG Alignment; struct
ULONGLONG Region; {
} SLIST_HEADER; ULONGLONG Alignment;
typedef struct _SLIST_HEADER *PSLIST_HEADER; ULONGLONG Region;
} DUMMYSTRUCTNAME;
#else /* _AMD64_ */ struct
{
ULONGLONG Depth:16;
ULONGLONG Sequence:9;
ULONGLONG NextEntry:39;
ULONGLONG HeaderType:1;
ULONGLONG Init:1;
ULONGLONG Reserved:59;
ULONGLONG Region:3;
} Header8;
struct
{
ULONGLONG Depth:16;
ULONGLONG Sequence:48;
ULONGLONG HeaderType:1;
ULONGLONG Reserved:3;
ULONGLONG NextEntry:60;
} HeaderX64;
} SLIST_HEADER, *PSLIST_HEADER;
#else /* _WIN64 */
typedef union _SLIST_HEADER typedef union _SLIST_HEADER
{ {
@ -96,13 +118,13 @@ typedef union _SLIST_HEADER
} DUMMYSTRUCTNAME; } DUMMYSTRUCTNAME;
} SLIST_HEADER, *PSLIST_HEADER; } SLIST_HEADER, *PSLIST_HEADER;
#endif /* _AMD64_ */ #endif /* _WIN64 */
WINPR_API VOID InitializeSListHead(PSLIST_HEADER ListHead); WINPR_API VOID InitializeSListHead(PSLIST_HEADER ListHead);
WINPR_API PSLIST_ENTRY InterlockedPopEntrySList(PSLIST_HEADER ListHead);
WINPR_API PSLIST_ENTRY InterlockedPushEntrySList(PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry); WINPR_API PSLIST_ENTRY InterlockedPushEntrySList(PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry);
WINPR_API PSLIST_ENTRY InterlockedPushListSListEx(PSLIST_HEADER ListHead, PSLIST_ENTRY List, PSLIST_ENTRY ListEnd, ULONG Count); WINPR_API PSLIST_ENTRY InterlockedPushListSListEx(PSLIST_HEADER ListHead, PSLIST_ENTRY List, PSLIST_ENTRY ListEnd, ULONG Count);
WINPR_API PSLIST_ENTRY InterlockedPopEntrySList(PSLIST_HEADER ListHead);
WINPR_API PSLIST_ENTRY InterlockedFlushSList(PSLIST_HEADER ListHead); WINPR_API PSLIST_ENTRY InterlockedFlushSList(PSLIST_HEADER ListHead);
WINPR_API USHORT QueryDepthSList(PSLIST_HEADER ListHead); WINPR_API USHORT QueryDepthSList(PSLIST_HEADER ListHead);
@ -113,8 +135,8 @@ WINPR_API LONG InterlockedDecrement(LONG volatile *Addend);
WINPR_API LONG InterlockedExchange(LONG volatile *Target, LONG Value); WINPR_API LONG InterlockedExchange(LONG volatile *Target, LONG Value);
WINPR_API LONG InterlockedExchangeAdd(LONG volatile *Addend, LONG Value); WINPR_API LONG InterlockedExchangeAdd(LONG volatile *Addend, LONG Value);
WINPR_API LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange, LONG Comperand); WINPR_API LONG InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange, LONG Comperand);
WINPR_API LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 ExChange, LONG64 Comperand); WINPR_API LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 Exchange, LONG64 Comperand);
#endif /* _WIN32 */ #endif /* _WIN32 */

View File

@ -27,6 +27,10 @@
#endif #endif
#endif /* _AMD64_ */ #endif /* _AMD64_ */
#ifdef _AMD64_
#define _WIN64
#endif
#ifndef DECLSPEC_ALIGN #ifndef DECLSPEC_ALIGN
#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(MIDL_PASS) #if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(MIDL_PASS)
#define DECLSPEC_ALIGN(x) __declspec(align(x)) #define DECLSPEC_ALIGN(x) __declspec(align(x))
@ -37,11 +41,13 @@
#endif #endif
#endif /* DECLSPEC_ALIGN */ #endif /* DECLSPEC_ALIGN */
#ifdef _AMD64_ #ifdef _WIN64
#define MEMORY_ALLOCATION_ALIGNMENT 16 #define MEMORY_ALLOCATION_ALIGNMENT 16
#else #else
#define MEMORY_ALLOCATION_ALIGNMENT 8 #define MEMORY_ALLOCATION_ALIGNMENT 8
#endif #endif
#define DUMMYSTRUCTNAME s
#endif /* WINPR_SPEC_H */ #endif /* WINPR_SPEC_H */

View File

@ -44,26 +44,106 @@
VOID InitializeSListHead(PSLIST_HEADER ListHead) VOID InitializeSListHead(PSLIST_HEADER ListHead)
{ {
#ifdef _WIN64
} ListHead->s.Alignment = 0;
ListHead->s.Region = 0;
PSLIST_ENTRY InterlockedPopEntrySList(PSLIST_HEADER ListHead) ListHead->Header8.Init = 1;
{ #else
return NULL; ListHead->Alignment = 0;
#endif
} }
PSLIST_ENTRY InterlockedPushEntrySList(PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry) PSLIST_ENTRY InterlockedPushEntrySList(PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry)
{ {
return NULL; SLIST_HEADER old;
SLIST_HEADER new;
#ifdef _WIN64
new.HeaderX64.NextEntry = (((ULONG_PTR) ListEntry) >> 4);
do
{
old = *ListHead;
ListEntry->Next = (PSLIST_ENTRY) (((ULONG_PTR) old.HeaderX64.NextEntry) << 4);
new.HeaderX64.Depth = old.HeaderX64.Depth + 1;
new.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
}
while (!InterlockedCompareExchange64((LONG64*) ListHead, new.s.Alignment, old.s.Alignment));
return (PSLIST_ENTRY) ((ULONG_PTR) old.HeaderX64.NextEntry << 4);
#else
new.s.Next.Next = entry;
do
{
old = *ListHead;
ListEntry->Next = old.s.Next.Next;
new.s.Depth = old.s.Depth + 1;
new.s.Sequence = old.s.Sequence + 1;
}
while(InterlockedCompareExchange64(&ListHead->Alignment, new.Alignment, old.Alignment) != old.Alignment);
return old.s.Next.Next;
#endif
} }
PSLIST_ENTRY InterlockedPushListSListEx(PSLIST_HEADER ListHead, PSLIST_ENTRY List, PSLIST_ENTRY ListEnd, ULONG Count) PSLIST_ENTRY InterlockedPushListSListEx(PSLIST_HEADER ListHead, PSLIST_ENTRY List, PSLIST_ENTRY ListEnd, ULONG Count)
{ {
#ifdef _WIN64
#else
#endif
return NULL; return NULL;
} }
PSLIST_ENTRY InterlockedPopEntrySList(PSLIST_HEADER ListHead)
{
SLIST_HEADER old;
SLIST_HEADER new;
PSLIST_ENTRY entry;
#ifdef _WIN64
do
{
old = *ListHead;
entry = (PSLIST_ENTRY) (((ULONG_PTR) old.HeaderX64.NextEntry) << 4);
if (!entry)
return NULL;
new.HeaderX64.NextEntry = ((ULONG_PTR) entry->Next) >> 4;
new.HeaderX64.Depth = old.HeaderX64.Depth - 1;
new.HeaderX64.Sequence = old.HeaderX64.Sequence - 1;
}
while (!InterlockedCompareExchange64((LONG64*) ListHead, new.s.Alignment, old.s.Alignment));
#else
do
{
old = *ListHead;
entry = old.s.Next.Next;
if (!entry)
return NULL;
new.s.Next.Next = entry->Next;
new.s.Depth = old.s.Depth - 1;
new.s.Sequence = old.s.Sequence + 1;
}
while(InterlockedCompareExchange64(&ListHead->Alignment, new.Alignment, old.Alignment) != old.Alignment);
#endif
return entry;
}
PSLIST_ENTRY InterlockedFlushSList(PSLIST_HEADER ListHead) PSLIST_ENTRY InterlockedFlushSList(PSLIST_HEADER ListHead)
{ {
#ifdef _WIN64
#else
#endif
return NULL; return NULL;
} }
@ -102,25 +182,25 @@ LONG InterlockedExchange(LONG volatile *Target, LONG Value)
LONG InterlockedExchangeAdd(LONG volatile *Addend, LONG Value) LONG InterlockedExchangeAdd(LONG volatile *Addend, LONG Value)
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_add_and_fetch(Addend, Value); return __sync_fetch_and_add(Addend, Value);
#else #else
return 0; return 0;
#endif #endif
} }
LONG InterlockedCompareExchange(LONG volatile *Destination, LONG ExChange, LONG Comperand) LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand)
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_val_compare_and_swap(Destination, Comperand, ExChange); return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
#else #else
return 0; return 0;
#endif #endif
} }
LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 ExChange, LONG64 Comperand) LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 Exchange, LONG64 Comperand)
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_val_compare_and_swap(Destination, Comperand, ExChange); return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
#else #else
return 0; return 0;
#endif #endif

View File

@ -5,6 +5,7 @@ set(MODULE_PREFIX "TEST_INTERLOCKED")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS set(${MODULE_PREFIX}_TESTS
TestInterlockedAccess.c
TestInterlockedSList.c) TestInterlockedSList.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS create_test_sourcelist(${MODULE_PREFIX}_SRCS

View File

@ -0,0 +1,164 @@
#include <stdio.h>
#include <malloc.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include <winpr/interlocked.h>
int TestInterlockedAccess(int argc, char* argv[])
{
int index;
LONG* Addend;
LONG* Target;
LONG oldValue;
LONG* Destination;
LONGLONG oldValue64;
LONGLONG* Destination64;
/* InterlockedIncrement */
Addend = _aligned_malloc(sizeof(LONG), sizeof(LONG));
*Addend = 0;
for (index = 0; index < 10; index ++)
InterlockedIncrement(Addend);
if (*Addend != 10)
{
printf("InterlockedIncrement failure: Actual: %d, Expected: %d\n", (int) *Addend, 10);
return -1;
}
/* InterlockedDecrement */
for (index = 0; index < 10; index ++)
InterlockedDecrement(Addend);
if (*Addend != 0)
{
printf("InterlockedDecrement failure: Actual: %d, Expected: %d\n", (int) *Addend, 0);
return -1;
}
/* InterlockedExchange */
Target = _aligned_malloc(sizeof(LONG), sizeof(LONG));
*Target = 0xAA;
oldValue = InterlockedExchange(Target, 0xFF);
if (oldValue != 0xAA)
{
printf("InterlockedExchange failure: Actual: 0x%08X, Expected: 0x%08X\n", (int) oldValue, 0xAA);
return -1;
}
if (*Target != 0xFF)
{
printf("InterlockedExchange failure: Actual: 0x%08X, Expected: 0x%08X\n", (int) *Target, 0xFF);
return -1;
}
/* InterlockedExchangeAdd */
*Addend = 25;
oldValue = InterlockedExchangeAdd(Addend, 100);
if (oldValue != 25)
{
printf("InterlockedExchangeAdd failure: Actual: %d, Expected: %d\n", (int) oldValue, 25);
return -1;
}
if (*Addend != 125)
{
printf("InterlockedExchangeAdd failure: Actual: %d, Expected: %d\n", (int) *Addend, 125);
return -1;
}
/* InterlockedCompareExchange (*Destination == Comparand) */
Destination = _aligned_malloc(sizeof(LONG), sizeof(LONG));
*Destination = 0xAABBCCDD;
oldValue = InterlockedCompareExchange(Destination, 0xCCDDEEFF, 0xAABBCCDD);
if (oldValue != 0xAABBCCDD)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08X, Expected: 0x%08X\n", (int) oldValue, 0xAABBCCDD);
return -1;
}
if (*Destination != 0xCCDDEEFF)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08X, Expected: 0x%08X\n", (int) *Destination, 0xCCDDEEFF);
return -1;
}
/* InterlockedCompareExchange (*Destination != Comparand) */
*Destination = 0xAABBCCDD;
oldValue = InterlockedCompareExchange(Destination, 0xCCDDEEFF, 0x66778899);
if (oldValue != 0xAABBCCDD)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08X, Expected: 0x%08X\n", (int) oldValue, 0xAABBCCDD);
return -1;
}
if (*Destination != 0xAABBCCDD)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08X, Expected: 0x%08X\n", (int) *Destination, 0xAABBCCDD);
return -1;
}
/* InterlockedCompareExchange64 (*Destination == Comparand) */
Destination64 = _aligned_malloc(sizeof(LONGLONG), sizeof(LONGLONG));
*Destination64 = 0x66778899AABBCCDD;
oldValue64 = InterlockedCompareExchange64(Destination64, 0x8899AABBCCDDEEFF, 0x66778899AABBCCDD);
if (oldValue64 != 0x66778899AABBCCDD)
{
printf("InterlockedCompareExchange failure: Actual: %lld, Expected: %lld\n", oldValue64, (LONGLONG) 0x66778899AABBCCDD);
return -1;
}
if (*Destination64 != 0x8899AABBCCDDEEFF)
{
printf("InterlockedCompareExchange failure: Actual: %lld, Expected: %lld\n", *Destination64, (LONGLONG) 0x8899AABBCCDDEEFF);
return -1;
}
/* InterlockedCompareExchange64 (*Destination != Comparand) */
*Destination64 = 0x66778899AABBCCDD;
oldValue64 = InterlockedCompareExchange64(Destination64, 0x8899AABBCCDDEEFF, 12345);
if (oldValue64 != 0x66778899AABBCCDD)
{
printf("InterlockedCompareExchange failure: Actual: %lld, Expected: %lld\n", oldValue64, (LONGLONG) 0x66778899AABBCCDD);
return -1;
}
if (*Destination64 != 0x66778899AABBCCDD)
{
printf("InterlockedCompareExchange failure: Actual: %lld, Expected: %lld\n", *Destination64, (LONGLONG) 0x66778899AABBCCDD);
return -1;
}
_aligned_free(Addend);
_aligned_free(Target);
_aligned_free(Destination);
_aligned_free(Destination64);
return 0;
}

View File

@ -22,11 +22,12 @@ int TestInterlockedSList(int argc, char* argv[])
/* Initialize the list header to a MEMORY_ALLOCATION_ALIGNMENT boundary. */ /* Initialize the list header to a MEMORY_ALLOCATION_ALIGNMENT boundary. */
pListHead = (PSLIST_HEADER) _aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT); pListHead = (PSLIST_HEADER) _aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);
if( NULL == pListHead ) if (!pListHead)
{ {
printf("Memory allocation failed.\n"); printf("Memory allocation failed.\n");
return -1; return -1;
} }
InitializeSListHead(pListHead); InitializeSListHead(pListHead);
/* Insert 10 items into the list. */ /* Insert 10 items into the list. */
@ -41,7 +42,7 @@ int TestInterlockedSList(int argc, char* argv[])
} }
pProgramItem->Signature = Count; pProgramItem->Signature = Count;
pFirstEntry = InterlockedPushEntrySList(pListHead, &(pProgramItem->ItemEntry)); pFirstEntry = InterlockedPushEntrySList(pListHead, &(pProgramItem->ItemEntry));
} }
/* Remove 10 items from the list and display the signature. */ /* Remove 10 items from the list and display the signature. */
@ -56,7 +57,7 @@ int TestInterlockedSList(int argc, char* argv[])
} }
pProgramItem = (PPROGRAM_ITEM) pListEntry; pProgramItem = (PPROGRAM_ITEM) pListEntry;
printf("Signature is %d\n", pProgramItem->Signature); printf("Signature is %d\n", (int) pProgramItem->Signature);
/* /*
* This example assumes that the SLIST_ENTRY structure is the * This example assumes that the SLIST_ENTRY structure is the