Fix support for threads already known to GC
authorAndy Wingo <wingo@pobox.com>
Tue, 28 Feb 2017 12:14:02 +0000 (13:14 +0100)
committerAndy Wingo <wingo@pobox.com>
Tue, 28 Feb 2017 12:14:02 +0000 (13:14 +0100)
* libguile/threads.h (scm_i_thread): Add bool tracking whether the
  thread needs to be unregistered from libgc.
* libguile/threads.c (guilify_self_1): Add needs_unregister arg.
  (on_thread_exit): Only unregister thread if the thread needs it.
  (scm_i_init_thread_for_guile): A thread needs unregistering if
  GC_register_my_thread succeeded.
  (scm_threads_prehistory): Don't unregister initial thread.

  Fixes #19523.  Thanks to Anthonin Bonnefoy for the report.

libguile/threads.c
libguile/threads.h

index 1faa539e102afe6fb492f6fb5dab06d6413e7a51..e67616c03d3fc8fb076351380e0e48dac4fd01b0 100644 (file)
@@ -372,7 +372,7 @@ static SCM default_dynamic_state;
 /* Perform first stage of thread initialisation, in non-guile mode.
  */
 static void
-guilify_self_1 (struct GC_stack_base *base)
+guilify_self_1 (struct GC_stack_base *base, int needs_unregister)
 {
   scm_i_thread t;
 
@@ -410,6 +410,7 @@ guilify_self_1 (struct GC_stack_base *base)
 
   t.exited = 0;
   t.guile_mode = 0;
+  t.needs_unregister = needs_unregister;
 
   /* The switcheroo.  */
   {
@@ -523,8 +524,13 @@ on_thread_exit (void *v)
       scm_i_vm_free_stack (vp);
   }
 
+#ifdef SCM_HAVE_THREAD_STORAGE_CLASS
+  scm_i_current_thread = NULL;
+#endif
+
 #if SCM_USE_PTHREAD_THREADS
-  GC_unregister_my_thread ();
+  if (t->needs_unregister)
+    GC_unregister_my_thread ();
 #endif
 }
 
@@ -586,6 +592,8 @@ scm_i_init_thread_for_guile (struct GC_stack_base *base,
        }
       else
        {
+          int needs_unregister = 0;
+
          /* Guile is already initialized, but this thread enters it for
             the first time.  Only initialize this thread.
          */
@@ -593,10 +601,11 @@ scm_i_init_thread_for_guile (struct GC_stack_base *base,
 
           /* Register this thread with libgc.  */
 #if SCM_USE_PTHREAD_THREADS
-          GC_register_my_thread (base);
+          if (GC_register_my_thread (base) == GC_SUCCESS)
+            needs_unregister = 1;
 #endif
 
-         guilify_self_1 (base);
+         guilify_self_1 (base, needs_unregister);
          guilify_self_2 (dynamic_state);
        }
       return 1;
@@ -1782,7 +1791,7 @@ scm_threads_prehistory (void *base)
                 GC_MAKE_PROC (GC_new_proc (thread_mark), 0),
                 0, 1);
 
-  guilify_self_1 ((struct GC_stack_base *) base);
+  guilify_self_1 ((struct GC_stack_base *) base, 0);
 }
 
 scm_t_bits scm_tc16_thread;
index 645e5eb6551028f4f030afb3ce657fdcb1583ca9..55c566d2385448ea52561f9a4a22ca744d153b05 100644 (file)
@@ -59,6 +59,9 @@ typedef struct scm_i_thread {
 
   /* Boolean indicating whether the thread is in guile mode.  */
   int guile_mode;
+  /* Boolean indicating whether to call GC_unregister_my_thread () when
+     this thread exits.  */
+  int needs_unregister;
 
   struct scm_thread_wake_data *wake;
   scm_i_pthread_cond_t sleep_cond;