summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2011-07-26 14:55:44 +0400
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 14:55:44 +0400
commit2d90eba35546e0aa17a1014026ddbf4f523cad85 (patch)
tree7b87e1fde4c601c88afa9ebaaa3abf8236b29950
parent126a335d1a4b898a0ce69eadfe8ff02c26562f7b (diff)
downloadbdwgc-gc4_10t3.tar.gz
gc4.10t3 tarball importgc4_10t3
-rw-r--r--Makefile6
-rw-r--r--Makefile.pthreads67
-rw-r--r--README.pthreads203
-rw-r--r--alpha_mach_dep.s22
-rw-r--r--config.h9
-rw-r--r--dec_threads.c558
-rw-r--r--dyn_load.c138
-rw-r--r--gc.h42
-rw-r--r--gc_priv.h35
-rw-r--r--misc.c34
-rw-r--r--mit_threads.c467
-rw-r--r--os_dep.c66
-rw-r--r--test.c140
13 files changed, 1755 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index 4e9eff38..9b605b4b 100644
--- 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
index 00000000..8981a014
--- /dev/null
+++ b/Makefile.pthreads
@@ -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
index 00000000..f411fc64
--- /dev/null
+++ b/README.pthreads
@@ -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 -----------------------
diff --git a/alpha_mach_dep.s b/alpha_mach_dep.s
index 265c3141..087baeac 100644
--- a/alpha_mach_dep.s
+++ b/alpha_mach_dep.s
@@ -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
diff --git a/config.h b/config.h
index 58d625ef..4881a9a4 100644
--- a/config.h
+++ b/config.h
@@ -604,18 +604,21 @@
# 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
index 00000000..1b323d40
--- /dev/null
+++ b/dec_threads.c
@@ -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
diff --git a/dyn_load.c b/dyn_load.c
index e3f2ac69..8b9ce768 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -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 0c7a2824..41a65947 100644
--- 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()
diff --git a/gc_priv.h b/gc_priv.h
index 102e8ee9..9c66ed0b 100644
--- 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 03f316af..63a8cecb 100644
--- a/misc.c
+++ b/misc.c
@@ -39,7 +39,12 @@
# 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
index 00000000..c778eda9
--- /dev/null
+++ b/mit_threads.c
@@ -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 */
diff --git a/os_dep.c b/os_dep.c
index 183e9a05..7235fa6b 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -19,7 +19,11 @@
/* 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)
@@ -43,6 +47,23 @@
# 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 035dad2b..03b5d284 100644
--- 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
@@ -373,6 +378,9 @@ VOLATILE int dropped_something = 0;
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");
FAIL;
@@ -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