1 // SPDX-FileCopyrightText: 2012 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com> 2 // 3 // SPDX-License-Identifier: LGPL-2.1-or-later 4 5 #ifndef _URCU_TLS_COMPAT_H 6 #define _URCU_TLS_COMPAT_H 7 8 /* 9 * Userspace RCU library - Thread-Local Storage Compatibility Header 10 */ 11 12 #include <stdlib.h> 13 #include <urcu/config.h> 14 #include <urcu/compiler.h> 15 #include <urcu/arch.h> 16 17 #ifdef __cplusplus 18 extern "C" { 19 #endif 20 21 #ifdef CONFIG_RCU_TLS 22 23 /* 24 * Default to '__thread' on all C and C++ compilers except MSVC. While C11 has 25 * '_Thread_local' and C++11 has 'thread_local', only '__thread' seems to have 26 * a compatible implementation when linking public extern symbols across 27 * language boundaries. 28 * 29 * For more details, see 'https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html'. 30 */ 31 #if defined(_MSC_VER) 32 # define URCU_TLS_STORAGE_CLASS __declspec(thread) 33 #else 34 # define URCU_TLS_STORAGE_CLASS __thread 35 #endif 36 37 /* 38 * Hint: How to define/declare TLS variables of compound types 39 * such as array or function pointers? 40 * 41 * Answer: Use typedef to assign a type_name to the compound type. 42 * Example: Define a TLS variable which is an int array with len=4: 43 * 44 * typedef int my_int_array_type[4]; 45 * DEFINE_URCU_TLS(my_int_array_type, var_name); 46 * 47 * Another example: 48 * typedef void (*call_rcu_flavor)(struct rcu_head *, XXXX); 49 * DECLARE_URCU_TLS(call_rcu_flavor, p_call_rcu); 50 * 51 * NOTE: URCU_TLS() is NOT async-signal-safe, you can't use it 52 * inside any function which can be called from signal handler. 53 * 54 * But if pthread_getspecific() is async-signal-safe in your 55 * platform, you can make URCU_TLS() async-signal-safe via: 56 * ensuring the first call to URCU_TLS() of a given TLS variable of 57 * all threads is called earliest from a non-signal handler function. 58 * 59 * Example: In any thread, the first call of URCU_TLS(rcu_reader) 60 * is called from rcu_register_thread(), so we can ensure all later 61 * URCU_TLS(rcu_reader) in any thread is async-signal-safe. 62 * 63 * Moreover, URCU_TLS variables should not be touched from signal 64 * handlers setup with with sigaltstack(2). 65 */ 66 67 # define DECLARE_URCU_TLS(type, name) \ 68 URCU_TLS_STORAGE_CLASS type name 69 70 # define DEFINE_URCU_TLS(type, name) \ 71 URCU_TLS_STORAGE_CLASS type name 72 73 # define DEFINE_URCU_TLS_INIT(type, name, init) \ 74 URCU_TLS_STORAGE_CLASS type name = (init) 75 76 # define URCU_TLS(name) (name) 77 78 #else /* #ifndef CONFIG_RCU_TLS */ 79 80 /* 81 * The *_1() macros ensure macro parameters are expanded. 82 */ 83 84 # include <pthread.h> 85 86 struct urcu_tls { 87 pthread_key_t key; 88 pthread_mutex_t init_mutex; 89 int init_done; 90 }; 91 92 # define DECLARE_URCU_TLS_1(type, name) \ 93 type *__tls_access_ ## name(void) 94 # define DECLARE_URCU_TLS(type, name) \ 95 DECLARE_URCU_TLS_1(type, name) 96 97 /* 98 * Note: we don't free memory at process exit, since it will be dealt 99 * with by the OS. 100 */ 101 # define DEFINE_URCU_TLS_INIT_1(type, name, do_init) \ 102 type *__tls_access_ ## name(void) \ 103 { \ 104 static struct urcu_tls __tls_ ## name = { \ 105 .key = 0, \ 106 .init_mutex = PTHREAD_MUTEX_INITIALIZER,\ 107 .init_done = 0, \ 108 }; \ 109 __typeof__(type) *__tls_p; \ 110 if (!__tls_ ## name.init_done) { \ 111 /* Mutex to protect concurrent init */ \ 112 pthread_mutex_lock(&__tls_ ## name.init_mutex); \ 113 if (!__tls_ ## name.init_done) { \ 114 (void) pthread_key_create(&__tls_ ## name.key, \ 115 free); \ 116 cmm_smp_wmb(); /* create key before write init_done */ \ 117 __tls_ ## name.init_done = 1; \ 118 } \ 119 pthread_mutex_unlock(&__tls_ ## name.init_mutex); \ 120 } \ 121 cmm_smp_rmb(); /* read init_done before getting key */ \ 122 __tls_p = (__typeof__(type) *) pthread_getspecific(__tls_ ## name.key); \ 123 if (caa_unlikely(__tls_p == NULL)) { \ 124 __tls_p = (__typeof__(type) *) calloc(1, sizeof(type)); \ 125 do_init \ 126 (void) pthread_setspecific(__tls_ ## name.key, \ 127 __tls_p); \ 128 } \ 129 return __tls_p; \ 130 } 131 132 # define _URCU_TLS_INIT(init) \ 133 *__tls_p = (init); 134 135 # define DEFINE_URCU_TLS_INIT(type, name, init) \ 136 DEFINE_URCU_TLS_INIT_1(type, name, _URCU_TLS_INIT(init)) 137 138 # define DEFINE_URCU_TLS(type, name) \ 139 DEFINE_URCU_TLS_INIT_1(type, name, /* empty */) 140 141 # define URCU_TLS_1(name) (*__tls_access_ ## name()) 142 143 # define URCU_TLS(name) URCU_TLS_1(name) 144 145 #endif /* #else #ifndef CONFIG_RCU_TLS */ 146 147 #ifdef __cplusplus 148 } 149 #endif 150 151 #endif /* _URCU_TLS_COMPAT_H */ 152