Blame winpr/libwinpr/interlocked/interlocked.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Interlocked Singly-Linked Lists
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/handle.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/interlocked.h>
Packit 1fb8d4
Packit 1fb8d4
/* Singly-Linked List */
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
Packit 1fb8d4
VOID InitializeSListHead(WINPR_PSLIST_HEADER ListHead)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef _WIN64
Packit 1fb8d4
	ListHead->s.Alignment = 0;
Packit 1fb8d4
	ListHead->s.Region = 0;
Packit 1fb8d4
	ListHead->Header8.Init = 1;
Packit 1fb8d4
#else
Packit 1fb8d4
	ListHead->Alignment = 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
WINPR_PSLIST_ENTRY InterlockedPushEntrySList(WINPR_PSLIST_HEADER ListHead,
Packit Service 5a9772
                                             WINPR_PSLIST_ENTRY ListEntry)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_SLIST_HEADER old;
Packit Service 5a9772
	WINPR_SLIST_HEADER newHeader;
Packit 1fb8d4
Packit 1fb8d4
#ifdef _WIN64
Packit Service 5a9772
	newHeader.HeaderX64.NextEntry = (((ULONG_PTR)ListEntry) >> 4);
Packit 1fb8d4
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		old = *ListHead;
Packit 1fb8d4
Packit Service 5a9772
		ListEntry->Next = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
Packit 1fb8d4
Packit 1fb8d4
		newHeader.HeaderX64.Depth = old.HeaderX64.Depth + 1;
Packit 1fb8d4
		newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
Packit 1fb8d4
Packit Service 5a9772
		if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader.s.Alignment,
Packit Service 5a9772
		                                 old.s.Alignment))
Packit 1fb8d4
		{
Packit Service 5a9772
			InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader.s.Region,
Packit Service 5a9772
			                             old.s.Region);
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	return (PSLIST_ENTRY)((ULONG_PTR)old.HeaderX64.NextEntry << 4);
Packit 1fb8d4
#else
Packit 1fb8d4
	newHeader.s.Next.Next = ListEntry;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		old = *ListHead;
Packit 1fb8d4
		ListEntry->Next = old.s.Next.Next;
Packit 1fb8d4
		newHeader.s.Depth = old.s.Depth + 1;
Packit 1fb8d4
		newHeader.s.Sequence = old.s.Sequence + 1;
