Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,22 @@
# WinPR: Windows Portable Runtime
# libwinpr-interlocked cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
winpr_module_add(interlocked.c)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "2")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "interlocked")
set(MINWIN_LONG_NAME "Interlocked Functions")
set(MODULE_LIBRARY_NAME
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
)

View File

@@ -0,0 +1,539 @@
/**
* WinPR: Windows Portable Runtime
* Interlocked Singly-Linked Lists
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <winpr/wlog.h>
#include <winpr/platform.h>
#include <winpr/synch.h>
#include <winpr/handle.h>
#include <winpr/interlocked.h>
/* Singly-Linked List */
#ifndef _WIN32
#include <stdio.h>
#include <stdlib.h>
VOID InitializeSListHead(WINPR_PSLIST_HEADER ListHead)
{
WINPR_ASSERT(ListHead);
#ifdef _WIN64
ListHead->s.Alignment = 0;
ListHead->s.Region = 0;
ListHead->Header8.Init = 1;
#else
ListHead->Alignment = 0;
#endif
}
WINPR_PSLIST_ENTRY InterlockedPushEntrySList(WINPR_PSLIST_HEADER ListHead,
WINPR_PSLIST_ENTRY ListEntry)
{
WINPR_SLIST_HEADER old = WINPR_C_ARRAY_INIT;
WINPR_SLIST_HEADER newHeader = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(ListHead);
WINPR_ASSERT(ListEntry);
#ifdef _WIN64
newHeader.HeaderX64.NextEntry = (((ULONG_PTR)ListEntry) >> 4);
while (1)
{
old = *ListHead;
ListEntry->Next = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
newHeader.HeaderX64.Depth = old.HeaderX64.Depth + 1;
newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
{
InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
old).Region);
break;
}
}
return (PSLIST_ENTRY)((ULONG_PTR)old.HeaderX64.NextEntry << 4);
#else
newHeader.s.Next.Next = ListEntry;
do
{
old = *ListHead;
ListEntry->Next = old.s.Next.Next;
newHeader.s.Depth = old.s.Depth + 1;
newHeader.s.Sequence = old.s.Sequence + 1;
if (old.Alignment > INT64_MAX)
return nullptr;
if (newHeader.Alignment > INT64_MAX)
return nullptr;
if (ListHead->Alignment > INT64_MAX)
return nullptr;
} while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
(LONGLONG)newHeader.Alignment,
(LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
return old.s.Next.Next;
#endif
}
WINPR_PSLIST_ENTRY InterlockedPushListSListEx(WINPR_ATTR_UNUSED WINPR_PSLIST_HEADER ListHead,
WINPR_ATTR_UNUSED WINPR_PSLIST_ENTRY List,
WINPR_ATTR_UNUSED WINPR_PSLIST_ENTRY ListEnd,
WINPR_ATTR_UNUSED ULONG Count)
{
WINPR_ASSERT(ListHead);
WINPR_ASSERT(List);
WINPR_ASSERT(ListEnd);
WLog_ERR("TODO", "TODO: implement");
#ifdef _WIN64
#else
#endif
return nullptr;
}
WINPR_PSLIST_ENTRY InterlockedPopEntrySList(WINPR_PSLIST_HEADER ListHead)
{
WINPR_SLIST_HEADER old = WINPR_C_ARRAY_INIT;
WINPR_SLIST_HEADER newHeader = WINPR_C_ARRAY_INIT;
WINPR_PSLIST_ENTRY entry = nullptr;
WINPR_ASSERT(ListHead);
#ifdef _WIN64
while (1)
{
old = *ListHead;
entry = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
if (!entry)
return nullptr;
newHeader.HeaderX64.NextEntry = ((ULONG_PTR)entry->Next) >> 4;
newHeader.HeaderX64.Depth = old.HeaderX64.Depth - 1;
newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence - 1;
if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
{
InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
old).Region);
break;
}
}
#else
do
{
old = *ListHead;
entry = old.s.Next.Next;
if (!entry)
return nullptr;
newHeader.s.Next.Next = entry->Next;
newHeader.s.Depth = old.s.Depth - 1;
newHeader.s.Sequence = old.s.Sequence + 1;
if (old.Alignment > INT64_MAX)
return nullptr;
if (newHeader.Alignment > INT64_MAX)
return nullptr;
if (ListHead->Alignment > INT64_MAX)
return nullptr;
} while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
(LONGLONG)newHeader.Alignment,
(LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
#endif
return entry;
}
WINPR_PSLIST_ENTRY InterlockedFlushSList(WINPR_PSLIST_HEADER ListHead)
{
WINPR_SLIST_HEADER old = WINPR_C_ARRAY_INIT;
WINPR_SLIST_HEADER newHeader = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(ListHead);
if (!QueryDepthSList(ListHead))
return nullptr;
#ifdef _WIN64
newHeader).Alignment = 0;
newHeader).Region = 0;
newHeader.HeaderX64.HeaderType = 1;
while (1)
{
old = *ListHead;
newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
{
InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
old).Region);
break;
}
}
return (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
#else
newHeader.Alignment = 0;
do
{
old = *ListHead;
newHeader.s.Sequence = old.s.Sequence + 1;
if (old.Alignment > INT64_MAX)
return nullptr;
if (newHeader.Alignment > INT64_MAX)
return nullptr;
if (ListHead->Alignment > INT64_MAX)
return nullptr;
} while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
(LONGLONG)newHeader.Alignment,
(LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
return old.s.Next.Next;
#endif
}
USHORT QueryDepthSList(WINPR_PSLIST_HEADER ListHead)
{
WINPR_ASSERT(ListHead);
#ifdef _WIN64
return ListHead->HeaderX64.Depth;
#else
return ListHead->s.Depth;
#endif
}
LONG InterlockedIncrement(LONG volatile* Addend)
{
WINPR_ASSERT(Addend);
#if defined(__GNUC__) || defined(__clang__)
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
return __sync_add_and_fetch(Addend, 1);
WINPR_PRAGMA_DIAG_POP
#else
return 0;
#endif
}
LONG InterlockedDecrement(LONG volatile* Addend)
{
WINPR_ASSERT(Addend);
#if defined(__GNUC__) || defined(__clang__)
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
return __sync_sub_and_fetch(Addend, 1);
WINPR_PRAGMA_DIAG_POP
#else
return 0;
#endif
}
LONG InterlockedExchange(LONG volatile* Target, LONG Value)
{
WINPR_ASSERT(Target);
#if defined(__GNUC__) || defined(__clang__)
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
return __sync_val_compare_and_swap(Target, *Target, Value);
WINPR_PRAGMA_DIAG_POP
#else
return 0;
#endif
}
LONG InterlockedExchangeAdd(LONG volatile* Addend, LONG Value)
{
WINPR_ASSERT(Addend);
#if defined(__GNUC__) || defined(__clang__)
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
return __sync_fetch_and_add(Addend, Value);
WINPR_PRAGMA_DIAG_POP
#else
return 0;
#endif
}
LONG InterlockedCompareExchange(LONG volatile* Destination, LONG Exchange, LONG Comperand)
{
WINPR_ASSERT(Destination);
#if defined(__GNUC__) || defined(__clang__)
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
WINPR_PRAGMA_DIAG_POP
#else
return 0;
#endif
}
PVOID InterlockedCompareExchangePointer(PVOID volatile* Destination, PVOID Exchange,
PVOID Comperand)
{
WINPR_ASSERT(Destination);
#if defined(__GNUC__) || defined(__clang__)
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
WINPR_PRAGMA_DIAG_POP
#else
return 0;
#endif
}
#endif /* _WIN32 */
#if defined(_WIN32) && !defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
/* InterlockedCompareExchange64 already defined */
#elif defined(_WIN32) && defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
static volatile HANDLE mutex = nullptr;
BOOL static_mutex_lock(volatile HANDLE* static_mutex)
{
if (*static_mutex == nullptr)
{
HANDLE handle;
if (!(handle = CreateMutex(nullptr, FALSE, nullptr)))
return FALSE;
if (InterlockedCompareExchangePointer((PVOID*)static_mutex, (PVOID)handle, nullptr) !=
nullptr)
(void)CloseHandle(handle);
}
return (WaitForSingleObject(*static_mutex, INFINITE) == WAIT_OBJECT_0);
}
LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
LONGLONG Comperand)
{
LONGLONG previousValue = 0;
BOOL locked = static_mutex_lock(&mutex);
previousValue = *Destination;
if (*Destination == Comperand)
*Destination = Exchange;
if (locked)
(void)ReleaseMutex(mutex);
else
(void)fprintf(stderr,
"WARNING: InterlockedCompareExchange64 operation might have failed\n");
return previousValue;
}
#elif (defined(ANDROID) && ANDROID) || \
(defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8))
#include <pthread.h>
static pthread_mutex_t mutex;
LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
LONGLONG Comperand)
{
LONGLONG previousValue = 0;
pthread_mutex_lock(&mutex);
previousValue = *Destination;
if (*Destination == Comperand)
*Destination = Exchange;
pthread_mutex_unlock(&mutex);
return previousValue;
}
#else
LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
LONGLONG Comperand)
{
WINPR_ASSERT(Destination);
#if defined(__GNUC__) || defined(__clang__)
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
WINPR_PRAGMA_DIAG_POP
#else
return 0;
#endif
}
#endif
/* 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/
*/
VOID InitializeListHead(WINPR_PLIST_ENTRY ListHead)
{
WINPR_ASSERT(ListHead);
ListHead->Flink = ListHead->Blink = ListHead;
}
BOOL IsListEmpty(const WINPR_LIST_ENTRY* ListHead)
{
WINPR_ASSERT(ListHead);
return (BOOL)(ListHead->Flink == ListHead);
}
BOOL RemoveEntryList(WINPR_PLIST_ENTRY Entry)
{
WINPR_ASSERT(Entry);
WINPR_PLIST_ENTRY OldFlink = Entry->Flink;
WINPR_ASSERT(OldFlink);
WINPR_PLIST_ENTRY OldBlink = Entry->Blink;
WINPR_ASSERT(OldBlink);
OldFlink->Blink = OldBlink;
OldBlink->Flink = OldFlink;
return (BOOL)(OldFlink == OldBlink);
}
VOID InsertHeadList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
{
WINPR_ASSERT(ListHead);
WINPR_ASSERT(Entry);
WINPR_PLIST_ENTRY OldFlink = ListHead->Flink;
WINPR_ASSERT(OldFlink);
Entry->Flink = OldFlink;
Entry->Blink = ListHead;
OldFlink->Blink = Entry;
ListHead->Flink = Entry;
}
WINPR_PLIST_ENTRY RemoveHeadList(WINPR_PLIST_ENTRY ListHead)
{
WINPR_ASSERT(ListHead);
WINPR_PLIST_ENTRY Entry = ListHead->Flink;
WINPR_ASSERT(Entry);
WINPR_PLIST_ENTRY Flink = Entry->Flink;
WINPR_ASSERT(Flink);
ListHead->Flink = Flink;
Flink->Blink = ListHead;
return Entry;
}
VOID InsertTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
{
WINPR_ASSERT(ListHead);
WINPR_ASSERT(Entry);
WINPR_PLIST_ENTRY OldBlink = ListHead->Blink;
WINPR_ASSERT(OldBlink);
Entry->Flink = ListHead;
Entry->Blink = OldBlink;
OldBlink->Flink = Entry;
ListHead->Blink = Entry;
}
WINPR_PLIST_ENTRY RemoveTailList(WINPR_PLIST_ENTRY ListHead)
{
WINPR_ASSERT(ListHead);
WINPR_PLIST_ENTRY Entry = ListHead->Blink;
WINPR_ASSERT(Entry);
WINPR_PLIST_ENTRY Blink = Entry->Blink;
WINPR_ASSERT(Blink);
ListHead->Blink = Blink;
Blink->Flink = ListHead;
return Entry;
}
VOID AppendTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY ListToAppend)
{
WINPR_ASSERT(ListHead);
WINPR_ASSERT(ListToAppend);
WINPR_PLIST_ENTRY ListEnd = ListHead->Blink;
ListHead->Blink->Flink = ListToAppend;
ListHead->Blink = ListToAppend->Blink;
ListToAppend->Blink->Flink = ListHead;
ListToAppend->Blink = ListEnd;
}
VOID PushEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead, WINPR_PSINGLE_LIST_ENTRY Entry)
{
WINPR_ASSERT(ListHead);
WINPR_ASSERT(Entry);
Entry->Next = ListHead->Next;
ListHead->Next = Entry;
}
WINPR_PSINGLE_LIST_ENTRY PopEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead)
{
WINPR_ASSERT(ListHead);
WINPR_PSINGLE_LIST_ENTRY FirstEntry = ListHead->Next;
if (FirstEntry != nullptr)
ListHead->Next = FirstEntry->Next;
return FirstEntry;
}

