diff --git a/winpr/include/winpr/interlocked.h b/winpr/include/winpr/interlocked.h index a3563a75e..6055a4bd2 100644 --- a/winpr/include/winpr/interlocked.h +++ b/winpr/include/winpr/interlocked.h @@ -57,7 +57,7 @@ typedef struct LIST_ENTRY64 } LIST_ENTRY64; typedef LIST_ENTRY64 *PLIST_ENTRY64; -#ifdef _AMD64_ +#ifdef _WIN64 typedef struct _SLIST_ENTRY *PSLIST_ENTRY; typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY @@ -65,24 +65,46 @@ typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY PSLIST_ENTRY Next; } SLIST_ENTRY; -#else /* _AMD64_ */ +#else /* _WIN64 */ #define SLIST_ENTRY SINGLE_LIST_ENTRY #define _SLIST_ENTRY _SINGLE_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; - ULONGLONG Region; -} SLIST_HEADER; -typedef struct _SLIST_HEADER *PSLIST_HEADER; + struct + { + ULONGLONG Alignment; + 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 { @@ -96,13 +118,13 @@ typedef union _SLIST_HEADER } DUMMYSTRUCTNAME; } SLIST_HEADER, *PSLIST_HEADER; -#endif /* _AMD64_ */ +#endif /* _WIN64 */ 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 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 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 InterlockedExchangeAdd(LONG volatile *Addend, LONG Value); -WINPR_API LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange, LONG Comperand); -WINPR_API LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 ExChange, LONG64 Comperand); +WINPR_API LONG InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange, LONG Comperand); +WINPR_API LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 Exchange, LONG64 Comperand); #endif /* _WIN32 */ diff --git a/winpr/include/winpr/spec.h b/winpr/include/winpr/spec.h index 9a64f9c82..25355e5bc 100644 --- a/winpr/include/winpr/spec.h +++ b/winpr/include/winpr/spec.h @@ -27,6 +27,10 @@ #endif #endif /* _AMD64_ */ +#ifdef _AMD64_ +#define _WIN64 +#endif + #ifndef DECLSPEC_ALIGN #if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(MIDL_PASS) #define DECLSPEC_ALIGN(x) __declspec(align(x)) @@ -37,11 +41,13 @@ #endif #endif /* DECLSPEC_ALIGN */ -#ifdef _AMD64_ +#ifdef _WIN64 #define MEMORY_ALLOCATION_ALIGNMENT 16 #else #define MEMORY_ALLOCATION_ALIGNMENT 8 #endif +#define DUMMYSTRUCTNAME s + #endif /* WINPR_SPEC_H */ diff --git a/winpr/libwinpr/interlocked/interlocked.c b/winpr/libwinpr/interlocked/interlocked.c index fdbdea5ad..02983d4b0 100644 --- a/winpr/libwinpr/interlocked/interlocked.c +++ b/winpr/libwinpr/interlocked/interlocked.c @@ -44,26 +44,106 @@ VOID InitializeSListHead(PSLIST_HEADER ListHead) { - -} - -PSLIST_ENTRY InterlockedPopEntrySList(PSLIST_HEADER ListHead) -{ - return NULL; +#ifdef _WIN64 + ListHead->s.Alignment = 0; + ListHead->s.Region = 0; + ListHead->Header8.Init = 1; +#else + ListHead->Alignment = 0; +#endif } 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) { +#ifdef _WIN64 + +#else + +#endif 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) { +#ifdef _WIN64 + +#else + +#endif return NULL; } @@ -102,25 +182,25 @@ LONG InterlockedExchange(LONG volatile *Target, LONG Value) LONG InterlockedExchangeAdd(LONG volatile *Addend, LONG Value) { #ifdef __GNUC__ - return __sync_add_and_fetch(Addend, Value); + return __sync_fetch_and_add(Addend, Value); #else return 0; #endif } -LONG InterlockedCompareExchange(LONG volatile *Destination, LONG ExChange, LONG Comperand) +LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) { #ifdef __GNUC__ - return __sync_val_compare_and_swap(Destination, Comperand, ExChange); + return __sync_val_compare_and_swap(Destination, Comperand, Exchange); #else return 0; #endif } -LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 ExChange, LONG64 Comperand) +LONG64 InterlockedCompareExchange64(LONG64 volatile *Destination, LONG64 Exchange, LONG64 Comperand) { #ifdef __GNUC__ - return __sync_val_compare_and_swap(Destination, Comperand, ExChange); + return __sync_val_compare_and_swap(Destination, Comperand, Exchange); #else return 0; #endif diff --git a/winpr/libwinpr/interlocked/test/CMakeLists.txt b/winpr/libwinpr/interlocked/test/CMakeLists.txt index b7232f115..c04306ba1 100644 --- a/winpr/libwinpr/interlocked/test/CMakeLists.txt +++ b/winpr/libwinpr/interlocked/test/CMakeLists.txt @@ -5,6 +5,7 @@ set(MODULE_PREFIX "TEST_INTERLOCKED") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS + TestInterlockedAccess.c TestInterlockedSList.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/interlocked/test/TestInterlockedAccess.c b/winpr/libwinpr/interlocked/test/TestInterlockedAccess.c new file mode 100644 index 000000000..38c557fa0 --- /dev/null +++ b/winpr/libwinpr/interlocked/test/TestInterlockedAccess.c @@ -0,0 +1,164 @@ + +#include +#include +#include +#include +#include + +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; +} diff --git a/winpr/libwinpr/interlocked/test/TestInterlockedSList.c b/winpr/libwinpr/interlocked/test/TestInterlockedSList.c index 04a4a9c63..b3eb357ec 100644 --- a/winpr/libwinpr/interlocked/test/TestInterlockedSList.c +++ b/winpr/libwinpr/interlocked/test/TestInterlockedSList.c @@ -22,11 +22,12 @@ int TestInterlockedSList(int argc, char* argv[]) /* Initialize the list header to a MEMORY_ALLOCATION_ALIGNMENT boundary. */ pListHead = (PSLIST_HEADER) _aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT); - if( NULL == pListHead ) + if (!pListHead) { printf("Memory allocation failed.\n"); return -1; } + InitializeSListHead(pListHead); /* Insert 10 items into the list. */ @@ -41,7 +42,7 @@ int TestInterlockedSList(int argc, char* argv[]) } pProgramItem->Signature = Count; - pFirstEntry = InterlockedPushEntrySList(pListHead, &(pProgramItem->ItemEntry)); + pFirstEntry = InterlockedPushEntrySList(pListHead, &(pProgramItem->ItemEntry)); } /* Remove 10 items from the list and display the signature. */ @@ -56,7 +57,7 @@ int TestInterlockedSList(int argc, char* argv[]) } 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