summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Therning <niklas@therning.org>2015-01-06 23:32:43 +0100
committerIvan Maidanski <ivmai@mail.ru>2015-09-04 20:36:50 +0300
commit2c870edc641f6b9e565f7cd297251cfd83de76af (patch)
tree740321c4b4718e4f0235c4b7ba47907062470030
parent60db5e97e8c61652f9b29b201832eaadd18f1dfc (diff)
downloadbdwgc-2c870edc641f6b9e565f7cd297251cfd83de76af.tar.gz
Fix (allow) thread local allocations from within pthread TLS destructors
Prevents the GC_thread_key from being cleared on thread exit until after the thread has been unregistered by GC_unregister_my_thread_inner. * include/private/thread_local_alloc.h (GC_remove_specific): Call pthread_setspecific(key, NULL) if USE_PTHREAD_SPECIFIC; update comment. * thread_local_alloc.c (reset_thread_key): New static function if USE_PTHREAD_SPECIFIC); define (as macro) to 0 otherwise. * thread_local_alloc.c (GC_init_thread_local): Pass reset_thread_key (instead of 0) to GC_key_create.
-rw-r--r--include/private/thread_local_alloc.h4
-rw-r--r--thread_local_alloc.c15
2 files changed, 17 insertions, 2 deletions
diff --git a/include/private/thread_local_alloc.h b/include/private/thread_local_alloc.h
index 82fe2987..ffa98c49 100644
--- a/include/private/thread_local_alloc.h
+++ b/include/private/thread_local_alloc.h
@@ -108,7 +108,9 @@ typedef struct thread_local_freelists {
# define GC_getspecific pthread_getspecific
# define GC_setspecific pthread_setspecific
# define GC_key_create pthread_key_create
-# define GC_remove_specific(key) /* No need for cleanup on exit. */
+# define GC_remove_specific(key) pthread_setspecific(key, NULL)
+ /* Explicitly delete the value to stop the TLS */
+ /* destructor from being called repeatedly. */
typedef pthread_key_t GC_key_t;
#elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
# define GC_getspecific(x) (x)
diff --git a/thread_local_alloc.c b/thread_local_alloc.c
index 8d184f51..29a337b2 100644
--- a/thread_local_alloc.c
+++ b/thread_local_alloc.c
@@ -82,6 +82,19 @@ static void return_freelists(void **fl, void **gfl)
}
}
+#ifdef USE_PTHREAD_SPECIFIC
+ /* Re-set the TLS value on thread cleanup to allow thread-local */
+ /* allocations to happen in the TLS destructors. */
+ /* GC_unregister_my_thread (and similar routines) will finally set */
+ /* the GC_thread_key to NULL preventing this destructor from being */
+ /* called repeatedly. */
+ static void reset_thread_key(void* v) {
+ pthread_setspecific(GC_thread_key, v);
+ }
+#else
+# define reset_thread_key 0
+#endif
+
/* Each thread structure must be initialized. */
/* This call must be made from the new thread. */
GC_INNER void GC_init_thread_local(GC_tlfs p)
@@ -91,7 +104,7 @@ GC_INNER void GC_init_thread_local(GC_tlfs p)
GC_ASSERT(I_HOLD_LOCK());
if (!EXPECT(keys_initialized, TRUE)) {
GC_ASSERT((word)&GC_thread_key % sizeof(word) == 0);
- if (0 != GC_key_create(&GC_thread_key, 0)) {
+ if (0 != GC_key_create(&GC_thread_key, reset_thread_key)) {
ABORT("Failed to create key for local allocator");
}
keys_initialized = TRUE;