From: Mathieu Desnoyers Date: Tue, 15 May 2012 20:19:07 +0000 (-0400) Subject: Implement urcu/tls-compat.h X-Git-Tag: v0.7.0~6 X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=commitdiff_plain;h=4d0d66bb795d1ed938e11a97a4e5f71326e20c71 Implement urcu/tls-compat.h Suggested-by: Marek VavruĊĦa Signed-off-by: Mathieu Desnoyers --- diff --git a/Makefile.am b/Makefile.am index 0a369fd..6263057 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,7 +18,8 @@ nobase_dist_include_HEADERS = urcu/compiler.h urcu/hlist.h urcu/list.h \ urcu/ref.h urcu/cds.h urcu/urcu_ref.h urcu/urcu-futex.h \ urcu/uatomic_arch.h urcu/rculfhash.h \ $(top_srcdir)/urcu/map/*.h \ - $(top_srcdir)/urcu/static/*.h + $(top_srcdir)/urcu/static/*.h \ + urcu/tls-compat.h nobase_nodist_include_HEADERS = urcu/arch.h urcu/uatomic.h urcu/config.h EXTRA_DIST = $(top_srcdir)/urcu/arch/*.h $(top_srcdir)/urcu/uatomic/*.h \ diff --git a/urcu/tls-compat.h b/urcu/tls-compat.h new file mode 100644 index 0000000..d7c7537 --- /dev/null +++ b/urcu/tls-compat.h @@ -0,0 +1,99 @@ +#ifndef _URCU_TLS_COMPAT_H +#define _URCU_TLS_COMPAT_H + +/* + * urcu/tls-compat.h + * + * Userspace RCU library - Thread-Local Storage Compatibility Header + * + * Copyright 2012 - Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_RCU_TLS /* Based on ax_tls.m4 */ + +# define DECLARE_URCU_TLS(type, name) \ + CONFIG_RCU_TLS type __tls_ ## name + +# define DEFINE_URCU_TLS(type, name) \ + CONFIG_RCU_TLS type __tls_ ## name + +# define URCU_TLS(name) (__tls_ ## name) + +#else /* #ifndef CONFIG_RCU_TLS */ + +# include + +struct urcu_tls { + pthread_key_t key; + pthread_mutex_t init_mutex; + int init_done; +}; + +# define DECLARE_URCU_TLS(type, name) \ + type *__tls_access_ ## name(void) + +/* + * 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) \ + { \ + static struct urcu_tls __tls_ ## name = { \ + .init_mutex = PTHREAD_MUTEX_INITIALIZER,\ + .init_done = 0, \ + }; \ + void *__tls_p; \ + if (!__tls_ ## name.init_done) { \ + /* Mutex to protect concurrent init */ \ + pthread_mutex_lock(&__tls_ ## name.init_mutex); \ + if (!__tls_ ## name.init_done) { \ + (void) pthread_key_create(&__tls_ ## name.key, \ + free); \ + cmm_smp_wmb(); /* create key before write init_done */ \ + __tls_ ## name.init_done = 1; \ + } \ + pthread_mutex_unlock(&__tls_ ## name.init_mutex); \ + } \ + cmm_smp_rmb(); /* read init_done before getting key */ \ + __tls_p = pthread_getspecific(__tls_ ## name.key); \ + if (caa_unlikely(__tls_p == NULL)) { \ + __tls_p = calloc(1, sizeof(type)); \ + (void) pthread_setspecific(__tls_ ## name.key, \ + __tls_p); \ + } \ + return __tls_p; \ + } + +# define URCU_TLS(name) (*__tls_access_ ## name()) + +#endif /* #else #ifndef CONFIG_RCU_TLS */ + +#ifdef __cplusplus +} +#endif + +#endif /* _URCU_TLS_COMPAT_H */