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>
37#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
38VOID InitializeSListHead(WINPR_PSLIST_HEADER ListHead)
40 WINPR_ASSERT(ListHead);
42 ListHead->s.Alignment = 0;
43 ListHead->s.Region = 0;
44 ListHead->Header8.Init = 1;
46 ListHead->Alignment = 0;
50WINPR_PSLIST_ENTRY InterlockedPushEntrySList(WINPR_PSLIST_HEADER ListHead,
51 WINPR_PSLIST_ENTRY ListEntry)
53 WINPR_SLIST_HEADER old = WINPR_C_ARRAY_INIT;
54 WINPR_SLIST_HEADER newHeader = WINPR_C_ARRAY_INIT;
56 WINPR_ASSERT(ListHead);
57 WINPR_ASSERT(ListEntry);
59 newHeader.HeaderX64.NextEntry = (((ULONG_PTR)ListEntry) >> 4);
65 ListEntry->Next = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
67 newHeader.HeaderX64.Depth = old.HeaderX64.Depth + 1;
68 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
70 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
72 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
78 return (PSLIST_ENTRY)((ULONG_PTR)old.HeaderX64.NextEntry << 4);
80 newHeader.s.Next.Next = ListEntry;
85 ListEntry->Next = old.s.Next.Next;
86 newHeader.s.Depth = old.s.Depth + 1;
87 newHeader.s.Sequence = old.s.Sequence + 1;
88 if (old.Alignment > INT64_MAX)
90 if (newHeader.Alignment > INT64_MAX)
92 if (ListHead->Alignment > INT64_MAX)
94 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
95 (LONGLONG)newHeader.Alignment,
96 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
98 return old.s.Next.Next;
102WINPR_PSLIST_ENTRY InterlockedPushListSListEx(WINPR_ATTR_UNUSED WINPR_PSLIST_HEADER ListHead,
103 WINPR_ATTR_UNUSED WINPR_PSLIST_ENTRY List,
104 WINPR_ATTR_UNUSED WINPR_PSLIST_ENTRY ListEnd,
105 WINPR_ATTR_UNUSED ULONG Count)
107 WINPR_ASSERT(ListHead);
109 WINPR_ASSERT(ListEnd);
111 WLog_ERR(
"TODO",
"TODO: implement");
120WINPR_PSLIST_ENTRY InterlockedPopEntrySList(WINPR_PSLIST_HEADER ListHead)
122 WINPR_SLIST_HEADER old = WINPR_C_ARRAY_INIT;
123 WINPR_SLIST_HEADER newHeader = WINPR_C_ARRAY_INIT;
124 WINPR_PSLIST_ENTRY entry =
nullptr;
126 WINPR_ASSERT(ListHead);
133 entry = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
138 newHeader.HeaderX64.NextEntry = ((ULONG_PTR)entry->Next) >> 4;
139 newHeader.HeaderX64.Depth = old.HeaderX64.Depth - 1;
140 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence - 1;
142 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
144 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
154 entry = old.s.Next.Next;
159 newHeader.s.Next.Next = entry->Next;
160 newHeader.s.Depth = old.s.Depth - 1;
161 newHeader.s.Sequence = old.s.Sequence + 1;
163 if (old.Alignment > INT64_MAX)
165 if (newHeader.Alignment > INT64_MAX)
167 if (ListHead->Alignment > INT64_MAX)
169 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
170 (LONGLONG)newHeader.Alignment,
171 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
176WINPR_PSLIST_ENTRY InterlockedFlushSList(WINPR_PSLIST_HEADER ListHead)
178 WINPR_SLIST_HEADER old = WINPR_C_ARRAY_INIT;
179 WINPR_SLIST_HEADER newHeader = WINPR_C_ARRAY_INIT;
181 WINPR_ASSERT(ListHead);
182 if (!QueryDepthSList(ListHead))
186 newHeader).Alignment = 0;
187 newHeader).Region = 0;
188 newHeader.HeaderX64.HeaderType = 1;
193 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
195 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
197 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
203 return (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
205 newHeader.Alignment = 0;
210 newHeader.s.Sequence = old.s.Sequence + 1;
212 if (old.Alignment > INT64_MAX)
214 if (newHeader.Alignment > INT64_MAX)
216 if (ListHead->Alignment > INT64_MAX)
218 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
219 (LONGLONG)newHeader.Alignment,
220 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
222 return old.s.Next.Next;
226USHORT QueryDepthSList(WINPR_PSLIST_HEADER ListHead)
228 WINPR_ASSERT(ListHead);
231 return ListHead->HeaderX64.Depth;
233 return ListHead->s.Depth;
239LONG InterlockedIncrement(LONG
volatile* Addend)
241 WINPR_ASSERT(Addend);
243#if defined(__GNUC__) || defined(__clang__)
244 WINPR_PRAGMA_DIAG_PUSH
245 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
246 return __sync_add_and_fetch(Addend, 1);
247 WINPR_PRAGMA_DIAG_POP
253LONG InterlockedDecrement(LONG
volatile* Addend)
255 WINPR_ASSERT(Addend);
257#if defined(__GNUC__) || defined(__clang__)
258 WINPR_PRAGMA_DIAG_PUSH
259 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
260 return __sync_sub_and_fetch(Addend, 1);
261 WINPR_PRAGMA_DIAG_POP
267LONG InterlockedExchange(LONG
volatile* Target, LONG Value)
269 WINPR_ASSERT(Target);
271#if defined(__GNUC__) || defined(__clang__)
272 WINPR_PRAGMA_DIAG_PUSH
273 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
274 return __sync_val_compare_and_swap(Target, *Target, Value);
275 WINPR_PRAGMA_DIAG_POP
281LONG InterlockedExchangeAdd(LONG
volatile* Addend, LONG Value)
283 WINPR_ASSERT(Addend);
285#if defined(__GNUC__) || defined(__clang__)
286 WINPR_PRAGMA_DIAG_PUSH
287 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
288 return __sync_fetch_and_add(Addend, Value);
289 WINPR_PRAGMA_DIAG_POP
295LONG InterlockedCompareExchange(LONG
volatile* Destination, LONG Exchange, LONG Comperand)
297 WINPR_ASSERT(Destination);
299#if defined(__GNUC__) || defined(__clang__)
300 WINPR_PRAGMA_DIAG_PUSH
301 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
302 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
303 WINPR_PRAGMA_DIAG_POP
309PVOID InterlockedCompareExchangePointer(PVOID
volatile* Destination, PVOID Exchange,
312 WINPR_ASSERT(Destination);
314#if defined(__GNUC__) || defined(__clang__)
315 WINPR_PRAGMA_DIAG_PUSH
316 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
317 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
318 WINPR_PRAGMA_DIAG_POP
326#if defined(_WIN32) && !defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
330#elif defined(_WIN32) && defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
332static volatile HANDLE mutex =
nullptr;
334BOOL static_mutex_lock(
volatile HANDLE* static_mutex)
336 if (*static_mutex ==
nullptr)
340 if (!(handle = CreateMutex(
nullptr, FALSE,
nullptr)))
343 if (InterlockedCompareExchangePointer((PVOID*)static_mutex, (PVOID)handle,
nullptr) !=
345 (void)CloseHandle(handle);
348 return (WaitForSingleObject(*static_mutex, INFINITE) == WAIT_OBJECT_0);
351LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
354 LONGLONG previousValue = 0;
355 BOOL locked = static_mutex_lock(&mutex);
357 previousValue = *Destination;
359 if (*Destination == Comperand)
360 *Destination = Exchange;
363 (void)ReleaseMutex(mutex);
365 (
void)fprintf(stderr,
366 "WARNING: InterlockedCompareExchange64 operation might have failed\n");
368 return previousValue;
371#elif (defined(ANDROID) && ANDROID) || \
372 (defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8))
376static pthread_mutex_t mutex;
378LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
381 LONGLONG previousValue = 0;
383 pthread_mutex_lock(&mutex);
385 previousValue = *Destination;
387 if (*Destination == Comperand)
388 *Destination = Exchange;
390 pthread_mutex_unlock(&mutex);
392 return previousValue;
397LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
400 WINPR_ASSERT(Destination);
402#if defined(__GNUC__) || defined(__clang__)
403 WINPR_PRAGMA_DIAG_PUSH
404 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
405 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
406 WINPR_PRAGMA_DIAG_POP
414#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
425VOID InitializeListHead(WINPR_PLIST_ENTRY ListHead)
427 WINPR_ASSERT(ListHead);
428 ListHead->Flink = ListHead->Blink = ListHead;
431BOOL IsListEmpty(
const WINPR_LIST_ENTRY* ListHead)
433 WINPR_ASSERT(ListHead);
434 return (BOOL)(ListHead->Flink == ListHead);
437BOOL RemoveEntryList(WINPR_PLIST_ENTRY Entry)
440 WINPR_PLIST_ENTRY OldFlink = Entry->Flink;
441 WINPR_ASSERT(OldFlink);
443 WINPR_PLIST_ENTRY OldBlink = Entry->Blink;
444 WINPR_ASSERT(OldBlink);
446 OldFlink->Blink = OldBlink;
447 OldBlink->Flink = OldFlink;
449 return (BOOL)(OldFlink == OldBlink);
452VOID InsertHeadList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
454 WINPR_ASSERT(ListHead);
457 WINPR_PLIST_ENTRY OldFlink = ListHead->Flink;
458 WINPR_ASSERT(OldFlink);
460 Entry->Flink = OldFlink;
461 Entry->Blink = ListHead;
462 OldFlink->Blink = Entry;
463 ListHead->Flink = Entry;
466WINPR_PLIST_ENTRY RemoveHeadList(WINPR_PLIST_ENTRY ListHead)
468 WINPR_ASSERT(ListHead);
470 WINPR_PLIST_ENTRY Entry = ListHead->Flink;
473 WINPR_PLIST_ENTRY Flink = Entry->Flink;
476 ListHead->Flink = Flink;
477 Flink->Blink = ListHead;
482VOID InsertTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
484 WINPR_ASSERT(ListHead);
487 WINPR_PLIST_ENTRY OldBlink = ListHead->Blink;
488 WINPR_ASSERT(OldBlink);
490 Entry->Flink = ListHead;
491 Entry->Blink = OldBlink;
492 OldBlink->Flink = Entry;
493 ListHead->Blink = Entry;
496WINPR_PLIST_ENTRY RemoveTailList(WINPR_PLIST_ENTRY ListHead)
498 WINPR_ASSERT(ListHead);
500 WINPR_PLIST_ENTRY Entry = ListHead->Blink;
503 WINPR_PLIST_ENTRY Blink = Entry->Blink;
506 ListHead->Blink = Blink;
507 Blink->Flink = ListHead;
512VOID AppendTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY ListToAppend)
514 WINPR_ASSERT(ListHead);
515 WINPR_ASSERT(ListToAppend);
517 WINPR_PLIST_ENTRY ListEnd = ListHead->Blink;
519 ListHead->Blink->Flink = ListToAppend;
520 ListHead->Blink = ListToAppend->Blink;
521 ListToAppend->Blink->Flink = ListHead;
522 ListToAppend->Blink = ListEnd;
525VOID PushEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead, WINPR_PSINGLE_LIST_ENTRY Entry)
527 WINPR_ASSERT(ListHead);
530 Entry->Next = ListHead->Next;
531 ListHead->Next = Entry;
534WINPR_PSINGLE_LIST_ENTRY PopEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead)
536 WINPR_ASSERT(ListHead);
537 WINPR_PSINGLE_LIST_ENTRY FirstEntry = ListHead->Next;
539 if (FirstEntry !=
nullptr)
540 ListHead->Next = FirstEntry->Next;