View File

@@ -0,0 +1,13 @@
LIBRARY "libwinpr-interlocked"
EXPORTS
InterlockedCompareExchange64 @1
InitializeListHead @2
IsListEmpty @3
RemoveEntryList @4
InsertHeadList @5
RemoveHeadList @6
InsertTailList @7
RemoveTailList @8
AppendTailList @9
PushEntryList @10
PopEntryList @11

View File

@@ -0,0 +1,23 @@
set(MODULE_NAME "TestInterlocked")
set(MODULE_PREFIX "TEST_INTERLOCKED")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestInterlockedAccess.c TestInterlockedSList.c TestInterlockedDList.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,200 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include <winpr/interlocked.h>
int TestInterlockedAccess(int argc, char* argv[])
{
LONG* Addend = nullptr;
LONG* Target = nullptr;
LONG oldValue = 0;
LONG* Destination = nullptr;
LONGLONG oldValue64 = 0;
LONGLONG* Destination64 = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* InterlockedIncrement */
Addend = winpr_aligned_malloc(sizeof(LONG), sizeof(LONG));
if (!Addend)
{
printf("Failed to allocate memory\n");
return -1;
}
*Addend = 0;
for (int index = 0; index < 10; index++)
InterlockedIncrement(Addend);
if (*Addend != 10)
{
printf("InterlockedIncrement failure: Actual: %" PRId32 ", Expected: 10\n", *Addend);
return -1;
}
/* InterlockedDecrement */
for (int index = 0; index < 10; index++)
(void)InterlockedDecrement(Addend);
if (*Addend != 0)
{
printf("InterlockedDecrement failure: Actual: %" PRId32 ", Expected: 0\n", *Addend);
return -1;
}
/* InterlockedExchange */
Target = winpr_aligned_malloc(sizeof(LONG), sizeof(LONG));
if (!Target)
{
printf("Failed to allocate memory\n");
return -1;
}
*Target = 0xAA;
oldValue = InterlockedExchange(Target, 0xFF);
if (oldValue != 0xAA)
{
printf("InterlockedExchange failure: Actual: 0x%08" PRIX32 ", Expected: 0xAA\n", oldValue);
return -1;
}
if (*Target != 0xFF)
{
printf("InterlockedExchange failure: Actual: 0x%08" PRIX32 ", Expected: 0xFF\n", *Target);
return -1;
}
/* InterlockedExchangeAdd */
*Addend = 25;
oldValue = InterlockedExchangeAdd(Addend, 100);
if (oldValue != 25)
{
printf("InterlockedExchangeAdd failure: Actual: %" PRId32 ", Expected: 25\n", oldValue);
return -1;
}
if (*Addend != 125)
{
printf("InterlockedExchangeAdd failure: Actual: %" PRId32 ", Expected: 125\n", *Addend);
return -1;
}
/* InterlockedCompareExchange (*Destination == Comparand) */
Destination = winpr_aligned_malloc(sizeof(LONG), sizeof(LONG));
if (!Destination)
{
printf("Failed to allocate memory\n");
return -1;
}
*Destination = (LONG)0xAABBCCDDL;
oldValue = InterlockedCompareExchange(Destination, (LONG)0xCCDDEEFFL, (LONG)0xAABBCCDDL);
if (oldValue != (LONG)0xAABBCCDDL)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08" PRIX32
", Expected: 0xAABBCCDD\n",
oldValue);
return -1;
}
if ((*Destination) != (LONG)0xCCDDEEFFL)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08" PRIX32
", Expected: 0xCCDDEEFF\n",
*Destination);
return -1;
}
/* InterlockedCompareExchange (*Destination != Comparand) */
*Destination = (LONG)0xAABBCCDDL;
oldValue = InterlockedCompareExchange(Destination, -857870593L, 0x66778899L);
if (oldValue != (LONG)0xAABBCCDDL)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08" PRIX32
", Expected: 0xAABBCCDD\n",
oldValue);
return -1;
}
if ((*Destination) != (LONG)0xAABBCCDDL)
{
printf("InterlockedCompareExchange failure: Actual: 0x%08" PRIX32
", Expected: 0xAABBCCDD\n",
*Destination);
return -1;
}
/* InterlockedCompareExchange64 (*Destination == Comparand) */
Destination64 = winpr_aligned_malloc(sizeof(LONGLONG), sizeof(LONGLONG));
if (!Destination64)
{
printf("Failed to allocate memory\n");
return -1;
}
*Destination64 = 0x66778899AABBCCDD;
oldValue64 =
InterlockedCompareExchange64(Destination64, 0x0899AABBCCDDEEFFLL, 0x66778899AABBCCDD);
if (oldValue64 != 0x66778899AABBCCDD)
{
printf("InterlockedCompareExchange failure: Actual: 0x%016" PRIX64
", Expected: 0x66778899AABBCCDD\n",
oldValue64);
return -1;
}
if ((*Destination64) != 0x0899AABBCCDDEEFFLL)
{
printf("InterlockedCompareExchange failure: Actual: 0x%016" PRIX64
", Expected: 0x0899AABBCCDDEEFFLL\n",
*Destination64);
return -1;
}
/* InterlockedCompareExchange64 (*Destination != Comparand) */
*Destination64 = 0x66778899AABBCCDDLL;
oldValue64 = InterlockedCompareExchange64(Destination64, 0x0899AABBCCDDEEFFLL, 12345);
if (oldValue64 != 0x66778899AABBCCDDLL)
{
printf("InterlockedCompareExchange failure: Actual: 0x%016" PRIX64
", Expected: 0x66778899AABBCCDD\n",
oldValue64);
return -1;
}
if (*Destination64 != 0x66778899AABBCCDDLL)
{
printf("InterlockedCompareExchange failure: Actual: 0x%016" PRIX64
", Expected: 0x66778899AABBCCDD\n",
*Destination64);
return -1;
}
winpr_aligned_free(Addend);
winpr_aligned_free(Target);
winpr_aligned_free(Destination);
winpr_aligned_free(Destination64);
return 0;
}

