1 /*
2  * Copyright 2022 Yonggang Luo
3  * SPDX-License-Identifier: MIT
4  *
5  * Extend C11 call_once to support context parameter
6  */
7 
8 #ifndef U_CALL_ONCE_H_
9 #define U_CALL_ONCE_H_
10 
11 #include <stdbool.h>
12 
13 #include "c11/threads.h"
14 #include "macros.h"
15 #include "u_atomic.h"
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 /* The data can be mutable or immutable. */
22 typedef void (*util_call_once_data_func)(const void *data);
23 
24 struct util_once_flag {
25    bool called;
26    once_flag flag;
27 };
28 typedef struct util_once_flag util_once_flag;
29 
30 #define UTIL_ONCE_FLAG_INIT { false, ONCE_FLAG_INIT }
31 
32 /**
33  * This is used to optimize the call to call_once out when the func are
34  * already called and finished, so when util_call_once are called in
35  * hot path it's only incur an extra load instruction cost.
36  */
37 static ALWAYS_INLINE void
util_call_once(util_once_flag * flag,void (* func)(void))38 util_call_once(util_once_flag *flag, void (*func)(void))
39 {
40    if (unlikely(!p_atomic_read_relaxed(&flag->called))) {
41       call_once(&flag->flag, func);
42       p_atomic_set(&flag->called, true);
43    }
44 }
45 
46 /**
47  * @brief Wrapper around call_once to pass data to func
48  */
49 void
50 util_call_once_data_slow(once_flag *once, util_call_once_data_func func, const void *data);
51 
52 /**
53  * This is used to optimize the call to util_call_once_data_slow out when
54  * the func function are already called and finished,
55  * so when util_call_once_data are called in hot path it's only incur an extra
56  * load instruction cost.
57  */
58 static ALWAYS_INLINE void
util_call_once_data(util_once_flag * flag,util_call_once_data_func func,const void * data)59 util_call_once_data(util_once_flag *flag, util_call_once_data_func func, const void *data)
60 {
61    if (unlikely(!p_atomic_read_relaxed(&flag->called))) {
62       util_call_once_data_slow(&(flag->flag), func, data);
63       p_atomic_set(&flag->called, true);
64    }
65 }
66 
67 #ifdef __cplusplus
68 }
69 #endif
70 
71 #endif /* U_CALL_ONCE_H_ */
72