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