FreeRDP
interlocked.c
1 
20 #include <winpr/config.h>
21 
22 #include <winpr/platform.h>
23 #include <winpr/synch.h>
24 #include <winpr/handle.h>
25 
26 #include <winpr/interlocked.h>
27 
28 /* Singly-Linked List */
29 
30 #ifndef _WIN32
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 
35 VOID InitializeSListHead(WINPR_PSLIST_HEADER ListHead)
36 {
37 #ifdef _WIN64
38  ListHead->s.Alignment = 0;
39  ListHead->s.Region = 0;
40  ListHead->Header8.Init = 1;
41 #else
42  ListHead->Alignment = 0;
43 #endif
44 }
45 
46 WINPR_PSLIST_ENTRY InterlockedPushEntrySList(WINPR_PSLIST_HEADER ListHead,
47  WINPR_PSLIST_ENTRY ListEntry)
48 {
50  WINPR_SLIST_HEADER newHeader;
51 
52 #ifdef _WIN64
53  newHeader.HeaderX64.NextEntry = (((ULONG_PTR)ListEntry) >> 4);
54 
55  while (1)
56  {
57  old = *ListHead;
58 
59  ListEntry->Next = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
60 
61  newHeader.HeaderX64.Depth = old.HeaderX64.Depth + 1;
62  newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
63 
64  if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader.s.Alignment,
65  old.s.Alignment))
66  {
67  InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader.s.Region,
68  old.s.Region);
69  break;
70  }
71  }
72 
73  return (PSLIST_ENTRY)((ULONG_PTR)old.HeaderX64.NextEntry << 4);
74 #else
75  newHeader.s.Next.Next = ListEntry;
76 
77  do
78  {
79  old = *ListHead;
80  ListEntry->Next = old.s.Next.Next;
81  newHeader.s.Depth = old.s.Depth + 1;
82  newHeader.s.Sequence = old.s.Sequence + 1;
83  if (old.Alignment > INT64_MAX)
84  return NULL;
85  if (newHeader.Alignment > INT64_MAX)
86  return NULL;
87  if (ListHead->Alignment > INT64_MAX)
88  return NULL;
89  } while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
90  (LONGLONG)newHeader.Alignment,
91  (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
92 
93  return old.s.Next.Next;
94 #endif
95 }
96 
97 WINPR_PSLIST_ENTRY InterlockedPushListSListEx(WINPR_PSLIST_HEADER ListHead, WINPR_PSLIST_ENTRY List,
98  WINPR_PSLIST_ENTRY ListEnd, ULONG Count)
99 {
100 #ifdef _WIN64
101 
102 #else
103 
104 #endif
105  return NULL;
106 }
107 
108 WINPR_PSLIST_ENTRY InterlockedPopEntrySList(WINPR_PSLIST_HEADER ListHead)
109 {
110  WINPR_SLIST_HEADER old;
111  WINPR_SLIST_HEADER newHeader;
112  WINPR_PSLIST_ENTRY entry = NULL;
113 
114 #ifdef _WIN64
115  while (1)
116  {
117  old = *ListHead;
118 
119  entry = (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
120 
121  if (!entry)
122  return NULL;
123 
124  newHeader.HeaderX64.NextEntry = ((ULONG_PTR)entry->Next) >> 4;
125  newHeader.HeaderX64.Depth = old.HeaderX64.Depth - 1;
126  newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence - 1;
127 
128  if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader.s.Alignment,
129  old.s.Alignment))
130  {
131  InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader.s.Region,
132  old.s.Region);
133  break;
134  }
135  }
136 #else
137  do
138  {
139  old = *ListHead;
140 
141  entry = old.s.Next.Next;
142 
143  if (!entry)
144  return NULL;
145 
146  newHeader.s.Next.Next = entry->Next;
147  newHeader.s.Depth = old.s.Depth - 1;
148  newHeader.s.Sequence = old.s.Sequence + 1;
149 
150  if (old.Alignment > INT64_MAX)
151  return NULL;
152  if (newHeader.Alignment > INT64_MAX)
153  return NULL;
154  if (ListHead->Alignment > INT64_MAX)
155  return NULL;
156  } while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
157  (LONGLONG)newHeader.Alignment,
158  (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
159 #endif
160  return entry;
161 }
162 
163 WINPR_PSLIST_ENTRY InterlockedFlushSList(WINPR_PSLIST_HEADER ListHead)
164 {
165  WINPR_SLIST_HEADER old;
166  WINPR_SLIST_HEADER newHeader;
167 
168  if (!QueryDepthSList(ListHead))
169  return NULL;
170 
171 #ifdef _WIN64
172  newHeader.s.Alignment = 0;
173  newHeader.s.Region = 0;
174  newHeader.HeaderX64.HeaderType = 1;
175 
176  while (1)
177  {
178  old = *ListHead;
179  newHeader.HeaderX64.Sequence = old.HeaderX64.Sequence + 1;
180 
181  if (InterlockedCompareExchange64((LONGLONG*)ListHead, newHeader.s.Alignment,
182  old.s.Alignment))
183  {
184  InterlockedCompareExchange64(&((LONGLONG*)ListHead)[1], newHeader.s.Region,
185  old.s.Region);
186  break;
187  }
188  }
189 
190  return (PSLIST_ENTRY)(((ULONG_PTR)old.HeaderX64.NextEntry) << 4);
191 #else
192  newHeader.Alignment = 0;
193 
194  do
195  {
196  old = *ListHead;
197  newHeader.s.Sequence = old.s.Sequence + 1;
198 
199  if (old.Alignment > INT64_MAX)
200  return NULL;
201  if (newHeader.Alignment > INT64_MAX)
202  return NULL;
203  if (ListHead->Alignment > INT64_MAX)
204  return NULL;
205  } while (InterlockedCompareExchange64((LONGLONG*)&ListHead->Alignment,
206  (LONGLONG)newHeader.Alignment,
207  (LONGLONG)old.Alignment) != (LONGLONG)old.Alignment);
208 
209  return old.s.Next.Next;
210 #endif
211 }
212 
213 USHORT QueryDepthSList(WINPR_PSLIST_HEADER ListHead)
214 {
215 #ifdef _WIN64
216  return ListHead->HeaderX64.Depth;
217 #else
218  return ListHead->s.Depth;
219 #endif
220 }
221 
222 LONG InterlockedIncrement(LONG volatile* Addend)
223 {
224 #if defined(__GNUC__) || defined(__clang__)
225  WINPR_PRAGMA_DIAG_PUSH
226  WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
227  return __sync_add_and_fetch(Addend, 1);
228  WINPR_PRAGMA_DIAG_POP
229 #else
230  return 0;
231 #endif
232 }
233 
234 LONG InterlockedDecrement(LONG volatile* Addend)
235 {
236 #if defined(__GNUC__) || defined(__clang__)
237  WINPR_PRAGMA_DIAG_PUSH
238  WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
239  return __sync_sub_and_fetch(Addend, 1);
240  WINPR_PRAGMA_DIAG_POP
241 #else
242  return 0;
243 #endif
244 }
245 
246 LONG InterlockedExchange(LONG volatile* Target, LONG Value)
247 {
248 #if defined(__GNUC__) || defined(__clang__)
249  WINPR_PRAGMA_DIAG_PUSH
250  WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
251  return __sync_val_compare_and_swap(Target, *Target, Value);
252  WINPR_PRAGMA_DIAG_POP
253 #else
254  return 0;
255 #endif
256 }
257 
258 LONG InterlockedExchangeAdd(LONG volatile* Addend, LONG Value)
259 {
260 #if defined(__GNUC__) || defined(__clang__)
261  WINPR_PRAGMA_DIAG_PUSH
262  WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
263  return __sync_fetch_and_add(Addend, Value);
264  WINPR_PRAGMA_DIAG_POP
265 #else
266  return 0;
267 #endif
268 }
269 
270 LONG InterlockedCompareExchange(LONG volatile* Destination, LONG Exchange, LONG Comperand)
271 {
272 #if defined(__GNUC__) || defined(__clang__)
273  WINPR_PRAGMA_DIAG_PUSH
274  WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
275  return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
276  WINPR_PRAGMA_DIAG_POP
277 #else
278  return 0;
279 #endif
280 }
281 
282 PVOID InterlockedCompareExchangePointer(PVOID volatile* Destination, PVOID Exchange,
283  PVOID Comperand)
284 {
285 #if defined(__GNUC__) || defined(__clang__)
286  WINPR_PRAGMA_DIAG_PUSH
287  WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
288  return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
289  WINPR_PRAGMA_DIAG_POP
290 #else
291  return 0;
292 #endif
293 }
294 
295 #endif /* _WIN32 */
296 
297 #if defined(_WIN32) && !defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
298 
299 /* InterlockedCompareExchange64 already defined */
300 
301 #elif defined(_WIN32) && defined(WINPR_INTERLOCKED_COMPARE_EXCHANGE64)
302 
303 static volatile HANDLE mutex = NULL;
304 
305 BOOL static_mutex_lock(volatile HANDLE* static_mutex)
306 {
307  if (*static_mutex == NULL)
308  {
309  HANDLE handle;
310 
311  if (!(handle = CreateMutex(NULL, FALSE, NULL)))
312  return FALSE;
313 
314  if (InterlockedCompareExchangePointer((PVOID*)static_mutex, (PVOID)handle, NULL) != NULL)
315  (void)CloseHandle(handle);
316  }
317 
318  return (WaitForSingleObject(*static_mutex, INFINITE) == WAIT_OBJECT_0);
319 }
320 
321 LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
322  LONGLONG Comperand)
323 {
324  LONGLONG previousValue = 0;
325  BOOL locked = static_mutex_lock(&mutex);
326 
327  previousValue = *Destination;
328 
329  if (*Destination == Comperand)
330  *Destination = Exchange;
331 
332  if (locked)
333  (void)ReleaseMutex(mutex);
334  else
335  (void)fprintf(stderr,
336  "WARNING: InterlockedCompareExchange64 operation might have failed\n");
337 
338  return previousValue;
339 }
340 
341 #elif (defined(ANDROID) && ANDROID) || \
342  (defined(__GNUC__) && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8))
343 
344 #include <pthread.h>
345 
346 static pthread_mutex_t mutex;
347 
348 LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
349  LONGLONG Comperand)
350 {
351  LONGLONG previousValue = 0;
352 
353  pthread_mutex_lock(&mutex);
354 
355  previousValue = *Destination;
356 
357  if (*Destination == Comperand)
358  *Destination = Exchange;
359 
360  pthread_mutex_unlock(&mutex);
361 
362  return previousValue;
363 }
364 
365 #else
366 
367 LONGLONG InterlockedCompareExchange64(LONGLONG volatile* Destination, LONGLONG Exchange,
368  LONGLONG Comperand)
369 {
370 #if defined(__GNUC__) || defined(__clang__)
371  WINPR_PRAGMA_DIAG_PUSH
372  WINPR_PRAGMA_DIAG_IGNORED_ATOMIC_SEQ_CST
373  return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
374  WINPR_PRAGMA_DIAG_POP
375 #else
376  return 0;
377 #endif
378 }
379 
380 #endif
381 
382 /* Doubly-Linked List */
383 
392 VOID InitializeListHead(WINPR_PLIST_ENTRY ListHead)
393 {
394  ListHead->Flink = ListHead->Blink = ListHead;
395 }
396 
397 BOOL IsListEmpty(const WINPR_LIST_ENTRY* ListHead)
398 {
399  return (BOOL)(ListHead->Flink == ListHead);
400 }
401 
402 BOOL RemoveEntryList(WINPR_PLIST_ENTRY Entry)
403 {
404  WINPR_PLIST_ENTRY OldFlink = NULL;
405  WINPR_PLIST_ENTRY OldBlink = NULL;
406 
407  OldFlink = Entry->Flink;
408  OldBlink = Entry->Blink;
409  OldFlink->Blink = OldBlink;
410  OldBlink->Flink = OldFlink;
411 
412  return (BOOL)(OldFlink == OldBlink);
413 }
414 
415 VOID InsertHeadList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
416 {
417  WINPR_PLIST_ENTRY OldFlink = NULL;
418 
419  OldFlink = ListHead->Flink;
420  Entry->Flink = OldFlink;
421  Entry->Blink = ListHead;
422  OldFlink->Blink = Entry;
423  ListHead->Flink = Entry;
424 }
425 
426 WINPR_PLIST_ENTRY RemoveHeadList(WINPR_PLIST_ENTRY ListHead)
427 {
428  WINPR_PLIST_ENTRY Flink = NULL;
429  WINPR_PLIST_ENTRY Entry = NULL;
430 
431  Entry = ListHead->Flink;
432  Flink = Entry->Flink;
433  ListHead->Flink = Flink;
434  Flink->Blink = ListHead;
435 
436  return Entry;
437 }
438 
439 VOID InsertTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY Entry)
440 {
441  WINPR_PLIST_ENTRY OldBlink = NULL;
442 
443  OldBlink = ListHead->Blink;
444  Entry->Flink = ListHead;
445  Entry->Blink = OldBlink;
446  OldBlink->Flink = Entry;
447  ListHead->Blink = Entry;
448 }
449 
450 WINPR_PLIST_ENTRY RemoveTailList(WINPR_PLIST_ENTRY ListHead)
451 {
452  WINPR_PLIST_ENTRY Blink = NULL;
453  WINPR_PLIST_ENTRY Entry = NULL;
454 
455  Entry = ListHead->Blink;
456  Blink = Entry->Blink;
457  ListHead->Blink = Blink;
458  Blink->Flink = ListHead;
459 
460  return Entry;
461 }
462 
463 VOID AppendTailList(WINPR_PLIST_ENTRY ListHead, WINPR_PLIST_ENTRY ListToAppend)
464 {
465  WINPR_PLIST_ENTRY ListEnd = ListHead->Blink;
466 
467  ListHead->Blink->Flink = ListToAppend;
468  ListHead->Blink = ListToAppend->Blink;
469  ListToAppend->Blink->Flink = ListHead;
470  ListToAppend->Blink = ListEnd;
471 }
472 
473 VOID PushEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead, WINPR_PSINGLE_LIST_ENTRY Entry)
474 {
475  Entry->Next = ListHead->Next;
476  ListHead->Next = Entry;
477 }
478 
479 WINPR_PSINGLE_LIST_ENTRY PopEntryList(WINPR_PSINGLE_LIST_ENTRY ListHead)
480 {
481  WINPR_PSINGLE_LIST_ENTRY FirstEntry = NULL;
482 
483  FirstEntry = ListHead->Next;
484 
485  if (FirstEntry != NULL)
486  ListHead->Next = FirstEntry->Next;
487 
488  return FirstEntry;
489 }