]> granicus.if.org Git - gc/commitdiff
gc4.10t3 tarball import gc4_10t3
authorIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 10:55:44 +0000 (14:55 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 10:55:44 +0000 (14:55 +0400)
13 files changed:
Makefile
Makefile.pthreads [new file with mode: 0644]
README.pthreads [new file with mode: 0644]
alpha_mach_dep.s
config.h
dec_threads.c [new file with mode: 0644]
dyn_load.c
gc.h
gc_priv.h
misc.c
mit_threads.c [new file with mode: 0644]
os_dep.c
test.c

index 4e9eff388d90fc782d11f8744c7c17991d79081a..9b605b4bf329b920bbaef1b336408ca51e2f6209 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ AS=as
 #  The above doesn't work with gas, which doesn't run cpp.
 #  Define AS as `gcc -c -x assembler-with-cpp' instead.
 
-CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT
+CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DSOLARIS_THREADS
 
 # Setjmp_test may yield overly optimistic results when compiled
 # without optimization.
@@ -79,9 +79,9 @@ RANLIB= ranlib
 srcdir = .
 VPATH = $(srcdir)
 
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mit_threads.o dec_threads.o
 
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mit_threads.c dec_threads.c
 
 CORD_SRCS=  cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c cord/cord.h cord/ec.h cord/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga
 
diff --git a/Makefile.pthreads b/Makefile.pthreads
new file mode 100644 (file)
index 0000000..8981a01
--- /dev/null
@@ -0,0 +1,67 @@
+# If your make barfs, try gnumake instead.
+
+# Supported targets:
+# <default> - builds gc.a and gctest
+# gc.a - builds basic library
+# gctest - tests basic library
+# c++ - adds C++ interface to library
+
+# Default threads package -- uncomment ONE of the following
+
+THR=MIT
+#THR=DEC
+
+ifeq ($(THR),MIT)
+
+# Definitions for MIT-pthreads
+CC=pgcc
+IFCC=cc
+CXX=pg++
+CFLAGS=-g -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT \
+               -DMIT_PTHREADS -DGATHERSTATS
+endif
+
+ifeq ($(THR),DEC)
+
+# Definitions for DECthreads
+CC=cc
+IFCC=cc
+CXX=gcc
+CFLAGS= -g -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT \
+               -DDEC_PTHREADS -DGATHERSTATS
+THRLIB=-lpthreads -lmach -lc_r
+endif
+
+ifeq ($(THR),SOLARIS)
+
+# Definitions for Solaris threads
+CC=gcc
+IFCC=gcc
+CXX=gcc
+CFLAGS= -g -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT \
+               -DSOLARIS_THREADS -DGATHERSTATS
+endif
+
+all:   gc.a gctest
+
+gc.a:  pre-built
+       $(MAKE) -f Makefile CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS)" $@
+
+test.o:
+       $(MAKE) -f Makefile CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS)" $@
+
+gctest:        pre-built gc.a test.o
+       $(MAKE) -f Makefile CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS) $(THRLIB)" $@
+
+c++:   gc.a test.o
+       $(MAKE) -f Makefile CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS) $(THRLIB)" $@
+
+# May need to avoid pgcc for if_not_there and if_mach...
+
+pre-built:     if_not_there if_mach
+
+if_not_there:  if_not_there.c
+       $(MAKE) -f Makefile CC=$(IFCC) if_not_there
+               
+if_mach:       if_mach.c config.h
+       $(MAKE) -f Makefile CC=$(IFCC) if_mach
diff --git a/README.pthreads b/README.pthreads
new file mode 100644 (file)
index 0000000..f411fc6
--- /dev/null
@@ -0,0 +1,203 @@
+See the README file for main Copyright notices.
+
+DECthreads/MIT-pthreads extensions:
+Copyright (c) 1995, 1996 by Ian Piumarta and INRIA, with permission
+for use under exactly the same terms as the original GC; i.e...
+
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+Permission is hereby granted to use or copy this program for any
+purpose, provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is
+granted, provided the above notices are retained, and a notice that
+the code was modified is included with the above copyright notice.
+
+
+MODIFICATIONS
+
+The pthreads extensions required the following GC source files to be
+modified:
+
+       dyn_load.c
+       gc.h
+       gc_priv.h
+       misc.c
+       os_dep.c
+       test.c
+
+The modified sections are clearly visible, being those affected by the
+existence of the preprocessor symbols MIT_PTHREADS and DEC_PTHREADS.
+No parts of the original sources outside these sections were modified.
+The following files are new:
+
+       README.pthreads
+       dec_threads.c
+       mit_threads.c
+
+The Makefile was also modified very slightly, to include the two new
+source files in the OBJS and CSRCS lists.
+
+
+GENERAL DESCRIPTION
+
+The pthreads extensions allow the GC to be used with DECpthreads
+(under Digital Unix, formerly DEC OSF/1) or the user-level
+MIT-pthreads implementation by Chris Provenzano (running on a large
+variety of platforms).  DECthreads is bundled with DEC's Unix
+machines; MIT-pthreads is available from:
+
+               ftp://sipb.mit.edu:/pub/pthreads
+       or      ftp://toxicwaste.mit.edu:/pub/archive/pthreads
+
+
+INSTALLATION AND PORTABILITY
+
+These extensions have been tested (and appear to work) on the
+following platforms:
+
+    DECthreads:
+       DEC Alpha       OSF/1 3.2C/3.2D
+
+    MIT-pthreads (tested with pthreads versions 1.60 beta4 and beta5.9):
+       DEC Alpha       OSF/1 3.2C/3.2D
+       Sparc           SunOS 4.1.3/4.1.3_U1/4.1.4
+       i586            Red Hat Linux 3.0.3, Kernel 1.99.4
+       HP 9000/725     HP-UX A.09.05
+
+Very minor additions may be needed to be make the extensions work with
+the other architectures supported by both the GC and MIT-pthreads.
+
+Note that some versions of gcc-2.7 are broken on DEC Alpha.  Version
+2.7.0 seems to be reliable, and versions 2.7.3 and later might be.
+
+    Unless you're already familiar with this GC:
+
+       Read the installtation notes in the README file!
+       Read the Makefile!
+
+    To install for DECpthreads:
+
+       Edit "Makefile.pthreads".  Uncomment the definition "THR=DEC".
+       Edit (if necessary) the definitions immediately following the
+       comment "Definitions for DECthreads" to use the correct
+       compiler and/or CFLAGS for your environment.  See Makefile for
+       an explanation of the GC-related flags.
+
+       If you are using gcc rather than the DEC C compiler, edit the
+       Makefile and remove the line indicated in the target
+       "mark_rts.o".
+
+       Type "make -f Makefile.pthreads" to build the basic library
+       and gctest program, with pthreads support.
+
+       Run gctest to check that things are working.
+
+       If you require C++ support, type "make -f Makefile.pthreads
+       c++ THR=DEC".  Make sure the test_cpp program does not fail.
+
+    To install for MIT-pthreads:
+
+       Install (if necessary) the MIT-pthreads package (see above).
+       Versions 1.60beta4 and earlier have a broken "pg++" script
+       (later versions may be corrected): if necessary change the
+       definition of "libs" from
+               libs='-lpthread -lstdc++ -lm -lgcc'
+       to
+               libs='-lpthread -lstdc++ -lm -lgcc -lpthread'
+
+       Edit "Makefile.pthreads".  Uncomment the definition "THR=MIT".
+       Edit (if necessary) the definitions immediately following the
+       comment "Definitions for MIT-pthreads" to use the correct
+       CFLAGS for your environment (the supplied compiler definitions
+       should be correct in most situations).  See Makefile for an
+       explanation of the GC-related flags.
+
+       If you are compiling on a DEC Alpha using gcc rather than the
+       DEC C compiler, edit the Makefile and remove the line
+       indicated in the target "mark_rts.o".
+
+       Type "make -f Makefile.pthreads" to build the basic library
+       and gctest program, with pthreads support.
+
+       Run gctest to check that things are working.
+
+       If you require C++ support, type "make -f Makefile.pthreads
+       c++ THR=MIT".  Make sure the test_cpp program does not fail.
+
+
+MODIFICATIONS TO THE PTHREADS INTERFACES
+
+The extensions rely on intercepting calls to a few pthreads routines.
+Any source file using the pthreads routines MUST include "gc.h", even
+if there is no GC-related code in the file.
+
+The following DECthreads routines are affected:
+
+  int pthread_create(pthread_t *thread, pthread_attr_t attr,
+                     pthread_startroutine_t start_routine,
+                     pthread_addr_t arg);
+
+  int pthread_detach(pthread_t *thread);
+
+The following MIT-pthreads routines are affected:
+
+  int pthread_create(pthread_t *thread, pthread_attr_t *attr,
+                     void *(*start_routine)(void *), void *arg);
+
+
+BUGS
+
+Incremental mode does not work with DECpthreads.  The reasons are not
+yet fully explored.  GC_enable_incremental() is therefore a no-op when
+the GC is compiled with DECpthreads support.
+
+The DECthreads extensions assume a one-to-one correspondance between
+each pthread and a kernel (mach) thread.  This appears to be true with
+round-robin scheduling, but may not be true for other scheduling
+policies.  (This concerns stopping the world: there is no documented
+mechanism to stop the pthreads world, so we have to stop the
+underlying kernel threads instead [which is documented].  When asked
+about setting the pthreads kernel lock, all that the DEC techincal
+people would tell me was: "don't meddle with things that you don't
+understand".)
+
+The extensions have been tested with both versions of pthreads,
+although in relatively undemanding situations.  Some subtle problems
+may still exist in programs which use thread synchronisation
+operations (pthread_join/pthread_detach) in bizarre ways, or which use
+scheduling policies other than the default round-robin.  The more
+exotic pthread routines (e.g. executing a call on another thread's
+stack) have not been tested very much at all.
+
+The MITpthreads extensions rely on snooping about in small parts of
+the pthreads' private internal structures.  This seems unavoidable.
+
+The extensions appear to work with unmodified versions of the GNU
+libgcc and libstdc++ (at least as far as iostreams are concerned), but
+large parts of these libraries remain untested in a pthreads/GC
+context.
+
+
+BUG REPORTS AND SUGGESTIONS FOR IMPROVEMENTS
+
+Should be sent to: Ian.Piumarta@inria.fr
+
+It would be most helpful if you could include a small program which
+reproduces the bug.
+
+
+ACKNOWLEDGEMENTS
+
+I am immensely grateful to David Halls (David.Halls@cl.cam.ac.uk) who
+spent many months "alpha testing" the extensions, suffering problems
+with the early implementations, and contributing suggestions for
+improvements.  He also kindly tested the MIT-pthreads extensions under
+Linux and provided the code specific to dynamic loading and the HP-PA
+architecture.
+
+
+------------------------------- projet SOR -------------------------------
+Ian Piumarta, INRIA Rocquencourt,          Internet: Ian.Piumarta@inria.fr
+BP105, 78153 Le Chesnay Cedex, FRANCE         Voice: +33 1 39 63 52 87
+----------------------- Systemes a Objets Repartis -----------------------
index 265c31414af547358582f434680a77383b32c072..087baeacf4ad503c22a503e54e3bb9721958f9f3 100644 (file)
@@ -1,15 +1,18 @@
  # $Id: alpha_mach_dep.s,v 1.2 1993/01/18 22:54:51 dosser Exp $
 
-# define call_push(x)    lda   $16, 0(x);    jsr   $26, GC_push_one
-
+# define call_push(x)                                                  \
+       lda   $16, 0(x);        /* copy x to first argument register */ \
+       jsr   $26, GC_push_one; /* call GC_push_one, ret addr in $26 */ \
+       ldgp  $gp, 0($26)       /* restore $gp register from $ra */
+       
         .text
         .align  4
         .globl  GC_push_regs
         .ent    GC_push_regs 2
 GC_push_regs:
-        ldgp    $gp, 0($27)
-        lda     $sp, -32($sp)
-        stq     $26, 8($sp)
+       ldgp    $gp, 0($27)             # set gp from the procedure value reg
+       lda     $sp, -32($sp)           # make stack frame
+       stq     $26, 8($sp)             # save return address
         .mask   0x04000000, -8
         .frame  $sp, 16, $26, 0
 
@@ -51,8 +54,7 @@ GC_push_regs:
         call_push($29)   # Global Pointer
  #      call_push($30)   # Stack Pointer
 
-        ldgp    $gp, 0($26)
-        ldq     $26, 8($sp)
-        lda     $sp, 32($sp)
-        ret     $31, ($26), 1
-        .end    GC_push_regs
+       ldq     $26, 8($sp)             # restore return address
+       lda     $sp, 32($sp)            # pop stack frame
+       ret     $31, ($26), 1           # return ($31 == hardwired zero)
+       .end    GC_push_regs
index 58d625efc1a0728028955fe2a34541e471d6a781..4881a9a4a39a14aba4fbe2a0af33bdcdf5b7c07a 100644 (file)
--- a/config.h
+++ b/config.h
 #       define HEURISTIC2
 #   endif
 #   define STACK_GROWS_UP
+#   define DYNAMIC_LOADING
 # endif
 
 # ifdef ALPHA
 #   define MACH_TYPE "ALPHA"
 #   define ALIGNMENT 8
 #   define DATASTART ((ptr_t) 0x140000000)
-#   define HEURISTIC2
+#   ifndef DEC_PTHREADS
+#     define HEURISTIC2
        /* Normally HEURISTIC2 is too conervative, since                */
        /* the text segment immediately follows the stack.              */
        /* Hence we give an upper pound.                                */
-    extern __start;
-#   define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1)))
+      extern __start;
+#     define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1)))
+#   endif
 #   define CPP_WORDSZ 64
 #   define MPROTECT_VDB
 #   define DYNAMIC_LOADING
diff --git a/dec_threads.c b/dec_threads.c
new file mode 100644 (file)
index 0000000..1b323d4
--- /dev/null
@@ -0,0 +1,558 @@
+/* dec_threads.c
+/* 
+/* Support for DECthreads in Boehm/Demer/Weiser garbage collector.
+/* Depends on a gc.a compiled with -DDEC_PTHREADS, plus local modifications.
+/* Final executable must be linked with "-lpthreads -lmach -lc_r".
+/* 
+/* Author: Ian.Piumarta@INRIA.fr
+/* 
+/* Copyright (C) 1996 by INRIA and Ian Piumarta
+/*
+/* Known problems:
+/*
+/*      - debugging needs to be tidied up
+/*
+/*      - some redundant code should be removed
+/*
+/* last edited: Wed Nov 13 15:42:21 1996 by piumarta (Ian Piumarta) on xombul
+/*
+/***************************************************************************/
+
+#ifdef DEC_PTHREADS
+
+/* Turn on debugging output */
+#undef DEBUG
+
+/* Turn on trace messages for thread creation/deletion */
+#undef TRACE
+
+/* visual indication of GC:                    */
+/*     * = push stack for GC thread,           */
+/*     + = push stack for other thread         */
+#undef VISUAL_CLUES
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <pthread.h>
+#include <sys/user.h>
+#include <sys/table.h>
+#include <mach/mach_interface.h>
+#include <mach/thread_status.h>
+
+extern char *GC_malloc_uncollectable();
+extern pthread_mutex_t GC_allocate_ml;
+extern int GC_pt_init_ok;
+
+#define ERR(X) { perror(X); abort(); }
+
+extern GC_err_printf();
+
+#ifdef DEBUG
+#  define FPRINTF(X) GC_err_printf X
+#else
+#  define FPRINTF(X)
+#endif
+
+#define PRINT_INFO(X,Y,Z)      /* or #define PRINT_INFO print_info */
+
+#define CHECK_DUPLICATE        (2<<0)
+#define CHECK_OVERLAP  (2<<1)
+
+#define struct_base(PTR, FLD, TYP) \
+       ((TYP*)((char*)(PTR)-(char*)(&(((TYP*)0)->FLD))))
+
+typedef struct QUEUE {
+  struct QUEUE *flink, *blink;
+} queue;
+
+typedef struct GC_PT_THREAD_INFO {
+  queue q;
+  /* user thread structure */
+  pthread_t thread;
+  /* start routine and argument */
+  pthread_startroutine_t starter;
+  pthread_addr_t arg;
+  /* mach port */
+  port_t port;
+  /* stack top */
+  void *stack_top;
+  /* approximate thread status */
+  short active;
+  short exited;
+  short detached;
+  /* saved register state */
+  struct alpha_thread_state reg_state;
+} gc_pt_thread_info;
+
+#define TID(info) (info->port)
+
+static queue infos = { &infos, &infos };
+
+#define DISABLE_SIGNALS() GC_disable_signals()
+#define ENABLE_SIGNALS() GC_enable_signals()
+
+#define LOCK(ML) \
+  if(pthread_mutex_lock(&GC_pt_##ML##_ml)<0) ERR("LOCK(GC_pt_"#ML"_ml)");
+
+#define UNLOCK(ML) \
+  if(pthread_mutex_unlock(&GC_pt_##ML##_ml)<0) ERR("UNLOCK(GC_pt_"#ML"_ml)");
+
+static pthread_mutex_t GC_pt_info_ml;
+static pthread_mutex_t GC_pt_init_ml;
+
+static pthread_key_t info_key;
+
+
+static print_info(gc_pt_thread_info *info, char *msg, long arg)
+{
+  GC_err_printf("********** INFO structure at %lx size %d for ",
+         info, sizeof(*info));
+  GC_err_printf(msg, arg);
+  GC_err_printf(":\n");
+  /* this is VERY naughty: this structure is supposed to be opaque. */
+  GC_err_printf("  thread at %lx = (%lx, %lx)\n",
+         info->thread, info->thread.field1, info->thread.field2);
+  GC_err_printf("  startroutine at %lx, arg %lx\n", info->starter, info->arg);
+  GC_err_printf("  mach port number is %d\n", info->port);
+  GC_err_printf("  stack_top is %lx\n", info->stack_top);
+  GC_err_printf("  stack pointer is %lx\n", info->reg_state.r30);
+  GC_err_printf("  thread is %s", info->active ? "active" : "inactive");
+  GC_err_printf(", %s", info->exited ? "exited" : "unexited");
+  GC_err_printf(", %s", info->detached ? "detached" : "attached");
+  GC_err_printf("\n  flink %lx, blink %lx\n", info->q.flink, info->q.blink);
+}
+
+
+static print_infos()
+{
+  queue *ptr= infos.flink;
+
+  GC_err_printf("infos.flink = %lx\n", infos.flink);
+  print_info(struct_base(ptr, q, gc_pt_thread_info), "flink", 0);
+  GC_err_printf("infos.blink = %lx\n", infos.flink);
+  print_info(struct_base(ptr, q, gc_pt_thread_info), "blink", 0);
+
+  while (ptr != &infos) {
+    GC_err_printf("q ===> %lx:", ptr);
+    print_info(struct_base(ptr, q, gc_pt_thread_info), "print_infos", 0);
+    ptr= ptr->flink;
+  }
+}
+
+
+/* GC_pt_check
+ *
+ * Check the given gc_pt_thread_info structure is consistent with the others.
+ *
+ * Caller must hold the info lock.
+ */
+static int GC_pt_check(gc_pt_thread_info *info)
+{
+  queue *ptr= infos.flink;
+  int fail= 0;
+  while (ptr != &infos) {
+    gc_pt_thread_info *old= struct_base(ptr, q, gc_pt_thread_info);
+/*
+    if (info != old && info->port == old->port) {
+      fail|= CHECK_DUPLICATE;
+      FPRINTF((stderr, "duplicate thread: %d\n", info->port));
+    }
+*/
+    if (info != old && pthread_equal(info->thread, old->thread)) {
+      fail|= CHECK_DUPLICATE;
+      FPRINTF((stderr, "duplicate thread: %d\n", info->port));
+    }
+/*
+    if (info != old &&
+       (((char *)info->stack_top > (char *)old->reg_state.r30 &&
+         (char *)info->stack_top < (char *)old->stack_top) ||
+        ((char *)info->reg_state.r30 > (char *)old->reg_state.r30 &&
+         (char *)info->reg_state.r30 < (char *)old->stack_top))) {
+      fail|= CHECK_OVERLAP;
+      FPRINTF((stderr, "stack overlaps for threads: %lx and %lx\n",
+              TID(old), TID(info)));
+    }
+*/
+    ptr= ptr->flink;
+  }
+  return fail;
+}
+
+
+/* This must be called with the info lock set.
+ */
+static gc_pt_thread_info *GC_pt_find_pthread_info(pthread_t *thread)
+{
+  queue *ptr= infos.flink;
+  while (ptr != &infos) {
+    gc_pt_thread_info *info= struct_base(ptr, q, gc_pt_thread_info);
+    if (pthread_equal(*thread, info->thread))
+      return info;
+    ptr= ptr->flink;
+  }
+  return 0;
+}
+
+
+static void GC_pt_info_destroy(pthread_addr_t infop);
+
+
+/* GC_pt_init
+ *
+ * Initialises DECthreads-specific data structures.  Should be called
+ * before any threads are created, and before any posibility of GC
+ * activity.
+ */
+void GC_pt_init()
+{
+  gc_pt_thread_info *info;
+  struct user u;
+  pthread_mutexattr_t attr;
+
+  if(GC_pt_init_ok) return;
+  GC_pt_init_ok= 1;
+  FPRINTF((stderr, "initialising GC_dt...\n"));
+  FPRINTF((stderr, "ENTER GC_pt_init()\n"));
+  if (pthread_mutexattr_create(&attr)
+      || pthread_mutexattr_setkind_np(&attr, MUTEX_RECURSIVE_NP)
+      || pthread_mutex_init(&GC_pt_info_ml, attr)
+      || pthread_mutex_init(&GC_pt_init_ml, attr)
+      || pthread_keycreate(&info_key, GC_pt_info_destroy))
+    ERR("GC_pt_init");
+
+  if (table(TBL_UAREA, getpid(), &u, 1, sizeof(struct user)) < 1) {
+    GC_err_printf("problem getting u area\n");
+  }
+
+  info= (gc_pt_thread_info *)GC_malloc_uncollectable(sizeof(gc_pt_thread_info));
+  if (!info) {
+    GC_err_printf("GC_dt: could not allocate thread_info\n");
+    exit(1);
+  }
+
+  info->port= thread_self();
+  info->stack_top= u.u_stack_end;
+  info->active= 1;
+  info->exited= 0;
+  info->detached= 0;
+  info->q.flink= &infos;
+  info->q.blink= &infos;
+  bzero((char *)&info->reg_state, sizeof(info->reg_state));
+
+  LOCK(info);
+  infos.flink= infos.blink= &info->q;
+  UNLOCK(info);
+
+  PRINT_INFO(info, "default thread", 0);
+
+  FPRINTF((stderr, "LEAVE GC_pt_init()\n"));
+}
+
+
+static void GC_pt_apply_other_threads(kern_return_t (*func)(port_t))
+{
+  port_t me= thread_self();
+
+  FPRINTF((stderr, "APPLYING for thread %d\n", me));
+
+  LOCK(info);
+  {
+    queue *ptr= infos.flink;
+    while (ptr != &infos)
+      {
+       gc_pt_thread_info *info= struct_base(ptr, q, gc_pt_thread_info);
+       if (info->port != me && info->active && !info->exited) 
+         {
+           FPRINTF((stderr, "applying to thread %d:", info->port));
+           FPRINTF((stderr, " %s %s %s\n",
+                    info->active ? "active" : "inactive",
+                    info->exited ? "exited" : "unexited",
+                    info->detached ? "detached" : "attached"));
+           if (func(info->port) != KERN_SUCCESS)
+             {
+               UNLOCK(info);
+               GC_err_printf("GC_pt_apply_other_threads failed:\n");
+               print_info(info, "apply failed from thread %d", me);
+               abort();
+             }
+         }
+       else
+         {
+           FPRINTF((stderr, "NOT applying to thread %d:", info->port));
+           FPRINTF((stderr, " %s %s %s\n",
+                    info->active ? "active" : "inactive",
+                    info->exited ? "exited" : "unexited",
+                    info->detached ? "detached" : "attached"));
+         }
+       ptr= ptr->flink;
+      }
+  }
+  UNLOCK(info);
+}
+
+
+void GC_pt_stop_world()
+{
+  if (!GC_pt_init_ok) GC_init();
+  FPRINTF((stderr, "stopping the world...\n"));
+  GC_pt_apply_other_threads(thread_suspend);
+  FPRINTF((stderr, "...stopped!\n"));
+}
+
+void GC_pt_start_world()
+{
+  FPRINTF((stderr, "starting the world...\n"));
+  GC_pt_apply_other_threads(thread_resume);
+  FPRINTF((stderr, "...started!\n"));
+}
+
+
+/* GC_pt_push_all_stacks
+ *
+ * Pushes all thread stacks, including the default stack.  Default stack
+ * pointer read from /proc, other thread stacks taken from stacks queue.
+ * Locks the stacks to prevent thread creation/deletion during pushing.
+ */
+void GC_pt_push_all_stacks()
+{
+  queue *ptr= infos.flink;
+  FPRINTF((stderr, "PUSHING THREAD STACKS:\n"));
+  while (ptr != &infos)
+    {
+      gc_pt_thread_info *info= struct_base(ptr, q, gc_pt_thread_info);
+      if (info->active && !info->exited)
+       if (info->port == thread_self())
+         {
+#ifdef VISUAL_CLUES
+           fputc('*', stderr);
+#endif VISUAL_CLUES
+           FPRINTF((stderr, "[%lx,%lx]\n", &ptr, info->stack_top));
+           GC_push_all_stack(&ptr, info->stack_top);
+         }
+       else
+         {
+           int count= ALPHA_THREAD_STATE_COUNT;
+           FPRINTF((stderr, "+"));
+           /* get register state to (a) know sp, and (b) mark registers */
+           PRINT_INFO(info, "thread %d PRE-GETSTATE", info->port);
+           FPRINTF((stderr, "  reg_state dumped to %lx, size %d\n",
+                    &(info->reg_state), sizeof(info->reg_state)));
+           if (thread_get_state(info->port,
+                                ALPHA_THREAD_STATE,
+                                (thread_state_t)&(info->reg_state),
+                                &count) != KERN_SUCCESS)
+             {
+               GC_err_printf("problem in thread_get_state");
+               exit(1);
+             }
+           PRINT_INFO(info, "thread %d POST-GETSTATE", info->port);
+#ifdef VISUAL_CLUES
+           fputc('+', stderr);
+#endif VISUAL_CLUES
+           FPRINTF((stderr, "[%lx,%lx]\n",
+                    info->reg_state.r30, info->stack_top));
+           GC_push_all_stack(info->reg_state.r30, info->stack_top);
+         }
+      ptr= ptr->flink;
+    }
+}
+
+
+/* GC_pt_thread_init
+ *
+ * Creates a gc_pt_thread_info structure describing the calling thread in the
+ * stacks queue.
+ */
+static void GC_pt_thread_init(gc_pt_thread_info *info, void *stacktop)
+{
+  FPRINTF((stderr, "ENTER GC_pt_thread_init(%lx)\n", TID(info)));
+  {
+    int status;
+    info->port= thread_self();
+    info->stack_top= stacktop;
+    PRINT_INFO(info, "thread %d", info->port);
+    if (status= GC_pt_check(info)) {
+      if (status & CHECK_DUPLICATE)
+       GC_err_printf("GC_pt_thread_init: duplicated thread %lx\n",
+               TID(info));
+      if (status & CHECK_OVERLAP)
+       GC_err_printf("GC_pt_thread_init: stack overlap %lx\n",
+               TID(info));
+      if (status) {
+       GC_err_printf("GC_pt_thread_init: aborting, sorry...\n");
+       abort();
+      }
+    }
+  }
+  FPRINTF((stderr, "LEAVE GC_pt_thread_init(%lx)\n", TID(info)));
+}
+
+
+/* GC_pt_info_destroy
+ *
+ * The thread is finished, and about to exit -- either due to a normal
+ * return or a cancel request.  If it is already detached, remove its
+ * stack.  If not, mark the thread as exited so that its stack will be
+ * removed when it is eventually detached.
+ */
+static void GC_pt_info_destroy(pthread_addr_t infop)
+{
+  gc_pt_thread_info *info= (gc_pt_thread_info *)infop;
+
+  FPRINTF((stderr, "ENTER GC_pt_info_destroy(%lx)\n", infop));
+  if (pthread_mutex_lock(&GC_allocate_ml) < 0)
+    ERR("GC_pt_info_destroy: lock(&GC_allocate_ml)");
+  {
+    /* safety first: check that the info structure really exists */
+    queue *target= &info->q;
+    queue *ptr= infos.flink;
+    while (ptr != &infos) 
+      {
+       if (ptr == target)
+         break;
+       else
+         ptr= ptr->flink;
+      }
+    if (ptr != target)
+      {
+       if (pthread_mutex_unlock(&GC_allocate_ml) < 0)
+         ERR("GC_pt_info_destroy: unlock(&GC_allocate_ml)");
+       GC_err_printf("GC_pt_info_destroy: unknown info -- aborting\n");
+       abort();
+      }
+    if (info->detached) 
+      {
+       /* thread detached => delete stack on exit */
+       queue *ptr= &info->q;
+       ptr->flink->blink= ptr->blink;
+       ptr->blink->flink= ptr->flink;
+#ifdef TRACE
+       GC_err_printf("DELETE (exit) %lx\n", TID(info));
+#endif TRACE
+       GC_free(info);
+      }
+    else
+      {
+       info->exited= 1;  /* cancelled thread won't do this otherwise */
+       info->active= 0;
+      }
+  }
+  if (pthread_mutex_unlock(&GC_allocate_ml) < 0)
+    ERR("GC_pt_info_destroy: unlock(&GC_allocate_ml)");
+  FPRINTF((stderr, "LEAVE GC_pt_info_destroy(%lx)\n", infop));
+}
+
+
+static pthread_addr_t GC_pt_start_routine(gc_pt_thread_info *info)
+{
+  pthread_addr_t status;
+  LOCK(info);
+  /* wait for GC_pt_pthread_create to finish building info */
+  FPRINTF((stderr, "ENTER GC_pt_start_routine(%lx)\n", TID(info)));
+  GC_pt_thread_init(info, &info);
+  UNLOCK(info); /* it is now safe to start the next thread */
+  pthread_setspecific(info_key, info);  /* the reaper for the thread */
+  /* this thread might be starting up during a GC!  Do not proceed beyond
+     this point until the allocation lock becomes available. */
+  pthread_mutex_lock(&GC_allocate_ml);
+  info->active= 1;
+  pthread_mutex_unlock(&GC_allocate_ml);
+#ifdef TRACE
+  GC_err_printf("LAUNCH (start) %lx\n", TID(info));
+#endif TRACE
+  status= info->starter(info->arg);
+  info->active= 0;
+  info->exited= 1;
+  FPRINTF((stderr, "LEAVE GC_pt_start_routine(%lx)\n", TID(info)));
+  return status;
+}
+
+/* GC_pt_pthread_create
+ *
+ * Creates a new thread, allocates a gc_pt_thread_info object describing the
+ * new thread,
+ *
+ * Get stack information by intercepting thread creation.
+ */
+int GC_pt_pthread_create(pthread_t *thread, pthread_attr_t attr,
+                        pthread_startroutine_t start_routine,
+                        pthread_addr_t arg)
+{
+  int result;
+  gc_pt_thread_info *info;
+
+  FPRINTF((stderr, "ENTER GC_pt_pthread_create(%lx)\n", thread));
+  info= (void *)GC_malloc_uncollectable(sizeof(gc_pt_thread_info));
+  info->starter= start_routine;
+  info->arg= arg;
+  info->active= 0;
+  info->detached= 0;
+  info->exited= 0;
+  LOCK(info);
+  if (result= pthread_create(thread, attr,
+                            (pthread_startroutine_t)GC_pt_start_routine,
+                            (pthread_addr_t)info)) {
+    GC_free(info);
+    FPRINTF((stderr, "LEAVE GC_pt_pthread_create(%lx) ===> ERROR\n", thread));
+    goto end; /* something is amiss */
+  }
+  info->thread= *thread;
+  PRINT_INFO(info, "uninitialized new thread", 0);
+  /* add to end of info queue */
+  {
+    queue *ptr= &info->q;
+    ptr->flink= &infos;
+    ptr->blink= infos.blink;
+    infos.blink->flink= ptr;
+    infos.blink= ptr;
+  }
+  FPRINTF((stderr, "LEAVE GC_pt_pthread_create(%lx) ===> %lx\n",
+          thread, TID(info)));
+ end:
+  UNLOCK(info);
+  return result;
+}
+
+
+/* GC_pt_pthread_detach
+ *
+ * If thread already exited, remove its stack.  Otherwise mark the thread
+ * as detached, so that its stack will be removed when it eventually exits.
+ */
+int GC_pt_pthread_detach(pthread_t *thread)
+{
+  int result;
+  FPRINTF((stderr, "ENTER GC_pt_pthread_detach(%lx)\n", thread));
+  LOCK(info);
+  {
+    gc_pt_thread_info *info= GC_pt_find_pthread_info(thread);
+    if (!info)
+      {
+       UNLOCK(info);
+       errno= ESRCH;
+       return -1;
+      }
+    if (info->exited)
+      {
+       /* thread exited => delete stack on detach */
+       queue *ptr= &info->q;
+       ptr->flink->blink= ptr->blink;
+       ptr->blink->flink= ptr->flink;
+       FPRINTF((stderr, "DELETE (detach) %lx\n", TID(info)));
+       GC_free(info);
+      }
+    else
+      {
+       info->detached= 1;
+      }
+  }
+  UNLOCK(info);
+  result= pthread_detach(thread);
+  FPRINTF((stderr, "LEAVE GC_pt_pthread_detach(%lx)\n", thread));
+  return result;
+}
+
+
+#endif DEC_PTHREADS
index e3f2ac699a1ffd04586898123e8ffedf75fa3eaa..8b9ce76845b2fe64349082e1745d11889009fc2e 100644 (file)
@@ -45,7 +45,7 @@
 # endif
 
 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
-#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && !defined(MSWIN32) && !defined(ALPHA)
+#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && !defined(MSWIN32) && !defined(ALPHA) && !defined(HP_PA)
  --> We only know how to find data segments of dynamic libraries under SunOS,
  --> IRIX5, DRSNX and Win32.  Additional SVR4 variants might not be too
  --> hard to add.
@@ -158,7 +158,8 @@ static ptr_t GC_first_common()
 
 # if defined(SUNOS4) || defined(SUNOS5DL)
 /* Add dynamic library data sections to the root set.          */
-# if !defined(PCR) && !defined(SOLARIS_THREADS) && defined(THREADS)
+# if !defined(PCR) && !defined(SOLARIS_THREADS) && defined(THREADS) \
+       && !defined(MIT_PTHREADS) && !defined(DEC_PTHREADS)
 #   ifndef SRC_M3
        --> fix mutual exclusion with dlopen
 #   endif  /* We assume M3 programs don't call dlopen for now */
@@ -523,6 +524,139 @@ void GC_register_dynamic_libraries()
 }
 #endif
 
+#if defined(HP_PA)
+
+#include <dl.h>
+#include <errno.h>
+
+#ifndef MIT_PTHREADS
+extern int errno;
+extern char *sys_errlist[];
+extern int sys_nerr;
+#endif
+
+void GC_register_dynamic_libraries()
+{
+  int status;
+  int index = 1; /* Ordinal position in shared library search list */
+  struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
+
+  /* For each dynamic library loaded */
+    while (TRUE) {
+
+      /* Get info about next shared library */
+        status = shl_get(index, &shl_desc);
+
+      /* Check if this is the end of the list or if some error occured */
+        if (status != 0) {
+          if (errno == EINVAL) {
+              break; /* Moved past end of shared library list --> finished */
+          } else {
+              if (errno <= sys_nerr) {
+                    GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
+              } else {
+                    GC_printf1("dynamic_load: %d\n", (long) errno);
+              }
+              ABORT("shl_get failed");
+          }
+        }
+
+#     ifdef VERBOSE
+          GC_printf0("---Shared library---\n");
+          GC_printf1("\tfilename        = \"%s\"\n", shl_desc->filename);
+          GC_printf1("\tindex           = %d\n", index);
+          GC_printf1("\thandle          = %08x\n",
+                                        (unsigned long) shl_desc->handle);
+          GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
+          GC_printf1("\ttext seg. end   = %08x\n", shl_desc->tend);
+          GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
+          GC_printf1("\tdata seg. end   = %08x\n", shl_desc->dend);
+          GC_printf1("\tref. count      = %lu\n", shl_desc->ref_count);
+#     endif
+
+      /* register shared library's data segment as a garbage collection root */
+        GC_add_roots_inner((char *) shl_desc->dstart,
+                           (char *) shl_desc->dend, TRUE);
+
+        index++;
+    }
+}
+#endif /* HP_PA */
+
+
+#if defined(MIT_PTHREADS) || defined(DEC_PTHREADS)
+#ifdef HP_PA
+
+  /* We're going to protect the lot, since there is evidence    */
+  /* that dlopen() isn't the only place where things can break. */
+
+#undef shl_load
+#undef shl_findsym
+#undef shl_unload
+
+# define GC_DL_DEF(RTYPE, PROTO, FUNC) RTYPE PROTO \
+   { RTYPE result; pthread_mutex_lock(&GC_allocate_ml);  result= FUNC; \
+     pthread_mutex_unlock(&GC_allocate_ml); return (result); }
+GC_DL_DEF(shl_t, GC_shl_load(const char *path, int flags, long address), shl_load(path, flags, address))
+GC_DL_DEF(int  , GC_shl_findsym(shl_t *handle, const char *sym, short type, void *value),
+                                                      shl_findsym(handle, sym, type, value))
+GC_DL_DEF(int  , GC_shl_unload(shl_t handle), shl_unload(handle))
+
+  /* unfortunately, MIT PThreads and dynamic loading on HPUX
+     causes programs to hang (not just for the GC);
+     we keep everything in but define some null-op stubs;
+     makes it easier to fix when pthreads is fixed */
+
+  shl_t shl_load(const char *path, int flags, long address)
+  {
+   return NULL;
+  }
+
+  int shl_findsym(shl_t *handle, const char *symname, short type, void *value)
+  {
+   return -1;
+  }
+
+  int shl_unload(shl_t handle)
+  {
+   return -1;
+  }
+
+  int shl_get(int index, struct shl_descriptor **desc)
+  {
+   errno = EINVAL;
+   return -1;
+  }
+
+# define shl_load    GC_shl_load
+# define shl_findsym GC_shl_findsym
+# define shl_unload  GC_shl_unload
+
+#else
+  /* We're going to protect the lot, since there is evidence    */
+  /* that dlopen() isn't the only place where things can break. */
+
+#undef dlopen
+#undef dlsym
+#undef dlclose
+#undef dlerror
+
+# define GC_DL_DEF(RTYPE, PROTO, FUNC) RTYPE PROTO \
+   { RTYPE result; pthread_mutex_lock(&GC_allocate_ml);  result= FUNC; \
+     pthread_mutex_unlock(&GC_allocate_ml); return (result); }
+GC_DL_DEF(void *, GC_dlopen(const char *path, int mode), dlopen(path, mode))
+GC_DL_DEF(void *, GC_dlsym(void *handle, const char *symbol),
+                                                      dlsym(handle, symbol))
+GC_DL_DEF(int   , GC_dlclose(void *handle), dlclose(handle))
+GC_DL_DEF(char *, GC_dlerror(), dlerror())
+
+# define dlopen  GC_dlopen
+# define dlsym   GC_dlsym
+# define dlclose GC_dlclose
+# define dlerror GC_dlerror
+#endif
+#endif /* PTHREADS */
+
 
 #else /* !DYNAMIC_LOADING */
 
diff --git a/gc.h b/gc.h
index 0c7a2824a36d74d55f8d6efcb543b40d46c60531..41a659475dcc3ba23dafdef3d0099a294eeb786c 100644 (file)
--- a/gc.h
+++ b/gc.h
@@ -564,6 +564,48 @@ GC_PTR GC_malloc_many(size_t lb);
 
 #endif /* SOLARIS_THREADS */
 
+#ifdef DEC_PTHREADS
+# include <pthread.h>
+  int GC_pt_pthread_create(pthread_t *thread, pthread_attr_t attr,
+                           pthread_startroutine_t start_routine,
+                           pthread_addr_t arg);
+  int GC_pt_pthread_detach(pthread_t *thread);
+# define pthread_create GC_pt_pthread_create
+# define pthread_detach GC_pt_pthread_detach
+  void * GC_malloc_many(size_t lb);
+# define GC_NEXT(p) (*(void **)(p))
+#endif /* DEC_PTHREADS */
+
+#ifdef MIT_PTHREADS
+# include <pthread.h>
+  int GC_pt_pthread_create(pthread_t *thread, pthread_attr_t *attr,
+                           void *(*start_routine)(void *), void *arg);
+# define pthread_create GC_pt_pthread_create
+  void * GC_malloc_many(size_t lb);
+# define GC_NEXT(p) (*(void **)(p))
+#endif /* MIT_PTHREADS */
+
+#if (defined(MIT_PTHREADS) || defined(DEC_PTHREADS))
+#ifdef __hp9000s700
+# include <dl.h>
+  shl_t GC_shl_load(const char *path, int flags, long address);
+  int   GC_shl_findsym(shl_t *handle, const char *sym, short type, void *value);
+  int   GC_shl_unload(shl_t handle);
+# define shl_load    GC_shl_load
+# define shl_findsym GC_shl_findsym
+# define shl_unload  GC_shl_unload
+#else
+  void *GC_dlopen(const char *pathname, int mode);
+  void *GC_dlsym(void *handle, const char *name);
+  int   GC_dlclose(void *handle);
+  char *GC_dlerror(void);
+# define dlopen  GC_dlopen
+# define dlsym   GC_dlsym
+# define dlclose GC_dlclose
+# define dlerror GC_dlerror
+#endif
+#endif /* PTHREADS */
+
 /*
  * If you are planning on putting
  * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
index 102e8ee9c52a6ad516778bff9c89ae04926e4a65..9c66ed0b5975bf3639a3f7f109a85eadb9945619 100644 (file)
--- a/gc_priv.h
+++ b/gc_priv.h
@@ -161,10 +161,12 @@ typedef char * ptr_t;     /* A generic pointer to which we can add        */
 #   define GATHERSTATS
 #endif
 
-# if defined(SOLARIS_THREADS) && !defined(SUNOS5)
+# if defined(SOLARIS_THREADS) && !defined(SUNOS5) \
+       || (defined(DEC_PTHREADS) && !defined(ALPHA))
 --> inconsistent configuration
 # endif
-# if defined(PCR) || defined(SRC_M3) || defined(SOLARIS_THREADS)
+# if defined(PCR) || defined(SRC_M3) || defined(SOLARIS_THREADS) \
+       || defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
 #   define THREADS
 # endif
 
@@ -420,6 +422,18 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
 #    define LOCK() mutex_lock(&GC_allocate_ml);
 #    define UNLOCK() mutex_unlock(&GC_allocate_ml);
 #  endif
+#  ifdef DEC_PTHREADS
+     extern pthread_mutex_t GC_allocate_ml;
+     extern int GC_pt_init_ok;
+#    define LOCK() {if (!GC_pt_init_ok) GC_init(); pthread_mutex_lock(&GC_allocate_ml);}
+#    define UNLOCK() if (GC_pt_init_ok) pthread_mutex_unlock(&GC_allocate_ml)
+#  endif
+#  ifdef MIT_PTHREADS
+     extern pthread_mutex_t GC_allocate_ml;
+     extern int GC_pt_init_ok;
+#    define LOCK() if (GC_pt_init_ok) pthread_mutex_lock(&GC_allocate_ml)
+#    define UNLOCK() if (GC_pt_init_ok) pthread_mutex_unlock(&GC_allocate_ml)
+#  endif
 # else
 #    define LOCK()
 #    define UNLOCK()
@@ -448,7 +462,8 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
 # else
 #   if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
        || defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \
-       || defined(NO_SIGNALS)
+       || defined(NO_SIGNALS) \
+        || defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
                        /* Also useful for debugging.           */
        /* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
 #     define DISABLE_SIGNALS()
@@ -479,8 +494,18 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
 #     define STOP_WORLD() GC_stop_world()
 #     define START_WORLD() GC_start_world()
 #   else
-#     define STOP_WORLD()
-#     define START_WORLD()
+#     ifdef DEC_PTHREADS
+#       define STOP_WORLD() GC_pt_stop_world()
+#       define START_WORLD() GC_pt_start_world()
+#     else
+#       ifdef MIT_PTHREADS
+#         define STOP_WORLD() GC_pt_stop_world()
+#         define START_WORLD() GC_pt_start_world()
+#       else
+#         define STOP_WORLD()
+#         define START_WORLD()
+#       endif
+#     endif
 #   endif
 # endif
 
diff --git a/misc.c b/misc.c
index 03f316afdd149c49d62ad4643f7bad7ca30ed36a..63a8cecbb4d3a98009d800906ea87c5bb5f11fda 100644 (file)
--- a/misc.c
+++ b/misc.c
 #      ifdef SOLARIS_THREADS
          mutex_t GC_allocate_ml;       /* Implicitly initialized.      */
 #      else
-         --> declare allocator lock here
+#         if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+            pthread_mutex_t GC_allocate_ml;
+            int GC_pt_init_ok= 0;
+#         else
+          --> declare allocator lock here
+#         endif
 #      endif
 #     endif
 #   endif
@@ -376,6 +381,17 @@ void GC_init()
 {
     DCL_LOCK_STATE;
     
+# ifdef DEC_PTHREADS
+    /* initialise the DECthreads support */
+    {
+      pthread_mutexattr_t attr;
+      pthread_mutexattr_create(&attr);
+      pthread_mutexattr_setkind_np(&attr, MUTEX_RECURSIVE_NP);
+      pthread_mutex_init(&GC_allocate_ml, attr);
+      GC_pt_init();
+    }
+# endif
+
     DISABLE_SIGNALS();
     LOCK();
     GC_init_inner();
@@ -393,6 +409,19 @@ void GC_init_inner()
     word dummy;
     
     if (GC_is_initialized) return;
+#ifdef MIT_PTHREADS
+    /* We need to beat the GC to initialisation, so that it doesn't
+       hang when it first tries to use the allocator lock. */
+    {
+      pthread_mutexattr_t attr;
+      extern void *pthread_initial;
+      if (!pthread_initial) pthread_init();
+      pthread_mutexattr_init(&attr);
+      pthread_mutexattr_settype(&attr, PTHREAD_MUTEXTYPE_RECURSIVE);
+      pthread_mutex_init(&GC_allocate_ml, &attr);
+      if (!GC_pt_init_ok) GC_pt_init();  /* faut eviter cela... */
+    }
+#endif
 #   ifdef MSWIN32
        GC_init_win32();
 #   endif
@@ -513,6 +542,8 @@ void GC_init_inner()
 
 void GC_enable_incremental GC_PROTO(())
 {
+  /* this is broken under DECthreads */
+#ifndef DEC_PTHREADS
     DCL_LOCK_STATE;
     
 # ifndef FIND_LEAK
@@ -551,6 +582,7 @@ out:
     UNLOCK();
     ENABLE_SIGNALS();
 # endif
+#endif /* DEC_PTHREADS */
 }
 
 
diff --git a/mit_threads.c b/mit_threads.c
new file mode 100644 (file)
index 0000000..c778eda
--- /dev/null
@@ -0,0 +1,467 @@
+/* mit_threads.c
+/*
+/* Support for MIT-pthreads in Boehm/Demer/Weiser garbage collector.
+/* Depends on a gc.a compiled with -DMIT_PTHREADS, plus local modifications.
+/* All files should be compiled with pgcc.
+/*
+/* GC_init() should be called before doing anything else (the collector tries
+/* to do this early enough, but may not always succeed).
+/*
+/* Author: Ian.Piumarta@INRIA.fr
+/* 
+/* Copyright (C) 1996 by INRIA and Ian Piumarta
+/*
+/* last edited: Sun Nov 17 22:49:05 1996 by piumarta (Ian Piumarta) on corto
+/*
+/***************************************************************************/
+
+#ifdef MIT_PTHREADS
+
+#undef DEBUG
+
+#include "config.h"
+
+/* there seems to be no other (easy) way to get at these... */
+
+#if defined(ALPHA)
+#  define THREAD_SP(thr) (thr)->machdep_data.machdep_state[34]  /* JB_SP */
+#elif defined(SPARC)
+#  define THREAD_SP(thr) (thr)->machdep_data.machdep_state[2]   /* sc_sp */
+#elif defined(LINUX)
+#  define THREAD_SP(thr) (thr)->machdep_data.machdep_state->__sp /* __sp  */
+#elif defined(HP_PA)
+#  define THREAD_SP(thr) (((int*)((thr)->machdep_data.machdep_state))[1])
+#elif defined(MIPS)
+#  define THREAD_SP(thr) (thr)->machdep_data.machdep_state[JB_SP]
+#else
+/*  ...define THREAD_SP for your architecture here...
+ */
+--> where is your stack pointer?
+#endif
+
+#include <stdio.h>
+#define PTHREAD_KERNEL
+#include <pthread.h>
+#undef RETURN
+
+extern void *GC_get_stack_base();
+
+/*  use malloc-safe printf from the GC, and GC-safe malloc from pthreads
+ */
+extern GC_err_printf();
+extern void *malloc(int);
+
+#ifdef DEBUG
+#  define _CR             GC_err_printf("\n")
+#  define ENTER(X)        static char*_me_=#X;GC_err_printf("ENTER: %s\n",_me_)
+#  define RETURN          GC_err_printf("LEAVE: %s\n",_me_);return
+#  define PRINT(X)        GC_err_printf("%s: %s\n",_me_,(X))
+#  define PRINT1(X,P)     GC_err_printf("%s: ",_me_);GC_err_printf((X),(P));_CR
+#  define PRINT2(X,P,Q)   GC_err_printf("%s: ",_me_);GC_err_printf((X),(P),(Q));_CR
+#  define PRINT3(X,P,Q,R) GC_err_printf("%s: ",_me_);GC_err_printf((X),(P),(Q),(R));_CR
+#  define ERR(X)          {GC_err_printf("%s: ",_me_);perror(X);abort();}
+#else
+#  define ENTER(X)
+#  define RETURN          return
+#  define PRINT(X)
+#  define PRINT1(X,P)
+#  define PRINT2(X,P,Q)
+#  define PRINT3(X,P,Q,R)
+#  define ERR(X)          {perror(X);abort();}
+#endif
+
+/* dequeues */
+
+#define struct_base(PTR, FLD, TYP) ((TYP*)((char*)(PTR)-(char*)(&(((TYP*)0)->FLD))))
+
+typedef struct QUEUE {
+  struct QUEUE *flink, *blink;
+} queue;
+
+/* GC thread info structure */
+
+typedef struct GC_PT_INFO {
+  queue q;                  /* the dequeue on which this structure exists */
+  pthread_t thread;         /* the corresponding thread structure */
+  void *stack_top;          /* the highest address in this thread's stack */
+  void *(*launch)(void *);   /* the thread's real start routine */
+  void *arg;                /* the thread's real start routine argument */
+  int mark_state;           /* this info structures current civil status */
+} gc_pt_info;
+
+#define GC_PT_UNMARKED 0
+#define GC_PT_MARKED   1
+#define GC_PT_NASCENT  2
+
+static queue infos = { &infos, &infos };  /* the dequeue of info structures */
+extern int GC_pt_init_ok;                /* true when init is done */
+
+static pthread_key_t info_key;           /* identity mechanism */
+
+
+/* stop the threads world, somewhat gracelessly
+ */
+void GC_pt_stop_world()
+{
+  pthread_kernel_lock++;
+}
+
+/* restart the threads world; also lacks charm
+ */
+void GC_pt_start_world()
+{
+  pthread_kernel_lock--;
+}
+
+
+extern pthread_mutex_t GC_allocate_ml;
+
+/* initialise the threads-related GC stuff
+ */
+void GC_pt_init()
+{
+  ENTER(GC_pt_init);
+  if (!GC_pt_init_ok)
+    {
+      GC_pt_init_ok= 1;
+      if (pthread_key_create(&info_key, 0)) ERR("pthread_key_create");
+      /*
+       * create an info structure for the initial thread and push it onto
+       * the info dequeue
+       */
+      {
+       gc_pt_info *info= (gc_pt_info *)malloc(sizeof(gc_pt_info));
+       if (!info) ERR("malloc");
+       infos.flink= infos.blink= &info->q;
+       info->q.flink= info->q.blink= &infos;
+       info->thread= pthread_initial;
+       info->stack_top= GC_get_stack_base();
+       PRINT3("initial thread %lx: info %lx, stack %lx",
+              pthread_initial, info, info->stack_top);
+       if (pthread_setspecific(info_key, info)) ERR("pthread_setspecific");
+       /*      GC_err_printf("THREAD INITIAL %lx: info set to %lx\n", pthread_run, info);*/
+      }
+    }
+  RETURN;
+}
+
+
+static void GC_pt_print_threads()
+{
+  pthread_t thread;
+
+  GC_err_printf("PLL:");
+
+  for(thread= pthread_link_list; thread; thread= thread->pll)
+      GC_err_printf(" %lx->%lx", thread, thread->pll);
+  GC_err_printf("\n");
+}
+
+
+/* print the info list
+ */
+static void gc_pt_print_info()
+{
+  queue *ptr= infos.flink;
+  ENTER(GC_pt_print_info);
+  while (ptr != &infos) 
+    {
+      gc_pt_info *info= struct_base(ptr, q, gc_pt_info);
+      GC_err_printf("INFO %lx:\n", info);
+      GC_err_printf("  queue:      %lx\n", info->q);
+      GC_err_printf("  thread:     %lx\n", info->thread);
+      GC_err_printf("  stack_top:  %lx\n", info->stack_top);
+      GC_err_printf("  launch:     %lx\n", info->launch);
+      GC_err_printf("  arg:        %lx\n", info->arg);
+      GC_err_printf("  mark_state: %lx\n", info->mark_state);
+      ptr= ptr->flink;
+    }
+  RETURN;
+}
+
+
+#define FIND_INFO_BY_LOOKUP
+
+/* given some thread, find the corresponding info
+ */
+static gc_pt_info *GC_pt_find_info(pthread_t target)
+{
+#ifdef FIND_INFO_BY_LOOKUP
+  queue *ptr= infos.flink;
+  ENTER(GC_pt_find_info);
+  PRINT1("looking for thread %lx", target);
+  while (ptr != &infos) 
+    {
+      gc_pt_info *info= struct_base(ptr, q, gc_pt_info);
+      PRINT1("looking at %lx", info->thread);
+      if (info->thread == target)
+       {
+         RETURN(info);
+       }
+      ptr= ptr->flink;
+    }
+  GC_err_printf("I can't find the info -- giving up.\n");
+  abort();
+#else 
+
+#  ifdef FIND_INFO_BY_GETSPECIFIC      /* THIS APPEARS TO BE BROKEN */
+  gc_pt_info *info= (gc_pt_info *)pthread_getspecific(info_key);
+  ENTER(GC_pt_find_info);
+  PRINT1("looking for thread %lx", target);
+  /*  GC_err_printf("THREAD %lx: found info %lx\n", target, info);*/
+  return info;
+#  else
+
+#    ifdef FIND_INFO_BY_INTERNALS
+  ENTER(GC_pt_find_info);
+  PRINT1("looking for thread %lx", target);
+  if (!target->specific_data)
+    {
+      PRINT("GC_pt_find_info: no specific data\n");
+      return 0;
+    }
+  if (!target->specific_data[info_key])
+    {
+      PRINT("GC_pt_find_info: info is null\n");
+      return 0;
+    }
+  return (gc_pt_info *)target->specific_data[info_key];
+#    else
+
+-->    so how do you do want me to find the info?
+
+#    endif
+#  endif
+#endif
+}
+
+
+/* unmark all info structures
+ */
+static void GC_pt_unmark_info()
+{
+  int size =0;
+  queue *ptr= infos.flink;
+  ENTER(GC_pt_unmark_info);
+  while (ptr != &infos) 
+    {
+      gc_pt_info *info= struct_base(ptr, q, gc_pt_info);
+      if (info->mark_state != GC_PT_NASCENT)
+       info->mark_state= GC_PT_UNMARKED;
+      ptr= ptr->flink;
+      size++;
+    }
+  PRINT1("INFO LIST SIZE IS %d", size);
+}
+
+
+/* cleanup for info structure -- this used to be called as a destructor
+ * for the thread-specific data, but now it's only ever called explicitly
+ * from within this file
+ */
+static void GC_pt_delete_info(gc_pt_info *info)
+{
+  ENTER(GC_pt_delete_info);
+  PRINT1("pthread_run is %lx", pthread_run);
+  PRINT1("info is %lx", info);
+  /*  GC_err_printf("THREAD %lx: DELETE INFO %lx\n", info->thread, info);*/
+  pthread_mutex_lock(&GC_allocate_ml);
+  {
+    info->q.blink->flink= info->q.flink;
+    info->q.flink->blink= info->q.blink;
+  }
+  pthread_mutex_unlock(&GC_allocate_ml);
+  PRINT1("info is %lx", info);
+  free(info);
+  RETURN;
+}
+
+
+/* sweep up unused info structures
+ */
+static void GC_pt_sweep_info()
+{
+  queue *ptr= infos.flink;
+  ENTER(GC_pt_sweep_info);
+  while (ptr != &infos) 
+    {
+      gc_pt_info *info= struct_base(ptr, q, gc_pt_info);
+      ptr= ptr->flink;
+      if (info->mark_state == GC_PT_UNMARKED)
+       GC_pt_delete_info(info);
+    }
+}
+
+
+/* traverse the pthread linked list (containing all threads) pushing
+ * the pthread structures and stack (if appropriate) for each thread.
+ */
+void GC_pt_push_all_stacks()
+{
+  pthread_t thread;
+  ENTER(GC_pt_push_all_stacks);
+
+  /*  GC_err_printf("MARKING STACKS...\n");*/
+
+  if ((infos.flink == &infos) && (infos.blink == &infos)) { RETURN; }
+
+  /* unmark all info structures */
+  GC_pt_unmark_info();
+
+  /* flush (register windows and other) state for running thread */
+  machdep_save_state();
+
+  /*  GC_err_printf("THREAD LOOP: START\n");*/
+
+  for(thread= pthread_link_list; thread; thread= thread->pll)
+    {
+      /*      GC_err_printf("THREAD LOOP: THREAD %lx, PLL %lx\n", thread, thread->pll);*/
+
+      PRINT("thread structures");
+      /* mark from the pthread internal structures */
+      PRINT2("GC_push_all(%lx, %lx)", thread, (char *)thread + sizeof(*thread));
+      GC_push_all(thread, (char *)thread + sizeof(*thread));
+      PRINT2("GC_push_all(%lx, %lx)", thread->machdep_data.machdep_state,
+            (char *)thread->machdep_data.machdep_state
+            + sizeof(*thread->machdep_data.machdep_state));
+      GC_push_all(thread->machdep_data.machdep_state,
+                 (char *)thread->machdep_data.machdep_state
+                 + sizeof(*thread->machdep_data.machdep_state));
+      PRINT("specific data");
+      /* mark the thread-specific data area */
+      if (thread->specific_data_count)
+       {
+         PRINT2("GC_push_all(%lx, %lx)\n", (void *)thread->specific_data,
+                ((void **)thread->specific_data) + PTHREAD_DATAKEYS_MAX - 1);
+         GC_push_all((void *)thread->specific_data,
+                     ((void **)thread->specific_data) + PTHREAD_DATAKEYS_MAX - 1);
+       }
+      PRINT("thread stacks");
+      /* mark from the thread's stack */
+/*      if (thread->state != PS_DEAD)
+ */
+       {
+         gc_pt_info *info= GC_pt_find_info(thread);
+         /*      GC_err_printf("LOOKING UP INFO FOR %lx\n", thread);*/
+         if (info)
+           {
+             /*              GC_err_printf("INFO FOR %lx AT %lx\n", thread, info);*/
+             GC_push_all(info, (char *)info+sizeof(*info));
+             /*              GC_err_printf("THREAD %lx: MARK INFO %lx\n", info->thread, info);*/
+             info->mark_state= GC_PT_MARKED;
+             if (thread == pthread_run)
+               {
+                 PRINT2("(RUN) GC_push_all_stack(%lx, %lx)", &thread, info->stack_top);
+                  if ((void*)&thread < info->stack_top)
+                   GC_push_all_stack(&thread, info->stack_top);
+                  else
+                   GC_push_all_stack(info->stack_top, &thread);
+               }
+             else /* suspended */
+               {
+                 if ((void*)THREAD_SP(thread) < info->stack_top)
+                   {
+                     PRINT2("(SUS) GC_push_all_stack(%lx, %lx)",
+                            THREAD_SP(thread), info->stack_top);
+                     GC_push_all_stack(THREAD_SP(thread), info->stack_top);
+                   }
+                 else
+                   {
+                     /*PRINT2("(SUS) GC_push_all_stack(%lx, %lx) --- IGNORING BAD SP!!!",
+                            THREAD_SP(thread), info->stack_top);*/
+                      GC_push_all_stack(info->stack_top, THREAD_SP(thread));
+                   }
+                   
+               }
+           }
+         else
+           GC_err_printf("THREAD %lx: NO INFO!!!!!!!!!\n", thread);
+         /*      else /* we're a dead thread */
+         /*    {
+         /*      PRINT1("NO STACK (thread %lx is dead)", thread);
+         /*    }
+          */
+       }
+    }
+
+  /*  GC_err_printf("THREAD LOOP: END\n");*/
+
+  /* sweep up dead info */
+  GC_pt_sweep_info();
+
+  RETURN;
+}
+
+
+/* start routine wrapper, which places the threads id into the info
+ * structure and registers it as thread-specific data; called with the
+ * info structure as argument.
+ */
+static void *GC_pt_starter(void *arg)
+{
+  gc_pt_info *info= (gc_pt_info *)arg;
+  void *result;
+  ENTER(GC_pt_starter);
+  if (pthread_setspecific(info_key, info)) ERR("pthread_setspecific");
+  /*  GC_err_printf("THREAD %lx: info set to %lx\n", pthread_run, info);*/
+  if (!GC_pt_find_info(pthread_run))
+    {
+      GC_err_printf("GC_pt_starter: the active thread does not exist!\n");
+      abort();
+    }
+  PRINT3("*** STARTING %lx: pthread_run is %lx, info %lx",
+        info->thread, pthread_run, info);
+  /*  GC_err_printf("THREAD RUN: %lx\n", info->thread);*/
+  info->mark_state= GC_PT_MARKED;
+  result= info->launch(info->arg);
+  /*  GC_err_printf("THREAD EXIT: %lx\n", info->thread);*/
+  PRINT3("*** EXITING %lx: pthread_run is %lx, info %lx",
+        info->thread, pthread_run, info);
+  RETURN(result);
+}
+
+
+/* pthread_create wrapper, which creates an info structure on the info
+ * dequeue and then has the thread start up in GC_pt_starter.
+ */
+int GC_pt_pthread_create(pthread_t *thread,
+                  const pthread_attr_t *attr,
+                  void *(*start_routine)(void *),
+                  void *arg)
+{
+  int status;
+  gc_pt_info *info= (gc_pt_info *)malloc(sizeof(gc_pt_info));
+  ENTER(GC_pt_pthread_create);
+  if (!info) ERR("malloc");
+
+  /* thread mustn't start until we've built the info struct */
+  GC_pt_stop_world();
+
+  status= pthread_create(thread, attr, GC_pt_starter, (void *)info);
+  if (!attr) attr= &pthread_attr_default;  /* no stack size? -- use the default */
+  /* push the info onto the dequeue */
+  info->q.flink= infos.flink;
+  info->q.blink= &infos;
+  infos.flink->blink= &info->q;
+  infos.flink= &info->q;
+  /* fill in the blanks */
+  info->thread= *thread;
+  info->launch= start_routine;
+  info->arg= arg;
+  info->mark_state= GC_PT_NASCENT;  /* thread not yet born */
+  /* pthread_create filled in the initial SP -- profitons-en ! */
+  info->stack_top= (void *)THREAD_SP(*thread);
+
+  /*  GC_err_printf("THREAD CREATE: %lx\n", *thread);*/
+
+  /*  GC_pt_print_threads();*/
+
+  PRINT1("*** CREATED THREAD %lx", *thread);
+
+  /* we're now ready for the thread to begin */
+  GC_pt_start_world();
+  RETURN(status);
+}
+
+
+#endif /* MIT_PTHREADS */
index 183e9a059e30819218b2367e870e0bdcdb2d126a..7235fa6bc27fa6820858019a6989cd2bb2b43100 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
     /* in some later Linux releases, asm/sigcontext.h may have to      */
     /* be included instead.                                            */
 #   define __KERNEL__
-#   include <asm/signal.h>
+#   ifndef MIT_PTHREADS
+#     include <asm/signal.h>
+#   else
+#     include <asm/sigcontext.h>
+#   endif
 #   undef __KERNEL__
 # endif
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
 #   define NEED_FIND_LIMIT
 # endif
 
+# if defined(MIT_PTHREADS)
+#   define NEED_FIND_LIMIT
+#   if defined (ALPHA)
+      extern void (*signal(int sig, void (*function)(int)))(int);
+      /* Get a definition for struct sigcontext, which the pthreads    */
+      /* headers fail to define.  Temporarily define _KERNEL to avoid  */
+      /* a redefinition of sig_atomic_t.                               */
+#     define _KERNEL
+#     include <machine/signal.h>
+#     undef _KERNEL
+#   endif
+    /* Provide the usual definition for signal(), which the pthreads  */
+    /* headers again fail to define.  (This may be an incorrect       */
+    /* assumption on some architectures!)                             */
+    extern void (*signal(int sig, void (*function)(int)))(int);
+# endif
+
 #ifdef NEED_FIND_LIMIT
 #   include <setjmp.h>
 #endif
@@ -861,7 +882,9 @@ void GC_register_data_segments()
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
        && !defined(MSWIN32) && !defined(MACOS)
 
+#  if !defined(DEC_PTHREADS)
 extern caddr_t sbrk();
+#  endif
 # ifdef __STDC__
 #   define SBRK_ARG_T size_t
 # else
@@ -1086,6 +1109,13 @@ void GC_default_push_other_roots()
 
 # endif /* SOLARIS_THREADS */
 
+# if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+void GC_default_push_other_roots()
+{
+  GC_pt_push_all_stacks();
+}
+# endif
+
 void (*GC_push_other_roots)() = GC_default_push_other_roots;
 
 #endif
@@ -1255,6 +1285,10 @@ word addr;
     return(FALSE);
 }
 
+#if defined(SUNOS4) && defined(MIT_PTHREADS)
+#  include <vm/faultcode.h>
+#endif
+
 #if defined(SUNOS4) || defined(FREEBSD)
     typedef void (* SIG_PF)();
 #endif
@@ -1539,8 +1573,12 @@ void GC_protect_heap()
 }
 
 # ifdef THREADS
+  /* HJB say that this bug manifests itself once in a lifetime, so let's
+     take the risk... */
+#  if !defined(DEC_PTHREADS) && !defined(MIT_PTHREADS)
 --> The following is broken.  We can lose dirty bits.  We would need
 --> the signal handler to cooperate, as in PCR.
+#  endif
 # endif
 
 void GC_read_dirty()
@@ -1565,9 +1603,13 @@ struct hblk * h;
  * the cord package issues a read while it already holds the allocation lock.
  */
  
-# ifdef THREADS
+# if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+void GC_begin_syscall() { LOCK(); }
+void GC_end_syscall() { UNLOCK(); }
+# else
+#  ifdef THREADS
        --> fix this
-# endif
+#  endif
 void GC_begin_syscall()
 {
 }
@@ -1575,6 +1617,7 @@ void GC_begin_syscall()
 void GC_end_syscall()
 {
 }
+# endif
 
 void GC_unprotect_range(addr, len)
 ptr_t addr;
@@ -1607,14 +1650,29 @@ word len;
 /* Replacement for UNIX system call.    */
 /* Other calls that write to the heap   */
 /* should be handled similarly.                 */
-# ifndef LINT
+# if !defined(LINT)
+#  if defined(MIT_PTHREADS)
+  /* read() is defined in libpthread.a, so we can't redefine it here. */
+  ssize_t GC_read(fd, buf, nbyte)
+#  else
+#   if defined(__GNUC__)
+  ssize_t read(fd, buf, nbyte)
+#   else
   int read(fd, buf, nbyte)
+#   endif
+#  endif
 # else
   int GC_read(fd, buf, nbyte)
 # endif
+# if defined(MIT_PTHREADS) || defined(DEC_PTHREADS)
+int fd;
+void *buf;
+size_t nbyte;
+# else
 int fd;
 char *buf;
 int nbyte;
+# endif
 {
     int result;
     
diff --git a/test.c b/test.c
index 035dad2b933321f63d2872bb72297f8458e349bd..03b5d2843859c554ed276101493a2b4599a99ec4 100644 (file)
--- a/test.c
+++ b/test.c
@@ -40,7 +40,8 @@
 #   include <synch.h>
 # endif
 
-# if defined(PCR) || defined(SOLARIS_THREADS)
+# if defined(PCR) || defined(SOLARIS_THREADS) \
+       || defined(MIT_PTHREADS) || defined(DEC_PTHREADS)
 #   define THREADS
 # endif
 
@@ -356,6 +357,10 @@ int finalizable_count = 0;
 int finalized_count = 0;
 VOLATILE int dropped_something = 0;
 
+# if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+static pthread_mutex_t incr_lock;
+# endif
+
 # ifdef __STDC__
   void finalizer(void * obj, void * client_data)
 # else
@@ -372,6 +377,9 @@ VOLATILE int dropped_something = 0;
 # ifdef SOLARIS_THREADS
     static mutex_t incr_lock;
     mutex_lock(&incr_lock);
+# endif
+# if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+    pthread_mutex_lock(&incr_lock);
 # endif
   if ((int)(GC_word)client_data != t -> level) {
      (void)GC_printf0("Wrong finalization data - collector is broken\n");
@@ -384,6 +392,9 @@ VOLATILE int dropped_something = 0;
 # ifdef SOLARIS_THREADS
     mutex_unlock(&incr_lock);
 # endif
+# if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+    pthread_mutex_unlock(&incr_lock);
+# endif
 }
 
 size_t counter = 0;
@@ -439,6 +450,9 @@ int n;
            static mutex_t incr_lock;
            mutex_lock(&incr_lock);
 #        endif
+#         if defined (DEC_PTHREADS) || defined(MIT_PTHREADS)
+            pthread_mutex_lock(&incr_lock);
+#         endif
                /* Losing a count here causes erroneous report of failure. */
           finalizable_count++;
           my_index = live_indicators_count++;
@@ -448,6 +462,9 @@ int n;
 #        ifdef SOLARIS_THREADS
            mutex_unlock(&incr_lock);
 #        endif
+#         if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+            pthread_mutex_unlock(&incr_lock);
+#         endif
        }
 
         GC_REGISTER_FINALIZER((GC_PTR)result, finalizer, (GC_PTR)(GC_word)n,
@@ -531,6 +548,51 @@ void * alloc8bytes()
     return(my_free_list);
 }
 
+#elif defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+pthread_key_t fl_key;
+
+void * alloc8bytes()
+{
+  void ** my_free_list_ptr;
+  void * my_free_list;
+
+# ifdef DEC_PTHREADS
+  if (pthread_getspecific(fl_key, (void **)(&my_free_list_ptr)) != 0)
+    {
+      (void)GC_printf0("pthread_getspecific failed\n");
+      FAIL;
+    }
+# endif
+# ifdef MIT_PTHREADS
+  if (!(my_free_list_ptr= pthread_getspecific(fl_key)))
+    {
+      /* there's no way to tell if this is an error, so what's to do? */
+    }
+# endif
+  if (my_free_list_ptr == 0)
+    {
+      my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
+      if (pthread_setspecific(fl_key, my_free_list_ptr) != 0)
+        {
+          (void)GC_printf0("pthread_setspecific failed\n");
+          FAIL;
+        }
+    }
+  my_free_list = *my_free_list_ptr;
+  if (my_free_list == 0)
+    {
+      my_free_list = GC_malloc_many(8);
+      if (my_free_list == 0)
+        {
+          (void)GC_printf0("alloc8bytes out of memory\n");
+          FAIL;
+        }
+    }
+  *my_free_list_ptr = GC_NEXT(my_free_list);
+  GC_NEXT(my_free_list) = 0;
+  return(my_free_list);
+}
+
 #else
 # define alloc8bytes() GC_MALLOC_ATOMIC(8)
 #endif
@@ -844,7 +906,10 @@ void SetMinimumStack(long minSize)
 }
 
 
-#if !defined(PCR) && !defined(SOLARIS_THREADS) || defined(LINT)
+#if !defined(PCR) && !defined(SOLARIS_THREADS) \
+       && !defined(DEC_PTHREADS) && !defined(MIT_PTHREADS) \
+       || defined(LINT)
+
 #ifdef MSWIN32
   int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
 #else
@@ -921,17 +986,21 @@ test()
 }
 #endif
 
-#ifdef SOLARIS_THREADS
+#if defined(SOLARIS_THREADS) || defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
 void * thr_run_one_test(void * arg)
 {
     run_one_test();
     return(0);
 }
 
-#ifdef GC_DEBUG
+# ifdef GC_DEBUG
 #  define GC_free GC_debug_free
+# endif
+
 #endif
 
+#ifdef SOLARIS_THREADS
+
 main()
 {
     thread_t th1;
@@ -968,3 +1037,66 @@ main()
     return(0);
 }
 #endif
+
+#if defined(DEC_PTHREADS) || defined(MIT_PTHREADS)
+
+main()
+{
+    pthread_t th1;
+    pthread_t th2;
+    int code;
+    pthread_attr_t thr_attr;
+    void *status;
+
+# ifdef DEC_PTHREADS
+    pthread_mutex_init(&incr_lock, pthread_mutexattr_default);
+    pthread_mutexattr_create(&thr_attr);
+# else
+    pthread_mutex_init(&incr_lock, NULL);
+    pthread_attr_init(&thr_attr);
+# endif
+    pthread_attr_setstacksize(&thr_attr, (long)1024*1024);
+
+    n_tests = 0;
+    GC_init(); /* Only needed if gc is dynamic library.        */
+    /*GC_enable_incremental();*/
+    (void) GC_set_warn_proc(warn_proc);
+# ifdef DEC_PTHREADS
+    if (pthread_keycreate(&fl_key, GC_free) != 0)
+# else
+    if (pthread_key_create(&fl_key, GC_free) != 0)
+# endif
+      {
+       (void)GC_printf1("Key creation failed %lu\n", (long)code);
+       FAIL;
+      }
+# ifdef DEC_PTHREADS
+    if ((code = pthread_create(&th1, thr_attr, thr_run_one_test, 0)) != 0) {
+# else
+    if ((code = pthread_create(&th1, &thr_attr, thr_run_one_test, 0)) != 0) {
+# endif
+       (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
+       FAIL;
+    }
+# ifdef DEC_PTHREADS
+    if ((code = pthread_create(&th2, thr_attr, thr_run_one_test, 0)) != 0) {
+# else
+    if ((code = pthread_create(&th2, &thr_attr, thr_run_one_test, 0)) != 0) {
+# endif
+       (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
+       FAIL;
+    }
+    run_one_test();
+    if ((code = pthread_join(th1, &status)) != 0) {
+        (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
+        FAIL;
+    }
+    if ((code = pthread_join(th2, &status)) != 0) {
+        (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
+        FAIL;
+    }
+    check_heap_stats();
+    (void)fflush(stdout);
+    return(0);
+}
+#endif