Re: [Gc] pthreads and libgc

Ivan Maidanski ivmai at mail.ru
Sat Mar 19 11:18:17 PST 2011


Hi Andy,

Fri, 18 Mar 2011 21:56:04 +0100 Andy Wingo <wingo at pobox.com>:

> Hello list,
> 
> I was tracking down a bug in Guile, got to a sticky situation, and could
> use some input.  Let me first show you the code.
> 
> #include <unistd.h>
> #include <pthread.h>
> #include <time.h>
> #include <libguile.h>
> 
> static void *thread_with_guile(void *null)
> {
> return NULL;
> }
> 
> static void *the_thread(void *args)
> {
> scm_with_guile (thread_with_guile, NULL);
> return NULL;
> }
> 
> 
> int main(void)
> {
> int n;
> 
> for (n = 0; n < 10000; n++) {
> pthread_t ptid;
> fprintf (stderr, "%d: create", n);
> pthread_create(&ptid, NULL, the_thread, NULL);
> void *ret;
> fprintf (stderr, " join");
> pthread_join(ptid, &ret);
> fprintf (stderr, " finished.\n");
> }
> 
> return 0;
> }
> 
> I don't presume that you will compile it, but if you do, you can do so
> with "gcc -o test test.c `pkg-config --cflags --libs guile-2.0`".
> 
> As you see, it creates a bunch of threads, and does something within
> "guile mode" on each of them.  The use case is obviously for some big
> threaded application with plugins, and you don't know what thread will
> see Guile first.
> 
> The first scm_with_guile call will initialize Guile, which does a
> GC_INIT, which basically goes like this:
> 
> GC_all_interior_pointers = 0;
> GC_INIT ();

GC_all_interior_pointers cannot be modified after GC_INIT according to the spec. GC_set_all_interior_pointers() has an assertion check for this condition.

> 
> However, libgc appears already to have been initialized when this
> happens, automagically, because of pthreads.  If I run the program under
> GDB, it happens here:
> 
> Breakpoint 1, GC_init () at misc.c:634
> 634	{
> (gdb) thr apply all bt
> 
> Thread 1 (Thread 0x7ffff78df700 (LWP 14166)):
> #0  GC_init () at misc.c:634
> #1  0x0000003fc8e1455e in GC_generic_malloc_inner (lb=56, k=1) at malloc.c:119
> #2  0x0000003fc8e1f4ce in GC_pthread_create (new_thread=0x7fffffffe020,
> attr=0x0, start_routine=0x4007e3 <the_thread>, 
> arg=0x0) at pthread_support.c:1469
> #3  0x0000000000400853 in main ()
> 
> Unhappily though, the initialization is done with
> GC_all_interior_pointers == 1.  So later after Guile initializes, it
> gets a segfault:
> 
> Program received signal SIGSEGV, Segmentation fault.
> 0x0000003fc8e0f6e3 in GC_is_black_listed (h=0x655000, len=<value optimized
> out>) at blacklst.c:233
> 233	      if (get_pht_entry_from_index(GC_old_normal_bl, index)
> (gdb) thr apply all bt
> 
> Thread 2 (Thread 0x7ffff78dd700 (LWP 14169)):
> #0  0x0000003fc8e0f6e3 in GC_is_black_listed (h=0x655000, len=<value optimized
> out>) at blacklst.c:233
> ...
> 
> In this case `GC_old_normal_bl' is NULL, as it is only initialized to a
> valid value if GC_all_interior_pointers is zero, which was not the case
> when libgc was automatically initialized.
> 
> What should we do here?

You could compile GC without -D ALL_INTERIOR_POINTERS.

But, anyway,  it is recommended to initialize GC explicitly (i.e. by GC_INIT), so placing GC_INIT() (together with GC_set_all_interior_pointer) to the beginning of your main() should be the best way out.

Regards.

> 
> Thanks,
> 
> Andy
> -- 
> http://wingolog.org/



More information about the Gc mailing list