From 30680da0fe1192be08f2ff02d912e3b8a0f1212f Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Thu, 22 Jul 2010 15:32:49 +0200 Subject: [PATCH] Use thread-local storage of GCC 4.x ucw/threads.c can now work in three different modes: o non-threaded o threaded with context in pthread per-thread storage o threaded with context stored as __thread I had to make a backward-incompatible change: ucwlib_context->thread_id is no longer accessible directly (because I do not know of any way how to initialize it in the __thread mode) and a wrapper function should be used. --- ucw/default.cfg | 5 +- ucw/perl/UCW/Configure/LibUCW.pm | 13 ++++- ucw/threads.c | 86 +++++++++++++++++--------------- ucw/threads.h | 27 ++++++++-- 4 files changed, 86 insertions(+), 45 deletions(-) diff --git a/ucw/default.cfg b/ucw/default.cfg index 938f8f40..6b919c6b 100644 --- a/ucw/default.cfg +++ b/ucw/default.cfg @@ -1,5 +1,5 @@ # Configuration variables of the UCW library and their default values -# (c) 2005--2009 Martin Mares +# (c) 2005--2010 Martin Mares # Version of the whole package Set("UCW_VERSION" => "4.0.1-dev"); @@ -52,5 +52,8 @@ UnSet("CONFIG_URL_ESCAPE_COMPAT"); Set("CONFIG_DIRECT_IO"); Set("CONFIG_UCW_FB_DIRECT"); +# Use thread-local storage (needs GCC-support, default: auto-detect) +# Set("CONFIG_UCW_TLS"); + # Return success 1; diff --git a/ucw/perl/UCW/Configure/LibUCW.pm b/ucw/perl/UCW/Configure/LibUCW.pm index 2b7eb23e..bd2ef5d1 100644 --- a/ucw/perl/UCW/Configure/LibUCW.pm +++ b/ucw/perl/UCW/Configure/LibUCW.pm @@ -1,5 +1,5 @@ # UCW Library configuration system: parameters of the library -# (c) 2005--2008 Martin Mares +# (c) 2005--2010 Martin Mares # (c) 2006 Robert Spalek # (c) 2008 Michal Vaner @@ -43,6 +43,17 @@ if (Get("CPU_ARCH") eq "default" || Get("CPU_ARCH") =~ /^i[345]86$/) { Set("CONFIG_UCW_RADIX_SORTER_BITS" => 12); } +# Detect if thread-local storage is supported +if (Get("CONFIG_UCW_THREADS")) { + TestBool("CONFIG_UCW_TLS", "Checking if GCC supports thread-local storage", sub { + if (UCW::Configure::C::TestCompile("__thread int i;\nint main(void) { return 0; }\n")) { + return 1; + } else { + return 0; + } + }); +} + PostConfig { AtWrite { UCW::Configure::C::ConfigHeader("ucw/autoconf.h", [ diff --git a/ucw/threads.c b/ucw/threads.c index 1260e875..f0c70140 100644 --- a/ucw/threads.c +++ b/ucw/threads.c @@ -1,7 +1,7 @@ /* * The UCW Library -- Threading Helpers * - * (c) 2006 Martin Mares + * (c) 2006--2010 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -28,23 +28,24 @@ gettid(void) #endif #endif -static pthread_key_t ucwlib_context_key; +/*** Library lock ***/ + static pthread_mutex_t ucwlib_master_mutex; -static void -ucwlib_free_thread_context(void *p) +void +ucwlib_lock(void) { - xfree(p); + pthread_mutex_lock(&ucwlib_master_mutex); } -static void CONSTRUCTOR -ucwlib_threads_init(void) +void +ucwlib_unlock(void) { - if (pthread_key_create(&ucwlib_context_key, ucwlib_free_thread_context) < 0) - die("Cannot create pthread_key: %m"); - pthread_mutex_init(&ucwlib_master_mutex, NULL); + pthread_mutex_unlock(&ucwlib_master_mutex); } +/*** Thread identifiers ***/ + static int ucwlib_tid(void) { @@ -64,50 +65,57 @@ ucwlib_tid(void) return tid; } -struct ucwlib_context * -ucwlib_thread_context(void) -{ - struct ucwlib_context *c = pthread_getspecific(ucwlib_context_key); - if (!c) - { - c = xmalloc_zero(sizeof(*c)); - c->thread_id = ucwlib_tid(); - pthread_setspecific(ucwlib_context_key, c); - } - return c; -} +/*** Thread context ***/ -void -ucwlib_lock(void) -{ - pthread_mutex_lock(&ucwlib_master_mutex); -} +#ifdef CONFIG_UCW_TLS -void -ucwlib_unlock(void) +__thread struct ucwlib_context ucwlib_context; + +int +ucwlib_thread_id(struct ucwlib_context *c) { - pthread_mutex_unlock(&ucwlib_master_mutex); + if (!c->_thread_id) + c->_thread_id = ucwlib_tid(); + return c->_thread_id; } #else -struct ucwlib_context * -ucwlib_thread_context(void) +static pthread_key_t ucwlib_context_key; + +static void +ucwlib_free_thread_context(void *p) { - static struct ucwlib_context ucwlib_context; - return &ucwlib_context; + xfree(p); } -void -ucwlib_lock(void) +static void CONSTRUCTOR +ucwlib_threads_init(void) { + if (pthread_key_create(&ucwlib_context_key, ucwlib_free_thread_context) < 0) + die("Cannot create pthread_key: %m"); + pthread_mutex_init(&ucwlib_master_mutex, NULL); } -void -ucwlib_unlock(void) +struct ucwlib_context * +ucwlib_thread_context(void) { + struct ucwlib_context *c = pthread_getspecific(ucwlib_context_key); + if (!c) + { + c = xmalloc_zero(sizeof(*c)); + c->_thread_id = ucwlib_tid(); + pthread_setspecific(ucwlib_context_key, c); + } + return c; } +#endif /* CONFIG_UCW_TLS */ + +#else /* !CONFIG_UCW_THREADS */ + +struct ucwlib_context default_ucwlib_context; + #endif #ifdef TEST @@ -116,7 +124,7 @@ int main(void) { ucwlib_lock(); ucwlib_unlock(); - msg(L_INFO, "tid=%d", ucwlib_thread_context()->thread_id); + msg(L_INFO, "tid=%d", ucwlib_thread_id(ucwlib_thread_context())); return 0; } diff --git a/ucw/threads.h b/ucw/threads.h index ef00dea1..7f100b20 100644 --- a/ucw/threads.h +++ b/ucw/threads.h @@ -1,7 +1,7 @@ /* * The UCW Library -- Threading Helpers * - * (c) 2006 Martin Mares + * (c) 2006--2010 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -13,23 +13,42 @@ /* This structure holds per-thread data */ struct ucwlib_context { - int thread_id; // Thread ID (either kernel tid or a counter) + int _thread_id; // Thread ID (either kernel tid or a counter, use ucwlib_thread_id()) int temp_counter; // Counter for fb-temp.c struct asio_queue *io_queue; // Async I/O queue for fb-direct.c ucw_sighandler_t *signal_handlers; // Signal handlers for sighandler.c }; +#ifdef CONFIG_UCW_THREADS + +#ifdef CONFIG_UCW_TLS +extern __thread struct ucwlib_context ucwlib_context; +static inline struct ucwlib_context *ucwlib_thread_context(void) { return &ucwlib_context; } +int ucwlib_thread_id(struct ucwlib_context *c); +#else struct ucwlib_context *ucwlib_thread_context(void); +static inline int ucwlib_thread_id(struct ucwlib_context *c) { return c->_thread_id; } +#endif /* Global lock used for initialization, cleanup and other not so frequently accessed global state */ void ucwlib_lock(void); void ucwlib_unlock(void); -#ifdef CONFIG_UCW_THREADS - extern uns ucwlib_thread_stack_size; +#else + +/* We have no threads, let's simulate the context and locking */ + +extern struct ucwlib_context default_ucwlib_context; +static inline struct ucwlib_context *ucwlib_thread_context(void) { return &default_ucwlib_context; } + +static inline int ucwlib_thread_id(struct ucwlib_context *c UNUSED) { return 0; } + +static inline void ucwlib_lock(void) { } +static inline void ucwlib_unlock(void) { } + #endif #endif -- 2.39.2