[gclist] Boehm GC & threads on Linux

Boehm, Hans hboehm@exch.hpl.hp.com
Sat, 19 Feb 2000 15:07:25 -0800


Linuxthreads in fact uses a two level tree data structure to store
thread specific data.  I think I scan the first, but the second is currently
(where current is defined to be the snapshot in my workarea) allocated
with calloc, and thus not scanned.  This may have changed fairly recently,
I haven't checked.

I would greatly prefer to somehow make this work correctly, more or less
transparently, though this probably won't happen real soon.  At a minimum,
the collector should #define pthread_setspecific and friends to
(semi-)transparently apply David's trick.  I might try to talk Ulrich into
exporting a bit more info from linuxthreads.

Hans

-----Original Message-----
From: David Chase [mailto:chase@world.std.com]
Sent: Thursday, February 17, 2000 10:23 AM
To: Fergus Henderson; gclist@iecc.com
Subject: Re: [gclist] Boehm GC & threads on Linux


At 03:49 AM 2/18/00 +1100, Fergus Henderson wrote:
>When compiled in "thread-safe" mode,
>the Mercury runtime allocates a big structure (that it uses that to
>hold some of our virtual machine registers, pointers to the Mercury
>stacks, etc.) on the GC'd heap, and puts a pointer to that structure
>in thread-local storage.

As I understand the usual implementations of thread local storage,
that memory is not going to get traced.  The thread runtime has
probably used malloc to allocate a per-thread vector of pointers
to stuff, stuffed a pointer to that vector in some Secret Place,
and that vector is not going to get traced.

I figure that modifying Linux is not an option, and modifying
the collector in a way that it depends on internal Linux data
stuctures is not a long-term good solution.  Plan C is to modify
your thread-starting code so that it contains something along the
following lines:

  typedef void * voidstar;
  static void inhibit_tail_call_proc(voidstar x) {}
  void (*inhibit_tail_call)(voidstar) = inhibit_tail_call_proc;
  

  mercury_thread_start(void * parameters) {
     volatile voidstar duplicate_of_tsd = gc_malloc (big_enough_for_data);
     pthread_setspecific(key, duplicate_of_tsd);
     ...
     /* run thread */
     ...
     inhibit_tail_call(duplicate_of_tsd);
  }

The name of the game here is to be sure that the stack contains
a copy of the same pointer you stuffed into the thread-specific-data.
That will prevent collection of the TSD, without you needing to know
the gory details.

>If you have any hints on how to debug this kind of thing,
>they'd be much appreciated.  Thanks.

It's always a little hard to figure out where you didn't
do the thing that you were supposed to be doing.

David Chase
chase@naturalbridge.com
http;//www.naturalbridge.com