20 #include <winpr/config.h>
22 #include <winpr/assert.h>
23 #include <winpr/platform.h>
24 #include <winpr/synch.h>
25 #include <winpr/handle.h>
27 #include <winpr/interlocked.h>
38 WINPR_ASSERT(ListHead);
40 ListHead->s.Alignment = 0;
41 ListHead->s.Region = 0;
42 ListHead->Header8.Init = 1;
44 ListHead->Alignment = 0;
49 WINPR_PSLIST_ENTRY ListEntry)
54 WINPR_ASSERT(ListHead);
55 WINPR_ASSERT(ListEntry);
57 newHeader.HeaderX64.NextEntry = (((ULONG_PTR)ListEntry) >> 4);
63 ListEntry->Next = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
65 newHeader.HeaderX64.Depth = old.HeaderX64.Depth + 1;
66 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
68 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
70 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
76 return (PSLIST_ENTRY)((ULONG_PTR)old.HeaderX64.NextEntry << 4);
78 newHeader.s.Next.Next = ListEntry;
83 ListEntry->Next = old.s.Next.Next;
84 newHeader.s.Depth = old.s.Depth + 1;
85 newHeader.s.Sequence = old.s.Sequence + 1;
86 if (old.Alignment > INT64_MAX)
88 if (newHeader.Alignment > INT64_MAX)
90 if (ListHead->Alignment > INT64_MAX)
92 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
93 (LONGLONG)newHeader.Alignment,
94 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
96 return old.s.Next.Next;
100 WINPR_PSLIST_ENTRY InterlockedPushListSListEx(
WINPR_PSLIST_HEADER ListHead, WINPR_PSLIST_ENTRY List,
101 WINPR_PSLIST_ENTRY ListEnd, ULONG Count)
103 WINPR_ASSERT(ListHead);
105 WINPR_ASSERT(ListEnd);
119 WINPR_PSLIST_ENTRY entry = NULL;
121 WINPR_ASSERT(ListHead);
128 entry = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
133 newHeader.HeaderX64.NextEntry = ((ULONG_PTR)entry->Next) >> 4;
134 newHeader.HeaderX64.Depth = old.HeaderX64.Depth - 1;
135 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence - 1;
137 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
139 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
149 entry = old.s.Next.Next;
154 newHeader.s.Next.Next = entry->Next;
155 newHeader.s.Depth = old.s.Depth - 1;
156 newHeader.s.Sequence = old.s.Sequence + 1;
158 if (old.Alignment > INT64_MAX)
160 if (newHeader.Alignment > INT64_MAX)
162 if (ListHead->Alignment > INT64_MAX)
164 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
165 (LONGLONG)newHeader.Alignment,
166 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
176 WINPR_ASSERT(ListHead);
177 if (!QueryDepthSList(ListHead))
181 newHeader).Alignment = 0;
182 newHeader).Region = 0;
183 newHeader.HeaderX64.HeaderType = 1;
188 newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
190 if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader).Alignment, old).Alignment))
192 InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader).Region,
198 return (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
200 newHeader.Alignment = 0;
205 newHeader.s.Sequence = old.s.Sequence + 1;
207 if (old.Alignment > INT64_MAX)
209 if (newHeader.Alignment > INT64_MAX)
211 if (ListHead->Alignment > INT64_MAX)
213 }
while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
214 (LONGLONG)newHeader.Alignment,
215 (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
217 return old.s.Next.Next;
223 WINPR_ASSERT(ListHead);
226 return ListHead->HeaderX64.Depth;
228 return ListHead->s.Depth;
232 LONG InterlockedIncrement(LONG
volatile* Addend)
234 WINPR_ASSERT(Addend);
236 #if defined(__GNUC__) || defined(__clang__)
237 WINPR_PRAGMA_DIAG_PUSH
238 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
239 return __sync_add_and_fetch(Addend, 1);
240 WINPR_PRAGMA_DIAG_POP
246 LONG InterlockedDecrement(LONG
volatile* Addend)
248 WINPR_ASSERT(Addend);
250 #if defined(__GNUC__) || defined(__clang__)
251 WINPR_PRAGMA_DIAG_PUSH
252 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
253 return __sync_sub_and_fetch(Addend, 1);
254 WINPR_PRAGMA_DIAG_POP
260 LONG InterlockedExchange(LONG
volatile* Target, LONG Value)
262 WINPR_ASSERT(Target);
264 #if defined(__GNUC__) || defined(__clang__)
265 WINPR_PRAGMA_DIAG_PUSH
266 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
267 return __sync_val_compare_and_swap(Target, *Target, Value);
268 WINPR_PRAGMA_DIAG_POP
274 LONG InterlockedExchangeAdd(LONG
volatile* Addend, LONG Value)
276 WINPR_ASSERT(Addend);
278 #if defined(__GNUC__) || defined(__clang__)
279 WINPR_PRAGMA_DIAG_PUSH
280 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
281 return __sync_fetch_and_add(Addend, Value);
282 WINPR_PRAGMA_DIAG_POP
288 LONG InterlockedCompareExchange(LONG
volatile* Destination, LONG Exchange, LONG Comperand)
290 WINPR_ASSERT(Destination);
292 #if defined(__GNUC__) || defined(__clang__)
293 WINPR_PRAGMA_DIAG_PUSH
294 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
295 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
296 WINPR_PRAGMA_DIAG_POP
302 PVOID InterlockedCompareExchangePointer(PVOID
volatile* Destination, PVOID Exchange,
305 WINPR_ASSERT(Destination);
307 #if defined(__GNUC__) || defined(__clang__)
308 WINPR_PRAGMA_DIAG_PUSH
309 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
310 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
311 WINPR_PRAGMA_DIAG_POP
319 #if defined(_WIN32) && !defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
323 #elif defined(_WIN32) && defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
325 static volatile HANDLE mutex = NULL;
327 BOOL static_mutex_lock(
volatile HANDLE* static_mutex)
329 if (*static_mutex == NULL)
333 if (!(handle = CreateMutex(NULL, FALSE, NULL)))
336 if (InterlockedCompareExchangePointer((PVOID*)static_mutex, (PVOID)handle, NULL) != NULL)
337 (void)CloseHandle(handle);
340 return (WaitForSingleObject(*static_mutex, INFINITE) == WAIT_OBJECT_0);
343 LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
346 LONGLONG previousValue = 0;
347 BOOL locked = static_mutex_lock(&mutex);
349 previousValue = *Destination;
351 if (*Destination == Comperand)
352 *Destination = Exchange;
355 (void)ReleaseMutex(mutex);
357 (
void)fprintf(stderr,
358 "WARNING: InterlockedCompareExchange64 operation might have failed\n");
360 return previousValue;
363 #elif (defined(ANDROID) && ANDROID) || \
364 (defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8))
368 static pthread_mutex_t mutex;
370 LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
373 LONGLONG previousValue = 0;
375 pthread_mutex_lock(&mutex);
377 previousValue = *Destination;
379 if (*Destination == Comperand)
380 *Destination = Exchange;
382 pthread_mutex_unlock(&mutex);
384 return previousValue;
389 LONGLONG InterlockedCompareExchange64(LONGLONG
volatile* Destination, LONGLONG Exchange,
392 WINPR_ASSERT(Destination);
394 #if defined(__GNUC__) || defined(__clang__)
395 WINPR_PRAGMA_DIAG_PUSH
396 WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
397 return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
398 WINPR_PRAGMA_DIAG_POP
416 VOID InitializeListHead(WINPR_PLIST_ENTRY ListHead)
418 WINPR_ASSERT(ListHead);
419 ListHead->Flink = ListHead->Blink = ListHead;
422 BOOL IsListEmpty(
const WINPR_LIST_ENTRY* ListHead)
424 WINPR_ASSERT(ListHead);
425 return (BOOL)(ListHead->Flink == ListHead);
428 BOOL RemoveEntryList(WINPR_PLIST_ENTRY Entry)
431 WINPR_PLIST_ENTRY OldFlink = Entry->Flink;
432 WINPR_ASSERT(OldFlink);
434 WINPR_PLIST_ENTRY OldBlink = Entry->Blink;
435 WINPR_ASSERT(OldBlink);
437 OldFlink->Blink = OldBlink;
438 OldBlink->Flink = OldFlink;
440 return (BOOL)(OldFlink == OldBlink);
443 VOID InsertHeadList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
445 WINPR_ASSERT(ListHead);
448 WINPR_PLIST_ENTRY OldFlink = ListHead->Flink;
449 WINPR_ASSERT(OldFlink);
451 Entry->Flink = OldFlink;
452 Entry->Blink = ListHead;
453 OldFlink->Blink = Entry;
454 ListHead->Flink = Entry;
457 WINPR_PLIST_ENTRY RemoveHeadList(WINPR_PLIST_ENTRY ListHead)
459 WINPR_ASSERT(ListHead);
461 WINPR_PLIST_ENTRY Entry = ListHead->Flink;
464 WINPR_PLIST_ENTRY Flink = Entry->Flink;
467 ListHead->Flink = Flink;
468 Flink->Blink = ListHead;
473 VOID InsertTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
475 WINPR_ASSERT(ListHead);
478 WINPR_PLIST_ENTRY OldBlink = ListHead->Blink;
479 WINPR_ASSERT(OldBlink);
481 Entry->Flink = ListHead;
482 Entry->Blink = OldBlink;
483 OldBlink->Flink = Entry;
484 ListHead->Blink = Entry;
487 WINPR_PLIST_ENTRY RemoveTailList(WINPR_PLIST_ENTRY ListHead)
489 WINPR_ASSERT(ListHead);
491 WINPR_PLIST_ENTRY Entry = ListHead->Blink;
494 WINPR_PLIST_ENTRY Blink = Entry->Blink;
497 ListHead->Blink = Blink;
498 Blink->Flink = ListHead;
503 VOID AppendTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY ListToAppend)
505 WINPR_ASSERT(ListHead);
506 WINPR_ASSERT(ListToAppend);
508 WINPR_PLIST_ENTRY ListEnd = ListHead->Blink;
510 ListHead->Blink->Flink = ListToAppend;
511 ListHead->Blink = ListToAppend->Blink;
512 ListToAppend->Blink->Flink = ListHead;
513 ListToAppend->Blink = ListEnd;
516 VOID PushEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead, WINPR_PSINGLE_LIST_ENTRY Entry)
518 WINPR_ASSERT(ListHead);
521 Entry->Next = ListHead->Next;
522 ListHead->Next = Entry;
525 WINPR_PSINGLE_LIST_ENTRY PopEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead)
527 WINPR_ASSERT(ListHead);
528 WINPR_PSINGLE_LIST_ENTRY FirstEntry = ListHead->Next;
530 if (FirstEntry != NULL)
531 ListHead->Next = FirstEntry->Next;