From: Mathieu Desnoyers Date: Fri, 1 Nov 2013 19:53:51 +0000 (-0400) Subject: Keep ABI compatible with already compiled LGPL applications X-Git-Tag: v0.7.9~2 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=1745be1a65fcf0398247b03ed30efeeeba52482a;p=userspace-rcu.git Keep ABI compatible with already compiled LGPL applications Applications with _LGPL_SOURCE defined that were compiled against bogus tls-compat.h header *and* which are using multiple urcu flavors concurrently need to be told that they need to be recompiled against a fixed tls-compat.h header. Detect these usage, and abort() with a message error on stderr. This is needed for stable-0.7 and stable-0.8 branches of userspace RCU only. The upcoming 0.9 will bump the soname version, and therefore does not have to care about this aspect of ABI compatibility. Signed-off-by: Mathieu Desnoyers --- diff --git a/tests/test_urcu_hash.c b/tests/test_urcu_hash.c index d5df1eb..3d7ee69 100644 --- a/tests/test_urcu_hash.c +++ b/tests/test_urcu_hash.c @@ -82,13 +82,13 @@ int (*get_populate_hash_cb(void))(void) return test_hash_cb[test_choice].populate_hash; } -DEFINE_URCU_TLS(unsigned int, rand_lookup); -DEFINE_URCU_TLS(unsigned long, nr_add); -DEFINE_URCU_TLS(unsigned long, nr_addexist); -DEFINE_URCU_TLS(unsigned long, nr_del); -DEFINE_URCU_TLS(unsigned long, nr_delnoent); -DEFINE_URCU_TLS(unsigned long, lookup_fail); -DEFINE_URCU_TLS(unsigned long, lookup_ok); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rand_lookup); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_add); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_addexist); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_del); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_delnoent); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, lookup_fail); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, lookup_ok); struct cds_lfht *test_ht; diff --git a/urcu-bp.c b/urcu-bp.c index 71474bc..0963dd0 100644 --- a/urcu-bp.c +++ b/urcu-bp.c @@ -105,7 +105,7 @@ static pthread_key_t urcu_bp_key; #ifdef DEBUG_YIELD unsigned int yield_active; -DEFINE_URCU_TLS(unsigned int, rand_yield); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rand_yield); #endif /* @@ -120,7 +120,7 @@ long rcu_gp_ctr = RCU_GP_COUNT; * Pointer to registry elements. Written to only by each individual reader. Read * by both the reader and the writers. */ -DEFINE_URCU_TLS(struct rcu_reader *, rcu_reader); +__DEFINE_URCU_TLS_GLOBAL(struct rcu_reader *, rcu_reader); static CDS_LIST_HEAD(registry); diff --git a/urcu-qsbr.c b/urcu-qsbr.c index d3a6849..ec483d9 100644 --- a/urcu-qsbr.c +++ b/urcu-qsbr.c @@ -69,11 +69,11 @@ unsigned long rcu_gp_ctr = RCU_GP_ONLINE; * Written to only by each individual reader. Read by both the reader and the * writers. */ -DEFINE_URCU_TLS(struct rcu_reader, rcu_reader); +__DEFINE_URCU_TLS_GLOBAL(struct rcu_reader, rcu_reader); #ifdef DEBUG_YIELD unsigned int yield_active; -DEFINE_URCU_TLS(unsigned int, rand_yield); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rand_yield); #endif static CDS_LIST_HEAD(registry); diff --git a/urcu.c b/urcu.c index a5178c0..7c03d90 100644 --- a/urcu.c +++ b/urcu.c @@ -97,11 +97,11 @@ unsigned long rcu_gp_ctr = RCU_GP_COUNT; * Written to only by each individual reader. Read by both the reader and the * writers. */ -DEFINE_URCU_TLS(struct rcu_reader, rcu_reader); +__DEFINE_URCU_TLS_GLOBAL(struct rcu_reader, rcu_reader); #ifdef DEBUG_YIELD unsigned int yield_active; -DEFINE_URCU_TLS(unsigned int, rand_yield); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rand_yield); #endif static CDS_LIST_HEAD(registry); diff --git a/urcu/tls-compat.h b/urcu/tls-compat.h index fe21cb6..34324e2 100644 --- a/urcu/tls-compat.h +++ b/urcu/tls-compat.h @@ -70,12 +70,20 @@ extern "C" { # 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 @@ -87,7 +95,8 @@ struct urcu_tls { }; # define DECLARE_URCU_TLS_1(type, name) \ - type *__tls_access_ ## name(void) + type *__tls_access2_ ## name(void) + # define DECLARE_URCU_TLS(type, name) \ DECLARE_URCU_TLS_1(type, name) @@ -95,8 +104,14 @@ struct urcu_tls { * Note: we don't free memory at process exit, since it will be dealt * with by the OS. */ +# 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_access_ ## name(void) \ + type *__tls_access2_ ## name(void) \ { \ static struct urcu_tls __tls_ ## name = { \ .init_mutex = PTHREAD_MUTEX_INITIALIZER,\ @@ -124,10 +139,32 @@ struct urcu_tls { return __tls_p; \ } +/* + * Define with an 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_access_ ## name()) +# define URCU_TLS_1(name) (*__tls_access2_ ## name()) # define URCU_TLS(name) URCU_TLS_1(name)