]> mj.ucw.cz Git - libucw.git/commitdiff
Use thread-local storage of GCC 4.x
authorMartin Mares <mj@ucw.cz>
Thu, 22 Jul 2010 13:32:49 +0000 (15:32 +0200)
committerMartin Mares <mj@ucw.cz>
Thu, 22 Jul 2010 13:32:49 +0000 (15:32 +0200)
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
ucw/perl/UCW/Configure/LibUCW.pm
ucw/threads.c
ucw/threads.h

index 938f8f407251efccbc468103e95f62fba8a83cb6..6b919c6bd4ae23a46c69484f52bd2886eb1dfe1d 100644 (file)
@@ -1,5 +1,5 @@
 # Configuration variables of the UCW library and their default values
-# (c) 2005--2009 Martin Mares <mj@ucw.cz>
+# (c) 2005--2010 Martin Mares <mj@ucw.cz>
 
 # 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;
index 2b7eb23e6b233c2218917c23b633283ed09890ed..bd2ef5d12ee73de89d2ae4def278816235d16c0d 100644 (file)
@@ -1,5 +1,5 @@
 # UCW Library configuration system: parameters of the library
-# (c) 2005--2008 Martin Mares <mj@ucw.cz>
+# (c) 2005--2010 Martin Mares <mj@ucw.cz>
 # (c) 2006 Robert Spalek <robert@ucw.cz>
 # (c) 2008 Michal Vaner <vorner@ucw.cz>
 
@@ -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", [
index 1260e8759ae1a3b0ee96303e850c752bba6ec3eb..f0c701403eae4de819cd1aa96718cce3ea567fd0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     The UCW Library -- Threading Helpers
  *
- *     (c) 2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2006--2010 Martin Mares <mj@ucw.cz>
  *
  *     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;
 }
 
index ef00dea1af953837793e49149379ab385e8ae262..7f100b20b2dc79882fb11a4f03250022f560a44b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     The UCW Library -- Threading Helpers
  *
- *     (c) 2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2006--2010 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
 /* 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