[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Gc] pthreads and libgc
From: |
Ivan Maidanski |
Subject: |
Re: [Gc] pthreads and libgc |
Date: |
Sat, 19 Mar 2011 22:18:17 +0300 |
Hi Andy,
Fri, 18 Mar 2011 21:56:04 +0100 Andy Wingo <address@hidden>:
> 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/