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