1 krisbash 1.1 #ifndef _pal_once_h
2 #define _pal_once_h
3
4 #include "palcommon.h"
5 #include "atomic.h"
6
7 #ifdef _MSC_VER
8 #include <intrin.h>
9 #endif
10
11 PAL_BEGIN_EXTERNC
12
13 typedef struct _Once
14 {
15 void* value;
16 }
17 Once;
18
19 #define ONCE_STATE_INVOKING -2
20 #define ONCE_STATE_NOTINVOKEDYET -1
21
22 krisbash 1.1 #define ONCE_INITIALIZER { (void*)ONCE_STATE_NOTINVOKEDYET }
23
24 typedef _Success_(return == 0) int (*OnceWorkerFunction)(
25 _In_ void* data,
26 _Outptr_result_maybenull_ void** value);
27
28 int __Once_Invoke(
29 _Inout_ Once* self,
30 _In_ OnceWorkerFunction func,
31 _In_ void* data);
32
33 PAL_INLINE int Once_Invoke(
34 _Inout_ Once* self,
35 _In_ OnceWorkerFunction func,
36 _In_ void* data)
37 {
38 int result = 0;
39 void* value = self->value;
40
41 /* To prevent confusing behavior, disallow compiler reordering. */
42 #if defined(_MSC_VER)
43 krisbash 1.1 _ReadBarrier();
44 #elif defined(__GNUC__)
45 asm volatile("" ::: "memory");
46 #else
47 /* Nothing. */
48 #endif
49
50 if ((size_t)value >= (size_t)ONCE_STATE_INVOKING)
51 result = __Once_Invoke(self, func, data);
52
53 return result;
54 }
55
56 /* All callers to Once_Invoke (except _WithBarrier) must dereference
57 * initialized data through this macro. */
58 #define Once_Invoke_Value(self) ((self)->value)
59
60 PAL_INLINE int Once_Invoke_WithBarrier(
61 _Inout_ Once* self,
62 _In_ OnceWorkerFunction func,
63 _In_ void* data)
64 krisbash 1.1 {
65 int result = Once_Invoke(self, func, data);
66
67 NonX86MemoryBarrier();
68 return result;
69 }
70
71 PAL_END_EXTERNC
72
73 #endif /* _pal_once_h */
|