From mboxrd@z Thu Jan 1 00:00:00 1970 From: compudj@krystal.dyndns.org (Mathieu Desnoyers) Date: Tue, 31 Jan 2012 13:23:49 -0500 Subject: [lttng-dev] liburcu patch for compilers without __thread support In-Reply-To: References: Message-ID: <20120131182349.GA13630@Krystal> Hi Marek, * Marek Vavru?a (marek.vavrusa at nic.cz) wrote: > Hello, > > we're using liburcu for our DNS server. It's really clever, but we > needed to get it running under NetBSD/OpenBSD and OS X. > Since compilers on those platform don't have support for __thread > keyword, I have made a patch that detects such a compiler > and uses compatibility implementation with > pthread_getspecific()/pthread_setspecific(). I have attempted to make > it as least intrusive > as possible. TLS variables are now declared/defined with a set of > macros in urcu/tls-compat.h > > The patch is against the latest release tag v0.6.7 (git format-patch), > but should work with latest git head save for configure.ac > Please let me know what you think and how could we incorporate it to upstream. I agree that this is needed. Some comments below, > From 998d005870782ed52ba0fe66a99589dc8b7eb20e Mon Sep 17 00:00:00 2001 > From: Marek Vavrusa > Date: Mon, 30 Jan 2012 16:40:12 +0100 > Subject: [PATCH] Compatibility for compilers without TLS support. > > If TLS is detected on configure, it is used as before. > If not, it is emulated using pthread_setspecific()/pthread_getspecific() > and set of macros. > > For usage info, see urcu/tls-compat.h Please add your Signed-off-by: > --- > .gitignore | 1 - > configure.ac | 3 + > m4/ax_tls.m4 | 76 ++++++++++++++++++++++++++++++++ > tests/test_mutex.c | 8 +++- > tests/test_perthreadlock.c | 8 +++- > tests/test_rwlock.c | 8 +++- > tests/test_urcu.c | 8 +++- > tests/test_urcu_assign.c | 8 +++- > tests/test_urcu_bp.c | 8 +++- > tests/test_urcu_defer.c | 8 +++- > tests/test_urcu_gc.c | 8 +++- > tests/test_urcu_lfq.c | 14 ++++-- > tests/test_urcu_lfs.c | 14 ++++-- > tests/test_urcu_qsbr.c | 8 +++- > tests/test_urcu_qsbr_gc.c | 8 +++- > tests/test_urcu_wfq.c | 14 ++++-- > tests/test_urcu_wfs.c | 14 ++++-- > urcu-bp.c | 10 +++-- > urcu-call-rcu-impl.h | 26 +++++++++++- > urcu-defer-impl.h | 49 +++++++++++--------- > urcu-qsbr.c | 18 ++++--- > urcu.c | 22 +++++---- > urcu/map/urcu-bp.h | 2 + > urcu/map/urcu-qsbr.h | 2 + > urcu/map/urcu.h | 4 ++ > urcu/static/urcu-bp.h | 18 +++++--- > urcu/static/urcu-qsbr.h | 22 ++++++---- > urcu/static/urcu.h | 21 ++++++--- > urcu/tls-compat.h | 104 ++++++++++++++++++++++++++++++++++++++++++++ > 29 files changed, 408 insertions(+), 106 deletions(-) > create mode 100644 m4/ax_tls.m4 > create mode 100644 urcu/tls-compat.h > > diff --git a/.gitignore b/.gitignore > index 6eeb2a1..7af5609 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -71,7 +71,6 @@ tests/*.log > .libs/ > Makefile.in > Makefile > -*.m4 > *.la > *.bz2 > *.o > diff --git a/configure.ac b/configure.ac > index 5a90008..1953a8a 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -14,6 +14,9 @@ AC_CANONICAL_HOST > AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip]) > m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) > > +AC_CONFIG_MACRO_DIR([m4]) > +m4_include([m4/ax_tls.m4]) > + > AC_CONFIG_SRCDIR([urcu.h]) > AM_PROG_MKDIR_P > > diff --git a/m4/ax_tls.m4 b/m4/ax_tls.m4 > new file mode 100644 > index 0000000..033e3b1 > --- /dev/null > +++ b/m4/ax_tls.m4 > @@ -0,0 +1,76 @@ > +# =========================================================================== > +# http://www.gnu.org/software/autoconf-archive/ax_tls.html > +# =========================================================================== > +# > +# SYNOPSIS > +# > +# AX_TLS([action-if-found], [action-if-not-found]) > +# > +# DESCRIPTION > +# > +# Provides a test for the compiler support of thread local storage (TLS) > +# extensions. Defines TLS if it is found. Currently knows about GCC/ICC > +# and MSVC. I think SunPro uses the same as GCC, and Borland apparently > +# supports either. > +# > +# LICENSE > +# > +# Copyright (c) 2008 Alan Woodland > +# Copyright (c) 2010 Diego Elio Petteno` > +# > +# This program is free software: you can redistribute it and/or modify it > +# under the terms of the GNU General Public License as published by the > +# Free Software Foundation, either version 3 of the License, or (at your > +# option) any later version. > +# > +# This program 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 General > +# Public License for more details. > +# > +# You should have received a copy of the GNU General Public License along > +# with this program. If not, see . > +# > +# As a special exception, the respective Autoconf Macro's copyright owner > +# gives unlimited permission to copy, distribute and modify the configure > +# scripts that are the output of Autoconf when processing the Macro. You > +# need not follow the terms of the GNU General Public License when using > +# or distributing such scripts, even though portions of the text of the > +# Macro appear in them. The GNU General Public License (GPL) does govern > +# all other use of the material that constitutes the Autoconf Macro. > +# > +# This special exception to the GPL applies to versions of the Autoconf > +# Macro released by the Autoconf Archive. When you make and distribute a > +# modified version of the Autoconf Macro, you may extend this special > +# exception to the GPL to apply to your modified version as well. > + > +#serial 10 > + > +AC_DEFUN([AX_TLS], [ > + AC_MSG_CHECKING(for thread local storage (TLS) class) > + AC_CACHE_VAL(ac_cv_tls, [ > + ax_tls_keywords="__thread __declspec(thread) none" > + for ax_tls_keyword in $ax_tls_keywords; do > + AS_CASE([$ax_tls_keyword], > + [none], [ac_cv_tls=none ; break], > + [AC_TRY_COMPILE( > + [#include > + static void > + foo(void) { > + static ] $ax_tls_keyword [ int bar; > + exit(1); > + }], > + [], > + [ac_cv_tls=$ax_tls_keyword ; break], > + ac_cv_tls=none > + )]) > + done > + ]) > + AC_MSG_RESULT($ac_cv_tls) > + > + AS_IF([test "$ac_cv_tls" != "none"], > + AC_DEFINE_UNQUOTED([TLS], $ac_cv_tls, [If the compiler supports a TLS storage class define it to that here]) > + m4_ifnblank([$1], [$1]), > + m4_ifnblank([$2], [$2]) > + ) > +]) > diff --git a/tests/test_mutex.c b/tests/test_mutex.c > index 3f84bbf..bb73f1c 100644 > --- a/tests/test_mutex.c > +++ b/tests/test_mutex.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -155,8 +157,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static > unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes; > diff --git a/tests/test_perthreadlock.c b/tests/test_perthreadlock.c > index fa9c89a..14362cf 100644 > --- a/tests/test_perthreadlock.c > +++ b/tests/test_perthreadlock.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -159,8 +161,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static > unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes; > diff --git a/tests/test_rwlock.c b/tests/test_rwlock.c > index 34d8c07..087ff58 100644 > --- a/tests/test_rwlock.c > +++ b/tests/test_rwlock.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -156,8 +158,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static unsigned int nr_readers; > static unsigned int nr_writers; > diff --git a/tests/test_urcu.c b/tests/test_urcu.c > index 870f133..cf8e12e 100644 > --- a/tests/test_urcu.c > +++ b/tests/test_urcu.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -154,8 +156,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static unsigned int nr_readers; > static unsigned int nr_writers; > diff --git a/tests/test_urcu_assign.c b/tests/test_urcu_assign.c > index 42d70c2..55eab0c 100644 > --- a/tests/test_urcu_assign.c > +++ b/tests/test_urcu_assign.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -154,8 +156,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static unsigned int nr_readers; > static unsigned int nr_writers; > diff --git a/tests/test_urcu_bp.c b/tests/test_urcu_bp.c > index 857913f..08170b6 100644 > --- a/tests/test_urcu_bp.c > +++ b/tests/test_urcu_bp.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -154,8 +156,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static unsigned int nr_readers; > static unsigned int nr_writers; > diff --git a/tests/test_urcu_defer.c b/tests/test_urcu_defer.c > index 1575e9c..c5aeeb4 100644 > --- a/tests/test_urcu_defer.c > +++ b/tests/test_urcu_defer.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program (with automatic reclamation) > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -155,8 +157,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static > unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes; > diff --git a/tests/test_urcu_gc.c b/tests/test_urcu_gc.c > index 21c5d56..31d3e65 100644 > --- a/tests/test_urcu_gc.c > +++ b/tests/test_urcu_gc.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program (with baatch reclamation) > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -163,8 +165,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static > unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes; > diff --git a/tests/test_urcu_lfq.c b/tests/test_urcu_lfq.c > index 11e7eb3..83db5d1 100644 > --- a/tests/test_urcu_lfq.c > +++ b/tests/test_urcu_lfq.c > @@ -5,6 +5,7 @@ > * > * Copyright February 2010 - Mathieu Desnoyers > * Copyright February 2010 - Paolo Bonzini > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -38,6 +39,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -148,11 +150,15 @@ static int test_duration_enqueue(void) > return !test_stop; > } > > -static unsigned long long __thread nr_dequeues; > -static unsigned long long __thread nr_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_dequeues, _tls_nr_dequeues); > +#define nr_dequeues (*_nr_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_enqueues, _tls_nr_enqueues); > +#define nr_enqueues (*_nr_enqueues()) > > -static unsigned long long __thread nr_successful_dequeues; > -static unsigned long long __thread nr_successful_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_dequeues, _tls_nr_successful_dequeues); > +#define nr_successful_dequeues (*_nr_successful_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_enqueues, _tls_nr_successful_enqueues); > +#define nr_successful_enqueues (*_nr_successful_enqueues()) > > static unsigned int nr_enqueuers; > static unsigned int nr_dequeuers; > diff --git a/tests/test_urcu_lfs.c b/tests/test_urcu_lfs.c > index 883fd0c..79a1ceb 100644 > --- a/tests/test_urcu_lfs.c > +++ b/tests/test_urcu_lfs.c > @@ -5,6 +5,7 @@ > * > * Copyright February 2010 - Mathieu Desnoyers > * Copyright February 2010 - Paolo Bonzini > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -38,6 +39,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -148,11 +150,15 @@ static int test_duration_enqueue(void) > return !test_stop; > } > > -static unsigned long long __thread nr_dequeues; > -static unsigned long long __thread nr_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_dequeues, _tls_nr_dequeues); > +#define nr_dequeues (*_nr_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_enqueues, _tls_nr_enqueues); > +#define nr_enqueues (*_nr_enqueues()) > > -static unsigned long long __thread nr_successful_dequeues; > -static unsigned long long __thread nr_successful_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_dequeues, _tls_nr_successful_dequeues); > +#define nr_successful_dequeues (*_nr_successful_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_enqueues, _tls_nr_successful_enqueues); > +#define nr_successful_enqueues (*_nr_successful_enqueues()) > > static unsigned int nr_enqueuers; > static unsigned int nr_dequeuers; > diff --git a/tests/test_urcu_qsbr.c b/tests/test_urcu_qsbr.c > index b986fd8..eaa4a67 100644 > --- a/tests/test_urcu_qsbr.c > +++ b/tests/test_urcu_qsbr.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -153,8 +155,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static unsigned int nr_readers; > static unsigned int nr_writers; > diff --git a/tests/test_urcu_qsbr_gc.c b/tests/test_urcu_qsbr_gc.c > index 9deb0aa..e65503a 100644 > --- a/tests/test_urcu_qsbr_gc.c > +++ b/tests/test_urcu_qsbr_gc.c > @@ -4,6 +4,7 @@ > * Userspace RCU library - test program (with baatch reclamation) > * > * Copyright February 2009 - Mathieu Desnoyers > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -35,6 +36,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -159,8 +161,10 @@ static int test_duration_read(void) > return !test_stop; > } > > -static unsigned long long __thread nr_writes; > -static unsigned long long __thread nr_reads; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_writes, _tls_nr_writes); > +#define nr_writes (*_nr_writes()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_reads, _tls_nr_reads); > +#define nr_reads (*_nr_reads()) > > static unsigned int nr_readers; > static unsigned int nr_writers; > diff --git a/tests/test_urcu_wfq.c b/tests/test_urcu_wfq.c > index 83ec635..32156dc 100644 > --- a/tests/test_urcu_wfq.c > +++ b/tests/test_urcu_wfq.c > @@ -5,6 +5,7 @@ > * > * Copyright February 2010 - Mathieu Desnoyers > * Copyright February 2010 - Paolo Bonzini > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -38,6 +39,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -147,11 +149,15 @@ static int test_duration_enqueue(void) > return !test_stop; > } > > -static unsigned long long __thread nr_dequeues; > -static unsigned long long __thread nr_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_dequeues, _tls_nr_dequeues); > +#define nr_dequeues (*_nr_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_enqueues, _tls_nr_enqueues); > +#define nr_enqueues (*_nr_enqueues()) > > -static unsigned long long __thread nr_successful_dequeues; > -static unsigned long long __thread nr_successful_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_dequeues, _tls_nr_successful_dequeues); > +#define nr_successful_dequeues (*_nr_successful_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_enqueues, _tls_nr_successful_enqueues); > +#define nr_successful_enqueues (*_nr_successful_enqueues()) > > static unsigned int nr_enqueuers; > static unsigned int nr_dequeuers; > diff --git a/tests/test_urcu_wfs.c b/tests/test_urcu_wfs.c > index 7746a1d..1e78211 100644 > --- a/tests/test_urcu_wfs.c > +++ b/tests/test_urcu_wfs.c > @@ -5,6 +5,7 @@ > * > * Copyright February 2010 - Mathieu Desnoyers > * Copyright February 2010 - Paolo Bonzini > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -38,6 +39,7 @@ > #include > > #include > +#include > > #ifdef __linux__ > #include > @@ -147,11 +149,15 @@ static int test_duration_enqueue(void) > return !test_stop; > } > > -static unsigned long long __thread nr_dequeues; > -static unsigned long long __thread nr_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_dequeues, _tls_nr_dequeues); > +#define nr_dequeues (*_nr_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_enqueues, _tls_nr_enqueues); > +#define nr_enqueues (*_nr_enqueues()) > > -static unsigned long long __thread nr_successful_dequeues; > -static unsigned long long __thread nr_successful_enqueues; > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_dequeues, _tls_nr_successful_dequeues); > +#define nr_successful_dequeues (*_nr_successful_dequeues()) > +TLS_DEFINE_SIMPLE(unsigned long long, _nr_successful_enqueues, _tls_nr_successful_enqueues); > +#define nr_successful_enqueues (*_nr_successful_enqueues()) > > static unsigned int nr_enqueuers; > static unsigned int nr_dequeuers; > diff --git a/urcu-bp.c b/urcu-bp.c > index f3249b4..1b38097 100644 > --- a/urcu-bp.c > +++ b/urcu-bp.c > @@ -5,6 +5,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -35,6 +36,7 @@ > #include > #include > #include > +#include > > #include "urcu/wfqueue.h" > #include "urcu/map/urcu-bp.h" > @@ -94,7 +96,7 @@ static pthread_mutex_t rcu_gp_lock = PTHREAD_MUTEX_INITIALIZER; > > #ifdef DEBUG_YIELD > unsigned int yield_active; > -unsigned int __thread rand_yield; > +TLS_DEFINE(unsigned int, get_rand_yield, _rand_yield); > #endif > > /* > @@ -109,7 +111,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. > */ > -struct rcu_reader __thread *rcu_reader; > +TLS_DEFINE(struct rcu_reader*, rcu_reader, _rcu_reader); > > static CDS_LIST_HEAD(registry); > > @@ -322,7 +324,7 @@ static void add_thread(void) > rcu_reader_reg->tid = pthread_self(); > assert(rcu_reader_reg->ctr == 0); > cds_list_add(&rcu_reader_reg->node, ®istry); > - rcu_reader = rcu_reader_reg; > + *rcu_reader() = rcu_reader_reg; > } > > /* Called with signals off and mutex locked */ > @@ -363,7 +365,7 @@ void rcu_bp_register(void) > /* > * Check if a signal concurrently registered our thread since > * the check in rcu_read_lock(). */ > - if (rcu_reader) > + if (*rcu_reader()) > goto end; > > mutex_lock(&rcu_gp_lock); > diff --git a/urcu-call-rcu-impl.h b/urcu-call-rcu-impl.h > index 36e3cf4..27cb1ac 100644 > --- a/urcu-call-rcu-impl.h > +++ b/urcu-call-rcu-impl.h > @@ -4,6 +4,7 @@ > * Userspace RCU library - batch memory reclamation with kernel API > * > * Copyright (c) 2010 Paul E. McKenney > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -61,8 +62,31 @@ struct call_rcu_data { > CDS_LIST_HEAD(call_rcu_data_list); > > /* Link a thread using call_rcu() to its call_rcu thread. */ > - > +#ifdef TLS > static __thread struct call_rcu_data *thread_call_rcu_data; > +#else > +static pthread_key_t tls_tcrd_key; > +static pthread_once_t tls_tcrd_once = PTHREAD_ONCE_INIT; > +static void tls_tcrd_deinit() { Please use static void fct(void) { } coding style for all your functions. > + void *p = pthread_getspecific(tls_tcrd_key); > + free(p); > +} > +static void tls_tcrd_init() { > + (void)pthread_key_create(&tls_tcrd_key, tls_tcrd_deinit); (void) pthread_key_create(&tls_tcrd_key, tls_tcrd_deinit); (missing space after cast) And instead of casting to void, can you put an assertion on erroneous return values ? > + atexit(tls_tcrd_deinit); > +} > +static struct call_rcu_data **tls_thread_call_rcu_data() { > + (void)pthread_once(&tls_tcrd_once, tls_tcrd_init); Is it possible to use the gcc __attribute__((constructor)) and __attribute__((destructor)) rather than pthread_once/atexit() ? This would be more in line with what we use elsewhere in the library. > + struct call_rcu_data **r = pthread_getspecific(tls_tcrd_key); > + if (r == NULL) { > + r = malloc(sizeof(struct call_rcu_data *)); > + *r = NULL; Random question here: instead of allocating memory, can we simply use a statically declared variable ? > + (void)pthread_setspecific(tls_tcrd_key, r); > + } > + return r; > +} > +#define thread_call_rcu_data (*tls_thread_call_rcu_data()) Please use a static inline function instead of a macro whenever possible. > +#endif > > /* Guard call_rcu thread creation. */ > > diff --git a/urcu-defer-impl.h b/urcu-defer-impl.h > index 4d1ca5e..21c337d 100644 > --- a/urcu-defer-impl.h > +++ b/urcu-defer-impl.h > @@ -11,6 +11,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -40,6 +41,7 @@ > #include > #include > #include > +#include > > #include "urcu/futex.h" > > @@ -48,6 +50,7 @@ > #include > #include > #include > +#include > > /* > * Number of entries in the per-thread defer queue. Must be power of 2. > @@ -130,7 +133,9 @@ static int32_t defer_thread_stop; > * Written to only by each individual deferer. Read by both the deferer and > * the reclamation tread. > */ > -static struct defer_queue __thread defer_queue; > +TLS_DEFINE_SIMPLE(struct defer_queue, get_defer_queue, defer_queue); > +#define _defer_queue (*get_defer_queue()) > + > static CDS_LIST_HEAD(registry_defer); > static pthread_t tid_defer; > > @@ -245,12 +250,12 @@ static void _rcu_defer_barrier_thread(void) > { > unsigned long head, num_items; > > - head = defer_queue.head; > - num_items = head - defer_queue.tail; > + head = _defer_queue.head; > + num_items = head - _defer_queue.tail; > if (caa_unlikely(!num_items)) > return; > synchronize_rcu(); > - rcu_defer_barrier_queue(&defer_queue, head); > + rcu_defer_barrier_queue(&_defer_queue, head); > } > > void rcu_defer_barrier_thread(void) > @@ -311,8 +316,8 @@ void _defer_rcu(void (*fct)(void *p), void *p) > * Head is only modified by ourself. Tail can be modified by reclamation > * thread. > */ > - head = defer_queue.head; > - tail = CMM_LOAD_SHARED(defer_queue.tail); > + head = _defer_queue.head; > + tail = CMM_LOAD_SHARED(_defer_queue.tail); > > /* > * If queue is full, or reached threshold. Empty queue ourself. > @@ -321,7 +326,7 @@ void _defer_rcu(void (*fct)(void *p), void *p) > if (caa_unlikely(head - tail >= DEFER_QUEUE_SIZE - 2)) { > assert(head - tail <= DEFER_QUEUE_SIZE); > rcu_defer_barrier_thread(); > - assert(head - CMM_LOAD_SHARED(defer_queue.tail) == 0); > + assert(head - CMM_LOAD_SHARED(_defer_queue.tail) == 0); > } > > /* > @@ -340,25 +345,25 @@ void _defer_rcu(void (*fct)(void *p), void *p) > * Decode: see the comments before 'struct defer_queue' > * or the code in rcu_defer_barrier_queue(). > */ > - if (caa_unlikely(defer_queue.last_fct_in != fct > + if (caa_unlikely(_defer_queue.last_fct_in != fct > || DQ_IS_FCT_BIT(p) > || p == DQ_FCT_MARK)) { > - defer_queue.last_fct_in = fct; > + _defer_queue.last_fct_in = fct; > if (caa_unlikely(DQ_IS_FCT_BIT(fct) || fct == DQ_FCT_MARK)) { > - _CMM_STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], > + _CMM_STORE_SHARED(_defer_queue.q[head++ & DEFER_QUEUE_MASK], > DQ_FCT_MARK); > - _CMM_STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], > + _CMM_STORE_SHARED(_defer_queue.q[head++ & DEFER_QUEUE_MASK], > fct); > } else { > DQ_SET_FCT_BIT(fct); > - _CMM_STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], > + _CMM_STORE_SHARED(_defer_queue.q[head++ & DEFER_QUEUE_MASK], > fct); > } > } > - _CMM_STORE_SHARED(defer_queue.q[head++ & DEFER_QUEUE_MASK], p); > + _CMM_STORE_SHARED(_defer_queue.q[head++ & DEFER_QUEUE_MASK], p); > cmm_smp_wmb(); /* Publish new pointer before head */ > /* Write q[] before head. */ > - CMM_STORE_SHARED(defer_queue.head, head); > + CMM_STORE_SHARED(_defer_queue.head, head); > cmm_smp_mb(); /* Write queue head before read futex */ > /* > * Wake-up any waiting defer thread. > @@ -422,16 +427,16 @@ int rcu_defer_register_thread(void) > { > int was_empty; > > - assert(defer_queue.last_head == 0); > - assert(defer_queue.q == NULL); > - defer_queue.q = malloc(sizeof(void *) * DEFER_QUEUE_SIZE); > - if (!defer_queue.q) > + assert(_defer_queue.last_head == 0); > + assert(_defer_queue.q == NULL); > + _defer_queue.q = malloc(sizeof(void *) * DEFER_QUEUE_SIZE); > + if (!_defer_queue.q) > return -ENOMEM; > > mutex_lock_defer(&defer_thread_mutex); > mutex_lock_defer(&rcu_defer_mutex); > was_empty = cds_list_empty(®istry_defer); > - cds_list_add(&defer_queue.list, ®istry_defer); > + cds_list_add(&_defer_queue.list, ®istry_defer); > mutex_unlock(&rcu_defer_mutex); > > if (was_empty) > @@ -446,10 +451,10 @@ void rcu_defer_unregister_thread(void) > > mutex_lock_defer(&defer_thread_mutex); > mutex_lock_defer(&rcu_defer_mutex); > - cds_list_del(&defer_queue.list); > + cds_list_del(&_defer_queue.list); > _rcu_defer_barrier_thread(); > - free(defer_queue.q); > - defer_queue.q = NULL; > + free(_defer_queue.q); > + _defer_queue.q = NULL; > is_empty = cds_list_empty(®istry_defer); > mutex_unlock(&rcu_defer_mutex); > > diff --git a/urcu-qsbr.c b/urcu-qsbr.c > index 5530295..6eeb90c 100644 > --- a/urcu-qsbr.c > +++ b/urcu-qsbr.c > @@ -5,6 +5,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -34,6 +35,7 @@ > #include > #include > #include > +#include > > #include "urcu/wfqueue.h" > #include "urcu/map/urcu-qsbr.h" > @@ -66,11 +68,11 @@ unsigned long rcu_gp_ctr = RCU_GP_ONLINE; > * Written to only by each individual reader. Read by both the reader and the > * writers. > */ > -struct rcu_reader __thread rcu_reader; > +TLS_DEFINE(struct rcu_reader, rcu_reader, _rcu_reader); > > #ifdef DEBUG_YIELD > unsigned int yield_active; > -unsigned int __thread rand_yield; > +TLS_DEFINE(unsigned int, get_rand_yield, _rand_yield); > #endif > > static CDS_LIST_HEAD(registry); > @@ -206,7 +208,7 @@ void synchronize_rcu(void) > { > unsigned long was_online; > > - was_online = rcu_reader.ctr; > + was_online = rcu_reader()->ctr; > > /* All threads should read qparity before accessing data structure > * where new ptr points to. In the "then" case, rcu_thread_offline > @@ -269,7 +271,7 @@ void synchronize_rcu(void) > { > unsigned long was_online; > > - was_online = rcu_reader.ctr; > + was_online = rcu_reader()->ctr; > > /* > * Mark the writer thread offline to make sure we don't wait for > @@ -326,11 +328,11 @@ void rcu_thread_online(void) > > void rcu_register_thread(void) > { > - rcu_reader.tid = pthread_self(); > - assert(rcu_reader.ctr == 0); > + rcu_reader()->tid = pthread_self(); > + assert(rcu_reader()->ctr == 0); > > mutex_lock(&rcu_gp_lock); > - cds_list_add(&rcu_reader.node, ®istry); > + cds_list_add(&rcu_reader()->node, ®istry); > mutex_unlock(&rcu_gp_lock); > _rcu_thread_online(); > } > @@ -343,7 +345,7 @@ void rcu_unregister_thread(void) > */ > _rcu_thread_offline(); > mutex_lock(&rcu_gp_lock); > - cds_list_del(&rcu_reader.node); > + cds_list_del(&rcu_reader()->node); > mutex_unlock(&rcu_gp_lock); > } > > diff --git a/urcu.c b/urcu.c > index ba013d9..69a8311 100644 > --- a/urcu.c > +++ b/urcu.c > @@ -5,6 +5,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -35,6 +36,7 @@ > #include > #include > #include > +#include > > #include "urcu/wfqueue.h" > #include "urcu/map/urcu.h" > @@ -94,11 +96,11 @@ unsigned long rcu_gp_ctr = RCU_GP_COUNT; > * Written to only by each individual reader. Read by both the reader and the > * writers. > */ > -struct rcu_reader __thread rcu_reader; > +TLS_DEFINE(struct rcu_reader, rcu_reader, _rcu_reader); > > #ifdef DEBUG_YIELD > unsigned int yield_active; > -unsigned int __thread rand_yield; > +TLS_DEFINE(unsigned int, get_rand_yield, _rand_yield); > #endif > > static CDS_LIST_HEAD(registry); > @@ -120,9 +122,9 @@ static void mutex_lock(pthread_mutex_t *mutex) > perror("Error in pthread mutex lock"); > exit(-1); > } > - if (CMM_LOAD_SHARED(rcu_reader.need_mb)) { > + if (CMM_LOAD_SHARED(rcu_reader()->need_mb)) { > cmm_smp_mb(); > - _CMM_STORE_SHARED(rcu_reader.need_mb, 0); > + _CMM_STORE_SHARED(rcu_reader()->need_mb, 0); > cmm_smp_mb(); > } > poll(NULL,0,10); > @@ -368,20 +370,20 @@ void rcu_read_unlock(void) > > void rcu_register_thread(void) > { > - rcu_reader.tid = pthread_self(); > - assert(rcu_reader.need_mb == 0); > - assert(!(rcu_reader.ctr & RCU_GP_CTR_NEST_MASK)); > + rcu_reader()->tid = pthread_self(); > + assert(rcu_reader()->need_mb == 0); > + assert(!(rcu_reader()->ctr & RCU_GP_CTR_NEST_MASK)); > > mutex_lock(&rcu_gp_lock); > rcu_init(); /* In case gcc does not support constructor attribute */ > - cds_list_add(&rcu_reader.node, ®istry); > + cds_list_add(&rcu_reader()->node, ®istry); > mutex_unlock(&rcu_gp_lock); > } > > void rcu_unregister_thread(void) > { > mutex_lock(&rcu_gp_lock); > - cds_list_del(&rcu_reader.node); > + cds_list_del(&rcu_reader()->node); > mutex_unlock(&rcu_gp_lock); > } > > @@ -405,7 +407,7 @@ static void sigrcu_handler(int signo, siginfo_t *siginfo, void *context) > * executed on. > */ > cmm_smp_mb(); > - _CMM_STORE_SHARED(rcu_reader.need_mb, 0); > + _CMM_STORE_SHARED(rcu_reader()->need_mb, 0); > cmm_smp_mb(); > } > > diff --git a/urcu/map/urcu-bp.h b/urcu/map/urcu-bp.h > index 4abe8dc..f269135 100644 > --- a/urcu/map/urcu-bp.h > +++ b/urcu/map/urcu-bp.h > @@ -9,6 +9,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * LGPL-compatible code should include this header with : > * > @@ -44,6 +45,7 @@ > #define rcu_exit rcu_exit_bp > #define synchronize_rcu synchronize_rcu_bp > #define rcu_reader rcu_reader_bp > +#define _rcu_reader _rcu_reader_bp > #define rcu_gp_ctr rcu_gp_ctr_bp > > #define get_cpu_call_rcu_data get_cpu_call_rcu_data_bp > diff --git a/urcu/map/urcu-qsbr.h b/urcu/map/urcu-qsbr.h > index 0d88d83..f947791 100644 > --- a/urcu/map/urcu-qsbr.h > +++ b/urcu/map/urcu-qsbr.h > @@ -9,6 +9,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * LGPL-compatible code should include this header with : > * > @@ -47,6 +48,7 @@ > #define rcu_exit rcu_exit_qsbr > #define synchronize_rcu synchronize_rcu_qsbr > #define rcu_reader rcu_reader_qsbr > +#define _rcu_reader _rcu_reader_qsbr > #define rcu_gp_ctr rcu_gp_ctr_qsbr > > #define get_cpu_call_rcu_data get_cpu_call_rcu_data_qsbr > diff --git a/urcu/map/urcu.h b/urcu/map/urcu.h > index 3f436a7..a6d5c37 100644 > --- a/urcu/map/urcu.h > +++ b/urcu/map/urcu.h > @@ -9,6 +9,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * LGPL-compatible code should include this header with : > * > @@ -75,6 +76,7 @@ > #define rcu_exit rcu_exit_memb > #define synchronize_rcu synchronize_rcu_memb > #define rcu_reader rcu_reader_memb > +#define _rcu_reader _rcu_reader_memb > #define rcu_gp_ctr rcu_gp_ctr_memb > > #define get_cpu_call_rcu_data get_cpu_call_rcu_data_memb > @@ -107,6 +109,7 @@ > #define rcu_exit rcu_exit_sig > #define synchronize_rcu synchronize_rcu_sig > #define rcu_reader rcu_reader_sig > +#define _rcu_reader _rcu_reader_sig > #define rcu_gp_ctr rcu_gp_ctr_sig > > #define get_cpu_call_rcu_data get_cpu_call_rcu_data_sig > @@ -139,6 +142,7 @@ > #define rcu_exit rcu_exit_mb > #define synchronize_rcu synchronize_rcu_mb > #define rcu_reader rcu_reader_mb > +#define _rcu_reader _rcu_reader_mb > #define rcu_gp_ctr rcu_gp_ctr_mb > > #define get_cpu_call_rcu_data get_cpu_call_rcu_data_mb > diff --git a/urcu/static/urcu-bp.h b/urcu/static/urcu-bp.h > index 8d22163..42e4b6e 100644 > --- a/urcu/static/urcu-bp.h > +++ b/urcu/static/urcu-bp.h > @@ -11,6 +11,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -38,6 +39,7 @@ > #include > #include > #include > +#include > > /* > * This code section can only be included in LGPL 2.1 compatible source code. > @@ -74,7 +76,9 @@ extern "C" { > #define MAX_SLEEP 50 > > extern unsigned int yield_active; > -extern unsigned int __thread rand_yield; > +TLS_DECLARE(unsigned int, get_rand_yield, _rand_yield); > +// Safe if rand_yield is not redefined > +#define rand_yield (*get_rand_yield()) > > static inline void debug_yield_read(void) > { > @@ -144,7 +148,7 @@ struct rcu_reader { > * Adds a pointer dereference on the read-side, but won't require to unregister > * the reader thread. > */ > -extern struct rcu_reader __thread *rcu_reader; > +TLS_DECLARE(struct rcu_reader*, rcu_reader, _rcu_reader); > > static inline int rcu_old_gp_ongoing(long *value) > { > @@ -166,24 +170,24 @@ static inline void _rcu_read_lock(void) > long tmp; > > /* Check if registered */ > - if (caa_unlikely(!rcu_reader)) > + if (caa_unlikely(!*rcu_reader())) > rcu_bp_register(); > > cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ > - tmp = rcu_reader->ctr; > + tmp = (*rcu_reader())->ctr; > /* > * rcu_gp_ctr is > * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) > */ > if (caa_likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { > - _CMM_STORE_SHARED(rcu_reader->ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); > + _CMM_STORE_SHARED((*rcu_reader())->ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); > /* > * Set active readers count for outermost nesting level before > * accessing the pointer. > */ > cmm_smp_mb(); > } else { > - _CMM_STORE_SHARED(rcu_reader->ctr, tmp + RCU_GP_COUNT); > + _CMM_STORE_SHARED((*rcu_reader())->ctr, tmp + RCU_GP_COUNT); > } > } > > @@ -193,7 +197,7 @@ static inline void _rcu_read_unlock(void) > * Finish using rcu before decrementing the pointer. > */ > cmm_smp_mb(); > - _CMM_STORE_SHARED(rcu_reader->ctr, rcu_reader->ctr - RCU_GP_COUNT); > + _CMM_STORE_SHARED((*rcu_reader())->ctr, (*rcu_reader())->ctr - RCU_GP_COUNT); > cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ > } > > diff --git a/urcu/static/urcu-qsbr.h b/urcu/static/urcu-qsbr.h > index 68bfc31..fac39a1 100644 > --- a/urcu/static/urcu-qsbr.h > +++ b/urcu/static/urcu-qsbr.h > @@ -11,6 +11,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -42,6 +43,7 @@ > #include > #include > #include > +#include > > #ifdef __cplusplus > extern "C" { > @@ -74,7 +76,9 @@ extern "C" { > #define MAX_SLEEP 50 > > extern unsigned int yield_active; > -extern unsigned int __thread rand_yield; > +TLS_DECLARE(unsigned int, get_rand_yield, _rand_yield); > +// Safe if rand_yield is not redefined > +#define rand_yield (*get_rand_yield()) > > static inline void debug_yield_read(void) > { > @@ -128,7 +132,7 @@ struct rcu_reader { > pthread_t tid; > }; > > -extern struct rcu_reader __thread rcu_reader; > +TLS_DECLARE(struct rcu_reader, rcu_reader, _rcu_reader); > > extern int32_t gp_futex; > > @@ -137,8 +141,8 @@ extern int32_t gp_futex; > */ > static inline void wake_up_gp(void) > { > - if (caa_unlikely(_CMM_LOAD_SHARED(rcu_reader.waiting))) { > - _CMM_STORE_SHARED(rcu_reader.waiting, 0); > + if (caa_unlikely(_CMM_LOAD_SHARED(rcu_reader()->waiting))) { > + _CMM_STORE_SHARED(rcu_reader()->waiting, 0); > cmm_smp_mb(); > if (uatomic_read(&gp_futex) != -1) > return; > @@ -158,7 +162,7 @@ static inline int rcu_gp_ongoing(unsigned long *ctr) > > static inline void _rcu_read_lock(void) > { > - rcu_assert(rcu_reader.ctr); > + rcu_assert(rcu_reader()->ctr); > } > > static inline void _rcu_read_unlock(void) > @@ -168,7 +172,7 @@ static inline void _rcu_read_unlock(void) > static inline void _rcu_quiescent_state(void) > { > cmm_smp_mb(); > - _CMM_STORE_SHARED(rcu_reader.ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); > + _CMM_STORE_SHARED(rcu_reader()->ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); > cmm_smp_mb(); /* write rcu_reader.ctr before read futex */ > wake_up_gp(); > cmm_smp_mb(); > @@ -177,8 +181,8 @@ static inline void _rcu_quiescent_state(void) > static inline void _rcu_thread_offline(void) > { > cmm_smp_mb(); > - CMM_STORE_SHARED(rcu_reader.ctr, 0); > - cmm_smp_mb(); /* write rcu_reader.ctr before read futex */ > + CMM_STORE_SHARED(rcu_reader()->ctr, 0); > + cmm_smp_mb(); /* write _rcu_reader.ctr before read futex */ > wake_up_gp(); > cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ > } > @@ -186,7 +190,7 @@ static inline void _rcu_thread_offline(void) > static inline void _rcu_thread_online(void) > { > cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ > - _CMM_STORE_SHARED(rcu_reader.ctr, CMM_LOAD_SHARED(rcu_gp_ctr)); > + _CMM_STORE_SHARED(rcu_reader()->ctr, CMM_LOAD_SHARED(rcu_gp_ctr)); > cmm_smp_mb(); > } > > diff --git a/urcu/static/urcu.h b/urcu/static/urcu.h > index 7ae0185..302404b 100644 > --- a/urcu/static/urcu.h > +++ b/urcu/static/urcu.h > @@ -11,6 +11,7 @@ > * > * Copyright (c) 2009 Mathieu Desnoyers > * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. > + * Copyright (C) 2012 Marek Vavrusa , CZ.NIC, z.s.p.o. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -33,6 +34,7 @@ > #include > #include > #include > +#include > > #include > #include > @@ -40,6 +42,7 @@ > #include > #include > #include > +#include > > #ifdef __cplusplus > extern "C" { > @@ -121,7 +124,9 @@ extern "C" { > #endif > > extern unsigned int yield_active; > -extern unsigned int __thread rand_yield; > +TLS_DECLARE(unsigned int, get_rand_yield, _rand_yield); > +// Safe shortcut if rand_yield is not redefined Please don't use // style comments in the code. > +#define rand_yield (*get_rand_yield()) > > static inline void debug_yield_read(void) > { > @@ -222,7 +227,7 @@ struct rcu_reader { > pthread_t tid; > }; > > -extern struct rcu_reader __thread rcu_reader; > +TLS_DECLARE(struct rcu_reader, rcu_reader, _rcu_reader); > > extern int32_t gp_futex; > > @@ -256,20 +261,20 @@ static inline void _rcu_read_lock(void) > unsigned long tmp; > > cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ > - tmp = rcu_reader.ctr; > + tmp = rcu_reader()->ctr; Hrm, this patch is too big, and needs to be split into smaller changes: Please provide a first patch that introduces just #define URCU_TLS_DECLARE(type, name) \ extern type __thread _urcu_tls_##name #define URCU_TLS_DEFINE(type, name) \ type __thread _urcu_tls_##name #define urcu_tls_get(name) \ (&_urcu_tls_##name) in urcu/tls.h Then, a second patch that use it and changes accesses tmp = rcu_reader.ctr; to tmp = urcu_tls_get(rcu_reader)->ctr; Then, as a third patch, please introduce the new features within this new API, adding support for non-TLS configs. > /* > * rcu_gp_ctr is > * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) > */ > if (caa_likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { > - _CMM_STORE_SHARED(rcu_reader.ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); > + _CMM_STORE_SHARED(rcu_reader()->ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); > /* > * Set active readers count for outermost nesting level before > * accessing the pointer. See smp_mb_master(). > */ > smp_mb_slave(RCU_MB_GROUP); > } else { > - _CMM_STORE_SHARED(rcu_reader.ctr, tmp + RCU_GP_COUNT); > + _CMM_STORE_SHARED(rcu_reader()->ctr, tmp + RCU_GP_COUNT); > } > } > > @@ -277,19 +282,19 @@ static inline void _rcu_read_unlock(void) > { > unsigned long tmp; > > - tmp = rcu_reader.ctr; > + tmp = rcu_reader()->ctr; > /* > * Finish using rcu before decrementing the pointer. > * See smp_mb_master(). > */ > if (caa_likely((tmp & RCU_GP_CTR_NEST_MASK) == RCU_GP_COUNT)) { > smp_mb_slave(RCU_MB_GROUP); > - _CMM_STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_COUNT); > + _CMM_STORE_SHARED(rcu_reader()->ctr, rcu_reader()->ctr - RCU_GP_COUNT); > /* write rcu_reader.ctr before read futex */ > smp_mb_slave(RCU_MB_GROUP); > wake_up_gp(); > } else { > - _CMM_STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_COUNT); > + _CMM_STORE_SHARED(rcu_reader()->ctr, rcu_reader()->ctr - RCU_GP_COUNT); > } > cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ > } > diff --git a/urcu/tls-compat.h b/urcu/tls-compat.h > new file mode 100644 > index 0000000..d47e803 > --- /dev/null > +++ b/urcu/tls-compat.h > @@ -0,0 +1,104 @@ Please use /* * ... */ style comment. > +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. > + > + This program is free software: you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation, either version 3 of the License, or > + (at your option) any later version. I cannot pull this header as GPLv3. It needs to be either LGPL v2.1 or BSD-style. > + > + This program 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 General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . > + */ > +#ifndef _TLS_COMPAT_H scoping: _URCU_TLS_COMPAT_H > +#define _TLS_COMPAT_H > +#include #include possibly that you will have to ensure that configure.ac puts your macros in the urcu config file specifically. > + > +/* Conditional includes. */ > +#ifndef TLS > +#include > +#endif > + > +/*! > + * \brief TLS variable declaration (requires TLS_DEFINITION in .c file) > + * \param T declared type. > + * \param name output function name. > + * \param vname internal variable name. > + * > + * Output: function "T* name()". > + * > + * Example: > + * TLS_DECLARE(int, a, _a); > + * TLS_DEFINE(int, a, _a); > + * *(a()) = 1 > + */ > +#ifdef TLS To respect urcu namespacing, we need: URCU_TLS_DECLARE URCU_TLS_DEFINE Same for vname and name below: they need to be prefixed with urcu_tls namespace. > + #define TLS_DECLARE(T, name, vname) \ > + extern TLS T vname; \ > + static inline T *name() { \ > + return &vname;\ > + } > +#else > + #define TLS_DECLARE(T, name, vname) \ > + T *name() > +#endif > + > +/*! > + * \brief TLS variable definition. > + * \param T declared type. > + * \param name output function name. > + * \param vname internal variable name. > + * > + * Output: function "T* name()" or TLS variable "vname". > + * Requires TLS_DECLARE for exported API. > + */ > +#ifdef TLS > +#define TLS_DEFINE(T, name, vname) \ > +TLS T vname > +#else > +#define TLS_DEFINE(T, name, vname) \ > +static pthread_key_t tls_ ## name ## _key; \ > +static pthread_once_t tls_ ## name ## _once = PTHREAD_ONCE_INIT; \ > +static void tls_ ## name ## _deinit() { \ > + free((void*)pthread_getspecific(tls_ ## name ## _key)); \ > +} \ > +static void tls_ ## name ## _init() { \ > + (void)pthread_key_create(&tls_ ## name ## _key, tls_ ## name ## _deinit); \ > + atexit(tls_ ## name ## _deinit); \ > +} \ > +T *name() { \ > + (void)pthread_once(&tls_ ## name ## _once, tls_ ## name ## _init); \ Please use constructor/desctructor if possible. > + void *p = pthread_getspecific(tls_ ## name ## _key); \ > + if (p == NULL) { \ > + p = malloc(sizeof(T)); \ > + memset(p, 0, sizeof(T)); \ malloc required here ? or can this be static ? Thanks, Mathieu > + (void)pthread_setspecific(tls_ ## name ## _key, p); \ > + } \ > + return p; \ > +} > +#endif > + > +/*! > + * \brief TLS variable declaration+definition. > + * \param T declared type. > + * \param name output function name. > + * \param vname internal variable name. > + * > + * Output: function "T* name()" or TLS variable "vname". > + * Requires TLS_DECLARE for exported API. > + */ > +#ifndef TLS > +#define TLS_DEFINE_SIMPLE(T, name, vname) \ > +TLS_DEFINE(T, name, vname) > +#else > +#define TLS_DEFINE_SIMPLE(T, name, vname) \ > +TLS_DEFINE(T, name, vname); \ > +static inline T *name() { \ > + return &vname;\ > +} > +#endif > + > +#endif // _TLS_COMPAT_H > -- > 1.7.7.1 -- Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com