\r\n

51Degrees Device Detection C/C++  4.4

A device detection library that is used natively or by 51Degrees products

threading.h

1 /* *********************************************************************
2  * This Original Work is copyright of 51 Degrees Mobile Experts Limited.
3  * Copyright 2023 51 Degrees Mobile Experts Limited, Davidson House,
4  * Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
5  *
6  * This Original Work is licensed under the European Union Public Licence
7  * (EUPL) v.1.2 and is subject to its terms as set out below.
8  *
9  * If a copy of the EUPL was not distributed with this file, You can obtain
10  * one at https://opensource.org/licenses/EUPL-1.2.
11  *
12  * The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
13  * amended by the European Commission) shall be deemed incompatible for
14  * the purposes of the Work and the provisions of the compatibility
15  * clause in Article 5 of the EUPL shall not apply.
16  *
17  * If using the Work as, or as part of, a network application, by
18  * including the attribution notice(s) required under Article 5 of the EUPL
19  * in the end user terms of the application under an appropriate heading,
20  * such notice(s) shall fulfill the requirements of that article.
21  * ********************************************************************* */
22 
33 #ifndef FIFTYONE_DEGREES_THREADING_INCLUDED
34 #define FIFTYONE_DEGREES_THREADING_INCLUDED
35 
36 #include <stdbool.h>
37 #include <stdint.h>
38 
39 #include <stdio.h>
40 #include "common.h"
41 
50 
54 #ifdef _MSC_VER
55 #define FIFTYONE_DEGREES_THREAD_ROUTINE LPTHREAD_START_ROUTINE
56 #else
57 typedef void*(*FIFTYONE_DEGREES_THREAD_ROUTINE)(void*);
58 #endif
59 
60 /* Define NDEBUG if needed, to ensure asserts are disabled in release builds */
61 #if !defined(DEBUG) && !defined(_DEBUG) && !defined(NDEBUG)
62 #define NDEBUG
63 #endif
64 
65 #ifdef _MSC_VER
66 #pragma warning (push)
67 #pragma warning (disable: 5105)
68 #include <windows.h>
69 #pragma warning (default: 5105)
70 #pragma warning (pop)
71 #include <intrin.h>
72 #pragma intrinsic (_InterlockedIncrement)
73 #pragma intrinsic (_InterlockedDecrement)
74 #else
75 #include <pthread.h>
76 #include <signal.h>
77 #endif
78 #include <assert.h>
79 
88 #ifdef _MSC_VER
89 typedef HANDLE fiftyoneDegreesMutex;
90 #else
91 typedef pthread_mutex_t fiftyoneDegreesMutex;
101 EXTERNAL void fiftyoneDegreesMutexClose(fiftyoneDegreesMutex *mutex);
106 EXTERNAL void fiftyoneDegreesMutexLock(fiftyoneDegreesMutex *mutex);
112 #endif
113 
118 #ifdef _MSC_VER
119 typedef HANDLE fiftyoneDegreesSignal;
120 #else
121 typedef struct fiftyone_degrees_signal_t {
122  volatile bool wait;
123  pthread_cond_t cond;
124  pthread_mutex_t mutex;
126 #endif
127 
138 
149 
158 
166 
170 #ifdef _MSC_VER
171 #define FIFTYONE_DEGREES_THREAD HANDLE
172 #else
173 #define FIFTYONE_DEGREES_THREAD pthread_t
174 #endif
175 
181 #define FIFTYONE_DEGREES_SIGNAL_CREATE(s) s = fiftyoneDegreesSignalCreate()
182 
187 #define FIFTYONE_DEGREES_SIGNAL_CLOSE(s) fiftyoneDegreesSignalClose(s)
188 
193 #define FIFTYONE_DEGREES_SIGNAL_SET(s) fiftyoneDegreesSignalSet(s)
194 
199 #define FIFTYONE_DEGREES_SIGNAL_WAIT(s) fiftyoneDegreesSignalWait(s)
200 
205 #ifdef _MSC_VER
206 #define FIFTYONE_DEGREES_MUTEX_CREATE(m) m = CreateMutex(NULL,FALSE,NULL)
207 #else
208 #define FIFTYONE_DEGREES_MUTEX_CREATE(m) fiftyoneDegreesMutexCreate(&m)
209 #endif
210 
215 #ifdef _MSC_VER
216 #define FIFTYONE_DEGREES_MUTEX_CLOSE(m) if (m != NULL) { CloseHandle(m); }
217 #else
218 #define FIFTYONE_DEGREES_MUTEX_CLOSE(m) fiftyoneDegreesMutexClose(&m)
219 #endif
220 
225 #ifdef _MSC_VER
226 #define FIFTYONE_DEGREES_MUTEX_LOCK(m) WaitForSingleObject(*m, INFINITE)
227 #else
228 #define FIFTYONE_DEGREES_MUTEX_LOCK(m) fiftyoneDegreesMutexLock(m)
229 #endif
230 
235 #ifdef _MSC_VER
236 #define FIFTYONE_DEGREES_MUTEX_UNLOCK(m) ReleaseMutex(*m)
237 #else
238 #define FIFTYONE_DEGREES_MUTEX_UNLOCK(m) fiftyoneDegreesMutexUnlock(m)
239 #endif
240 
246 #ifdef _MSC_VER
247 #define FIFTYONE_DEGREES_MUTEX_VALID(m) (*m != NULL)
248 #else
249 #define FIFTYONE_DEGREES_MUTEX_VALID(m) fiftyoneDegreesMutexValid(m)
250 #endif
251 
259 #ifdef _MSC_VER
260 #define FIFTYONE_DEGREES_THREAD_CREATE(t, m, s) t = \
261  (FIFTYONE_DEGREES_THREAD)CreateThread(NULL, 0, m, s, 0, NULL)
262 #else
263 #define FIFTYONE_DEGREES_THREAD_CREATE(t, m, s) pthread_create(&t, NULL, m, s)
264 #endif
265 
271 #ifdef _MSC_VER
272 #define FIFTYONE_DEGREES_THREAD_JOIN(t) WaitForSingleObject(t, INFINITE)
273 #else
274 #define FIFTYONE_DEGREES_THREAD_JOIN(t) pthread_join(t, NULL)
275 #endif
276 
281 #ifdef _MSC_VER
282 #define FIFTYONE_DEGREES_THREAD_CLOSE(t) CloseHandle(t)
283 #else
284 #define FIFTYONE_DEGREES_THREAD_CLOSE(t)
285 #endif
286 
290 #ifdef _MSC_VER
291 #define FIFTYONE_DEGREES_THREAD_EXIT ExitThread(0)
292 #else
293 #define FIFTYONE_DEGREES_THREAD_EXIT pthread_exit(NULL)
294 #endif
295 
301 #ifdef _MSC_VER
302 #define FIFTYONE_DEGREES_INTERLOCK_INC(v) _InterlockedIncrement(v)
303 #else
304 #define FIFTYONE_DEGREES_INTERLOCK_INC(v) (__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST))
305 #endif
306 
312 #ifdef _MSC_VER
313 #define FIFTYONE_DEGREES_INTERLOCK_DEC(v) _InterlockedDecrement(v)
314 #else
315 #define FIFTYONE_DEGREES_INTERLOCK_DEC(v) (__atomic_add_fetch(v, -1, __ATOMIC_SEQ_CST))
316 #endif
317 
326 #ifdef _MSC_VER
327 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c) \
328  InterlockedCompareExchange(&d, e, c)
329 #else
330 /* __sync is still used here, as __atomic only offers a bool return value.
331 This will end up being resolved to __atomic functions anyway, so is still
332 supported. */
333 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c) \
334  __sync_val_compare_and_swap(&d,c,e)
335 #endif
336 
345 #ifdef _MSC_VER
346 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_64(d,e,c) \
347  InterlockedCompareExchange64((volatile __int64*)&d, (__int64)e, (__int64)c)
348 #else
349 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_64(d,e,c) \
350  FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c)
351 #endif
352 
361 #ifdef _MSC_VER
362 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_PTR(d,e,c) \
363  InterlockedCompareExchangePointer((volatile PVOID*)&d,e,c)
364 #else
365 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_PTR(d,e,c) \
366  FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c)
367 #endif
368 
400 #ifdef _MSC_VER
401 #ifdef _WIN64
402 typedef struct fiftyone_degrees_interlock_dw_type_t {
403  LONG64 low;
404  LONG64 high;
406 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
407  InterlockedCompareExchange128(&d.low, e.high, e.low, &c.low)
408 #else // _WIN64
409 typedef struct fiftyone_degrees_interlock_dw_type_t {
410  LONG64 value;
412 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
413  InterlockedCompareExchange64(&d.value, e.value, c.value) == c.value
414 #endif // _WIN64
415 #else // _MSC_VER
416 #if (defined(_LP64) || defined(__MINGW64__))
417 typedef struct fiftyone_degrees_interlock_dw_type_t {
418  int64_t low;
419  int64_t high;
420 } __attribute__((aligned(16),packed)) fiftyoneDegreesInterlockDoubleWidth;
421 #else // _LP64
422 typedef struct fiftyone_degrees_interlock_dw_type_t {
423  int64_t value;
425 #endif //_LP64
426 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
427  (__atomic_compare_exchange( \
428  (fiftyoneDegreesInterlockDoubleWidth*)&d, \
429  (fiftyoneDegreesInterlockDoubleWidth*)&c, \
430  (fiftyoneDegreesInterlockDoubleWidth*)&e, \
431  false, \
432  __ATOMIC_SEQ_CST, \
433  __ATOMIC_SEQ_CST))
434 #endif // _MSC_VER
435 
436 
437 #ifdef _MSC_VER
438 #ifdef _WIN64
439 #define FIFTYONE_DEGREES_IS_LOCK_FREE IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE128)
440 #else
441 #define FIFTYONE_DEGREES_IS_LOCK_FREE true
442 #endif
443 #else
444 #define FIFTYONE_DEGREES_IS_LOCK_FREE __atomic_is_lock_free(sizeof(fiftyoneDegreesInterlockDoubleWidth), NULL)
445 #endif
446 
451 #endif
void fiftyoneDegreesMutexCreate(fiftyoneDegreesMutex *mutex)
Initialises the mutex passed to the method.
void fiftyoneDegreesMutexUnlock(fiftyoneDegreesMutex *mutex)
Unlocks the mutex passed to the method.
pthread_mutex_t mutex
Mutex for the signal.
Definition: threading.h:124
void fiftyoneDegreesMutexLock(fiftyoneDegreesMutex *mutex)
Locks the mutex passed to the method.
fiftyoneDegreesSignal * fiftyoneDegreesSignalCreate()
Initialises the signal pointer by setting the condition first followed by the mutex if the condition ...
pthread_mutex_t fiftyoneDegreesMutex
MUTEX AND THREADING MACROS.
Definition: threading.h:91
void fiftyoneDegreesMutexClose(fiftyoneDegreesMutex *mutex)
Closes the mutex passed to the method.
pthread_cond_t cond
Condition variable for the signal.
Definition: threading.h:123
A signal used to limit the number of items that can be created by the pool.
Definition: threading.h:121
bool fiftyoneDegreesThreadingGetIsThreadSafe()
Determines if the methods that should be thread safe have been compiled so they are thread safe.
void fiftyoneDegreesSignalWait(fiftyoneDegreesSignal *signal)
Wait for a signal to be set.
void fiftyoneDegreesSignalClose(fiftyoneDegreesSignal *signal)
Closes the signal ensuring there is a lock on the signal before destroying the signal.
volatile bool wait
Flag indicating if the thread should wait.
Definition: threading.h:122
void fiftyoneDegreesSignalSet(fiftyoneDegreesSignal *signal)
If the signal has not been destroyed then sends a signal to a waiting thread that the signal has been...
Double width (64 or 128 depending on the architecture) compare and exchange.
Definition: threading.h:422