Home | History | Annotate | Line # | Download | only in urcu
      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