]> granicus.if.org Git - gc/commitdiff
Fix (allow) thread local allocations from within pthread TLS destructors
authorNiklas Therning <niklas@therning.org>
Tue, 6 Jan 2015 22:32:43 +0000 (23:32 +0100)
committerIvan Maidanski <ivmai@mail.ru>
Fri, 4 Sep 2015 17:36:50 +0000 (20:36 +0300)
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
thread_local_alloc.c

index 82fe2987133acafc72685616e757c1b1951bd844..ffa98c4990bdd70c3c302d91842f5d52ca4ad139 100644 (file)
@@ -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)
index 8d184f51aacc5f836a1fc877f2e823754b20b8ce..29a337b2773c737b75e8e8c9b374cb6968b0d4ce 100644 (file)
@@ -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;