-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcall_once.h
92 lines (77 loc) · 2.29 KB
/
call_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
#pragma once
// https://godbolt.org/z/WjWfEhbde
#ifndef __GNUC__
#error GCC or clang is required
#endif
#if __STDC_VERSION__ < 201112L
#error C11 or better is required
#endif
#include <stdio.h>
// http://open-std.org/jtc1/sc22/wg14/www/docs/n2840.htm
#include <stdatomic.h>
typedef _Atomic(unsigned) once_flag;
#define ONCE_FLAG_INIT 0u
void call_once(once_flag *flag, void (*func)(void)) {
unsigned actual = atomic_load_explicit(flag, memory_order_acquire);
if (actual < 2u) {
switch (actual) {
case 0u:
// The very first sets this to 1 and then to 2 to indicate that the function has been run.
if (atomic_compare_exchange_strong_explicit(flag, &(unsigned){ 0 }, 1u, memory_order_relaxed, memory_order_relaxed)) {
func();
atomic_store_explicit(flag, 2u, memory_order_release);
return;
}
// we lose and fall through
case 1u:
while (atomic_load_explicit(flag, memory_order_acquire) < 2u) {
// active polling or some sleep if supported
}
}
}
}
#ifndef __GNUC__
#error GCC or clang is required
#endif
#if __STDC_VERSION__ < 201112L
#error C11 or better is required
#endif
#include <stdio.h>
// http://open-std.org/jtc1/sc22/wg14/www/docs/n2840.htm
#include <stdatomic.h>
typedef _Atomic(unsigned) once_flag;
#define ONCE_FLAG_INIT 0u
void call_once(once_flag *flag, void (*func)(void)) {
unsigned actual = atomic_load_explicit(flag, memory_order_acquire);
if (actual < 2u) {
switch (actual) {
case 0u:
// The very first sets this to 1 and then to 2 to indicate that the function has been run.
if (atomic_compare_exchange_strong_explicit(flag, &(unsigned){ 0 }, 1u, memory_order_relaxed, memory_order_relaxed)) {
func();
atomic_store_explicit(flag, 2u, memory_order_release);
return;
}
// we lose and fall through
case 1u:
while (atomic_load_explicit(flag, memory_order_acquire) < 2u) {
// active polling or some sleep if supported
}
}
}
}
#ifdef DBJ_TESTING_CALL_ONCE
#include <stdio.h>
static void on_startup (void)
{
printf("\nStarted!\n");
}
int main (int argc, char ** argv)
{
once_flag flag_ ;
call_once(&flag_, on_startup);
return 42;
}
#endif // DBJ_TESTING_CALL_ONCE
#endif // __STDC_VERSION__ >= 201112L
#endif // __GNUC__