2012-09-18 15:51:33 -04:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <winpr/interlocked.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* api-ms-win-core-interlocked-l1-2-0.dll:
|
|
|
|
*
|
|
|
|
* InitializeSListHead
|
|
|
|
* InterlockedPopEntrySList
|
|
|
|
* InterlockedPushEntrySList
|
|
|
|
* InterlockedPushListSListEx
|
|
|
|
* InterlockedFlushSList
|
|
|
|
* QueryDepthSList
|
|
|
|
* InterlockedIncrement
|
|
|
|
* InterlockedDecrement
|
|
|
|
* InterlockedExchange
|
|
|
|
* InterlockedExchangeAdd
|
|
|
|
* InterlockedCompareExchange
|
|
|
|
* InterlockedCompareExchange64
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
2012-10-01 23:00:41 -04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2012-09-18 15:51:33 -04:00
|
|
|
VOID InitializeSListHead(PSLIST_HEADER ListHead)
|
|
|
|
{
|
2012-10-01 21:58:24 -04:00
|
|
|
#ifdef _WIN64
|
|
|
|
ListHead->s.Alignment = 0;
|
|
|
|
ListHead->s.Region = 0;
|
|
|
|
ListHead->Header8.Init = 1;
|
|
|
|
#else
|
|
|
|
ListHead->Alignment = 0;
|
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
2012-10-01 21:58:24 -04:00
|
|
|
PSLIST_ENTRY InterlockedPushEntrySList(PSLIST_HEADER ListHead, PSLIST_ENTRY ListEntry)
|
2012-09-18 15:51:33 -04:00
|
|
|
{
|
2012-10-01 21:58:24 -04:00
|
|
|
SLIST_HEADER old;
|
|
|
|
SLIST_HEADER new;
|
|
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
new.HeaderX64.NextEntry = (((ULONG_PTR) ListEntry) >> 4);
|
|
|
|
|
2012-10-01 23:00:41 -04:00
|
|
|
while (1)
|
2012-10-01 21:58:24 -04:00
|
|
|
{
|
|
|
|
old = *ListHead;
|
2012-10-01 23:00:41 -04:00
|
|
|
|
2012-10-01 21:58:24 -04:00
|
|
|
ListEntry->Next = (PSLIST_ENTRY) (((ULONG_PTR) old.HeaderX64.NextEntry) << 4);
|
2012-10-01 23:00:41 -04:00
|
|
|
|
2012-10-01 21:58:24 -04:00
|
|
|
new.HeaderX64.Depth = old.HeaderX64.Depth + 1;
|
|
|
|
new.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
|
2012-10-01 23:00:41 -04:00
|
|
|
|
|
|
|
if (InterlockedCompareExchange64((LONGLONG*) ListHead, new.s.Alignment, old.s.Alignment))
|
|
|
|
{
|
|
|
|
InterlockedCompareExchange64(&((LONGLONG*) ListHead)[1], new.s.Region, old.s.Region);
|
|
|
|
break;
|
|
|
|
}
|
2012-10-01 21:58:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
2012-10-01 21:58:24 -04:00
|
|
|
PSLIST_ENTRY InterlockedPushListSListEx(PSLIST_HEADER ListHead, PSLIST_ENTRY List, PSLIST_ENTRY ListEnd, ULONG Count)
|
2012-09-18 15:51:33 -04:00
|
|
|
{
|
2012-10-01 21:58:24 -04:00
|
|
|
#ifdef _WIN64
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-10-01 21:58:24 -04:00
|
|
|
PSLIST_ENTRY InterlockedPopEntrySList(PSLIST_HEADER ListHead)
|
2012-09-18 15:51:33 -04:00
|
|
|
{
|
2012-10-01 21:58:24 -04:00
|
|
|
SLIST_HEADER old;
|
|
|
|
SLIST_HEADER new;
|
|
|
|
PSLIST_ENTRY entry;
|
|
|
|
|
|
|
|
#ifdef _WIN64
|
2012-10-01 23:00:41 -04:00
|
|
|
while (1)
|
2012-10-01 21:58:24 -04:00
|
|
|
{
|
|
|
|
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;
|
2012-10-01 23:00:41 -04:00
|
|
|
|
|
|
|
if (InterlockedCompareExchange64((LONGLONG*) ListHead, new.s.Alignment, old.s.Alignment))
|
|
|
|
{
|
|
|
|
InterlockedCompareExchange64(&((LONGLONG*) ListHead)[1], new.s.Region, old.s.Region);
|
|
|
|
break;
|
|
|
|
}
|
2012-10-01 21:58:24 -04:00
|
|
|
}
|
|
|
|
#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;
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
PSLIST_ENTRY InterlockedFlushSList(PSLIST_HEADER ListHead)
|
|
|
|
{
|
2012-10-01 23:31:49 -04:00
|
|
|
SLIST_HEADER old;
|
|
|
|
SLIST_HEADER new;
|
|
|
|
|
|
|
|
if (!QueryDepthSList(ListHead))
|
|
|
|
return NULL;
|
|
|
|
|
2012-10-01 21:58:24 -04:00
|
|
|
#ifdef _WIN64
|
2012-10-01 23:31:49 -04:00
|
|
|
new.s.Alignment = 0;
|
|
|
|
new.s.Region = 0;
|
|
|
|
new.HeaderX64.HeaderType = 1;
|
2012-10-01 21:58:24 -04:00
|
|
|
|
2012-10-01 23:31:49 -04:00
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
old = *ListHead;
|
|
|
|
new.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
|
|
|
|
|
|
|
|
if (InterlockedCompareExchange64((LONGLONG*) ListHead, new.s.Alignment, old.s.Alignment))
|
|
|
|
{
|
|
|
|
InterlockedCompareExchange64(&((LONGLONG*) ListHead)[1], new.s.Region, old.s.Region);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (PSLIST_ENTRY) (((ULONG_PTR) old.HeaderX64.NextEntry) << 4);
|
2012-10-01 21:58:24 -04:00
|
|
|
#else
|
2012-10-01 23:31:49 -04:00
|
|
|
new.Alignment = 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
old = *ListHead;
|
|
|
|
new.s.Sequence = old.s.Sequence + 1;
|
|
|
|
}
|
|
|
|
while(InterlockedCompareExchange64(&ListHead->Alignment, new.Alignment, old.Alignment) != old.Alignment);
|
2012-10-01 21:58:24 -04:00
|
|
|
|
2012-10-01 23:31:49 -04:00
|
|
|
return old.s.Next.Next;
|
2012-10-01 21:58:24 -04:00
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
USHORT QueryDepthSList(PSLIST_HEADER ListHead)
|
|
|
|
{
|
2012-10-01 23:00:41 -04:00
|
|
|
#ifdef _WIN64
|
|
|
|
return ListHead->HeaderX64.Depth;
|
|
|
|
#else
|
|
|
|
return ListHead->s.Depth;
|
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
LONG InterlockedIncrement(LONG volatile *Addend)
|
|
|
|
{
|
2012-09-19 21:42:46 -04:00
|
|
|
#ifdef __GNUC__
|
|
|
|
return __sync_add_and_fetch(Addend, 1);
|
|
|
|
#else
|
2012-09-18 15:51:33 -04:00
|
|
|
return 0;
|
2012-09-19 21:42:46 -04:00
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
LONG InterlockedDecrement(LONG volatile *Addend)
|
|
|
|
{
|
2012-09-19 21:42:46 -04:00
|
|
|
#ifdef __GNUC__
|
|
|
|
return __sync_sub_and_fetch(Addend, 1);
|
|
|
|
#else
|
2012-09-18 15:51:33 -04:00
|
|
|
return 0;
|
2012-09-19 21:42:46 -04:00
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
LONG InterlockedExchange(LONG volatile *Target, LONG Value)
|
|
|
|
{
|
2012-09-19 21:42:46 -04:00
|
|
|
#ifdef __GNUC__
|
|
|
|
return __sync_val_compare_and_swap(Target, *Target, Value);
|
|
|
|
#else
|
2012-09-18 15:51:33 -04:00
|
|
|
return 0;
|
2012-09-19 21:42:46 -04:00
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
LONG InterlockedExchangeAdd(LONG volatile *Addend, LONG Value)
|
|
|
|
{
|
2012-09-19 21:42:46 -04:00
|
|
|
#ifdef __GNUC__
|
2012-10-01 21:58:24 -04:00
|
|
|
return __sync_fetch_and_add(Addend, Value);
|
2012-09-19 21:42:46 -04:00
|
|
|
#else
|
2012-09-18 15:51:33 -04:00
|
|
|
return 0;
|
2012-09-19 21:42:46 -04:00
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
2012-10-01 21:58:24 -04:00
|
|
|
LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand)
|
2012-09-18 15:51:33 -04:00
|
|
|
{
|
2012-09-19 21:42:46 -04:00
|
|
|
#ifdef __GNUC__
|
2012-10-01 21:58:24 -04:00
|
|
|
return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
|
2012-09-19 21:42:46 -04:00
|
|
|
#else
|
2012-09-18 15:51:33 -04:00
|
|
|
return 0;
|
2012-09-19 21:42:46 -04:00
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
2012-10-01 23:00:41 -04:00
|
|
|
LONGLONG InterlockedCompareExchange64(LONGLONG volatile *Destination, LONGLONG Exchange, LONGLONG Comperand)
|
2012-09-18 15:51:33 -04:00
|
|
|
{
|
2012-09-19 21:42:46 -04:00
|
|
|
#ifdef __GNUC__
|
2012-10-01 21:58:24 -04:00
|
|
|
return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
|
2012-09-19 21:42:46 -04:00
|
|
|
#else
|
2012-09-18 15:51:33 -04:00
|
|
|
return 0;
|
2012-09-19 21:42:46 -04:00
|
|
|
#endif
|
2012-09-18 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|