[PATCH] [Gc] Using the Boehm-Demers-Weiser GC with a new threading library

Stephane Epardaud Stephane.Epardaud at sophia.inria.fr
Tue Jul 26 02:39:41 PDT 2005


Hello,

Thanks to your kind help, I'm now proposing a patch for inclusion in the 7.0a3
branch of the GC, in order to add support for LURC threads. LURC is available at
http://www.inria.fr/mimosa/Stephane.Epardaud/lurc/ and includes the proper API
for the GC support.

LURC threads are available in two flavours: either only cooperative synchronous
threads, or with the addition of asynchronous threads supported via PThreads.

My patch does the following:
- Add '--enable-threads=lurc' argument to configure.ac in order to build support
for the first flavour of LURC threads (no PThreads) located in lurc_support.c.
This defines GC_LURC_THREADS but not GC_PTHREADS.
- Add '--enable-threads=lurc-pthreads' argument to configure.ac in order to
build support for the second flavour of LURC threads (with PThreads). This acts
just as if --enable-threads=pthreads was passed and compiles pthread_support.c,
pthread_stop_world.c or darwin_stop_world.c (where applicable), to which I added
support for LURC threads. This accounts for two configurations of LURC: LURC
synchronous threads only, but other unrelated (non-LURC) PThreads side-to-side,
or LURC sync and async threads, and other unrelated (non-LURC) PThreads
side-to-side.

I've included a fix to get MacOSX to compile with PThreads (in mach_dep.c) which
consists in not using the ASM GC_push_regs but __builtin_unwind_init in order to
get the GC_with_callee_saves_pushed function needed by pthread_support.c. But my
problem when compiling on Alpha/Linux with PThreads is still not fixed.
The problem (as I've stated in a previous mail) is still that on alphas,
mach_dep.c is not compiled, and GC_with_callee_saves_pushed is thus undefined.
My fix was to include mach_dep.c in $machdep in configure.ac for alphas, but
since I'm not too sure about the consequences, I haven't done it in this patch
(it did work for my LURC tests though).

My patches only add code if compiling for LURC, and thus come at no expense to
other types of threads, and I'm officially proposing to support any problems
related to it and maintain that code when new versions of the GC and/or LURC
come around. So I guess I hope it does get included in the mainstream 7.0 branch
so that I can advertise LURC support in the Boehm GC on my website :)

If there's anything wrong or unwelcome in my patch, please let me know and I'll
try to fix it ASAP.

Note that I've only added support for LURC on some architectures/OSes, but since
LURC only compiles and runs on these for now, it should not matter to anyone
trying to use LURC.
-------------- next part --------------
diff -ruw gc7.0alpha3-mint/configure.ac gc7.0alpha3-lurc/configure.ac
--- gc7.0alpha3-mint/configure.ac	2005-04-20 02:44:58.000000000 +0200
+++ gc7.0alpha3-lurc/configure.ac	2005-07-04 16:52:56.000000000 +0200
@@ -45,6 +45,23 @@
 GC_CFLAGS=${gc_cflags}
 AC_SUBST(GC_CFLAGS)
 
+AC_LANG(C)
+AC_DEFUN(GC_CHECK_DEFINE, [
+ dnl $1: header file
+ dnl $2: CPP variable
+ dnl $3: then
+ dnl $4: else
+ AC_PREPROC_IFELSE([
+ #include <$1>
+ #ifndef $2
+ # error "$2 undefined"
+ #else
+  ok
+ #endif
+ ],
+                   [$3], [$4])
+])
+
 AC_ARG_ENABLE(threads,
   [AC_HELP_STRING([--enable-threads=TYPE], [choose threading package])],
   THREADS=$enableval,
@@ -68,6 +85,12 @@
 AC_ARG_ENABLE(cplusplus,
     [AC_HELP_STRING([--enable-cplusplus], [install C++ support])])
 
+AC_CHECK_HEADER([lurc.h], [gc_lurc_h=1], [])
+AC_MSG_CHECKING(for LURC GC support)
+GC_CHECK_DEFINE([lurc.h], [LURC_ENABLE_GC],
+                [AC_MSG_RESULT(ok); gc_lurc_gc=1],
+                [])
+
 INCLUDES=-I${srcdir}/include
 THREADDLLIBS=
 ## Libraries needed to support dynamic loading and/or threads.
@@ -75,9 +98,26 @@
  no | none | single)
     THREADS=none
     ;;
