Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
22
third_party/FreeRDP/winpr/libwinpr/interlocked/CMakeLists.txt
vendored
Normal file
22
third_party/FreeRDP/winpr/libwinpr/interlocked/CMakeLists.txt
vendored
Normal 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()
|
||||
9
third_party/FreeRDP/winpr/libwinpr/interlocked/ModuleOptions.cmake
vendored
Normal file
9
third_party/FreeRDP/winpr/libwinpr/interlocked/ModuleOptions.cmake
vendored
Normal 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}"
|
||||
)
|
||||
539
third_party/FreeRDP/winpr/libwinpr/interlocked/interlocked.c
vendored
Normal file
539
third_party/FreeRDP/winpr/libwinpr/interlocked/interlocked.c
vendored
Normal 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;
|
||||
}
|
||||
13
third_party/FreeRDP/winpr/libwinpr/interlocked/module_5.1.def
vendored
Normal file
13
third_party/FreeRDP/winpr/libwinpr/interlocked/module_5.1.def
vendored
Normal 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
|
||||
23
third_party/FreeRDP/winpr/libwinpr/interlocked/test/CMakeLists.txt
vendored
Normal file
23
third_party/FreeRDP/winpr/libwinpr/interlocked/test/CMakeLists.txt
vendored
Normal 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")
|
||||
200
third_party/FreeRDP/winpr/libwinpr/interlocked/test/TestInterlockedAccess.c
vendored
Normal file
200
third_party/FreeRDP/winpr/libwinpr/interlocked/test/TestInterlockedAccess.c
vendored
Normal 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;
|
||||
}
|
||||
79
third_party/FreeRDP/winpr/libwinpr/interlocked/test/TestInterlockedDList.c
vendored
Normal file
79
third_party/FreeRDP/winpr/libwinpr/interlocked/test/TestInterlockedDList.c
vendored
Normal 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;
|
||||
}
|
||||
95
third_party/FreeRDP/winpr/libwinpr/interlocked/test/TestInterlockedSList.c
vendored
Normal file
95
third_party/FreeRDP/winpr/libwinpr/interlocked/test/TestInterlockedSList.c
vendored
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user