Modify threads-pthreads to possibly use __thread for TLS

In an approach taken from qthreads, we modify the threads-pthreads
implementation to use __thread when it is available by defining
macros for declaring, initializing, deleting, reading, and writing
thread local storage. When __thread is not available, we use
the usual pthread_key_create/delete pthread_getspecific/setspecific calls.

Lastly, I noticed that in pthread_func, the threadEnd function is
not called if the thread is not canceled (but the thread function
completes normally). I believe that it should be called in either
case -- it might free memory for example (and does for FIFO), so this
patch calls pthread_cleanup_pop(1) -- the 1 meaning to invoke the
cleanup handler. I don't think that this comes up with FIFO's current
use of threads-pthreads because it seems that thread_begin never exits;
nonetheless I think this is a worthwhile bug fix in case the future
usage pattern changes.

diff --git a/runtime/include/threads/pthreads/threads-pthreads.h b/runtime/include/threads/pthreads/threads-pthreads.h
index a0d3c8f..bbd248d 100644
--- a/runtime/include/threads/pthreads/threads-pthreads.h
+++ b/runtime/include/threads/pthreads/threads-pthreads.h
@@ -16,4 +16,55 @@ typedef int64_t chpl_thread_id_t;
 
 typedef pthread_mutex_t chpl_thread_mutex_t;
 
+#ifdef __GNUC__
+// For GCC and CLANG, where we know there is __thread, use it instead
+// of pthread_get/setspecific since __thread appears to be 2x faster.
+#define TLS __thread
+#elif __STDC_VERSION >= 201112L && !defined __STDC_NO_THREADS__
+// For the C11 standard, _Thread_local is the name of it
+#define TLS _Thread_local
+#elif defined(_MSC_VER)
+#define TLS __declspec(thread)
+#endif
+
+// Unscrupulously stolen from qthreads
+#ifdef TLS
+# define TLS_DECL(type, name)      TLS type name
+# define TLS_DECL_INIT(type, name) TLS type name = 0
+# define TLS_GET(name)             name
+# define TLS_SET(name, val)        name = (val)
+# define TLS_INIT(name)
+# define TLS_INIT2(name, func)
+# define TLS_DELETE(name)          name = 0
+#else
+
+static void mytassert(int got, int expect)      
+{
+  if( got != expect ) {
+    chpl_internal_error("failure in thread private data");
+  }
+}
+
+# define TLS_DECL(type, name)      pthread_key_t name
+# define TLS_DECL_INIT(type, name) pthread_key_t name
+# define TLS_GET(name)             pthread_getspecific(name)
+# define TLS_SET(name, val)        mytassert(pthread_setspecific((name), (void *)(val)), 0)
+# define TLS_INIT(name)            mytassert(pthread_key_create(&(name), NULL), 0)
+# define TLS_INIT2(name, func)     mytassert(pthread_key_create(&(name), (func)), 0)
+# define TLS_DELETE(name)          mytassert(pthread_key_delete(name), 0)
+#endif // ifdef TLS
+
+extern TLS_DECL(chpl_thread_id_t,chpl_thread_id);
+extern TLS_DECL(void*, chpl_thread_data);
+
+static inline
+void* chpl_thread_getPrivateData(void) {
+  return TLS_GET(chpl_thread_data);
+}
+
+static inline
+void chpl_thread_setPrivateData(void* p) {
+  TLS_SET(chpl_thread_data, p);
+}
+
 #endif // _threads_pthreads_h_
diff --git a/runtime/src/threads/pthreads/threads-pthreads.c b/runtime/src/threads/pthreads/threads-pthreads.c
index e9dda8e..b3ddc7f 100644
--- a/runtime/src/threads/pthreads/threads-pthreads.c
+++ b/runtime/src/threads/pthreads/threads-pthreads.c
@@ -52,8 +52,8 @@ static thread_list_p   thread_list_tail = NULL; // tail of thread_list
 
 static pthread_attr_t  thread_attributes;
 
