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 2026 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
32
33#ifndef FIFTYONE_DEGREES_THREADING_INCLUDED
34#define FIFTYONE_DEGREES_THREADING_INCLUDED
35
36#ifdef FIFTYONE_DEGREES_IPI_SYMBOLS
37#include "ipiSymbols.h"
38#endif
39
40#include <stdbool.h>
41#include <stdint.h>
42
43#include <stdio.h>
44#include "common.h"
45
54
59#define FIFTYONE_DEGREES_PROCESSOR_COUNT_MAX (UINT16_MAX - 1)
60
68
72#ifdef _MSC_VER
73#define FIFTYONE_DEGREES_THREAD_ROUTINE LPTHREAD_START_ROUTINE
74#else
75typedef void*(*FIFTYONE_DEGREES_THREAD_ROUTINE)(void*);
76#endif
77
78/* Define NDEBUG if needed, to ensure asserts are disabled in release builds */
79#if !defined(DEBUG) && !defined(_DEBUG) && !defined(NDEBUG)
80#define NDEBUG
81#endif
82
83#ifdef _MSC_VER
84#pragma warning (push)
85#pragma warning (disable: 5105)
86#include <windows.h>
87#pragma warning (default: 5105)
88#pragma warning (pop)
89#include <intrin.h>
90#pragma intrinsic (_InterlockedIncrement)
91#pragma intrinsic (_InterlockedDecrement)
92#else
93#include <pthread.h>
94#include <signal.h>
95#endif
96#include <assert.h>
97
101
109#ifdef _MSC_VER
110typedef SRWLOCK fiftyoneDegreesMutex;
111#else
112typedef pthread_mutex_t fiftyoneDegreesMutex;
133#endif
134
139#ifdef _MSC_VER
140typedef HANDLE fiftyoneDegreesSignal;
141#else
142typedef struct fiftyone_degrees_signal_t {
143 volatile bool wait;
144 pthread_cond_t cond;
145 pthread_mutex_t mutex;
147#endif
148
159
170
179
187
191#ifdef _MSC_VER
192#define FIFTYONE_DEGREES_THREAD HANDLE
193#else
194#define FIFTYONE_DEGREES_THREAD pthread_t
195#endif
196
202#define FIFTYONE_DEGREES_SIGNAL_CREATE(s) s = fiftyoneDegreesSignalCreate()
203
208#define FIFTYONE_DEGREES_SIGNAL_CLOSE(s) fiftyoneDegreesSignalClose(s)
209
214#define FIFTYONE_DEGREES_SIGNAL_SET(s) fiftyoneDegreesSignalSet(s)
215
220#define FIFTYONE_DEGREES_SIGNAL_WAIT(s) fiftyoneDegreesSignalWait(s)
221
226#ifdef _MSC_VER
227#define FIFTYONE_DEGREES_MUTEX_CREATE(m) InitializeSRWLock(&m)
228#else
229#define FIFTYONE_DEGREES_MUTEX_CREATE(m) fiftyoneDegreesMutexCreate(&m)
230#endif
231
237#ifdef _MSC_VER
238#define FIFTYONE_DEGREES_MUTEX_CLOSE(m)
239#else
240#define FIFTYONE_DEGREES_MUTEX_CLOSE(m) fiftyoneDegreesMutexClose(&m)
241#endif
242
247#ifdef _MSC_VER
248#define FIFTYONE_DEGREES_MUTEX_LOCK(m) AcquireSRWLockExclusive(m)
249#else
250#define FIFTYONE_DEGREES_MUTEX_LOCK(m) fiftyoneDegreesMutexLock(m)
251#endif
252
257#ifdef _MSC_VER
258#define FIFTYONE_DEGREES_MUTEX_UNLOCK(m) ReleaseSRWLockExclusive(m)
259#else
260#define FIFTYONE_DEGREES_MUTEX_UNLOCK(m) fiftyoneDegreesMutexUnlock(m)
261#endif
262
268#ifdef _MSC_VER
269#define FIFTYONE_DEGREES_MUTEX_VALID(m) (m != NULL)
270#else
271#define FIFTYONE_DEGREES_MUTEX_VALID(m) fiftyoneDegreesMutexValid(m)
272#endif
273
281#ifdef _MSC_VER
282#define FIFTYONE_DEGREES_THREAD_CREATE(t, m, s) t = \
283 (FIFTYONE_DEGREES_THREAD)CreateThread(NULL, 0, m, s, 0, NULL)
284#else
285#define FIFTYONE_DEGREES_THREAD_CREATE(t, m, s) pthread_create(&t, NULL, m, s)
286#endif
287
293#ifdef _MSC_VER
294#define FIFTYONE_DEGREES_THREAD_JOIN(t) WaitForSingleObject(t, INFINITE)
295#else
296#define FIFTYONE_DEGREES_THREAD_JOIN(t) pthread_join(t, NULL)
297#endif
298
303#ifdef _MSC_VER
304#define FIFTYONE_DEGREES_THREAD_CLOSE(t) CloseHandle(t)
305#else
306#define FIFTYONE_DEGREES_THREAD_CLOSE(t)
307#endif
308
312#ifdef _MSC_VER
313#define FIFTYONE_DEGREES_THREAD_EXIT ExitThread(0)
314#else
315#define FIFTYONE_DEGREES_THREAD_EXIT pthread_exit(NULL)
316#endif
317
323#ifdef _MSC_VER
324#define FIFTYONE_DEGREES_INTERLOCK_INC(v) _InterlockedIncrement(v)
325#else
326#define FIFTYONE_DEGREES_INTERLOCK_INC(v) (__atomic_add_fetch(v, 1, __ATOMIC_SEQ_CST))
327#endif
328
334#ifdef _MSC_VER
335#define FIFTYONE_DEGREES_INTERLOCK_DEC(v) _InterlockedDecrement(v)
336#else
337#define FIFTYONE_DEGREES_INTERLOCK_DEC(v) (__atomic_add_fetch(v, -1, __ATOMIC_SEQ_CST))
338#endif
339
348#ifdef _MSC_VER
349#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c) \
350 InterlockedCompareExchange(&d, e, c)
351#else
352/* __sync is still used here, as __atomic only offers a bool return value.
353This will end up being resolved to __atomic functions anyway, so is still
354supported. */
355#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c) \
356 __sync_val_compare_and_swap(&d,c,e)
357#endif
358
367#ifdef _MSC_VER
368#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_64(d,e,c) \
369 InterlockedCompareExchange64((volatile __int64*)&d, (__int64)e, (__int64)c)
370#else
371#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_64(d,e,c) \
372 FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c)
373#endif
374
383#ifdef _MSC_VER
384#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_PTR(d,e,c) \
385 InterlockedCompareExchangePointer((volatile PVOID*)&d,e,c)
386#else
387#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_PTR(d,e,c) \
388 FIFTYONE_DEGREES_INTERLOCK_EXCHANGE(d,e,c)
389#endif
390
422#ifdef _MSC_VER
423#ifdef _WIN64
424typedef struct fiftyone_degrees_interlock_dw_type_t {
425 LONG64 low;
426 LONG64 high;
428#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
429 InterlockedCompareExchange128(&d.low, e.high, e.low, &c.low)
430#else // _WIN64
431typedef struct fiftyone_degrees_interlock_dw_type_t {
432 LONG64 value;
434#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
435 InterlockedCompareExchange64(&d.value, e.value, c.value) == c.value
436#endif // _WIN64
437#else // _MSC_VER
438#if (defined(_LP64) || defined(__MINGW64__))
439typedef struct fiftyone_degrees_interlock_dw_type_t {
440 int64_t low;
441 int64_t high;
442} __attribute__((aligned(16),packed)) fiftyoneDegreesInterlockDoubleWidth;
443#else // _LP64
444typedef struct fiftyone_degrees_interlock_dw_type_t {
445 int64_t value;
447#endif //_LP64
448#define FIFTYONE_DEGREES_INTERLOCK_EXCHANGE_DW(d,e,c) \
449 (__atomic_compare_exchange( \
450 (fiftyoneDegreesInterlockDoubleWidth*)&d, \
451 (fiftyoneDegreesInterlockDoubleWidth*)&c, \
452 (fiftyoneDegreesInterlockDoubleWidth*)&e, \
453 false, \
454 __ATOMIC_SEQ_CST, \
455 __ATOMIC_SEQ_CST))
456#endif // _MSC_VER
457
458
459#ifdef _MSC_VER
460#ifdef _WIN64
461#define FIFTYONE_DEGREES_IS_LOCK_FREE IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE128)
462#else
463#define FIFTYONE_DEGREES_IS_LOCK_FREE true
464#endif
465#else
466#define FIFTYONE_DEGREES_IS_LOCK_FREE __atomic_is_lock_free(sizeof(fiftyoneDegreesInterlockDoubleWidth), NULL)
467#endif
468
472
473#endif
pthread_mutex_t fiftyoneDegreesMutex
MUTEX AND THREADING MACROS.
Definition threading.h:112
void fiftyoneDegreesMutexUnlock(fiftyoneDegreesMutex *mutex)
Unlocks the mutex passed to the method.
void fiftyoneDegreesSignalClose(fiftyoneDegreesSignal *signal)
Closes the signal ensuring there is a lock on the signal before destroying the signal.
void fiftyoneDegreesMutexCreate(fiftyoneDegreesMutex *mutex)
Initialises the mutex passed to the method.
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.
uint16_t fiftyoneDegreesThreadingGetProcessorCount()
Gets the number of processors the system has online, which is the default for the number of operation...
void fiftyoneDegreesSignalSet(fiftyoneDegreesSignal *signal)
If the signal has not been destroyed then sends a signal to a waiting thread that the signal has been...
fiftyoneDegreesSignal * fiftyoneDegreesSignalCreate()
Initialises the signal pointer by setting the condition first followed by the mutex if the condition ...
void fiftyoneDegreesMutexClose(fiftyoneDegreesMutex *mutex)
Closes the mutex passed to the method.
void fiftyoneDegreesMutexLock(fiftyoneDegreesMutex *mutex)
Locks the mutex passed to the method.
Double width (64 or 128 depending on the architecture) compare and exchange.
Definition threading.h:444
A signal used to limit the number of items that can be created by the pool.
Definition threading.h:142
pthread_cond_t cond
Condition variable for the signal.
Definition threading.h:144
pthread_mutex_t mutex
Mutex for the signal.
Definition threading.h:145
volatile bool wait
Flag indicating if the thread should wait.
Definition threading.h:143