Version 0.7.17
[userspace-rcu.git] / urcu / tls-compat.h
index 9686ecaab139343547151e0f95697324c0442a55..98940a88d3e0ac7f5dec66051e1623cd96b54a6c 100644 (file)
@@ -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 <pthread.h>
 
 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 */
 
This page took 0.023888 seconds and 4 git commands to generate.