View File

@@ -0,0 +1,79 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include <winpr/interlocked.h>
typedef struct
{
WINPR_LIST_ENTRY ItemEntry;
ULONG Signature;
} LIST_ITEM, *PLIST_ITEM;
int TestInterlockedDList(int argc, char* argv[])
{
ULONG Count = 0;
PLIST_ITEM pListItem = nullptr;
WINPR_PLIST_ENTRY pListHead = nullptr;
WINPR_PLIST_ENTRY pListEntry = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
pListHead = (WINPR_PLIST_ENTRY)winpr_aligned_malloc(sizeof(WINPR_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)winpr_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;
winpr_aligned_free(pListItem);
}
/* InsertTailList / RemoveTailList */
printf("InsertTailList / RemoveTailList\n");
for (Count = 1; Count <= 10; Count += 1)
{
pListItem =
(PLIST_ITEM)winpr_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;
winpr_aligned_free(pListItem);
}
winpr_aligned_free(pListHead);
return 0;
}

View File

@@ -0,0 +1,95 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include <winpr/interlocked.h>
#define ITEM_COUNT 23
typedef struct
{
WINPR_SLIST_ENTRY ItemEntry;
ULONG Signature;
} PROGRAM_ITEM, *PPROGRAM_ITEM;
int TestInterlockedSList(int argc, char* argv[])
{
int rc = -1;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Initialize the list header to a MEMORY_ALLOCATION_ALIGNMENT boundary. */
WINPR_PSLIST_HEADER pListHead = (WINPR_PSLIST_HEADER)winpr_aligned_malloc(
sizeof(WINPR_SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);
if (!pListHead)
{
printf("Memory allocation failed.\n");
return -1;
}
InitializeSListHead(pListHead);
/* Insert 10 items into the list. */
for (ULONG Count = 0; Count < ITEM_COUNT; Count++)
{
PPROGRAM_ITEM pProgramItem =
(PPROGRAM_ITEM)winpr_aligned_malloc(sizeof(PROGRAM_ITEM), MEMORY_ALLOCATION_ALIGNMENT);
if (!pProgramItem)
{
printf("Memory allocation failed.\n");
goto fail;
}
pProgramItem->Signature = Count + 1UL;
WINPR_PSLIST_ENTRY pFirstEntry =
InterlockedPushEntrySList(pListHead, &(pProgramItem->ItemEntry));
if (((Count == 0) && pFirstEntry) || ((Count != 0) && !pFirstEntry))
{
printf("Error: List is empty.\n");
winpr_aligned_free(pProgramItem);
goto fail;
}
}
/* Remove 10 items from the list and display the signature. */
for (ULONG Count = 0; Count < ITEM_COUNT; Count++)
{
WINPR_PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(pListHead);
if (!pListEntry)
{
printf("List is empty.\n");
goto fail;
}
PPROGRAM_ITEM pProgramItem = (PPROGRAM_ITEM)pListEntry;
printf("Signature is %" PRIu32 "\n", pProgramItem->Signature);
/*
* This example assumes that the SLIST_ENTRY structure is the
* first member of the structure. If your structure does not
* follow this convention, you must compute the starting address
* of the structure before calling the free function.
*/
winpr_aligned_free(pListEntry);
}
/* Flush the list and verify that the items are gone. */
WINPR_PSLIST_ENTRY pFirstEntry = InterlockedPopEntrySList(pListHead);
if (pFirstEntry)
{
printf("Error: List is not empty.\n");
goto fail;
}
rc = 0;
fail:
winpr_aligned_free(pListHead);
return rc;
}