- posix | pthreads)
+ posix | pthreads | lurc-pthreads)
+    _SAVE_THREADS=$THREADS
     THREADS=posix
     THREADDLLIBS=-lpthread
+    # check wether we have lurc with GC && PThread support
+    if test $_SAVE_THREADS = lurc-pthreads
+    then
+        if test "x$gc_lurc_h" = x 
+        then AC_MSG_ERROR(Missing lurc.h)
+        fi
+        if test "x$gc_lurc_gc" = x
+        then AC_MSG_ERROR(LURC not compiled with GC support)
+        fi
+        AC_MSG_CHECKING(for LURC PThread support)
+        GC_CHECK_DEFINE([lurc.h], [LURC_ENABLE_PTHREAD],
+                        [AC_MSG_RESULT(ok)],
+                        [AC_MSG_ERROR(LURC not compiled with PThread support)])
+        THREADDLLIBS="$THREADLIBS -llurc"
+        AC_DEFINE(GC_LURC_THREADS)
+    fi
     case "$host" in
      x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
 	AC_DEFINE(GC_LINUX_THREADS)
@@ -149,6 +189,16 @@
 	;;
     esac
     ;;
+ lurc)
+    if test "x$gc_lurc_h" = x 
+    then AC_MSG_ERROR(Missing lurc.h)
+    fi
+    if test "x$gc_lurc_gc" = x
+    then AC_MSG_ERROR(LURC not compiled with GC support)
+    fi
+    THREADDLLIBS=-llurc
+    AC_DEFINE(GC_LURC_THREADS)
+    ;;
  win32)
     AC_DEFINE(GC_WIN32_THREADS)
     dnl Wine getenv may not return NULL for missing entry
@@ -184,6 +234,7 @@
 AC_SUBST(THREADDLLIBS)
 AM_CONDITIONAL(THREADS, test x$THREADS != xnone)
 AM_CONDITIONAL(PTHREADS, test x$THREADS = xposix)
+AM_CONDITIONAL(LURC_THREADS, test x$THREADS = xlurc)
 AM_CONDITIONAL(AIX_IRIX_THREADS, test x$aix_irix_threads = xtrue)
 AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue)
 AM_CONDITIONAL(ARCH_SOLARIS, test x$solaris_threads = xtrue)
@@ -199,7 +250,9 @@
 # We never want libdl on darwin. It is a fake libdl that just ends up making
 # dyld calls anyway
 case "$host" in
-  *-*-darwin*) ;;
+  *-*-darwin*) 
+    CFLAGS="$CFLAGS -no-cpp-precomp"
+    ;;
   *) 
     AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl")
     ;;
diff -ruw gc7.0alpha3-mint/include/gc_config_macros.h gc7.0alpha3-lurc/include/gc_config_macros.h
--- gc7.0alpha3-mint/include/gc_config_macros.h	2005-04-22 02:57:23.000000000 +0200
+++ gc7.0alpha3-lurc/include/gc_config_macros.h	2005-06-29 15:00:28.000000000 +0200
@@ -22,6 +22,9 @@
 #if defined(AIX_THREADS)
 # define GC_AIX_THREADS
 #endif
+#if defined(LURC_THREADS)
+# define GC_LURC_THREADS
+#endif
 #if defined(HPUX_THREADS)
 # define GC_HPUX_THREADS
 #endif
diff -ruw gc7.0alpha3-mint/include/gc.h gc7.0alpha3-lurc/include/gc.h
--- gc7.0alpha3-mint/include/gc.h	2005-04-22 02:59:00.000000000 +0200
+++ gc7.0alpha3-lurc/include/gc.h	2005-06-29 14:59:25.000000000 +0200
@@ -917,7 +917,8 @@
 #define GC_NEXT(p) (*(void * *)(p)) 	/* Retrieve the next element	*/
 					/* in returned list.		*/
 extern void GC_thr_init(void);	/* Needed for Solaris/X86	*/
