20#include <winpr/config.h>
22#include <winpr/assert.h>
23#include <winpr/wlog.h>
24#include <winpr/platform.h>
25#include <winpr/synch.h>
26#include <winpr/handle.h>
28#include <winpr/interlocked.h>
39 WINPR_ASSERT(ListHead);
41 ListHead->s.Alignment = 0;
42 ListHead->s.Region = 0;
43 ListHead->Header8.Init = 1;
45 ListHead->Alignment = 0;
50 WINPR_PSLIST_ENTRY ListEntry)
55 WINPR_ASSERT(ListHead);
56 WINPR_ASSERT(ListEntry);
58 newHeader.HeaderX64.NextEntry = (((ULONG_PTR)ListEntry) >> 4);
64 ListEntry->Next = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
66 newHeader.HeaderX64.Depth = old.HeaderX64.Depth + 1;
67 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
69 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
71 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
77 return (PSLIST_ENTRY)((ULONG_PTR)old.HeaderX64.NextEntry << 4);
79 newHeader.s.Next.Next = ListEntry;
84 ListEntry->Next = old.s.Next.Next;
85 newHeader.s.Depth = old.s.Depth + 1;
86 newHeader.s.Sequence = old.s.Sequence + 1;
87 if (old.Alignment > INT64_MAX)
89 if (newHeader.Alignment > INT64_MAX)
91 if (ListHead->Alignment > INT64_MAX)
93 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
94 (LONGLONG)newHeader.Alignment,
95 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
97 return old.s.Next.Next;
101WINPR_PSLIST_ENTRY InterlockedPushListSListEx(WINPR_ATTR_UNUSED
WINPR_PSLIST_HEADER ListHead,
102 WINPR_ATTR_UNUSED WINPR_PSLIST_ENTRY List,
103 WINPR_ATTR_UNUSED WINPR_PSLIST_ENTRY ListEnd,
104 WINPR_ATTR_UNUSED ULONG Count)
106 WINPR_ASSERT(ListHead);
108 WINPR_ASSERT(ListEnd);
110 WLog_ERR(
"TODO",
"TODO: implement");
123 WINPR_PSLIST_ENTRY entry = NULL;
125 WINPR_ASSERT(ListHead);
132 entry = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
137 newHeader.HeaderX64.NextEntry = ((ULONG_PTR)entry->Next) >> 4;
138 newHeader.HeaderX64.Depth = old.HeaderX64.Depth - 1;
139 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence - 1;
141 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
143 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
153 entry = old.s.Next.Next;
158 newHeader.s.Next.Next = entry->Next;
159 newHeader.s.Depth = old.s.Depth - 1;
160 newHeader.s.Sequence = old.s.Sequence + 1;
162 if (old.Alignment > INT64_MAX)
164 if (newHeader.Alignment > INT64_MAX)
166 if (ListHead->Alignment > INT64_MAX)
168 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
169 (LONGLONG)newHeader.Alignment,
170 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
180 WINPR_ASSERT(ListHead);
181 if (!QueryDepthSList(ListHead))
185 newHeader).Alignment = 0;
186 newHeader).Region = 0;
187 newHeader.HeaderX64.HeaderType = 1;
192 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
194 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
196 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
202 return (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
204 newHeader.Alignment = 0;
209 newHeader.s.Sequence = old.s.Sequence + 1;
211 if (old.Alignment > INT64_MAX)
213 if (newHeader.Alignment > INT64_MAX)
215 if (ListHead->Alignment > INT64_MAX)
217 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
218 (LONGLONG)newHeader.Alignment,
219 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
221 return old.s.Next.Next;
227 WINPR_ASSERT(ListHead);
230 return ListHead->HeaderX64.Depth;
232 return ListHead->s.Depth;
236LONG InterlockedIncrement(LONG
volatile* Addend)
238 WINPR_ASSERT(Addend);
240#if defined(__GNUC__) || defined(__clang__)
241 WINPR_PRAGMA_DIAG_PUSH
242 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
243 return __sync_add_and_fetch(Addend, 1);
244 WINPR_PRAGMA_DIAG_POP
250LONG InterlockedDecrement(LONG
volatile* Addend)
252 WINPR_ASSERT(Addend);
254#if defined(__GNUC__) || defined(__clang__)
255 WINPR_PRAGMA_DIAG_PUSH
256 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
257 return __sync_sub_and_fetch(Addend, 1);
258 WINPR_PRAGMA_DIAG_POP
264LONG InterlockedExchange(LONG
volatile* Target, LONG Value)
266 WINPR_ASSERT(Target);
268#if defined(__GNUC__) || defined(__clang__)
269 WINPR_PRAGMA_DIAG_PUSH
270 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
271 return __sync_val_compare_and_swap(Target, *Target, Value);
272 WINPR_PRAGMA_DIAG_POP
278LONG InterlockedExchangeAdd(LONG
volatile* Addend, LONG Value)
280 WINPR_ASSERT(Addend);
282#if defined(__GNUC__) || defined(__clang__)
283 WINPR_PRAGMA_DIAG_PUSH
284 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
285 return __sync_fetch_and_add(Addend, Value);
286 WINPR_PRAGMA_DIAG_POP
292LONG InterlockedCompareExchange(LONG
volatile* Destination, LONG Exchange, LONG Comperand)
294 WINPR_ASSERT(Destination);
296#if defined(__GNUC__) || defined(__clang__)
297 WINPR_PRAGMA_DIAG_PUSH
298 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
299 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
300 WINPR_PRAGMA_DIAG_POP
306PVOID InterlockedCompareExchangePointer(PVOID
volatile* Destination, PVOID Exchange,
309 WINPR_ASSERT(Destination);
311#if defined(__GNUC__) || defined(__clang__)
312 WINPR_PRAGMA_DIAG_PUSH
313 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
314 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
315 WINPR_PRAGMA_DIAG_POP
323#if defined(_WIN32) && !defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
327#elif defined(_WIN32) && defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
329static volatile HANDLE mutex = NULL;
331BOOL static_mutex_lock(
volatile HANDLE* static_mutex)
333 if (*static_mutex == NULL)
337 if (!(handle = CreateMutex(NULL, FALSE, NULL)))
340 if (InterlockedCompareExchangePointer((PVOID*)static_mutex, (PVOID)handle, NULL) != NULL)
341 (void)CloseHandle(handle);
344 return (WaitForSingleObject(*static_mutex, INFINITE) == WAIT_OBJECT_0);
347LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
350 LONGLONG previousValue = 0;
351 BOOL locked = static_mutex_lock(&mutex);
353 previousValue = *Destination;
355 if (*Destination == Comperand)
356 *Destination = Exchange;
359 (void)ReleaseMutex(mutex);
361 (
void)fprintf(stderr,
362 "WARNING: InterlockedCompareExchange64 operation might have failed\n");
364 return previousValue;
367#elif (defined(ANDROID) && ANDROID) || \
368 (defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8))
372static pthread_mutex_t mutex;
374LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
377 LONGLONG previousValue = 0;
379 pthread_mutex_lock(&mutex);
381 previousValue = *Destination;
383 if (*Destination == Comperand)
384 *Destination = Exchange;
386 pthread_mutex_unlock(&mutex);
388 return previousValue;
393LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
396 WINPR_ASSERT(Destination);
398#if defined(__GNUC__) || defined(__clang__)
399 WINPR_PRAGMA_DIAG_PUSH
400 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
401 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
402 WINPR_PRAGMA_DIAG_POP
420VOID InitializeListHead(WINPR_PLIST_ENTRY ListHead)
422 WINPR_ASSERT(ListHead);
423 ListHead->Flink = ListHead->Blink = ListHead;
426BOOL IsListEmpty(
const WINPR_LIST_ENTRY* ListHead)
428 WINPR_ASSERT(ListHead);
429 return (BOOL)(ListHead->Flink == ListHead);
432BOOL RemoveEntryList(WINPR_PLIST_ENTRY Entry)
435 WINPR_PLIST_ENTRY OldFlink = Entry->Flink;
436 WINPR_ASSERT(OldFlink);
438 WINPR_PLIST_ENTRY OldBlink = Entry->Blink;
439 WINPR_ASSERT(OldBlink);
441 OldFlink->Blink = OldBlink;
442 OldBlink->Flink = OldFlink;
444 return (BOOL)(OldFlink == OldBlink);
447VOID InsertHeadList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
449 WINPR_ASSERT(ListHead);
452 WINPR_PLIST_ENTRY OldFlink = ListHead->Flink;
453 WINPR_ASSERT(OldFlink);
455 Entry->Flink = OldFlink;
456 Entry->Blink = ListHead;
457 OldFlink->Blink = Entry;
458 ListHead->Flink = Entry;
461WINPR_PLIST_ENTRY RemoveHeadList(WINPR_PLIST_ENTRY ListHead)
463 WINPR_ASSERT(ListHead);
465 WINPR_PLIST_ENTRY Entry = ListHead->Flink;
468 WINPR_PLIST_ENTRY Flink = Entry->Flink;
471 ListHead->Flink = Flink;
472 Flink->Blink = ListHead;
477VOID InsertTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
479 WINPR_ASSERT(ListHead);
482 WINPR_PLIST_ENTRY OldBlink = ListHead->Blink;
483 WINPR_ASSERT(OldBlink);
485 Entry->Flink = ListHead;
486 Entry->Blink = OldBlink;
487 OldBlink->Flink = Entry;
488 ListHead->Blink = Entry;
491WINPR_PLIST_ENTRY RemoveTailList(WINPR_PLIST_ENTRY ListHead)
493 WINPR_ASSERT(ListHead);
495 WINPR_PLIST_ENTRY Entry = ListHead->Blink;
498 WINPR_PLIST_ENTRY Blink = Entry->Blink;
501 ListHead->Blink = Blink;
502 Blink->Flink = ListHead;
507VOID AppendTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY ListToAppend)
509 WINPR_ASSERT(ListHead);
510 WINPR_ASSERT(ListToAppend);
512 WINPR_PLIST_ENTRY ListEnd = ListHead->Blink;
514 ListHead->Blink->Flink = ListToAppend;
515 ListHead->Blink = ListToAppend->Blink;
516 ListToAppend->Blink->Flink = ListHead;
517 ListToAppend->Blink = ListEnd;
520VOID PushEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead, WINPR_PSINGLE_LIST_ENTRY Entry)
522 WINPR_ASSERT(ListHead);
525 Entry->Next = ListHead->Next;
526 ListHead->Next = Entry;
529WINPR_PSINGLE_LIST_ENTRY PopEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead)
531 WINPR_ASSERT(ListHead);
532 WINPR_PSINGLE_LIST_ENTRY FirstEntry = ListHead->Next;
534 if (FirstEntry != NULL)
535 ListHead->Next = FirstEntry->Next;