-static pthread_key_t   thread_id_key;
-static pthread_key_t   thread_private_key;
+TLS_DECL(chpl_thread_id_t,chpl_thread_id);
+TLS_DECL(void*, chpl_thread_data);
 
 static int32_t         maxThreads = 0;
 static uint32_t        numThreads = 0;
@@ -100,7 +100,7 @@ void chpl_thread_mutexUnlock(chpl_thread_mutex_p mutex) {
 // Thread management
 
 chpl_thread_id_t chpl_thread_getId(void) {
-  void* val = pthread_getspecific(thread_id_key);
+  void* val = (void*) TLS_GET(chpl_thread_id);
 
   if (val == NULL)
     return chpl_thread_nullThreadId;
@@ -196,14 +196,9 @@ void chpl_thread_init(void(*threadBeginFn)(void*),
   saved_threadBeginFn = threadBeginFn;
   saved_threadEndFn   = threadEndFn;
 
-  if (pthread_key_create(&thread_id_key, NULL))
-    chpl_internal_error("pthread_key_create(thread_id_key) failed");
-
-  if (pthread_setspecific(thread_id_key, (void*) (intptr_t) --curr_thread_id))
-    chpl_internal_error("thread id data key doesn't work");
-
-  if (pthread_key_create(&thread_private_key, NULL))
-    chpl_internal_error("pthread_key_create(thread_private_key) failed");
+  TLS_INIT(chpl_thread_id);
+  TLS_SET(chpl_thread_id, (intptr_t) --curr_thread_id);
+  TLS_INIT(chpl_thread_data);
 
   pthread_mutex_init(&thread_info_lock, NULL);
   pthread_mutex_init(&numThreadsLock, NULL);
@@ -267,8 +262,8 @@ void chpl_thread_exit(void) {
     chpl_mem_free(tlp, 0, 0);
   }
 
-  if (pthread_key_delete(thread_id_key) != 0)
-    chpl_internal_error("pthread_key_delete(thread_id_key) failed");
+  TLS_DELETE(chpl_thread_id);
+  TLS_DELETE(chpl_thread_data);
 
   if (pthread_attr_destroy(&thread_attributes) != 0)
     chpl_internal_error("pthread_attr_destroy() failed");
@@ -355,15 +350,15 @@ static void* pthread_func(void* arg) {
 
   pthread_mutex_unlock(&thread_info_lock);
 
-  if (pthread_setspecific(thread_id_key, (void*) (intptr_t) my_thread_id))
-    chpl_internal_error("thread id data key doesn't work");
+  TLS_SET(chpl_thread_id, (intptr_t) my_thread_id);
 
   if (saved_threadEndFn == NULL)
     (*saved_threadBeginFn)(arg);
   else {
     pthread_cleanup_push((void (*)(void*)) saved_threadEndFn, NULL);
     (*saved_threadBeginFn)(arg);
-    pthread_cleanup_pop(0);
+    pthread_cleanup_pop(1); // Shouldn't we run the thread
+                            // end function even if not cancelled?
   }
 
   return NULL;
@@ -388,15 +383,6 @@ void chpl_thread_destroy(void) {
   (void) pthread_setcancelstate(last_cancel_state, NULL);
 }
 
-void* chpl_thread_getPrivateData(void) {
-  return pthread_getspecific(thread_private_key);
-}
-
-void chpl_thread_setPrivateData(void* p) {
-  if (pthread_setspecific(thread_private_key, p))
-    chpl_internal_error("thread private data key doesn't work");
-}
-
 uint32_t chpl_thread_getMaxThreads(void) {
   return maxThreads;
 }
------------------------------------------------------------------------------
Subversion Kills Productivity. Get off Subversion & Make the Move to Perforce.
With Perforce, you get hassle-free workflows. Merge that actually works. 
Faster operations. Version large binaries.  Built-in WAN optimization and the
freedom to use Git, Perforce or both. Make the move to Perforce.
http://pubads.g.doubleclick.net/gampad/clk?id=122218951&iu=/4140/ostg.clktrk
_______________________________________________
Chapel-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/chapel-developers

Reply via email to