-
+#elif defined(GC_LURC_THREADS)
+extern void GC_thr_init(void);	/* Needed for Solaris/X86	*/
 #endif /* THREADS && !SRC_M3 */
 
 #if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
diff -ruw gc7.0alpha3-mint/include/private/gcconfig.h gc7.0alpha3-lurc/include/private/gcconfig.h
--- gc7.0alpha3-mint/include/private/gcconfig.h	2005-04-22 19:57:01.000000000 +0200
+++ gc7.0alpha3-lurc/include/private/gcconfig.h	2005-07-05 16:53:32.000000000 +0200
@@ -1956,7 +1956,7 @@
 
 # if defined(PCR) || defined(SRC_M3) || \
 		defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \
-		defined(GC_PTHREADS)
+		defined(GC_PTHREADS) || defined(GC_LURC_THREADS)
 #   define THREADS
 # endif
 
diff -ruw gc7.0alpha3-mint/include/private/gc_locks.h gc7.0alpha3-lurc/include/private/gc_locks.h
--- gc7.0alpha3-mint/include/private/gc_locks.h	2005-04-19 00:51:38.000000000 +0200
+++ gc7.0alpha3-lurc/include/private/gc_locks.h	2005-07-06 14:04:12.000000000 +0200
@@ -164,6 +164,11 @@
 		/* Used on platforms were locks can be reacquired,	*/
 		/* so it doesn't matter if we lie.			*/
 #  endif
+
+#  if defined(GC_LURC_THREADS) && !defined(GC_PTHREADS)
+#   define LOCK()
+#   define UNLOCK()
+#  endif
 # else /* !THREADS */
 #    define LOCK()
 #    define UNLOCK()
diff -ruw gc7.0alpha3-mint/include/private/gc_priv.h gc7.0alpha3-lurc/include/private/gc_priv.h
--- gc7.0alpha3-mint/include/private/gc_priv.h	2005-03-30 06:34:09.000000000 +0200
+++ gc7.0alpha3-lurc/include/private/gc_priv.h	2005-07-05 16:12:08.000000000 +0200
@@ -315,7 +315,7 @@
  				   PCR_waitForever);
 # else
 #   if defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) \
-	|| defined(GC_PTHREADS)
+	|| defined(GC_PTHREADS) || defined(GC_LURC_THREADS)
       void GC_stop_world();
       void GC_start_world();
 #     define STOP_WORLD() GC_stop_world()
diff -ruw gc7.0alpha3-mint/mach_dep.c gc7.0alpha3-lurc/mach_dep.c
--- gc7.0alpha3-mint/mach_dep.c	2005-02-24 02:13:08.000000000 +0100
+++ gc7.0alpha3-lurc/mach_dep.c	2005-07-05 16:55:51.000000000 +0200
@@ -75,6 +75,10 @@
 
 #undef HAVE_PUSH_REGS
 
+#if defined(DARWIN) && defined(THREADS)
+# undef USE_ASM_PUSH_REGS
+#endif
+
 #if defined(USE_ASM_PUSH_REGS)
 #  define HAVE_PUSH_REGS
 #else  /* No asm implementation */
@@ -210,7 +214,7 @@
 
 #   if defined(HAVE_PUSH_REGS)
       GC_push_regs();
-#   elif defined(UNIX_LIKE)
+#   elif defined(UNIX_LIKE) && !defined(DARWIN)
       ucontext_t ctxt;
       getcontext(&ctxt);
       context = &ctxt;
diff -ruw gc7.0alpha3-mint/misc.c gc7.0alpha3-lurc/misc.c
--- gc7.0alpha3-mint/misc.c	2005-03-29 03:23:38.000000000 +0200
+++ gc7.0alpha3-lurc/misc.c	2005-07-05 16:21:31.000000000 +0200
@@ -64,7 +64,7 @@
 		/* Used only for assertions, and to prevent	 */
 		/* recursive reentry in the system call wrapper. */
 #     endif 
