From 2c870edc641f6b9e565f7cd297251cfd83de76af Mon Sep 17 00:00:00 2001 From: Niklas Therning Date: Tue, 6 Jan 2015 23:32:43 +0100 Subject: [PATCH] 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. --- include/private/thread_local_alloc.h | 4 +++- thread_local_alloc.c | 15 ++++++++++++++- 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; -- 2.40.0