X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=urcu%2Ftls-compat.h;h=98940a88d3e0ac7f5dec66051e1623cd96b54a6c;hb=refs%2Fheads%2Fstable-0.7;hp=9686ecaab139343547151e0f95697324c0442a55;hpb=3db1417f5d2f17fdb62f328650c888ae3097c4c5;p=userspace-rcu.git diff --git a/urcu/tls-compat.h b/urcu/tls-compat.h index 9686eca..98940a8 100644 --- a/urcu/tls-compat.h +++ b/urcu/tls-compat.h @@ -34,16 +34,58 @@ extern "C" { #ifdef CONFIG_RCU_TLS /* Based on ax_tls.m4 */ +/* + * Hint: How to define/declare TLS variables of compound types + * such as array or function pointers? + * + * Answer: Use typedef to assign a type_name to the compound type. + * Example: Define a TLS variable which is an int array with len=4: + * + * typedef int my_int_array_type[4]; + * DEFINE_URCU_TLS(my_int_array_type, var_name); + * + * Another exmaple: + * typedef void (*call_rcu_flavor)(struct rcu_head *, XXXX); + * DECLARE_URCU_TLS(call_rcu_flavor, p_call_rcu); + * + * NOTE: URCU_TLS() is NOT async-signal-safe, you can't use it + * inside any function which can be called from signal handler. + * + * But if pthread_getspecific() is async-signal-safe in your + * platform, you can make URCU_TLS() async-signal-safe via: + * ensuring the first call to URCU_TLS() of a given TLS variable of + * all threads is called earliest from a non-signal handler function. + * + * Example: In any thread, the first call of URCU_TLS(rcu_reader) + * is called from rcu_register_thread(), so we can ensure all later + * URCU_TLS(rcu_reader) in any thread is async-signal-safe. + * + * Moreover, URCU_TLS variables should not be touched from signal + * handlers setup with with sigaltstack(2). + */ + # define DECLARE_URCU_TLS(type, name) \ CONFIG_RCU_TLS type name # define DEFINE_URCU_TLS(type, name) \ CONFIG_RCU_TLS type name +# define __DEFINE_URCU_TLS_GLOBAL(type, name) \ + CONFIG_RCU_TLS type name + # define URCU_TLS(name) (name) #else /* #ifndef CONFIG_RCU_TLS */ +/* + * The *_1() macros ensure macro parameters are expanded. + * + * __DEFINE_URCU_TLS_GLOBAL and __URCU_TLS_CALL exist for the sole + * purpose of notifying applications compiled against non-fixed 0.7 and + * 0.8 userspace RCU headers and using multiple flavors concurrently to + * recompile against fixed userspace RCU headers. + */ + # include struct urcu_tls { @@ -52,15 +94,24 @@ struct urcu_tls { int init_done; }; +# define DECLARE_URCU_TLS_1(type, name) \ + type *__tls_access2_ ## name(void) + # define DECLARE_URCU_TLS(type, name) \ - type *__tls_access_ ## name(void) + DECLARE_URCU_TLS_1(type, name) /* * Note: we don't free memory at process exit, since it will be dealt * with by the OS. */ -# define DEFINE_URCU_TLS(type, name) \ - type *__tls_access_ ## name(void) \ +# define __URCU_TLS_CALL_1(name) \ + __tls_access2_ ## name + +# define __URCU_TLS_CALL(name) \ + __URCU_TLS_CALL_1(name) + +# define DEFINE_URCU_TLS_1(type, name) \ + type *__tls_access2_ ## name(void) \ { \ static struct urcu_tls __tls_ ## name = { \ .init_mutex = PTHREAD_MUTEX_INITIALIZER,\ @@ -88,7 +139,34 @@ struct urcu_tls { return __tls_p; \ } -# define URCU_TLS(name) (*__tls_access_ ## name()) +/* + * Define with and without macro expansion to handle erroneous callers. + * Trigger an abort() if the caller application uses the clashing symbol + * if a weak symbol is overridden. + */ +# define __DEFINE_URCU_TLS_GLOBAL(type, name) \ + DEFINE_URCU_TLS_1(type, name) \ + int __urcu_tls_symbol_refcount_ ## name __attribute__((weak)); \ + static __attribute__((constructor)) \ + void __urcu_tls_inc_refcount_ ## name(void) \ + { \ + __urcu_tls_symbol_refcount_ ## name++; \ + } \ + type *__tls_access_ ## name(void) \ + { \ + if (__urcu_tls_symbol_refcount_ ## name > 1) { \ + fprintf(stderr, "Error: Userspace RCU symbol clash for multiple concurrent flavors. Please upgrade liburcu libraries and headers, then recompile your application.\n"); \ + abort(); \ + } \ + return __URCU_TLS_CALL(name)(); \ + } + +# define DEFINE_URCU_TLS(type, name) \ + DEFINE_URCU_TLS_1(type, name) + +# define URCU_TLS_1(name) (*__tls_access2_ ## name()) + +# define URCU_TLS(name) URCU_TLS_1(name) #endif /* #else #ifndef CONFIG_RCU_TLS */