a aa <[email protected]> writes:

> # Intended behaviour
> According to the [documentation](
> https://www.gnu.org/software/guile/manual/html_node/Guile-Initialization-Functions.html),
> you should be able to call `scm_with_guile` concurrently.

It looks like this is an issue in thread.c when multiple threads are
racing, before guile has been initialized, with respect to
scm_i_init_thread_for_guile. All of them will have a dynamic_state value
that came from default_dynamic_state, which is 0L at startup. One of
them will get the scm_i_init_mutex and initialize guile, which will set
the default_dynamic_state to SCM_BOOL_F via scm_init_threads.

Then, when the thread that initialized guile releases scm_i_init_mutex,
the other threads will proceed, pass the stale 0L to guilify_self_2, and
segfault in the is_dynamic_state call in scm_set_current_dynamic_state:

  (gdb) where
  #0  0x00007ffff7ed4eb6 in is_dynamic_state (x=0x0)
      at .../src/guile/up/main/libguile/fluids.c:108
  #1  scm_set_current_dynamic_state (state=0x0)
      at .../src/guile/up/main/libguile/fluids.c:624
  #2  0x00007ffff7f4476d in guilify_self_2 
(dynamic_state=dynamic_state@entry=0x0)
      at .../src/guile/up/main/libguile/threads.c:449
  #3  0x00007ffff7f48b28 in scm_i_init_thread_for_guile 
(base=base@entry=0x7ffff7038e60, 
      dynamic_state=dynamic_state@entry=0x0) at 
.../src/guile/up/main/libguile/threads.c:599
  #4  0x00007ffff7f48d56 in scm_i_init_thread_for_guile (base=0x7ffff7038e60, 
dynamic_state=0x0)
      at .../src/guile/up/main/libguile/threads.c:681
  #5  with_guile (base=0x7ffff7038e60, data=0x7ffff7038e90)
      at .../src/guile/up/main/libguile/threads.c:642
  #6  0x00007ffff7c007e4 in GC_call_with_stack_base (fn=fn@entry=0x7ffff7f48cb0 
<with_guile>, 
      arg=arg@entry=0x7ffff7038e90) at ../extra/../misc.c:2178
  #7  0x00007ffff7f41ce8 in scm_i_with_guile (func=<optimized out>, 
data=<optimized out>, 
      dynamic_state=<optimized out>) at 
.../src/guile/up/main/libguile/threads.c:692
  #8  scm_with_guile (func=<optimized out>, data=<optimized out>)
      at .../src/guile/up/main/libguile/threads.c:698
  #9  0x0000555555555188 in run_with_guile () at main.c:10
  #10 0x00007ffff7cebb7b in start_thread (arg=<optimized out>) at 
./nptl/pthread_create.c:448
  #11 0x00007ffff7d697b8 in __GI___clone3 () at 
../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

As an aside, I'm also not sure "who" the default_dynamic_state
SCM_BOOL_F value is for (via scm_init_threads).

In any case, you can "fix" the problem by having the other threads
notice that they now have a stale dynamic_state and retrieve a fresh one
like this:

diff --git a/libguile/threads.c b/libguile/threads.c
index 6b4510d53..442ce4c45 100644
--- a/libguile/threads.c
+++ b/libguile/threads.c
@@ -368,7 +368,7 @@ static scm_i_pthread_mutex_t thread_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZE
 static scm_thread *all_threads = NULL;
 static int thread_count;
 
-static SCM default_dynamic_state;
+static SCM default_dynamic_state; // Either 0 or SCM_BOOL_F during init
 
 /* Perform first stage of thread initialisation, in non-guile mode.
  */
@@ -595,6 +595,11 @@ scm_i_init_thread_for_guile (struct GC_stack_base *base,
             needs_unregister = 1;
 #endif
 
+          // We were blocked while another thread was initializing
+          // guile, so we need to re-read the (now correct) state.
+          if (dynamic_state == 0L || scm_is_eq (dynamic_state, SCM_BOOL_F))
+              dynamic_state = default_dynamic_state;
+
 	  guilify_self_1 (base, needs_unregister);
 	  guilify_self_2 (dynamic_state);
 	}
which avoids the segfault, but I suspect it may not be the fix we want.

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4

Reply via email to