forked from travisdowns/avx-turbo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
once.h
128 lines (118 loc) · 4.17 KB
/
once.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* Once (v1)
* Portable Snippets - https://gitub.com/nemequ/portable-snippets
* Created by Evan Nemerson <[email protected]>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*/
#if !defined(PSNIP_ONCE__H)
#define PSNIP_ONCE__H
#define PSNIP_ONCE__BACKEND_ATOMIC 1
#define PSNIP_ONCE__BACKEND_PTHREAD 2
#define PSNIP_ONCE__BACKEND_NONE 3
#define PSNIP_ONCE__BACKEND_C11 11
#define PSNIP_ONCE__BACKEND_WIN32 32
#if !defined(PSNIP_ONCE_BACKEND)
# if defined(__STDC_NO_THREADS__) && __STDC_NO_THREADS__
# elif defined(__EMSCRIPTEN__)
# elif defined(__has_include)
# if __has_include(<threads.h>)
# include <threads.h>
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_C11
# endif
# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L) && !defined(__STDC_NO_THREADS__)
# include <limits.h>
# if defined(__STDC_NO_THREADS__) || (defined(__GNUC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 16)))
/* stdc-predef.h didn't include __STDC_NO_THREADS__ until 2.16. icc
doesn't include stdc-predef.h until we pull in limits.h, so the
first check doesn't work. */
# else
# include <threads.h>
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_C11
# endif
# endif
#endif
#if !defined(PSNIP_ONCE_BACKEND) && defined(_WIN32) && (!defined(WINVER) || (defined(WINVER) && (WINVER >= 0x0600)))
# include <Windows.h>
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_WIN32
#endif
#if !defined(PSNIP_ONCE_BACKEND) && defined(PTHREAD_ONCE_INIT)
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_PTHREAD
#endif
#if !defined(PSNIP_ONCE_BACKEND)
# include "atomic.h"
# if !defined(PSNIP_ATOMIC_NOT_FOUND)
# define PSNIP_ONCE_BACKEND PSNIP_ONCE__BACKEND_ATOMIC
# endif
#endif
#if !defined(PSNIP_ONCE_BACKEND)
# error No once backend found.
#endif
#if defined(__GNUC__) && (__GNUC__ >= 3)
# define PSNIP_ONCE__UNLIKELY(expr) __builtin_expect(!!(expr), !!0)
#else
# define PSNIP_ONCE__UNLIKELY(expr) (!!(expr))
#endif
#if PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_C11
# define PSNIP_ONCE_INIT ONCE_FLAG_INIT
typedef once_flag psnip_once;
# define psnip_once_call(flag, func) call_once(flag, func)
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_PTHREAD
# define PSNIP_ONCE_INIT PTHREAD_ONCE_INIT
typedef pthread_once_t psnip_once;
# define psnip_once_call(flag, func) pthread_once(flag, func)
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_WIN32
# define PSNIP_ONCE_INIT INIT_ONCE_STATIC_INIT
typedef INIT_ONCE psnip_once;
static BOOL CALLBACK psnip_once__callback_wrap(INIT_ONCE* InitOnce, void* Parameter, void** Context) {
(void) Context;
(void) InitOnce;
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable:4055)
#endif
((void (*)(void)) Parameter)();
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
return !0;
}
# if defined(_MSC_VER) && (_MSC_VER >= 1500)
# define psnip_once_call(flag, func) \
__pragma(warning(push)) \
__pragma(warning(disable:4152)) \
InitOnceExecuteOnce(flag, &psnip_once__callback_wrap, func, NULL) \
__pragma(warning(pop))
# else
# define psnip_once_call(flag, func) InitOnceExecuteOnce(flag, &psnip_once__callback_wrap, func, NULL)
# endif
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_ATOMIC
# define PSNIP_ONCE_INIT PSNIP_ATOMIC_VAR_INIT(0)
typedef psnip_atomic_int32 psnip_once;
static void psnip_once_call(psnip_once* flag, void (*func)(void)) {
psnip_int32_t state = psnip_atomic_int32_load(flag);
if (PSNIP_ONCE__UNLIKELY(state == 0)) {
if (psnip_atomic_int32_compare_exchange(flag, &state, 1)) {
func();
psnip_atomic_int32_store(flag, 2);
} else {
do {
/* Spin; another thread is calling the initialization
function. */
} while (psnip_atomic_int32_load(flag) == 1);
}
}
}
#elif PSNIP_ONCE_BACKEND == PSNIP_ONCE__BACKEND_NONE
# define PSNIP_ONCE_INIT 0
typedef int psnip_once;
static void psnip_once_call(psnip_once* flag, void (*func)(void)) {
if (*flag == 0) {
func();
*flag = 1;
}
}
#endif
#endif /* !defined(PSNIP_ONCE__H) */