-#   else
+#   elif !defined(GC_LURC_THREADS)
        --> declare allocator lock here
 #   endif
 # endif
@@ -638,7 +638,7 @@
 	GC_init_netbsd_elf();
 #   endif
 #   if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
-       || defined(GC_WIN32_THREADS)
+       || defined(GC_WIN32_THREADS) || defined(GC_LURC_THREADS)
         GC_thr_init();
 #   endif
 #   ifdef GC_SOLARIS_THREADS
@@ -646,7 +646,7 @@
         GC_dirty_init();
 #   endif
 #   if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
-	|| defined(GC_SOLARIS_THREADS)
+	|| defined(GC_SOLARIS_THREADS) || defined(GC_LURC_THREADS)
       if (GC_stackbottom == 0) {
 	GC_stackbottom = GC_get_main_stack_base();
 #       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
diff -ruw gc7.0alpha3-mint/os_dep.c gc7.0alpha3-lurc/os_dep.c
--- gc7.0alpha3-mint/os_dep.c	2005-04-19 00:57:15.000000000 +0200
+++ gc7.0alpha3-lurc/os_dep.c	2005-06-28 14:32:43.000000000 +0200
@@ -2023,7 +2023,7 @@
 
 
 # if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS) || \
-     defined(GC_WIN32_THREADS)
+     defined(GC_WIN32_THREADS) || defined(GC_LURC_THREADS)
 
 extern void GC_push_all_stacks(void);
 
diff -ruw gc7.0alpha3-mint/pthread_stop_world.c gc7.0alpha3-lurc/pthread_stop_world.c
--- gc7.0alpha3-mint/pthread_stop_world.c	2005-04-07 22:48:38.000000000 +0200
+++ gc7.0alpha3-lurc/pthread_stop_world.c	2005-07-04 10:08:40.000000000 +0200
@@ -4,6 +4,10 @@
      && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
      && !defined(GC_DARWIN_THREADS) && !defined(GC_AIX_THREADS)
 
+#ifdef GC_LURC_THREADS
+# include <lurc.h>
+#endif /* GC_LURC_THREADS */
+
 #include <signal.h>
 #include <semaphore.h>
 #include <errno.h>
@@ -227,6 +231,10 @@
     /* On IA64, we also need to scan the register backing store. */
     IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
     pthread_t me = pthread_self();
+#   ifdef GC_LURC_THREADS
+      lurc_thread_t lt = NULL;
+      void *llo,*lhi;
+#   endif /* GC_LURC_THREADS */
     
     if (!GC_thr_initialized) GC_thr_init();
     #if DEBUG_THREADS
@@ -260,6 +268,10 @@
     	              (unsigned)(p -> id), lo, hi);
         #endif
 	if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
+#       ifdef GC_LURC_THREADS
+        /* check wether the lurc lib wants us to push this now or later */
+          if (lurc_gc_is_lurc_thread(p -> id, lo, hi)) continue;
+#       endif /* GC_LURC_THREADS */
 #       ifdef STACK_GROWS_UP
 	  /* We got them backwards! */
           GC_push_all_stack(hi, lo);
@@ -279,6 +291,18 @@
 #	endif
       }
     }
+#   ifdef GC_LURC_THREADS
+    /* walk all those threads to ask for the roots */
+    while ((lt = lurc_get_next_thread(lt)) != NULL) {
+      lurc_gc_get_root(lt, &llo, &lhi);
+      if(llo != NULL)
+        GC_push_all_stack(llo, lhi);
+    }
+    /* does it have another part ? */
+    lurc_gc_get_additional_root(&llo, &lhi);
+    if (llo != NULL)
+      GC_push_all_stack(llo, lhi);
+#   endif /* GC_LURC_THREADS */
     if (!found_me && !GC_in_thread_creation)
       ABORT("Collecting from unknown thread.");
 }
