\r\n

51Degrees Device Detection C/C++  4.3

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 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close,
4  * Caversham, Reading, Berkshire, United Kingdom RG4 7BY.
5  *
6  * This Original Work is licensed under the European Union Public Licence (EUPL)
7  * 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 
41 #ifdef __cplusplus
42 #define EXTERNAL extern "C"
43 #else
44 #define EXTERNAL
45 #endif
46 
55 
59 #ifdef _MSC_VER
60 #define FIFTYONE_DEGREES_THREAD_ROUTINE LPTHREAD_START_ROUTINE
61 #else
62 typedef void*(*FIFTYONE_DEGREES_THREAD_ROUTINE)(void*);
63 #endif
64 
65 /* Define NDEBUG if needed, to ensure asserts are disabled in release builds */
66 #if !defined(DEBUG) && !defined(_DEBUG) && !defined(NDEBUG)
67 #define NDEBUG
68 #endif
69 
70 #ifdef _MSC_VER
71 #pragma warning (push)
72 #pragma warning (disable: 5105)
73 #include <windows.h>
74 #pragma warning (default: 5105)
75 #pragma warning (pop)
76 #include <intrin.h>
77 #pragma intrinsic (_InterlockedIncrement)
78 #pragma intrinsic (_InterlockedDecrement)
79 #else
80 #include <pthread.h>
81 #include <signal.h>
82 #endif
83 #include <assert.h>
84 
93 #ifdef _MSC_VER
94 typedef HANDLE fiftyoneDegreesMutex;
95 #else
96 typedef pthread_mutex_t fiftyoneDegreesMutex;
106 EXTERNAL void fiftyoneDegreesMutexClose(fiftyoneDegreesMutex *mutex);
111 EXTERNAL void fiftyoneDegreesMutexLock(fiftyoneDegreesMutex *mutex);
117 #endif
118 
123 #ifdef _MSC_VER
124 typedef HANDLE fiftyoneDegreesSignal;
125 #else
126 typedef struct fiftyone_degrees_signal_t {
127  volatile bool wait;
128  pthread_cond_t cond;
129  pthread_mutex_t mutex;
131 #endif
132 
143 
154 
163 
171 
175 #ifdef _MSC_VER
176 #define FIFTYONE_DEGREES_THREAD HANDLE
177 #else
178 #define FIFTYONE_DEGREES_THREAD pthread_t
179 #endif
180 
186 #define FIFTYONE_DEGREES_SIGNAL_CREATE(s) s = fiftyoneDegreesSignalCreate()
187 
192 #define FIFTYONE_DEGREES_SIGNAL_CLOSE(s) fiftyoneDegreesSignalClose(s)
193 
198 #define FIFTYONE_DEGREES_SIGNAL_SET(s) fiftyoneDegreesSignalSet(s)
199 
204 #define FIFTYONE_DEGREES_SIGNAL_WAIT(s) fiftyoneDegreesSignalWait(s)
205 
210 #ifdef _MSC_VER
211 #define FIFTYONE_DEGREES_MUTEX_CREATE(m) m = CreateMutex(NULL,FALSE,NULL)
212 #else
213 #define FIFTYONE_DEGREES_MUTEX_CREATE(m) fiftyoneDegreesMutexCreate(&m)
214 #endif
215 
220 #ifdef _MSC_VER
221 #define FIFTYONE_DEGREES_MUTEX_CLOSE(m) if (m != NULL) { CloseHandle(m); }
222 #else
223 #define FIFTYONE_DEGREES_MUTEX_CLOSE(m) fiftyoneDegreesMutexClose(&m)
224 #endif
225 
230 #ifdef _MSC_VER
231 #define FIFTYONE_DEGREES_MUTEX_LOCK(m) WaitForSingleObject(*m, INFINITE)
232 #else
233 #define FIFTYONE_DEGREES_MUTEX_LOCK(m) fiftyoneDegreesMutexLock(m)
234 #endif
235 
240 #ifdef _MSC_VER
241 #define FIFTYONE_DEGREES_MUTEX_UNLOCK(m) ReleaseMutex(*m)
242 #else
243 #define FIFTYONE_DEGREES_MUTEX_UNLOCK(m) fiftyoneDegreesMutexUnlock(m)
244 #endif
245 
251 #ifdef _MSC_VER
252 #define FIFTYONE_DEGREES_MUTEX_VALID(m) (*m != NULL)
253 #else
254 #define FIFTYONE_DEGREES_MUTEX_VALID(m) fiftyoneDegreesMutexValid(m)
255 #endif
256 
264 #ifdef _MSC_VER
265 #define FIFTYONE_DEGREES_THREAD_CREATE(t, m, s) t = \
266  (FIFTYONE_DEGREES_THREAD)CreateThread(NULL, 0, m, s, 0, NULL)
267 #else
268 #define FIFTYONE_DEGREES_THREAD_CREATE(t, m, s) pthread_create(&t, NULL, m, s)
269 #endif
270 
276 #ifdef _MSC_VER
277 #define FIFTYONE_DEGREES_THREAD_JOIN(t) WaitForSingleObject(t, INFINITE)
278 #else
279 #define FIFTYONE_DEGREES_THREAD_JOIN(t) pthread_join(t, NULL)
280 #endif
281 
286 #ifdef _MSC_VER
287 #define FIFTYONE_DEGREES_THREAD_CLOSE(t) CloseHandle(t)
288 #else
289 #define FIFTYONE_DEGREES_THREAD_CLOSE(t)
290 #endif
291 
295 #ifdef _MSC_VER
296 #define FIFTYONE_DEGREES_THREAD_EXIT ExitThread(0)
297 #else
298 #define FIFTYONE_DEGREES_THREAD_EXIT pthread_exit(NULL)
299 #endif
300 
306 #ifdef _MSC_VER
307 #define FIFTYONE_DEGREES_INTERLOCK_INC(v) _InterlockedIncrement(v)
308 #else
309 #define FIFTYONE_DEGREES_INTERLOCK_INC(v) (__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST))
310 #endif
311 
317 #ifdef _MSC_VER
318 #define FIFTYONE_DEGREES_INTERLOCK_DEC(v) _InterlockedDecrement(v)
319 #else
320 #define FIFTYONE_DEGREES_INTERLOCK_DEC(v) (__atomic_add_fetch(v, -1, __ATOMIC_SEQ_CST))
321 #endif
322 
331 #ifdef _MSC_VER
332 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c) \
333  InterlockedCompareExchange(&d, e, c)
334 #else
335 /* __sync is still used here, as __atomic only offers a bool return value.
336 This will end up being resolved to __atomic functions anyway, so is still
337 supported. */
338 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c) \
339  __sync_val_compare_and_swap(&d,c,e)
340 #endif
341 
350 #ifdef _MSC_VER
351 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_64(d,e,c) \
352  InterlockedCompareExchange64((volatile __int64*)&d, (__int64)e, (__int64)c)
353 #else
354 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_64(d,e,c) \
355  FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c)
356 #endif
357 
366 #ifdef _MSC_VER
367 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_PTR(d,e,c) \
368  InterlockedCompareExchangePointer((volatile PVOID*)&d,e,c)
369 #else
370 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_PTR(d,e,c) \
371  FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c)
372 #endif
373 
405 #ifdef _MSC_VER
406 #ifdef _WIN64
407 typedef struct fiftyone_degrees_interlock_dw_type_t {
408  LONG64 low;
409  LONG64 high;
411 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
412  InterlockedCompareExchange128(&d.low, e.high, e.low, &c.low)
413 #else // _WIN64
414 typedef struct fiftyone_degrees_interlock_dw_type_t {
415  LONG64 value;
417 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
418  InterlockedCompareExchange64(&d.value, e.value, c.value) == c.value
419 #endif // _WIN64
420 #else // _MSC_VER
421 #ifdef _LP64
422 typedef struct fiftyone_degrees_interlock_dw_type_t {
423  int64_t low;
424  int64_t high;
425 } __attribute__((aligned(8),packed)) fiftyoneDegreesInterlockDoubleWidth;
426 #else // _LP64
427 typedef struct fiftyone_degrees_interlock_dw_type_t {
428  int64_t value;
430 #endif //_LP64
431 #define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
432  (__atomic_compare_exchange( \
433  (fiftyoneDegreesInterlockDoubleWidth*)&d, \
434  (fiftyoneDegreesInterlockDoubleWidth*)&c, \
435  (fiftyoneDegreesInterlockDoubleWidth*)&e, \
436  false, \
437  __ATOMIC_SEQ_CST, \
438  __ATOMIC_SEQ_CST))
439 #endif // _MSC_VER
440 
441 
442 #ifdef _MSC_VER
443 #ifdef _WIN64
444 #define FIFTYONE_DEGREES_IS_LOCK_FREE IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE128)
445 #else
446 #define FIFTYONE_DEGREES_IS_LOCK_FREE true
447 #endif
448 #else
449 #define FIFTYONE_DEGREES_IS_LOCK_FREE __atomic_is_lock_free(sizeof(fiftyoneDegreesInterlockDoubleWidth), NULL)
450 #endif
451 
456 #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:129
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:96
void fiftyoneDegreesMutexClose(fiftyoneDegreesMutex *mutex)
Closes the mutex passed to the method.
pthread_cond_t cond
Condition variable for the signal.
Definition: threading.h:128
A signal used to limit the number of items that can be created by the pool.
Definition: threading.h:126
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:127
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:427