Packit Service 5a9772
		if (old.Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
		if (newHeader.Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
		if (ListHead->Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
	} while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
Packit Service 5a9772
	                                      (LONGLONG)newHeader.Alignment,
Packit Service 5a9772
	                                      (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
Packit 1fb8d4
Packit 1fb8d4
	return old.s.Next.Next;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
WINPR_PSLIST_ENTRY InterlockedPushListSListEx(WINPR_PSLIST_HEADER ListHead, WINPR_PSLIST_ENTRY List,
Packit Service 5a9772
                                              WINPR_PSLIST_ENTRY ListEnd, ULONG Count)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef _WIN64
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
WINPR_PSLIST_ENTRY InterlockedPopEntrySList(WINPR_PSLIST_HEADER ListHead)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_SLIST_HEADER old;
Packit Service 5a9772
	WINPR_SLIST_HEADER newHeader;
Packit Service 5a9772
	WINPR_PSLIST_ENTRY entry;
Packit 1fb8d4
Packit 1fb8d4
#ifdef _WIN64
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		old = *ListHead;
Packit 1fb8d4
Packit Service 5a9772
		entry = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
Packit 1fb8d4
Packit 1fb8d4
		if (!entry)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit Service 5a9772
		newHeader.HeaderX64.NextEntry = ((ULONG_PTR)entry->Next) >> 4;
Packit 1fb8d4
		newHeader.HeaderX64.Depth = old.HeaderX64.Depth - 1;
Packit 1fb8d4
		newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence - 1;
Packit 1fb8d4
Packit Service 5a9772
		if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader.s.Alignment,
Packit Service 5a9772
		                                 old.s.Alignment))
Packit 1fb8d4
		{
Packit Service 5a9772
			InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader.s.Region,
Packit Service 5a9772
			                             old.s.Region);
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
#else
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		old = *ListHead;
Packit 1fb8d4
Packit 1fb8d4
		entry = old.s.Next.Next;
Packit 1fb8d4
Packit 1fb8d4
		if (!entry)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		newHeader.s.Next.Next = entry->Next;
Packit 1fb8d4
		newHeader.s.Depth = old.s.Depth - 1;
Packit 1fb8d4
		newHeader.s.Sequence = old.s.Sequence + 1;
Packit Service 5a9772
Packit Service 5a9772
		if (old.Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
		if (newHeader.Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
		if (ListHead->Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
	} while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
Packit Service 5a9772
	                                      (LONGLONG)newHeader.Alignment,
Packit Service 5a9772
	                                      (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
WINPR_PSLIST_ENTRY InterlockedFlushSList(WINPR_PSLIST_HEADER ListHead)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_SLIST_HEADER old;
Packit Service 5a9772
	WINPR_SLIST_HEADER newHeader;
Packit 1fb8d4
Packit 1fb8d4
	if (!QueryDepthSList(ListHead))
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
#ifdef _WIN64
Packit 1fb8d4
	newHeader.s.Alignment = 0;
Packit 1fb8d4
	newHeader.s.Region = 0;
Packit 1fb8d4
	newHeader.HeaderX64.HeaderType = 1;
Packit 1fb8d4
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		old = *ListHead;
Packit 1fb8d4
		newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
Packit 1fb8d4
Packit Service 5a9772
		if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader.s.Alignment,
Packit Service 5a9772
		                                 old.s.Alignment))
Packit 1fb8d4
		{
Packit Service 5a9772
			InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader.s.Region,
Packit Service 5a9772
			                             old.s.Region);
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	return (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
Packit 1fb8d4
#else
Packit 1fb8d4
	newHeader.Alignment = 0;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		old = *ListHead;
Packit 1fb8d4
		newHeader.s.Sequence = old.s.Sequence + 1;
Packit Service 5a9772
Packit Service 5a9772
		if (old.Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
		if (newHeader.Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
		if (ListHead->Alignment > INT64_MAX)
Packit Service 5a9772
			return NULL;
Packit Service 5a9772
	} while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
Packit Service 5a9772
	                                      (LONGLONG)newHeader.Alignment,
Packit Service 5a9772
	                                      (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
Packit 1fb8d4
Packit 1fb8d4
	return old.s.Next.Next;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
USHORT QueryDepthSList(WINPR_PSLIST_HEADER ListHead)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef _WIN64
Packit 1fb8d4
	return ListHead->HeaderX64.Depth;
Packit 1fb8d4
#else
Packit 1fb8d4
	return ListHead->s.Depth;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
LONG InterlockedIncrement(LONG volatile* Addend)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef __GNUC__
Packit 1fb8d4
	return __sync_add_and_fetch(Addend, 1);
Packit 1fb8d4
#else
Packit 1fb8d4
	return 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
LONG InterlockedDecrement(LONG volatile* Addend)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef __GNUC__
Packit 1fb8d4
	return __sync_sub_and_fetch(Addend, 1);
Packit 1fb8d4
#else
Packit 1fb8d4
	return 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
LONG InterlockedExchange(LONG volatile* Target, LONG Value)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef __GNUC__
Packit 1fb8d4
	return __sync_val_compare_and_swap(Target, *Target, Value);
Packit 1fb8d4
#else
Packit 1fb8d4
	return 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
LONG InterlockedExchangeAdd(LONG volatile* Addend, LONG Value)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef __GNUC__
Packit 1fb8d4
	return __sync_fetch_and_add(Addend, Value);
Packit 1fb8d4
#else
Packit 1fb8d4
	return 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
LONG InterlockedCompareExchange(LONG volatile* Destination, LONG Exchange, LONG Comperand)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef __GNUC__
Packit 1fb8d4
	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
Packit 1fb8d4
#else
Packit 1fb8d4
	return 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
PVOID InterlockedCompareExchangePointer(PVOID volatile* Destination, PVOID Exchange,
Packit Service 5a9772
                                        PVOID Comperand)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef __GNUC__
Packit 1fb8d4
	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
Packit 1fb8d4
#else
Packit 1fb8d4
	return 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#endif /* _WIN32 */
Packit 1fb8d4
Packit 1fb8d4
#if defined(_WIN32) && !defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
Packit 1fb8d4
Packit 1fb8d4
/* InterlockedCompareExchange64 already defined */
Packit 1fb8d4
Packit 1fb8d4
#elif defined(_WIN32) && defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
Packit 1fb8d4
Packit 1fb8d4
static volatile HANDLE mutex = NULL;
Packit 1fb8d4
Packit 1fb8d4
BOOL static_mutex_lock(volatile HANDLE* static_mutex)
Packit 1fb8d4
{
Packit 1fb8d4
	if (*static_mutex == NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		HANDLE handle;
Packit 1fb8d4
Packit 1fb8d4
		if (!(handle = CreateMutex(NULL, FALSE, NULL)))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit Service 5a9772
		if (InterlockedCompareExchangePointer((PVOID*)static_mutex, (PVOID)handle, NULL) != NULL)
Packit 1fb8d4
			CloseHandle(handle);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (WaitForSingleObject(*static_mutex, INFINITE) == WAIT_OBJECT_0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
Packit Service 5a9772
                                      LONGLONG Comperand)
Packit 1fb8d4
{
Packit 1fb8d4
	LONGLONG previousValue = 0;
Packit 1fb8d4
	BOOL locked = static_mutex_lock(&mutex);
Packit 1fb8d4
Packit 1fb8d4
	previousValue = *Destination;
Packit 1fb8d4
Packit 1fb8d4
	if (*Destination == Comperand)
Packit 1fb8d4
		*Destination = Exchange;
Packit 1fb8d4
Packit 1fb8d4
	if (locked)
Packit 1fb8d4
		ReleaseMutex(mutex);
Packit 1fb8d4
	else
Packit 1fb8d4
		fprintf(stderr, "WARNING: InterlockedCompareExchange64 operation might have failed\n");
Packit 1fb8d4
Packit 1fb8d4
	return previousValue;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
#elif (defined(ANDROID) && ANDROID) || \
Packit Service 5a9772
    (defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8))
Packit 1fb8d4
Packit 1fb8d4
#include <pthread.h>
Packit 1fb8d4
Packit 1fb8d4
static pthread_mutex_t mutex;
Packit 1fb8d4
Packit Service 5a9772
LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
Packit Service 5a9772
                                      LONGLONG Comperand)
Packit 1fb8d4
{
Packit 1fb8d4
	LONGLONG previousValue = 0;
Packit 1fb8d4
Packit 1fb8d4
	pthread_mutex_lock(&mutex);
Packit 1fb8d4
Packit 1fb8d4
	previousValue = *Destination;
Packit 1fb8d4
Packit 1fb8d4
	if (*Destination == Comperand)
Packit 1fb8d4
		*Destination = Exchange;
Packit 1fb8d4
Packit 1fb8d4
	pthread_mutex_unlock(&mutex);
Packit 1fb8d4
Packit 1fb8d4
	return previousValue;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
Packit Service 5a9772
LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
Packit Service 5a9772
                                      LONGLONG Comperand)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef __GNUC__
Packit 1fb8d4
	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
Packit 1fb8d4
#else
Packit 1fb8d4
	return 0;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
/* Doubly-Linked List */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Kernel-Mode Basics: Windows Linked Lists:
Packit 1fb8d4
 * http://www.osronline.com/article.cfm?article=499
Packit 1fb8d4
 *
Packit 1fb8d4
 * Singly and Doubly Linked Lists:
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/windows/hardware/ff563802/
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
VOID InitializeListHead(WINPR_PLIST_ENTRY ListHead)
Packit 1fb8d4
{
Packit 1fb8d4
	ListHead->Flink = ListHead->Blink = ListHead;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL IsListEmpty(const WINPR_LIST_ENTRY* ListHead)
Packit 1fb8d4
{
Packit Service 5a9772
	return (BOOL)(ListHead->Flink == ListHead);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL RemoveEntryList(WINPR_PLIST_ENTRY Entry)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_PLIST_ENTRY OldFlink;
Packit Service 5a9772
	WINPR_PLIST_ENTRY OldBlink;
Packit 1fb8d4
Packit 1fb8d4
	OldFlink = Entry->Flink;
Packit 1fb8d4
	OldBlink = Entry->Blink;
Packit 1fb8d4
	OldFlink->Blink = OldBlink;
Packit 1fb8d4
	OldBlink->Flink = OldFlink;
Packit 1fb8d4
Packit Service 5a9772
	return (BOOL)(OldFlink == OldBlink);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
VOID InsertHeadList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_PLIST_ENTRY OldFlink;
Packit 1fb8d4
Packit 1fb8d4
	OldFlink = ListHead->Flink;
Packit 1fb8d4
	Entry->Flink = OldFlink;
Packit 1fb8d4
	Entry->Blink = ListHead;
Packit 1fb8d4
	OldFlink->Blink = Entry;
Packit 1fb8d4
	ListHead->Flink = Entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
WINPR_PLIST_ENTRY RemoveHeadList(WINPR_PLIST_ENTRY ListHead)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_PLIST_ENTRY Flink;
Packit Service 5a9772
	WINPR_PLIST_ENTRY Entry;
Packit 1fb8d4
Packit 1fb8d4
	Entry = ListHead->Flink;
Packit 1fb8d4
	Flink = Entry->Flink;
Packit 1fb8d4
	ListHead->Flink = Flink;
Packit 1fb8d4
	Flink->Blink = ListHead;
Packit 1fb8d4
Packit 1fb8d4
	return Entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
VOID InsertTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_PLIST_ENTRY OldBlink;
Packit 1fb8d4
Packit 1fb8d4
	OldBlink = ListHead->Blink;
Packit 1fb8d4
	Entry->Flink = ListHead;
Packit 1fb8d4
	Entry->Blink = OldBlink;
Packit 1fb8d4
	OldBlink->Flink = Entry;
Packit 1fb8d4
	ListHead->Blink = Entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
WINPR_PLIST_ENTRY RemoveTailList(WINPR_PLIST_ENTRY ListHead)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_PLIST_ENTRY Blink;
Packit Service 5a9772
	WINPR_PLIST_ENTRY Entry;
Packit 1fb8d4
Packit 1fb8d4
	Entry = ListHead->Blink;
Packit 1fb8d4
	Blink = Entry->Blink;
Packit 1fb8d4
	ListHead->Blink = Blink;
Packit 1fb8d4
	Blink->Flink = ListHead;
Packit 1fb8d4
Packit 1fb8d4
	return Entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
VOID AppendTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY ListToAppend)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_PLIST_ENTRY ListEnd = ListHead->Blink;
Packit 1fb8d4
Packit 1fb8d4
	ListHead->Blink->Flink = ListToAppend;
Packit 1fb8d4
	ListHead->Blink = ListToAppend->Blink;
Packit 1fb8d4
	ListToAppend->Blink->Flink = ListHead;
Packit 1fb8d4
	ListToAppend->Blink = ListEnd;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
VOID PushEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead, WINPR_PSINGLE_LIST_ENTRY Entry)
Packit 1fb8d4
{
Packit 1fb8d4
	Entry->Next = ListHead->Next;
Packit 1fb8d4
	ListHead->Next = Entry;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
WINPR_PSINGLE_LIST_ENTRY PopEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead)
Packit 1fb8d4
{
Packit Service 5a9772
	WINPR_PSINGLE_LIST_ENTRY FirstEntry;
Packit 1fb8d4
Packit 1fb8d4
	FirstEntry = ListHead->Next;
Packit 1fb8d4
Packit 1fb8d4
	if (FirstEntry != NULL)
Packit 1fb8d4
		ListHead->Next = FirstEntry->Next;
Packit 1fb8d4
Packit 1fb8d4
	return FirstEntry;
Packit 1fb8d4
}