@@ -307,6 +331,9 @@
             if (p -> flags & FINISHED) continue;
             if (p -> stop_info.last_stop_count == GC_stop_count) continue;
 	    if (p -> thread_blocked) /* Will wait */ continue;
+#           ifdef GC_LURC_THREADS
+            if (!lurc_gc_can_stop_thread(p -> id)) continue;
+#           endif /* GC_LURC_THREADS */
             n_live_threads++;
 	    #if DEBUG_THREADS
 	      GC_printf("Sending suspend signal to 0x%x\n",
@@ -420,7 +447,10 @@
         if (p -> id != my_thread) {
             if (p -> flags & FINISHED) continue;
 	    if (p -> thread_blocked) continue;
+#           ifdef GC_LURC_THREADS
+            if (!lurc_gc_can_stop_thread(p -> id)) continue;
+#           endif /* GC_LURC_THREADS */
             n_live_threads++;
 	    #if DEBUG_THREADS
 	      GC_printf("Sending restart signal to 0x%x\n",
--- gc7.0alpha3-mint/darwin_stop_world.c	2004-10-19 20:47:16.000000000 +0200
+++ gc7.0alpha3-lurc/darwin_stop_world.c	2005-07-26 10:59:56.206902128 +0200
@@ -2,6 +2,10 @@
 
 # if defined(GC_DARWIN_THREADS)
 
+#ifdef GC_LURC_THREADS
+# include <lurc.h>
+#endif /* GC_LURC_THREADS */
+
 /* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
    Page 49:
    "The space beneath the stack pointer, where a new stack frame would normally
@@ -56,6 +60,22 @@
   return (unsigned int)frame;
 }	
 
+#ifdef GC_LURC_THREADS
+static GC_thread lookup_gc_thread(thread_act_t mach_thread){
+  int i;
+  GC_thread p;
+  
+  for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+    for (p = GC_threads[i]; 0 != p; p = p -> next) {
+      if(p->stop_info.mach_thread == mach_thread)
+        return p;
+    }
+  }
+  /* not found ? */
+  return NULL;
+}
+#endif /* GC_LURC_THREADS */
+
 void GC_push_all_stacks() {
     int i;
     kern_return_t r;
@@ -63,6 +83,10 @@
     ptr_t lo, hi;
     thread_act_array_t act_list = 0;
     mach_msg_type_number_t listcount = 0;
+#   ifdef GC_LURC_THREADS
+      lurc_thread_t lt = NULL;
+      void *llo,*lhi;
+#   endif /* GC_LURC_THREADS */
 
     me = mach_thread_self();
     if (!GC_thr_initialized) GC_thr_init();
@@ -71,6 +95,9 @@
     if(r != KERN_SUCCESS) ABORT("task_threads failed");
     for(i = 0; i < listcount; i++) {
       thread_act_t thread = act_list[i];
+#     ifdef GC_LURC_THREADS
+        GC_thread gct = lookup_gc_thread(thread);
+#     endif /* GC_LURC_THREADS */
       if (thread == me) {
 	lo = GC_approx_sp();
 	hi = (ptr_t)FindTopOfStack(0);
@@ -150,8 +177,27 @@
 		  (unsigned long) thread, lo, hi
 		);
 #     endif
+#     ifdef GC_LURC_THREADS
+        /* check wether the lurc lib wants us to push this now or later */
+        if (gct != NULL
+            && lurc_gc_is_lurc_thread(gct -> id, lo, hi)) 
+          continue;
+#     endif /* GC_LURC_THREADS */
       GC_push_all_stack(lo, hi); 
     } /* for(p=GC_threads[i]...) */
+#   ifdef GC_LURC_THREADS
+    /* walk all those threads to ask for the roots */
+    while ((lt = lurc_get_next_thread(lt)) != NULL) {
+      lurc_gc_get_root(lt, &llo, &lhi);
+      if(llo != NULL)
+        GC_push_all_stack(llo, lhi);
+    }
+    /* does it have another part ? */
+    lurc_gc_get_additional_root(&llo, &lhi);
+    if (llo != NULL)
+      GC_push_all_stack(llo, lhi);
+#   endif /* GC_LURC_THREADS */
+
 }
 
 static mach_port_t GC_mach_handler_thread;
--- gc7.0alpha3-mint/lurc_support.c	1970-01-01 01:00:00.000000000 +0100
+++ gc7.0alpha3-lurc/lurc_support.c	2005-07-26 11:11:12.261126264 +0200
@@ -0,0 +1,42 @@
+#if defined(GC_LURC_THREADS) && !defined(GC_PTHREADS)
+
+#include "private/gc_priv.h"
+#include <lurc.h>
+
+#ifdef LURC_ENABLE_PTHREAD
+#error "LURC is compiled with pthread support, but the GC is not. Please use ./configure --enable-threads=lurc-pthreads if you intend to use LURC with PThreads. Or compile LURC without PThread support."
+#endif
+
+static int GC_lurc_initialized = 0;
+
+void
+GC_push_all_stacks(void){
+  lurc_thread_t lt = NULL;
+  void *llo, *lhi;
+  /* give lurc the main thread's lo and hi */
+  lurc_gc_setup_stack(GC_approx_sp(), GC_stackbottom);
+  /* now iterate through all lurcs' threads */
+  while ((lt = lurc_get_next_thread(lt)) != NULL) {
+    lurc_gc_get_root(lt, &llo, &lhi);
+    if(llo != NULL)
+      GC_push_all_stack(llo, lhi);
+  }
+  /* does it have another part ? */
+  lurc_gc_get_additional_root(&llo, &lhi);
+  if (llo != NULL)
+    GC_push_all_stack(llo, lhi);
+}
+
+void GC_push_thread_structures(void){}
+
+void GC_stop_world(void){}
+void GC_start_world(void){}
+
+void GC_thr_init(void){
+  if(!GC_lurc_initialized){
+    GC_lurc_initialized = 1;
+    lurc_gc_init(GC_enable, GC_disable);
+  }
+}
+
+#endif /* GC_LURC_THREADS && ! GC_PTHREADS */
--- gc7.0alpha3-mint/Makefile.am	2005-04-20 02:44:58.000000000 +0200
+++ gc7.0alpha3-lurc/Makefile.am	2005-07-26 11:07:29.614973624 +0200
@@ -58,6 +58,10 @@
 libgc_la_SOURCES += pthread_support.c pthread_stop_world.c
 endif
 
+if LURC_THREADS
+libgc_la_SOURCES += lurc_support.c
+endif
+
 if AIX_IRIX_THREADS
 libgc_la_SOURCES += aix_irix_threads.c
 endif
@@ -122,10 +126,11 @@
 #include/gc_mark.h @addincludes@
 
 ## FIXME: we shouldn't have to do this, but automake forces us to.
-.s.lo:
-.S.lo:
 ## We use -Wp,-P to strip #line directives.  Irix `as' chokes on
 ## these.
+.s.lo:
+	$(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<
+.S.lo:
 	$(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<
 
 ## We have our own definition of LTCOMPILE because we want to use our
--- gc7.0alpha3-mint/pthread_support.c	2005-04-22 19:57:01.000000000 +0200
+++ gc7.0alpha3-lurc/pthread_support.c	2005-07-26 11:10:54.808779424 +0200
@@ -125,6 +125,10 @@
   typedef unsigned int  sem_t;
 #endif /* GC_DGUX386_THREADS */
 
+#ifdef GC_LURC_THREADS
+# include <lurc.h>
+#endif /* GC_LURC_THREADS */
+
 #ifndef __GNUC__
 #   define __inline__
 #endif
@@ -955,6 +959,12 @@
       /* If we are using a parallel marker, actually start helper threads.  */
         if (GC_parallel) start_mark_threads();
 #   endif
+#ifdef GC_LURC_THREADS
+        /* initialize the lurc lib so that it calls the proper 
+           gc_pthread_create */
+        lurc_gc_init(&WRAP_FUNC(pthread_create),
+                     &GC_enable, &GC_disable);
+#endif /* GC_LURC_THREADS */
 }
 
 


More information about the Gc mailing list