diff --git a/winpr/include/winpr/interlocked.h b/winpr/include/winpr/interlocked.h index c12461a44..519eb6a18 100644 --- a/winpr/include/winpr/interlocked.h +++ b/winpr/include/winpr/interlocked.h @@ -26,6 +26,11 @@ #ifndef _WIN32 +#ifndef CONTAINING_RECORD +#define CONTAINING_RECORD(address, type, field) \ + ((type *)(((ULONG_PTR) address) - (ULONG_PTR)(&(((type *) 0)->field)))) +#endif + typedef struct _LIST_ENTRY LIST_ENTRY; typedef struct _LIST_ENTRY* PLIST_ENTRY; @@ -120,6 +125,8 @@ typedef union _SLIST_HEADER #endif /* _WIN64 */ +/* Singly-Linked List */ + WINPR_API VOID InitializeSListHead(PSLIST_HEADER ListHead); WINPR_API PSLIST_ENTRY InterlockedPushEntrySList(PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry); @@ -141,5 +148,27 @@ WINPR_API LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Excha WINPR_API LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination, LONGLONG Exchange, LONGLONG Comperand); +/* Doubly-Linked List */ + +#ifndef _WIN32 + +VOID InitializeListHead(PLIST_ENTRY ListHead); + +BOOL IsListEmpty(const LIST_ENTRY* ListHead); + +BOOL RemoveEntryList(PLIST_ENTRY Entry); + +VOID InsertHeadList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry); +PLIST_ENTRY RemoveHeadList(PLIST_ENTRY ListHead); + +VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry); +PLIST_ENTRY RemoveTailList(PLIST_ENTRY ListHead); +VOID AppendTailList(PLIST_ENTRY ListHead, PLIST_ENTRY ListToAppend); + +VOID PushEntryList(PSINGLE_LIST_ENTRY ListHead, PSINGLE_LIST_ENTRY Entry); +PSINGLE_LIST_ENTRY PopEntryList(PSINGLE_LIST_ENTRY ListHead); + +#endif + #endif /* WINPR_INTERLOCKED_H */ diff --git a/winpr/libwinpr/interlocked/interlocked.c b/winpr/libwinpr/interlocked/interlocked.c index 7dd333711..e1741ed45 100644 --- a/winpr/libwinpr/interlocked/interlocked.c +++ b/winpr/libwinpr/interlocked/interlocked.c @@ -26,22 +26,7 @@ #include -/** - * api-ms-win-core-interlocked-l1-2-0.dll: - * - * InitializeSListHead - * InterlockedPopEntrySList - * InterlockedPushEntrySList - * InterlockedPushListSListEx - * InterlockedFlushSList - * QueryDepthSList - * InterlockedIncrement - * InterlockedDecrement - * InterlockedExchange - * InterlockedExchangeAdd - * InterlockedCompareExchange - * InterlockedCompareExchange64 - */ +/* Singly-Linked List */ #ifndef _WIN32 @@ -299,3 +284,115 @@ LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination, LONGLONG E #endif /* (_WIN32 && (_WIN32_WINNT < 0x0502)) */ +/* Doubly-Linked List */ + +/** + * Kernel-Mode Basics: Windows Linked Lists: + * http://www.osronline.com/article.cfm?article=499 + * + * Singly and Doubly Linked Lists: + * http://msdn.microsoft.com/en-us/library/windows/hardware/ff563802/ + */ + +#ifndef _WIN32 + +VOID InitializeListHead(PLIST_ENTRY ListHead) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +BOOL IsListEmpty(const LIST_ENTRY* ListHead) +{ + return (BOOL) (ListHead->Flink == ListHead); +} + +BOOL RemoveEntryList(PLIST_ENTRY Entry) +{ + PLIST_ENTRY OldFlink; + PLIST_ENTRY OldBlink; + + OldFlink = Entry->Flink; + OldBlink = Entry->Blink; + OldFlink->Blink = OldBlink; + OldBlink->Flink = OldFlink; + + return (BOOL) (OldFlink == OldBlink); +} + +VOID InsertHeadList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry) +{ + PLIST_ENTRY OldFlink; + + OldFlink = ListHead->Flink; + Entry->Flink = OldFlink; + Entry->Blink = ListHead; + OldFlink->Blink = Entry; + ListHead->Flink = Entry; +} + +PLIST_ENTRY RemoveHeadList(PLIST_ENTRY ListHead) +{ + PLIST_ENTRY Flink; + PLIST_ENTRY Entry; + + Entry = ListHead->Flink; + Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + + return Entry; +} + +VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry) +{ + PLIST_ENTRY OldBlink; + + OldBlink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = OldBlink; + OldBlink->Flink = Entry; + ListHead->Blink = Entry; +} + +PLIST_ENTRY RemoveTailList(PLIST_ENTRY ListHead) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Entry; + + Entry = ListHead->Blink; + Blink = Entry->Blink; + ListHead->Blink = Blink; + Blink->Flink = ListHead; + + return Entry; +} + +VOID AppendTailList(PLIST_ENTRY ListHead, PLIST_ENTRY ListToAppend) +{ + PLIST_ENTRY ListEnd = ListHead->Blink; + + ListHead->Blink->Flink = ListToAppend; + ListHead->Blink = ListToAppend->Blink; + ListToAppend->Blink->Flink = ListHead; + ListToAppend->Blink = ListEnd; +} + +VOID PushEntryList(PSINGLE_LIST_ENTRY ListHead, PSINGLE_LIST_ENTRY Entry) +{ + Entry->Next = ListHead->Next; + ListHead->Next = Entry; +} + +PSINGLE_LIST_ENTRY PopEntryList(PSINGLE_LIST_ENTRY ListHead) +{ + PSINGLE_LIST_ENTRY FirstEntry; + + FirstEntry = ListHead->Next; + + if (FirstEntry != NULL) + ListHead->Next = FirstEntry->Next; + + return FirstEntry; +} + +#endif diff --git a/winpr/libwinpr/interlocked/test/CMakeLists.txt b/winpr/libwinpr/interlocked/test/CMakeLists.txt index 072aa9e93..c55804f94 100644 --- a/winpr/libwinpr/interlocked/test/CMakeLists.txt +++ b/winpr/libwinpr/interlocked/test/CMakeLists.txt @@ -6,7 +6,8 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestInterlockedAccess.c - TestInterlockedSList.c) + TestInterlockedSList.c + TestInterlockedDList.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} @@ -22,3 +23,4 @@ foreach(test ${${MODULE_PREFIX}_TESTS}) endforeach() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") + diff --git a/winpr/libwinpr/interlocked/test/TestInterlockedDList.c b/winpr/libwinpr/interlocked/test/TestInterlockedDList.c new file mode 100644 index 000000000..fa3a61fe6 --- /dev/null +++ b/winpr/libwinpr/interlocked/test/TestInterlockedDList.c @@ -0,0 +1,77 @@ + +#include +#include +#include +#include +#include + +typedef struct _LIST_ITEM +{ + LIST_ENTRY ItemEntry; + ULONG Signature; +} LIST_ITEM, *PLIST_ITEM; + +int TestInterlockedDList(int argc, char* argv[]) +{ + ULONG Count; + PLIST_ITEM pListItem; + PLIST_ENTRY pListHead; + PLIST_ENTRY pListEntry; + + pListHead = (PLIST_ENTRY) _aligned_malloc(sizeof(LIST_ENTRY), MEMORY_ALLOCATION_ALIGNMENT); + + if (!pListHead) + { + printf("Memory allocation failed.\n"); + return -1; + } + + InitializeListHead(pListHead); + + if (!IsListEmpty(pListHead)) + { + printf("Expected empty list\n"); + return -1; + } + + /* InsertHeadList / RemoveHeadList */ + + printf("InsertHeadList / RemoveHeadList\n"); + + for (Count = 1; Count <= 10; Count += 1) + { + pListItem = (PLIST_ITEM) _aligned_malloc(sizeof(LIST_ITEM), MEMORY_ALLOCATION_ALIGNMENT); + pListItem->Signature = Count; + InsertHeadList(pListHead, &(pListItem->ItemEntry)); + } + + for (Count = 10; Count >= 1; Count -= 1) + { + pListEntry = RemoveHeadList(pListHead); + pListItem = (PLIST_ITEM) pListEntry; + _aligned_free(pListEntry); + } + + /* InsertTailList / RemoveTailList */ + + printf("InsertTailList / RemoveTailList\n"); + + for (Count = 1; Count <= 10; Count += 1) + { + pListItem = (PLIST_ITEM) _aligned_malloc(sizeof(LIST_ITEM), MEMORY_ALLOCATION_ALIGNMENT); + pListItem->Signature = Count; + InsertTailList(pListHead, &(pListItem->ItemEntry)); + } + + for (Count = 10; Count >= 1; Count -= 1) + { + pListEntry = RemoveTailList(pListHead); + pListItem = (PLIST_ITEM) pListEntry; + _aligned_free(pListEntry); + } + + _aligned_free(pListHead); + + return 0; +} +