[Gc] Calling ‘GC_INIT’ from a secondary thread

Ludovic Courtès ludo at gnu.org
Fri Apr 15 14:35:04 PDT 2011


Hi Hans,

"Boehm, Hans" <hans.boehm at hp.com> writes:

>> From: Andy Wingo
>> ...
>> [From Ivan:]
>> > 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.
>> 
>> We can add some documentation to this regard in the manual, if needed.
>> But is there no way to get around this, and do the right thing?  For
>> example, to avoid implicit GC initialization in response to a
>> pthread_create.
>> 
> The problem is that GC_pthread_create needs to allocate memory, and relies on some other GC state.  Hence the GC must have been initialized for it to work.
>
> For newer collectors, it might be possible to instead arrange for pthread_create not to be redirected to GC_pthread_create, and for threads that need to be known to the GC to register themselves.  I haven't thought through whether that might be feasible here.

With current CVS, it doesn’t seem to be possible to call GC_INIT from a
secondary thread, as in this example:

--8<---------------cut here---------------start------------->8---
#define GC_THREADS 1
#define GC_NO_THREAD_REDIRECTS 1

#include <gc/gc.h>
#include <pthread.h>
#include <stdlib.h>

static void *
thread (void *arg)
{
  GC_INIT ();
  GC_MALLOC (123);
  GC_MALLOC (12345);
  return NULL;
}

int
main (int argc, char *argv[])
{
  pthread_t t;

  pthread_create (&t, NULL, thread, NULL);
  pthread_join (t, NULL);

  return EXIT_SUCCESS;
}

/*
   Local Variables:
   compile-command: "gcc -Wall t.c `pkg-config bdw-gc --cflags --libs`"
   End:
 */
--8<---------------cut here---------------end--------------->8---

This program segfaults:

--8<---------------cut here---------------start------------->8---
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff73e5700 (LWP 772)]
GC_push_all_eager (bottom=<value optimized out>, top=<value optimized out>) at ../mark.c:1528
1528            GC_PUSH_ONE_STACK(q, p);
(gdb) thread apply all bt

Thread 2 (Thread 0x7ffff73e5700 (LWP 772)):
#0  GC_push_all_eager (bottom=<value optimized out>, top=<value optimized out>) at ../mark.c:1528
#1  0x00007ffff7b91d4a in GC_push_all_stacks () at ../pthread_stop_world.c:336
#2  0x00007ffff7b898c4 in GC_mark_some (cold_gc_frame=0x7ffff73e4e0c "") at ../mark.c:373
#3  0x00007ffff7b800e8 in GC_stopped_mark (stop_func=0x7ffff7b7fbf0 <GC_never_stop_func>) at ../alloc.c:639
#4  0x00007ffff7b80880 in GC_try_to_collect_inner (stop_func=0x7ffff7b7fbf0 <GC_never_stop_func>) at ../alloc.c:457
#5  0x00007ffff7b8bb19 in GC_init () at ../misc.c:991
#6  0x0000000000400865 in thread ()
#7  0x00007ffff75f0cec in start_thread () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libpthread.so.0
#8  0x00007ffff78d81ed in clone () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libc.so.6

Thread 1 (Thread 0x7ffff7ff5700 (LWP 769)):
#0  0x00007ffff75f1f15 in pthread_join () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libpthread.so.0
#1  0x00000000004008bb in main ()
--8<---------------cut here---------------end--------------->8---

Is it expected?

> Another imperfect solution might be to set all_interior_pointers and probably call GC_INIT in a constructor, either a C++ constructor, or a C function that's suitably attributed.  That still fails if other constructors run into this problem before our constructor runs.

If GC_INIT must be called from the main thread, then constructors would
seem to be the only way to get it called.

Thanks,
Ludo’.



More information about the Gc mailing list