summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile47
-rw-r--r--OS2_MAKEFILE5
-rw-r--r--PCR-Makefile55
-rw-r--r--README15
-rw-r--r--alloc.c122
-rw-r--r--allochblk.c155
-rw-r--r--black_list.c8
-rw-r--r--config.h375
-rw-r--r--debug_malloc.c48
-rw-r--r--dynamic_load.c170
-rw-r--r--gc.h2
-rw-r--r--gc_private.h473
-rw-r--r--headers.c4
-rw-r--r--if_mach.c22
-rw-r--r--if_not_there.c24
-rw-r--r--mach_dep.c33
-rw-r--r--mark.c18
-rw-r--r--mark_roots.c102
-rw-r--r--misc.c59
-rw-r--r--obj_map.c2
-rw-r--r--os_dep.c109
-rw-r--r--pcr_interface.c12
-rw-r--r--reclaim.c20
-rw-r--r--setjmp_test.c14
-rw-r--r--test.c29
25 files changed, 1123 insertions, 800 deletions
diff --git a/Makefile b/Makefile
index 0f0d9cf8..ab77025e 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,12 @@ OBJS= alloc.o reclaim.o allochblk.o misc.o mach_dep.o os_dep.o mark_roots.o head
CSRCS= reclaim.c allochblk.c misc.c alloc.c mach_dep.c os_dep.c mark_roots.c headers.c mark.c obj_map.c pcr_interface.c black_list.c finalize.c new_hblk.c real_malloc.c dynamic_load.c debug_malloc.c
-SRCS= $(CSRCS) mips_mach_dep.s rs6000_mach_dep.s interface.c gc.h gc_headers.h gc_private.h gc_inline.h gc.man
+SRCS= $(CSRCS) mips_mach_dep.s rs6000_mach_dep.s interface.c gc.h gc_headers.h gc_private.h config.h gc_inline.h gc.man if_mach.c if_not_there.c
+
+# The following is irrelevant on most systems. But a few
+# versions of make otherwise fork the shell specified in
+# the SHELL environment variable.
+SHELL= /bin/sh
CC= cc
CFLAGS= -O
@@ -17,40 +22,34 @@ SPECIALCFLAGS =
all: gc.a gctest
-pcr: PCR-Makefile gc_private.h gc_headers.h gc.h $(SRCS)
+pcr: PCR-Makefile gc_private.h gc_headers.h gc.h config.h mach_dep.o $(SRCS)
+ make -f PCR-Makefile depend
make -f PCR-Makefile
-$(OBJS) test.o: gc_private.h gc_headers.h gc.h Makefile
+$(OBJS) test.o: gc_private.h gc_headers.h gc.h config.h Makefile
-# On some machines, the ranlib command may have to be removed.
-# On an SGI for example, ranlib doesn't exist, and is not needed.
-# Ditto for Solaris 2.X.
gc.a: $(OBJS)
ar ru gc.a $(OBJS)
- ranlib gc.a
-
-# On a MIPS-based machine, replace the rule for mach_dep.o by the
-# following:
-# mach_dep.o: mips_mach_dep.s
-# as -o mach_dep.o mips_mach_dep.s
-# On an IBM RS6000, use the following two lines:
-# mach_dep.o: rs6000_mach_dep.s
-# as -o mach_dep.o rs6000_mach_dep.s
-mach_dep.o: mach_dep.c
- $(CC) -c $(SPECIALCFLAGS) mach_dep.c
+ ranlib gc.a || cat /dev/null
+# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
+
+mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there
+ rm -f mach_dep.o
+ ./if_mach MIPS "" as -o mach_dep.o mips_mach_dep.s
+ ./if_mach RS6000 "" as -o mach_dep.o rs6000_mach_dep.s
+ ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c
+
+if_mach: if_mach.c config.h
+ $(CC) $(CFLAGS) -o if_mach if_mach.c
+
+if_not_there: if_not_there.c
+ $(CC) $(CFLAGS) -o if_not_there if_not_there.c
clean:
rm -f gc.a test.o gctest output-local output-diff $(OBJS) \
setjmp_test mon.out gmon.out a.out core
-rm -f *~
-
-# On a MIPS system, the BSD version of libc.a should be used to get
-# sigsetmask. I found it necessary to link against the system V
-# library first, to get a working version of fprintf. But this may have
-# been due to my failure to find the right version of stdio.h or some
-# such thing.
-# On a Solaris 2.X system, also make sure you're using BSD libraries.
gctest: test.o gc.a
$(CC) $(CFLAGS) -o gctest test.o gc.a
diff --git a/OS2_MAKEFILE b/OS2_MAKEFILE
index 249486df..07460d84 100644
--- a/OS2_MAKEFILE
+++ b/OS2_MAKEFILE
@@ -4,12 +4,13 @@
# look at another threads registers.
# We also haven't figured out how to do partial links or build static libraries. Hence a
-# client currentlu needs to link against all of the following:
+# client currently needs to link against all of the following:
OBJS= alloc.obj reclaim.obj allochblk.obj misc.obj mach_dep.obj os_dep.obj mark_roots.obj headers.obj mark.obj obj_map.obj black_list.obj finalize.obj new_hblk.obj real_malloc.obj dynamic_load.obj debug_malloc.obj
CC= icc
-CFLAGS= /Ti /Q
+CFLAGS= /O /Q
+# Use /Ti instead of /O for debugging
# Setjmp_test may yield overly optimistic results when compiled
# without optimization.
diff --git a/PCR-Makefile b/PCR-Makefile
index 616ffdc7..a432999b 100644
--- a/PCR-Makefile
+++ b/PCR-Makefile
@@ -1,41 +1,44 @@
OBJS= alloc.o reclaim.o allochblk.o misc.o mach_dep.o os_dep.o mark_roots.o headers.o mark.o obj_map.o pcr_interface.o black_list.o finalize.o new_hblk.o real_malloc.o dynamic_load.o debug_malloc.o
+CSRCS= reclaim.c allochblk.c misc.c alloc.c mach_dep.c os_dep.c mark_roots.c headers.c mark.c obj_map.c pcr_interface.c black_list.c finalize.c new_hblk.c real_malloc.c dynamic_load.c debug_malloc.c
+
+SHELL= /bin/sh
+
# Fix to point to local pcr installation directory.
-PCRDIR= /project/ppcr/dev
+PCRDIR= /project/ppcr/v1.5
CC= gcc
CFLAGS= -g -DPCR -I$(PCRDIR) -I$(PCRDIR)/pcr -I$(PCRDIR)/pcr/ansi -I$(PCRDIR)/pcr/posix
-# On Sun systems under 4.x, it's safer to link with -Bstatic.
-# On other systems, -Bstatic usually doesn't make sense, and should be
-# removed.
-# Setjmp_test may yield overly optimistic results when compiled
-# without optimization.
-
-SPECIALCFLAGS =
-# Alternative flags to the C compiler for mach_dep.c.
-# Mach_dep.c often doesn't like optimization, and it's
-# not time-critical anyway.
-# Set SPECIALCFLAGS to -q nodirect_code on Encore.
-
-PCRINCLS= $(PCRDIR)/pcr/il/PCR_IL.h $(PCRDIR)/pcr/th/PCR_ThCtl.h $(PCRDIR)/pcr/mm/PCR_MM.h
+# We assume that mach_dep.o has already been built by top level makefile. It doesn't
+# care about pcr vs UNIX, and we don't want to repeat that cruft.
all: gc.o test.o gcpcr
gcpcr: gc.o test.o $(PCRDIR)/pcr/base/pcr.o $(PCRDIR)/pcr/base/PCR_BaseMain.o
- $(CC) -static -o gcpcr $(PCRDIR)/pcr/base/pcr.o $(PCRDIR)/pcr/base/PCR_BaseMain.o gc.o test.o
-
-$(OBJS) test.o: gc_private.h gc_headers.h gc.h PCR-Makefile $(PCRINCLS)
+ $(CC) -o gcpcr $(PCRDIR)/pcr/base/pcr.o $(PCRDIR)/pcr/base/PCR_BaseMain.o gc.o test.o -ldl
gc.o: $(OBJS)
-ld -r -o gc.o $(OBJS)
-# On a MIPS machine, replace the rule for mach_dep.o by the
-# following:
-# mach_dep.o: mips_mach_dep.s
-# as -o mach_dep.o mips_mach_dep.s
-# On an IBM RS6000, use the following two lines:
-# mach_dep.o: rs6000_mach_dep.s
-# as -o mach_dep.o rs6000_mach_dep.s
-mach_dep.o: mach_dep.c
- $(CC) -c ${SPECIALCFLAGS} mach_dep.c
+#
+# Dependency construction
+#
+# NOTE: the makefile must include "# DO NOT DELETE THIS LINE" after the
+# last target. "make depend" will replace everything following that line
+# by a newly-constructed list of dependencies.
+#
+depend: $(CSRCS)
+ rm -f makedep eddep ; \
+ $(CC) -M $(CFLAGS) $(CSRCS) \
+ | sed -e '/:$$/d' > makedep ; \
+ echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep ; \
+ echo '$$r makedep' >>eddep ; \
+ echo 'w' >>eddep ; \
+ cp PCR-Makefile PCR-Makefile.bak ; \
+ ex - PCR-Makefile < eddep ; \
+ rm -f eddep makedep
+ touch depend
+
+# DO NOT DELETE THIS LINE
+
diff --git a/README b/README
index 13133fa6..390f50b2 100644
--- a/README
+++ b/README
@@ -8,7 +8,7 @@ Permission is hereby granted to copy this garbage collector for any purpose,
provided the above notices are retained on all copies.
-This is version 2.4. Note that functions were renamed since version 1.9
+This is version 2.6. Note that functions were renamed since version 1.9
to make naming consistent with PCR collectors.
HISTORY -
@@ -542,3 +542,16 @@ for PPCR.
under 4.1.1U1, but apparently not 4.1.1. If you have such a machine,
use -Bstatic.)
+ Version 2.5 added Solaris dynamic libary support, Solaris/Intel support,
+ and fixed the following bugs:
+- Removed an explicit call to exit(1)
+- Fixed calls to GC_printf and GC_err_printf, so the correct number of
+ arguments are always supplied. The OS/2 C compiler gets confused if
+ the number of actuals and the number of formals differ. (ANSI C
+ doesn't require this to work. The ANSI sanctioned way of doing things
+ causes too many compatibility problems.)
+
+ Version 2.6 fixed a bug diagnosed by Al Dosser at DEC. The marker
+ could lose some pointers in the event of a mark stack overflow, a case
+ it was intended to handle correctly. (He also pointed out a performance
+ bug that was tickled under the same circumstances.)
diff --git a/alloc.c b/alloc.c
index e97492f0..1456d529 100644
--- a/alloc.c
+++ b/alloc.c
@@ -10,7 +10,7 @@
*
* This file contains the functions:
* static void clear_marks()
- * void GC_gcollect_inner(force)
+ * bool GC_gcollect_inner(force)
* void GC_gcollect()
* bool GC_expand_hp(n)
* ptr_t GC_allocobj(sz, kind)
@@ -86,7 +86,12 @@ char * GC_copyright[] =
extern signed_word GC_mem_found; /* Number of reclaimed longwords */
/* after garbage collection */
-extern errno;
+/* clear all mark bits in the header */
+void GC_clear_hdr_marks(hhdr)
+register hdr * hhdr;
+{
+ bzero((char *)hhdr -> hb_marks, (int)(MARK_BITS_SZ*sizeof(word)));
+}
/*
* Clear all mark bits associated with block h.
@@ -97,11 +102,8 @@ struct hblk *h;
word dummy;
{
register hdr * hhdr = HDR(h);
- register int j;
- for (j = 0; j < MARK_BITS_SZ; j++) {
- hhdr -> hb_marks[j] = 0;
- }
+ GC_clear_hdr_marks(hhdr);
}
/*
@@ -136,6 +138,36 @@ static word min_words_allocd()
return(BYTES_TO_WORDS(GC_heapsize + total_root_size)/GC_free_space_divisor);
}
+/* Return the number of words allocated, adjusted for explicit storage */
+/* management. This number can be used in deciding when to trigger */
+/* collections. */
+word GC_adj_words_allocd()
+{
+ register signed_word result;
+ register signed_word expl_managed =
+ BYTES_TO_WORDS((long)GC_non_gc_bytes
+ - (long)GC_non_gc_bytes_at_gc);
+
+ /* Don't count what was explicitly freed, or newly allocated for */
+ /* explicit management. Note that deallocating an explicitly */
+ /* managed object should not alter result, assuming the client */
+ /* is playing by the rules. */
+ result = (signed_word)GC_words_allocd
+ - (signed_word)GC_mem_freed - expl_managed;
+ if (result > (signed_word)GC_words_allocd) result = GC_words_allocd;
+ /* probably client bug or unfortunate scheduling */
+ if (result < (signed_word)(GC_words_allocd >> 2)) {
+ /* Always count at least 1/8 of the allocations. We don't want */
+ /* to collect too infrequently, since that would inhibit */
+ /* coalescing of free storage blocks. */
+ /* This also makes us partially robust against client bugs. */
+ return(GC_words_allocd >> 3);
+ } else {
+ return(result);
+ }
+}
+
+
/* Clear up a few frames worth og garbage left at the top of the stack. */
/* This is used to prevent us from accidentally treating garbade left */
/* on the stack by other parts of the collector as roots. This */
@@ -156,8 +188,10 @@ void GC_clear_a_few_frames()
* garbage collection)
* We assume we hold the allocation lock, and are not interruptable by
* signals, if that matters.
+ * If force is FALSE and we didn't do anything, return FALSE.
+ * Otherwise return TRUE
*/
-void GC_gcollect_inner(force)
+bool GC_gcollect_inner(force)
bool force; /* Collect even if only a small amount of allocation */
/* has taken place. Otherwise we refuse, allowing the */
/* heap to grow. */
@@ -169,12 +203,12 @@ bool force; /* Collect even if only a small amount of allocation */
# endif
if (!force && !GC_dont_expand
- && GC_words_allocd < min_words_allocd()) return;
+ && GC_adj_words_allocd() < min_words_allocd()) return(FALSE);
# ifdef PRINTTIMES
GET_TIME(start_time);
# endif
# ifdef PRINTSTATS
- GC_printf("Collection %lu reclaimed %ld bytes\n",
+ GC_printf2("Collection %lu reclaimed %ld bytes\n",
(unsigned long) GC_gc_no,
(long)WORDS_TO_BYTES(GC_mem_found));
# endif
@@ -185,15 +219,14 @@ bool force; /* Collect even if only a small amount of allocation */
GC_atomic_in_use = 0;
# endif
# ifdef PRINTSTATS
- GC_printf("Collection number %lu after %lu allocated bytes ",
+ GC_printf2("Collection number %lu after %lu allocated bytes ",
(unsigned long) GC_gc_no,
(unsigned long) WORDS_TO_BYTES(GC_words_allocd));
- GC_printf("(heapsize = %lu bytes)\n",
+ GC_printf1("(heapsize = %lu bytes)\n",
(unsigned long) GC_heapsize);
/* Printf arguments may be pushed in funny places. Clear the */
/* space. */
- GC_printf("", (unsigned long)0, (unsigned long)0, (unsigned long)0,
- (unsigned long)0, (unsigned long)0, (unsigned long)0);
+ GC_printf0("");
# endif
clear_marks();
@@ -278,7 +311,7 @@ bool force; /* Collect even if only a small amount of allocation */
# ifdef PRINTSTATS
- GC_printf("Bytes recovered before GC_reclaim - f.l. count = %ld\n",
+ GC_printf1("Bytes recovered before GC_reclaim - f.l. count = %ld\n",
(long)WORDS_TO_BYTES(GC_mem_found));
# endif
@@ -288,25 +321,29 @@ bool force; /* Collect even if only a small amount of allocation */
# endif /* FIND_LEAK */
# ifdef PRINTSTATS
- GC_printf("Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
+ GC_printf2(
+ "Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
(long)WORDS_TO_BYTES(GC_mem_found),
(unsigned long)GC_heapsize);
- GC_printf("%lu (atomic) + %lu (composite) bytes in use\n",
- (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
- (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
+ GC_printf2("%lu (atomic) + %lu (composite) bytes in use\n",
+ (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
+ (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
# endif
/* Reset or increment counters for next cycle */
GC_words_allocd_before_gc += GC_words_allocd;
+ GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
GC_words_allocd = 0;
+ GC_mem_freed = 0;
/* Get final time */
# ifdef PRINTTIMES
GET_TIME(done_time);
- GC_printf("Garbage collection took %lu + %lu msecs\n",
- MS_TIME_DIFF(mark_time,start_time),
- MS_TIME_DIFF(done_time,mark_time));
+ GC_printf2("Garbage collection took %lu + %lu msecs\n",
+ MS_TIME_DIFF(mark_time,start_time),
+ MS_TIME_DIFF(done_time,mark_time));
# endif
+ return(TRUE);
}
/* Externally callable version of above */
@@ -319,7 +356,7 @@ void GC_gcollect()
if (!GC_is_initialized) GC_init_inner();
/* Minimize junk left in my registers */
GC_noop(0,0,0,0,0,0);
- GC_gcollect_inner(TRUE);
+ (void) GC_gcollect_inner(TRUE);
UNLOCK();
ENABLE_SIGNALS();
}
@@ -388,7 +425,7 @@ word n;
return(FALSE);
}
# ifdef PRINTSTATS
- GC_printf("Increasing heap size by %lu\n",
+ GC_printf1("Increasing heap size by %lu\n",
(unsigned long)bytes);
# endif
expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd());
@@ -429,6 +466,26 @@ int n;
return(result);
}
+void GC_collect_or_expand(needed_blocks)
+word needed_blocks;
+{
+ static int count = 0; /* How many failures? */
+
+ if (GC_dont_gc || !GC_gcollect_inner(FALSE)) {
+ if (!GC_expand_hp_inner(GC_hincr + needed_blocks)
+ && !GC_expand_hp_inner(needed_blocks)) {
+ if (count++ < 20) {
+ WARN("Out of Memory! Trying to continue ...\n");
+ (void) GC_gcollect_inner(TRUE);
+ } else {
+ GC_err_printf0("Out of Memory! Giving up!\n");
+ EXIT();
+ }
+ }
+ update_GC_hincr;
+ }
+}
+
/*
* Make sure the object free list for sz is not empty.
* Return a pointer to the first object on the free list.
@@ -440,25 +497,16 @@ word sz;
int kind;
{
register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
+
if (sz == 0) return(0);
- if (*flh == 0) {
+ while (*flh == 0) {
GC_continue_reclaim(sz, kind);
- }
- if (*flh == 0) {
- if (!GC_sufficient_hb(sz, kind) && !GC_dont_gc) {
- if (GC_DIV * GC_non_gc_bytes < GC_MULT * GC_heapsize) {
- GC_gcollect_inner(FALSE);
- GC_continue_reclaim(sz, kind);
- } else {
- if (!GC_expand_hp_inner(NON_GC_HINCR)) {
- GC_gcollect_inner(FALSE);
- GC_continue_reclaim(sz, kind);
- }
- }
+ if (*flh == 0) {
+ GC_new_hblk(sz, kind);
}
if (*flh == 0) {
- GC_new_hblk(sz, kind);
+ GC_collect_or_expand((word)1);
}
}
return(*flh);
diff --git a/allochblk.c b/allochblk.c
index 1dcf581b..48212b7f 100644
--- a/allochblk.c
+++ b/allochblk.c
@@ -38,61 +38,24 @@ struct hblk *GC_savhbp = (struct hblk *)0; /* heap block preceding next */
/* block to be examined by */
/* GC_allochblk. */
-/*
- * Return TRUE if there is a heap block sufficient for object size sz,
- * FALSE otherwise. Advance GC_savhbp to point to the block prior to the
- * first such block.
- */
-bool GC_sufficient_hb(sz, kind)
-word sz;
+/* Initialize hdr for a block containing the indicated size and */
+/* kind of objects. */
+static setup_header(hhdr, sz, kind)
+register hdr * hhdr;
+word sz; /* object size in words */
int kind;
{
-register struct hblk *hbp;
-register hdr * hhdr;
-struct hblk *prevhbp;
-signed_word size_needed;
-signed_word size_avail;
-bool first_time = TRUE;
-
- size_needed = WORDS_TO_BYTES(sz);
- size_needed = (size_needed+HDR_BYTES+HBLKSIZE-1) & ~HBLKMASK;
-# ifdef DEBUG
- GC_printf("GC_sufficient_hb: sz = %ld, size_needed = 0x%lx\n",
- (long)sz, (unsigned long)size_needed);
-# endif
- /* search for a big enough block in free list */
- hbp = GC_savhbp;
- hhdr = HDR(hbp);
- for(;;) {
- prevhbp = hbp;
- hbp = ((prevhbp == (struct hblk *)0)
- ? GC_hblkfreelist
- : hhdr->hb_next);
- hhdr = HDR(hbp);
-
- if( prevhbp == GC_savhbp && !first_time) {
- /* no sufficiently big blocks on free list */
- return(FALSE);
- }
- first_time = 0;
- if( hbp == (struct hblk *)0 ) continue;
- size_avail = hhdr->hb_sz;
- if ( kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC) {
- struct hblk * thishbp;
- struct hblk * lasthbp = hbp;
-
- while ((ptr_t)lasthbp - (ptr_t)hbp < size_avail
- && (thishbp = GC_is_black_listed(lasthbp,
- (word)size_needed))) {
- lasthbp = thishbp;
- }
- size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
- }
- if( size_avail >= size_needed ) {
- GC_savhbp = prevhbp;
- return(TRUE);
- }
- }
+ /* Set size, kind and mark proc fields */
+ hhdr -> hb_sz = sz;
+ hhdr -> hb_obj_kind = kind;
+ hhdr -> hb_mark_proc = GC_obj_kinds[kind].ok_mark_proc;
+
+ /* Add description of valid object pointers */
+ GC_add_map_entry(sz);
+ hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
+
+ /* Clear mark bits */
+ GC_clear_hdr_marks(hhdr);
}
/*
@@ -134,31 +97,10 @@ int kind;
hhdr = HDR(hbp);
if( prevhbp == GC_savhbp && !first_time) {
- /* no sufficiently big blocks on free list, */
- /* let thishbp --> a newly-allocated block, */
- /* free it (to merge into existing block */
- /* list) and start the search again, this */
- /* time with guaranteed success. */
- word size_to_get = size_needed + GC_hincr * HBLKSIZE;
-
- if (! GC_expand_hp_inner(divHBLKSZ(size_to_get))) {
- if (! GC_expand_hp_inner(divHBLKSZ((word)size_needed)))
- {
- /* GC_printf("Out of Memory! Giving up ...\n"); */
- /* There are other things we could try. It */
- /* would probably be reasonable to clear */
- /* black lists at tthis point. */
- return(0);
- } else {
- WARN("Out of Memory! Trying to continue ...\n");
- GC_gcollect_inner(TRUE);
- }
- }
- update_GC_hincr;
- return (GC_allochblk(sz, kind));
+ return(0);
}
- first_time = 0;
+ first_time = FALSE;
if( hbp == 0 ) continue;
@@ -205,7 +147,30 @@ int kind;
phdr = hhdr;
hbp = thishbp;
hhdr = thishdr;
- }
+ } else if (size_avail == 0
+ && size_needed == HBLKSIZE
+ && prevhbp != 0) {
+ static unsigned count = 0;
+
+ /* The block is completely blacklisted. We need */
+ /* to drop some such blocks, since otherwise we spend */
+ /* all our time traversing them if pointerfree */
+ /* blocks are unpopular. */
+ /* A dropped block will be reconsidered at next GC. */
+ if ((++count & 3) == 0) {
+ /* Allocate and drop the block */
+ phdr -> hb_next = hhdr -> hb_next;
+ GC_install_counts(hbp, hhdr->hb_sz);
+ setup_header(hhdr,
+ BYTES_TO_WORDS(hhdr->hb_sz - HDR_BYTES),
+ PTRFREE);
+ if (GC_savhbp == hbp) GC_savhbp = prevhbp;
+ /* Restore hbp to point at free block */
+ hbp = prevhbp;
+ hhdr = phdr;
+ if (hbp == GC_savhbp) first_time = TRUE;
+ }
+ }
}
if( size_avail >= size_needed ) {
/* found a big enough block */
@@ -237,34 +202,16 @@ int kind;
}
}
- /* set size and mask field of *thishbp correctly */
- thishdr->hb_sz = sz;
-
/* Clear block if necessary */
if (sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) {
bzero((char *)thishbp + HDR_BYTES, (int)(size_needed - HDR_BYTES));
}
-
- /* Clear mark bits */
- {
- register word *p = (word *)(&(thishdr -> hb_marks[0]));
- register word * plim =
- (word *)(&(thishdr -> hb_marks[MARK_BITS_SZ]));
- while (p < plim) {
- *p++ = 0;
- }
- }
-
- /* Add it to data structure describing hblks in use */
- GC_install_counts(thishbp, (word)size_needed);
-
- /* Add description of valid object pointers. */
- GC_add_map_entry(sz);
- thishdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
+
+ /* Set up header */
+ setup_header(thishdr, sz, kind);
- /* Set kind related fields */
- thishdr -> hb_obj_kind = kind;
- thishdr -> hb_mark_proc = GC_obj_kinds[kind].ok_mark_proc;
+ /* Add it to map of valid blocks */
+ GC_install_counts(thishbp, (word)size_needed);
return( thishbp );
}
@@ -311,10 +258,10 @@ register signed_word size;
/* Check for duplicate deallocation in the easy case */
if (hbp != 0 && (ptr_t)p + size > (ptr_t)hbp
|| prevhbp != 0 && (ptr_t)prevhbp + prevhdr->hb_sz > (ptr_t)p) {
- GC_printf("Duplicate large block deallocation of 0x%lx\n",
- (unsigned long) p);
- GC_printf("Surrounding free blocks are 0x%lx and 0x%lx\n",
- (unsigned long) prevhbp, (unsigned long) hbp);
+ GC_printf1("Duplicate large block deallocation of 0x%lx\n",
+ (unsigned long) p);
+ GC_printf2("Surrounding free blocks are 0x%lx and 0x%lx\n",
+ (unsigned long) prevhbp, (unsigned long) hbp);
}
/* Coalesce with successor, if possible */
diff --git a/black_list.c b/black_list.c
index 9471dc52..ba54f892 100644
--- a/black_list.c
+++ b/black_list.c
@@ -114,8 +114,8 @@ word p;
if (HDR(p) == 0 || get_bl_entry_from_index(GC_new_normal_bl, index)) {
# ifdef PRINTBLACKLIST
if (!get_bl_entry_from_index(GC_incomplete_normal_bl, index)) {
- GC_printf("Black listing (normal) 0x%lx\n",
- (unsigned long) p);
+ GC_printf1("Black listing (normal) 0x%lx\n",
+ (unsigned long) p);
}
# endif
set_bl_entry_from_index(GC_incomplete_normal_bl, index);
@@ -134,8 +134,8 @@ word p;
if (HDR(p) == 0 || get_bl_entry_from_index(GC_new_stack_bl, index)) {
# ifdef PRINTBLACKLIST
if (!get_bl_entry_from_index(GC_incomplete_stack_bl, index)) {
- GC_printf("Black listing (stack) 0x%lx\n",
- (unsigned long)p);
+ GC_printf1("Black listing (stack) 0x%lx\n",
+ (unsigned long)p);
}
# endif
set_bl_entry_from_index(GC_incomplete_stack_bl, index);
diff --git a/config.h b/config.h
new file mode 100644
index 00000000..48464e43
--- /dev/null
+++ b/config.h
@@ -0,0 +1,375 @@
+#ifndef CONFIG_H
+
+# define CONFIG_H
+
+/* Machine dependent parameters. Some tuning parameters can be found */
+/* near the top of gc_private.h. */
+
+/* Machine specific parts contributed by various people. See README file. */
+
+/* Determine the machine type: */
+# if defined(sun) && defined(mc68000)
+# define M68K
+# define SUNOS
+# define mach_type_known
+# endif
+# if defined(hp9000s300)
+# define M68K
+# define HP
+# define mach_type_known
+# endif
+# if defined(vax)
+# define VAX
+# ifdef ultrix
+# define ULTRIX
+# else
+# define BSD
+# endif
+# define mach_type_known
+# endif
+# if defined(mips)
+# define MIPS
+# ifdef ultrix
+# define ULTRIX
+# else
+# define RISCOS
+# endif
+# define mach_type_known
+# endif
+# if defined(sequent) && defined(i386)
+# define I386
+# define SEQUENT
+# define mach_type_known
+# endif
+# if defined(sun) && defined(i386)
+# define I386
+# define SUNOS5
+# define mach_type_known
+# endif
+# if defined(__OS2__) && defined(__32BIT__)
+# define I386
+# define OS2
+# define mach_type_known
+# endif
+# if defined(ibm032)
+# define RT
+# define mach_type_known
+# endif
+# if defined(sun) && defined(sparc)
+# define SPARC
+ /* Test for SunOS 5.x */
+# include <errno.h>
+# ifdef ECHRNG
+# define SUNOS5
+# else
+# define SUNOS4
+# endif
+# define mach_type_known
+# endif
+# if defined(_IBMR2)
+# define IBMRS6000
+# define mach_type_known
+# endif
+# if defined(SCO)
+# define I386
+# define SCO
+# define mach_type_known
+/* --> incompletely implemented */
+# endif
+# if defined(_AUX_SOURCE)
+# define M68K
+# define SYSV
+# define mach_type_known
+# endif
+# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1)
+# define HP_PA
+# define mach_type_known
+# endif
+# if defined(linux) && defined(i386)
+# define I386
+# define LINUX
+# define mach_type_known
+# endif
+
+/* Feel free to add more clauses here */
+
+/* Or manually define the machine type here. A machine type is */
+/* characterized by the architecture. Some */
+/* machine types are further subdivided by OS. */
+/* the macros ULTRIX, RISCOS, and BSD to distinguish. */
+/* Note that SGI IRIX is treated identically to RISCOS. */
+/* SYSV on an M68K actually means A/UX. */
+/* The distinction in these cases is usually the stack starting address */
+# ifndef mach_type_known
+ --> unknown machine type
+# endif
+ /* Mapping is: M68K ==> Motorola 680X0 */
+ /* (SUNOS, HP, and SYSV (A/UX) variants)*/
+ /* M68K_HP ==> HP9000/300 */
+ /* M68K_SYSV ==> A/UX, maybe others */
+ /* I386 ==> Intel 386 */
+ /* (SEQUENT, OS2, SCO, LINUX variants) */
+ /* SCO is incomplete. */
+ /* NS32K ==> Encore Multimax */
+ /* MIPS ==> R2000 or R3000 */
+ /* (RISCOS, ULTRIX variants) */
+ /* VAX ==> DEC VAX */
+ /* (BSD, ULTRIX variants) */
+ /* RS6000 ==> IBM RS/6000 AIX3.1 */
+ /* RT ==> IBM PC/RT */
+ /* HP_PA ==> HP9000/700 & /800 */
+ /* HP/UX */
+ /* SPARC ==> SPARC under SunOS */
+ /* (SUNOS4, SUNOS5 variants)
+
+
+/*
+ * For each architecture and OS, the following need to be defined:
+ *
+ * CPP_WORD_SZ is a simple integer constant representing the word size.
+ * in bits. We assume byte addressibility, where a byte has 8 bits.
+ * We also assume CPP_WORD_SZ is either 32 or 64. Only 32 is completely
+ * implemented. (We care about the length of pointers, not hardware
+ * bus widths. Thus a 64 bit processor with a C compiler that uses
+ * 32 bit pointers should use CPP_WORD_SZ of 32, not 64.)
+ *
+ * MACH_TYPE is a string representation of the machine type.
+ * OS_TYPE is analogous for the OS.
+ *
+ * ALIGNMENT is the largest N, such that
+ * all pointer are guaranteed to be aligned on N byte boundaries.
+ * defining it to be 1 will always work, but perform poorly.
+ *
+ * DATASTART is the beginning of the data segment.
+ * On UNIX systems, the collector will scan the area between DATASTART
+ * and &end for root pointers.
+ *
+ * STACKBOTTOM is the cool end of the stack, which is usually the
+ * highest address in the stack.
+ * Under PCR or OS/2, we have other ways of finding thread stacks.
+ * For each machine, the following should:
+ * 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
+ * 2) define exactly one of
+ * STACKBOTTOM (should be defined to be an expression)
+ * HEURISTIC1
+ * HEURISTIC2
+ * If either of the last two macros are defined, then STACKBOTTOM is computed
+ * during collector startup using one of the following two heuristics:
+ * HEURISTIC1: Take an address inside GC_init's frame, and round it up to
+ * the next multiple of 16 MB.
+ * HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly
+ * in small steps (decrement if STACK_GROWS_UP), and read the value
+ * at each location. Remember the value when the first
+ * Segmentation violation or Bus error is signalled. Round that
+ * to the nearest plausible page boundary, and use that instead
+ * of STACKBOTTOM.
+ *
+ * If no expression for STACKBOTTOM can be found, and neither of the above
+ * heuristics are usable, the collector can still be used with all of the above
+ * undefined, provided one of the following is done:
+ * 1) GC_mark_roots can be changed to somehow mark from the correct stack(s)
+ * without reference to STACKBOTTOM. This is appropriate for use in
+ * conjunction with thread packages, since there will be multiple stacks.
+ * (Allocating thread stacks in the heap, and treating them as ordinary
+ * heap data objects is also possible as a last resort. However, this is
+ * likely to introduce significant amounts of excess storage retention
+ * unless the dead parts of the thread stacks are periodically cleared.)
+ * 2) Client code may set GC_stackbottom before calling any GC_ routines.
+ * If the author of the client code controls the main program, this is
+ * easily accomplished by introducing a new main program, setting
+ * GC_stackbottom to the address of a local variable, and then calling
+ * the original main program. The new main program would read something
+ * like:
+ *
+ * # include "gc_private.h"
+ *
+ * main(argc, argv, envp)
+ * int argc;
+ * char **argv, **envp;
+ * {
+ * int dummy;
+ *
+ * GC_stackbottom = (ptr_t)(&dummy);
+ * return(real_main(argc, argv, envp));
+ * }
+ */
+
+
+# ifdef M68K
+# define MACH_TYPE "M68K"
+# define ALIGNMENT 2
+# ifdef SUNOS
+# define OS_TYPE "SUNOS"
+ extern char etext;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ffff) & ~0x1ffff))
+# define HEURISTIC1 /* differs */
+# endif
+# ifdef HP
+# define OS_TYPE "HP"
+ extern char etext;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+# define STACKBOTTOM ((ptr_t) 0xffeffffc)
+ /* empirically determined. seems to work. */
+# endif
+# ifdef SYSV
+# define OS_TYPE "SYSV"
+ extern etext;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
+ & ~0x3fffff) \
+ +((word)&etext & 0x1fff))
+ /* This only works for shared-text binaries with magic number 0413.
+ The other sorts of SysV binaries put the data at the end of the text,
+ in which case the default of &etext would work. Unfortunately,
+ handling both would require having the magic-number available.
+ -- Parag
+ */
+# define STACKBOTTOM ((ptr_t)0xFFFFFFFE)
+ /* The stack starts at the top of memory, but */
+ /* 0x0 cannot be used as setjump_test complains */
+ /* that the stack direction is incorrect. Two */
+ /* bytes down from 0x0 should be safe enough. */
+ /* --Parag */
+# endif
+# endif
+
+# ifdef VAX
+# define MACH_TYPE "VAX"
+# define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */
+ extern char etext;
+# define DATASTART ((ptr_t)(&etext))
+# ifdef BSD
+# define OS_TYPE "BSD"
+# define HEURISTIC1
+ /* HEURISTIC2 may be OK, but it's hard to test. */
+# endif
+# ifdef ULTRIX
+# define OS_TYPE "ULTRIX"
+# define STACKBOTTOM ((ptr_t) 0x7fffc800)
+# endif
+# endif
+
+# ifdef RT
+# define MACH_TYPE "RT"
+# define ALIGNMENT 4
+# define DATASTART ((ptr_t) 0x10000000)
+# define STACKBOTTOM ((ptr_t) 0x1fffd800)
+# endif
+
+# ifdef SPARC
+# define MACH_TYPE "SPARC"
+# define ALIGNMENT 4 /* Required by hardware */
+ extern int etext;
+# ifdef SUNOS5
+# define OS_TYPE "SUNOS5"
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0x10003) & ~0x3))
+ /* Experimentally determined. */
+ /* Inconsistent with man a.out, which appears */
+ /* to be wrong. */
+# endif
+# ifdef SUNOS4
+# define OS_TYPE "SUNOS4"
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+ /* On very old SPARCs this is too conservative. */
+# endif
+# define HEURISTIC1
+# endif
+
+# ifdef I386
+# define MACH_TYPE "I386"
+# define ALIGNMENT 4 /* 32-bit compilers align pointers */
+# ifdef SEQUENT
+# define OS_TYPE "SEQUENT"
+ extern int etext;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+# define STACKBOTTOM ((ptr_t) 0x3ffff000)
+# endif
+# ifdef SUNOS5
+# define OS_TYPE "SUNOS5"
+ extern int etext;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1003) & ~0x3))
+ extern int _start();
+# define STACKBOTTOM ((ptr_t)(&_start))
+# endif
+# ifdef SCO
+# define OS_TYPE "SCO"
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
+ & ~0x3fffff) \
+ +((word)&etext & 0xfff))
+# define STACKBOTTOM ((ptr_t) 0x7ffffffc)
+# endif
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+ extern int etext;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+# define STACKBOTTOM ((ptr_t)0xc0000000)
+# endif
+# ifdef OS2
+# define OS_TYPE "OS2"
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
+ & ~0x3fffff) \
+ +((word)&etext & 0xfff))
+ /* STACKBOTTOM is handled specially in GC_init_inner. */
+ /* OS2 actually has the right system call! */
+# endif
+# endif
+
+# ifdef NS32K
+# define MACH_TYPE "NS32K"
+# define ALIGNMENT 4
+ extern char **environ;
+# define DATASTART ((ptr_t)(&environ))
+ /* hideous kludge: environ is the first */
+ /* word in crt0.o, and delimits the start */
+ /* of the data segment, no matter which */
+ /* ld options were passed through. */
+# define STACKBOTTOM ((ptr_t) 0xfffff000) /* for Encore */
+# endif
+
+# ifdef MIPS
+# define MACH_TYPE "MIPS"
+# define ALIGNMENT 4 /* Required by hardware */
+# define DATASTART 0x10000000
+ /* Could probably be slightly higher since */
+ /* startup code allocates lots of junk */
+# define HEURISTIC2
+# endif
+
+# ifdef RS6000
+# define MACH_TYPE "RS6000"
+# define ALIGNMENT 4
+# define DATASTART ((ptr_t)0x20000000)
+# define STACKBOTTOM ((ptr_t)0x2ff80000)
+# endif
+
+# ifdef HP_PA
+# define MACH_TYPE "HP_PA"
+# define ALIGNMENT 4
+ extern int __data_start;
+# define DATASTART ((ptr_t)(&__data_start))
+# define HEURISTIC2
+# define STACK_GROWS_UP
+# endif
+
+# ifndef STACK_GROWS_UP
+# define STACK_GROWS_DOWN
+# endif
+
+# ifndef CPP_WORDSZ
+# define CPP_WORDSZ 32
+# endif
+
+# ifndef OS_TYPE
+# define OS_TYPE ""
+# endif
+
+# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
+ -> bad word size
+# endif
+
+# ifdef PCR
+# undef STACKBOTTOM
+# undef HEURISTIC1
+# undef HEURISTIC2
+# endif
+
+# endif
diff --git a/debug_malloc.c b/debug_malloc.c
index f8b27d22..6bb61980 100644
--- a/debug_malloc.c
+++ b/debug_malloc.c
@@ -94,25 +94,25 @@ ptr_t p;
{
register oh * ohdr = (oh *)GC_base(p);
- GC_err_printf("0x%lx (", (unsigned long)ohdr + sizeof(oh));
+ GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh));
GC_err_puts(ohdr -> oh_string);
- GC_err_printf(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
- (unsigned long)(ohdr -> oh_sz));
+ GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
+ (unsigned long)(ohdr -> oh_sz));
}
void GC_print_smashed_obj(p, clobbered_addr)
ptr_t p, clobbered_addr;
{
register oh * ohdr = (oh *)GC_base(p);
- GC_err_printf("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
- (unsigned long)p);
+ GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
+ (unsigned long)p);
if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))) {
- GC_err_printf("<smashed>, appr. sz = %ld)\n",
- BYTES_TO_WORDS(GC_size((ptr_t)ohdr)));
+ GC_err_printf1("<smashed>, appr. sz = %ld)\n",
+ BYTES_TO_WORDS(GC_size((ptr_t)ohdr)));
} else {
GC_err_puts(ohdr -> oh_string);
- GC_err_printf(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
- (unsigned long)(ohdr -> oh_sz));
+ GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
+ (unsigned long)(ohdr -> oh_sz));
}
}
@@ -128,10 +128,10 @@ ptr_t p, clobbered_addr;
extern_ptr_t result = GC_malloc(lb + DEBUG_BYTES);
if (result == 0) {
- GC_err_printf("GC_debug_malloc(%ld) returning NIL (",
- (unsigned long) lb);
+ GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
+ (unsigned long) lb);
GC_err_puts(s);
- GC_err_printf(":%ld)\n", (unsigned long)i);
+ GC_err_printf1(":%ld)\n", (unsigned long)i);
return(0);
}
if (!GC_debugging_started) {
@@ -153,10 +153,10 @@ ptr_t p, clobbered_addr;
extern_ptr_t result = GC_malloc_atomic(lb + DEBUG_BYTES);
if (result == 0) {
- GC_err_printf("GC_debug_malloc_atomic(%ld) returning NIL (",
+ GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
(unsigned long) lb);
GC_err_puts(s);
- GC_err_printf(":%ld)\n", (unsigned long)i);
+ GC_err_printf1(":%ld)\n", (unsigned long)i);
return(0);
}
if (!GC_debugging_started) {
@@ -176,17 +176,18 @@ ptr_t p, clobbered_addr;
register ptr_t clobbered;
if (base == 0) {
- GC_err_printf("Attempt to free invalid pointer %lx\n",
- (unsigned long)p);
+ GC_err_printf1("Attempt to free invalid pointer %lx\n",
+ (unsigned long)p);
ABORT("free(invalid pointer)");
}
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
- GC_err_printf("GC_debug_free called on pointer %lx wo debugging info\n",
+ GC_err_printf1(
+ "GC_debug_free called on pointer %lx wo debugging info\n",
(unsigned long)p);
} else {
clobbered = GC_check_annotated_obj((oh *)base);
if (clobbered != 0) {
- GC_err_printf("GC_debug_free: found smashed object at ");
+ GC_err_printf0("GC_debug_free: found smashed object at ");
GC_print_smashed_obj(p, clobbered);
}
}
@@ -210,19 +211,19 @@ ptr_t p, clobbered_addr;
register size_t old_sz;
if (base == 0) {
- GC_err_printf(
+ GC_err_printf1(
"Attempt to free invalid pointer %lx\n", (unsigned long)p);
ABORT("realloc(invalid pointer)");
}
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
- GC_err_printf(
+ GC_err_printf1(
"GC_debug_realloc called on pointer %lx wo debugging info\n",
(unsigned long)p);
return(GC_realloc(p, lb));
}
clobbered = GC_check_annotated_obj((oh *)base);
if (clobbered != 0) {
- GC_err_printf("GC_debug_realloc: found smashed object at ");
+ GC_err_printf0("GC_debug_realloc: found smashed object at ");
GC_print_smashed_obj(p, clobbered);
}
old_sz = ((oh *)base) -> oh_sz;
@@ -255,7 +256,7 @@ word dummy;
ptr_t clobbered = GC_check_annotated_obj((oh *)p);
if (clobbered != 0) {
- GC_err_printf(
+ GC_err_printf0(
"GC_check_heap_block: found smashed object at ");
GC_print_smashed_obj((ptr_t)p, clobbered);
}
@@ -305,4 +306,5 @@ struct closure {
register struct closure * cl = (struct closure *) data;
(*(cl -> cl_fn))((extern_ptr_t)((char *)obj + sizeof(oh)), cl -> cl_data);
-} \ No newline at end of file
+}
+
diff --git a/dynamic_load.c b/dynamic_load.c
index 80eda3a9..c5e111e1 100644
--- a/dynamic_load.c
+++ b/dynamic_load.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1991,1992 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1991-1993 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -9,84 +9,134 @@
* Author: Bill Janssen
* Modified by: Hans Boehm
*/
+
+/*
+ * This is incredibly OS specific code for tracking down data sections in
+ * dynamic libraries. There appears to be no way of doing this quickly
+ * without groveling through undocumented data structures. We would argue
+ * that this is a bug in the design of the dlopen interface. THIS CODE
+ * MAY BREAK IN FUTURE OS RELEASES. If this matters to you, don't hesitate
+ * to let your vendor know ...
+ */
#include "gc_private.h"
#ifdef DYNAMIC_LOADING
-#if !defined(M68K_SUN) && !defined(SPARC)
+#if !(defined(M68K) && defined(SUNOS)) && !defined(SPARC)
--> We only know how to find data segments of dynamic libraries under SunOS 4.X
#endif
-#include <sys/types.h>
+
#include <stdio.h>
-#include <dlfcn.h>
-#include <link.h>
-#include <a.out.h>
-#include <stab.h>
+#if defined SUNOS5
+# include <sys/elf.h>
+# include <dlfcn.h>
+# include <link.h>
+#else
+# include <dlfcn.h>
+# include <link.h>
+# include <a.out.h>
+ /* struct link_map field overrides */
+# define l_next lm_next
+# define l_addr lm_addr
+# define l_name lm_name
+# endif
+
-extern struct link_dynamic _DYNAMIC;
+#ifdef SUNOS5
-void GC_setup_dynamic_loading()
+static struct link_map *
+GC_FirstDLOpenedLinkMap()
{
- struct link_map *lm;
- struct exec *e;
-
- if (&_DYNAMIC == 0) {
- /* No dynamic libraries. Furthermore, the rest of this would */
- /* segment fault. */
- return;
- }
- for (lm = _DYNAMIC.ld_un.ld_1->ld_loaded;
- lm != (struct link_map *) 0; lm = lm->lm_next)
- {
- e = (struct exec *) lm->lm_addr;
- GC_add_roots_inner(
- ((char *) (N_DATOFF(*e) + lm->lm_addr)),
- ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)));
+ extern Elf32_Dyn _DYNAMIC;
+ Elf32_Dyn *dp;
+ struct r_debug *r;
+ static struct link_map * cachedResult = 0;
+
+ if( &_DYNAMIC == 0) {
+ return(0);
+ }
+ if( cachedResult == 0 ) {
+ int tag;
+ for( dp = ((Elf32_Dyn *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
+ if( tag == DT_DEBUG ) {
+ struct link_map *lm
+ = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
+ if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
+ break;
+ }
+ }
}
+ return cachedResult;
}
-#ifdef DEFINE_DLOPEN
-char *GC_dlopen (path, mode)
- char *path;
- int mode;
+# endif
+
+# ifdef SUNOS4
+
+static struct link_map *
+GC_FirstDLOpenedLinkMap()
{
- char *etext, *end;
- struct link_map *lm;
- struct exec *e;
- char *handle;
+ extern struct link_dynamic _DYNAMIC;
- handle = dlopen(path, mode);
- if (handle == NULL)
- {
- fprintf (stderr,
- "GC_sun_dlopen: dlopen(%s, %d) failed: %s.\n",
- path, mode, dlerror());
- return (NULL);
+ if( &_DYNAMIC == 0) {
+ return(0);
}
+ return(_DYNAMIC.ld_un.ld_1->ld_loaded);
+}
- for (lm = _DYNAMIC.ld_un.ld_1->ld_loaded;
- lm != (struct link_map *) 0; lm = lm->lm_next)
- {
- if (strcmp(path, lm->lm_name) == 0)
- {
- e = (struct exec *) lm->lm_addr;
- etext = (void *) (N_DATOFF(*e) + lm->lm_addr);
- end = (void *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr);
- GC_add_roots (etext, end);
- break;
- }
- }
- if (lm == (struct link_map *) 0)
+# endif
+
+/* Add dynamic library data sections to the root set. */
+# if !defined(PCR) && defined(THREADS)
+ --> fix mutual exclusion with dlopen
+# endif
+void GC_register_dynamic_libraries()
+{
+ struct link_map *lm = GC_FirstDLOpenedLinkMap();
+
+
+ for (lm = GC_FirstDLOpenedLinkMap();
+ lm != (struct link_map *) 0; lm = lm->l_next)
{
- fprintf (stderr,
- "GC_sun_dlopen: couldn't find \"%s\" in _DYNAMIC link list.\n",
- path);
- dlclose(handle);
- return (NULL);
+# ifdef SUNOS4
+ struct exec *e;
+
+ e = (struct exec *) lm->lm_addr;
+ GC_add_roots_inner(
+ ((char *) (N_DATOFF(*e) + lm->lm_addr)),
+ ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)));
+# endif
+# ifdef SUNOS5
+ Elf32_Ehdr * e;
+ Elf32_Phdr * p;
+ unsigned long offset;
+ char * start;
+ register int i;
+
+ e = (Elf32_Ehdr *) lm->l_addr;
+ p = ((Elf32_Phdr *)(((char *)(e)) + e->e_phoff));
+ offset = ((unsigned long)(lm->l_addr));
+ for( i = 0; i < e->e_phnum; ((i++),(p++)) ) {
+ switch( p->p_type ) {
+ case PT_LOAD:
+ {
+ if( !(p->p_flags & PF_W) ) break;
+ start = ((char *)(p->p_vaddr)) + offset;
+ GC_add_roots_inner(
+ start,
+ start + p->p_memsz
+ );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+# endif
}
- else
- return (handle);
}
-#endif
+
#else
+void GC_register_dynamic_libraries(){}
+
int GC_no_dynamic_loading;
#endif
diff --git a/gc.h b/gc.h
index e090522d..7814f46c 100644
--- a/gc.h
+++ b/gc.h
@@ -44,7 +44,7 @@ extern int GC_dont_expand;
extern word GC_non_gc_bytes;
/* Bytes not considered candidates for collection. */
-
+ /* Used only to control scheduling of collections. */
extern word GC_free_space_divisor;
/* We try to make sure that we allocate at */
diff --git a/gc_private.h b/gc_private.h
index 2ef44503..1e09370f 100644
--- a/gc_private.h
+++ b/gc_private.h
@@ -10,7 +10,6 @@
* provided the above notices are retained on all copies.
*/
-/* Machine specific parts contributed by various people. See README file. */
# ifndef GC_PRIVATE_H
# define GC_PRIVATE_H
@@ -19,6 +18,10 @@
# include "gc.h"
# endif
+# ifndef CONFIG_H
+# include "config.h"
+# endif
+
# ifndef HEADERS_H
# include "gc_headers.h"
# endif
@@ -41,6 +44,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
typedef char * extern_ptr_t;
#endif
+# ifndef OS2
+# include <sys/types.h>
+# endif
+
/*********************************/
/* */
/* Definitions for conservative */
@@ -54,113 +61,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* */
/*********************************/
-# if defined(sun) && defined(mc68000)
-# define M68K_SUN
-# define mach_type_known
-# endif
-# if defined(hp9000s300)
-# define M68K_HP
-# define mach_type_known
-# endif
-# if defined(vax)
-# define VAX
-# ifdef ultrix
-# define ULTRIX
-# else
-# define BSD
-# endif
-# define mach_type_known
-# endif
-# if defined(mips)
-# define MIPS
-# ifdef ultrix
-# define ULTRIX
-# else
-# define RISCOS
-# endif
-# define mach_type_known
-# endif
-# if defined(sequent) && defined(i386)
-# define I386
-# define SEQUENT
-# define mach_type_known
-# endif
-# if defined(__OS2__) && defined(__32BIT__)
-# define I386
-# define OS2
-# define mach_type_known
-# endif
-# if defined(ibm032)
-# define RT
-# define mach_type_known
-# endif
-# if defined(sun) && defined(sparc)
-# define SPARC
-# define mach_type_known
-# endif
-# if defined(_IBMR2)
-# define IBMRS6000
-# define mach_type_known
-# endif
-# if defined(SCO)
-# define I386
-# define SCO
-# define mach_type_known
-/* --> incompletely implemented */
-# endif
-# if defined(_AUX_SOURCE)
-# define M68K_SYSV
-# define mach_type_known
-# endif
-# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1)
-# define HP_PA
-# define mach_type_known
-# endif
-# if defined(linux) && defined(i386)
-# define I386
-# define LINUX
-# define mach_type_known
-# endif
-
-# ifndef OS2
-# include <sys/types.h>
-# endif
-
-/* Feel free to add more clauses here */
-
-/* Or manually define the machine type here. A machine type is */
-/* characterized by the architecture and assembler syntax. Some */
-/* machine types are further subdivided by OS. In that case, we use */
-/* the macros ULTRIX, RISCOS, and BSD to distinguish. */
-/* Note that SGI IRIX is treated identically to RISCOS. */
-/* The distinction in these cases is usually the stack starting address */
-# ifndef mach_type_known
-# define M68K_SUN /* Guess "Sun" */
- /* Mapping is: M68K_SUN ==> Sun3 assembler */
- /* M68K_HP ==> HP9000/300 */
- /* M68K_SYSV ==> A/UX, maybe others */
- /* I386 ==> Intel 386 */
- /* (SEQUENT, OS2, SCO, LINUX variants) */
- /* SCO is incomplete. */
- /* NS32K ==> Encore Multimax */
- /* MIPS ==> R2000 or R3000 */
- /* (RISCOS, ULTRIX variants) */
- /* VAX ==> DEC VAX */
- /* (BSD, ULTRIX variants) */
- /* RS6000 ==> IBM RS/6000 AIX3.1 */
- /* RT ==> IBM PC/RT */
- /* HP_PA ==> HP9000/700 & /800 */
- /* HP/UX */
- /* SPARC ==> SPARC under SunOS */
-# endif
-
-# ifdef SPARC
- /* Test for SunOS 5.x */
-# include <errno.h>
-# ifdef ECHRNG
-# define SUNOS5
-# endif
-# endif
#define ALL_INTERIOR_POINTERS
/* Forces all pointers into the interior of an */
@@ -231,9 +131,11 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* apparently required by SPARC architecture. */
#endif
-#if defined(SPARC) || defined(M68K_SUN)
-# if !defined(PCR) && !defined(SUNOS5)
+#if defined(SPARC) || defined(M68K) && defined(SUNOS)
+# if !defined(PCR)
# define DYNAMIC_LOADING /* Search dynamic libraries for roots. */
+# else
+ /* PCR handles any dynamic loading whether with dlopen or otherwise */
# endif
#endif
@@ -253,261 +155,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# define MERGE_SIZES
# endif
-#if defined(M68K_SUN) || defined(M68K_SYSV)
-# define ALIGNMENT 2 /* Pointers are aligned on 2 byte boundaries */
- /* by the Sun C compiler. */
-#else
-# ifdef VAX
-# define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */
-# else
-# ifdef RT
-# define ALIGNMENT 4
-# else
-# ifdef SPARC
-# define ALIGNMENT 4
-# else
-# ifdef I386
-# define ALIGNMENT 4 /* 32-bit compilers align pointers */
-# else
-# ifdef NS32K
-# define ALIGNMENT 4 /* Pointers are aligned on NS32K */
-# else
-# ifdef MIPS
-# define ALIGNMENT 4 /* MIPS hardware requires pointer */
- /* alignment */
-# else
-# ifdef M68K_HP
-# define ALIGNMENT 2 /* 2 byte alignment inside struct/union, */
- /* 4 bytes elsewhere */
-# else
-# ifdef IBMRS6000
-# define ALIGNMENT 4
-# else
-# ifdef HP_PA
-# define ALIGNMENT 4
-# else
- --> specify alignment <--
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-
-/*
- * STACKBOTTOM is the cool end of the stack, which is usually the
- * highest address in the stack.
- * Under PCR or OS/2, we have other ways of finding thread stacks.
- * For each machine, the following should:
- * 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
- * 2) define exactly one of
- * STACKBOTTOM (should be defined to be an expression)
- * HEURISTIC1
- * HEURISTIC2
- * If either of the last two macros are defined, then STACKBOTTOM is computed
- * during collector startup using one of the following two heuristics:
- * HEURISTIC1: Take an address inside GC_init's frame, and round it up to
- * the next multiple of 16 MB.
- * HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly
- * in small steps (decrement if STACK_GROWS_UP), and read the value
- * at each location. Remember the value when the first
- * Segmentation violation or Bus error is signalled. Round that
- * to the nearest plausible page boundary, and use that instead
- * of STACKBOTTOM.
- *
- * If no expression for STACKBOTTOM can be found, and neither of the above
- * heuristics are usable, the collector can still be used with all of the above
- * undefined, provided one of the following is done:
- * 1) GC_mark_roots can be changed to somehow mark from the correct stack(s)
- * without reference to STACKBOTTOM. This is appropriate for use in
- * conjunction with thread packages, since there will be multiple stacks.
- * (Allocating thread stacks in the heap, and treating them as ordinary
- * heap data objects is also possible as a last resort. However, this is
- * likely to introduce significant amounts of excess storage retention
- * unless the dead parts of the thread stacks are periodically cleared.)
- * 2) Client code may set GC_stackbottom before calling any GC_ routines.
- * If the author of the client code controls the main program, this is
- * easily accomplished by introducing a new main program, setting
- * GC_stackbottom to the address of a local variable, and then calling
- * the original main program. The new main program would read something
- * like:
- *
- * # include "gc_private.h"
- *
- * main(argc, argv, envp)
- * int argc;
- * char **argv, **envp;
- * {
- * int dummy;
- *
- * GC_stackbottom = (ptr_t)(&dummy);
- * return(real_main(argc, argv, envp));
- * }
- */
-#ifndef PCR
-# ifdef RT
-# define STACKBOTTOM ((ptr_t) 0x1fffd800)
-# else
-# ifdef I386
-# ifdef SEQUENT
-# define STACKBOTTOM ((ptr_t) 0x3ffff000) /* For Sequent */
-# else
-# ifdef SCO
-# define STACKBOTTOM ((ptr_t) 0x7ffffffc)
-# else
-# ifdef LINUX
-# define STACKBOTTOM ((ptr_t)0xc0000000)
-# else
-# ifdef OS2
- /* This is handled specially in GC_init_inner. */
- /* OS2 actually has the right system call! */
-# else
- --> Your OS isnt supported yet
-# endif
-# endif
-# endif
-# endif
-# else
-# ifdef NS32K
-# define STACKBOTTOM ((ptr_t) 0xfffff000) /* for Encore */
-# else
-# ifdef M68K_SYSV
-# define STACKBOTTOM ((ptr_t)0xFFFFFFFE)
- /* The stack starts at the top of memory, but */
- /* 0x0 cannot be used as setjump_test complains */
- /* that the stack direction is incorrect. Two */
- /* bytes down from 0x0 should be safe enough. */
- /* --Parag */
-# else
-# ifdef M68K_HP
-# define STACKBOTTOM ((ptr_t) 0xffeffffc)
- /* empirically determined. seems to work. */
-# else
-# ifdef IBMRS6000
-# define STACKBOTTOM ((ptr_t) 0x2ff80000)
-# else
-# if defined(VAX) && defined(ULTRIX)
-# ifdef ULTRIX
-# define STACKBOTTOM ((ptr_t) 0x7fffc800)
-# else
-# define HEURISTIC1
- /* HEURISTIC2 may be OK, but it's hard to test. */
-# endif
-# else
- /* Sun systems, HP PA systems, and DEC MIPS systems have */
- /* STACKBOTTOM values that differ between machines that */
- /* are intended to be object code compatible. */
-# if defined(SPARC) || defined(M68K_SUN)
-# define HEURISTIC1
-# else
-# ifdef HP_PA
-# define STACK_GROWS_UP
-# endif
-# define HEURISTIC2
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-#endif /* PCR */
-
-
-# ifndef STACK_GROWS_UP
-# define STACK_GROWS_DOWN
-# endif
-
-/* Start of data segment for each of the above systems. Note that the */
-/* default case works only for contiguous text and data, such as on a */
-/* Vax. */
-# ifdef M68K_SUN
- extern char etext;
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ffff) & ~0x1ffff))
-# else
-# ifdef RT
-# define DATASTART ((ptr_t) 0x10000000)
-# else
-# if (defined(I386) && (defined(SEQUENT)||defined(LINUX))) || defined(SPARC)
- extern int etext;
-# ifdef SUNOS5
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0x10003) & ~0x3))
- /* Experimentally determined. */
- /* Inconsistent with man a.out, which appears */
- /* to be wrong. */
-# else
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
- /* On very old SPARCs this is too conservative. */
-# endif
-# else
-# ifdef NS32K
- extern char **environ;
-# define DATASTART ((ptr_t)(&environ))
- /* hideous kludge: environ is the first */
- /* word in crt0.o, and delimits the start */
- /* of the data segment, no matter which */
- /* ld options were passed through. */
-# else
-# ifdef MIPS
-# define DATASTART 0x10000000
- /* Could probably be slightly higher since */
- /* startup code allocates lots of junk */
-# else
-# ifdef M68K_HP
- extern char etext;
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
-# else
-# ifdef IBMRS6000
-# define DATASTART ((ptr_t)0x20000000)
-# else
-# ifdef I386
-# ifdef SCO
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
- & ~0x3fffff) \
- +((word)&etext & 0xfff))
-# else
-# ifdef OS2
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
- & ~0x3fffff) \
- +((word)&etext & 0xfff))
-# else
- --> Your OS not supported yet
-# endif
-# endif
-# else
-# ifdef M68K_SYSV
- /* This only works for shared-text binaries with magic number 0413.
- The other sorts of SysV binaries put the data at the end of the text,
- in which case the default of &etext would work. Unfortunately,
- handling both would require having the magic-number available.
- -- Parag
- */
- extern etext;
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
- & ~0x3fffff) \
- +((word)&etext & 0x1fff))
-# else
-# ifdef HP_PA
- extern int __data_start;
-# define DATASTART ((ptr_t)(&__data_start))
-# else
- extern char etext;
-# define DATASTART ((ptr_t)(&etext))
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
# define HINCR 16 /* Initial heap increment, in blocks of 4K */
# define MAXHINCR 512 /* Maximum heap increment, in blocks */
@@ -549,7 +196,17 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
(1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC))
/* We use bzero and bcopy internally. They may not be available. */
-# ifdef OS2
+# if defined(SPARC) && defined(SUNOS4)
+# define BCOPY_EXISTS
+# endif
+# if defined(M68K) && defined(SUNOS)
+# define BCOPY_EXISTS
+# endif
+# if defined(VAX)
+# define BCOPY_EXISTS
+# endif
+
+# ifndef BCOPY_EXISTS
# include <string.h>
# define bcopy(x,y,n) memcpy(y,x,n)
# define bzero(x,n) memset(x, 0, n)
@@ -674,7 +331,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# endif
/* Print warning message, e.g. almost out of memory. */
-# define WARN(s) GC_printf(s)
+# define WARN(s) GC_printf0(s)
/*********************************/
/* */
@@ -682,22 +339,25 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* */
/*********************************/
-#define WORDS_TO_BYTES(x) ((x)<<2)
-#define BYTES_TO_WORDS(x) ((x)>>2)
+#if CPP_WORDSZ == 32
+# define WORDS_TO_BYTES(x) ((x)<<2)
+# define BYTES_TO_WORDS(x) ((x)>>2)
+# define LOGWL ((word)5) /* log[2] of CPP_WORDSZ */
+# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */
+#endif
+
+#if CPP_WORDSZ == 64
+# define WORDS_TO_BYTES(x) ((x)<<3)
+# define BYTES_TO_WORDS(x) ((x)>>3)
+# define LOGWL ((word)6) /* log[2] of CPP_WORDSZ */
+# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */
+#endif
-#define CPP_WORDSZ 32
#define WORDSZ ((word)CPP_WORDSZ)
-#define LOGWL ((word)5) /* log[2] of above */
+#define SIGNB ((word)1 << (WORDSZ-1))
#define BYTES_PER_WORD ((word)(sizeof (word)))
-#define ONES 0xffffffff
-#define MSBYTE 0xff000000
-#define SIGNB 0x80000000
-#define MAXSHORT 0x7fff
-#define modHALFWORDSZ(n) ((n) & 0xf) /* mod n by size of half word */
-#define divHALFWORDSZ(n) ((n) >> 4) /* divide n by size of half word */
-#define modWORDSZ(n) ((n) & 0x1f) /* mod n by size of word */
-#define divWORDSZ(n) ((n) >> 5) /* divide n by size of word */
-#define twice(n) ((n) << 1) /* double n */
+#define ONES ((word)(-1))
+#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */
/*********************/
/* */
@@ -841,6 +501,13 @@ struct _GC_arrays {
# endif
word _words_allocd;
/* Number of words allocated during this collection cycle */
+ word _non_gc_bytes_at_gc;
+ /* Number of explicitly managed bytes of storage */
+ /* at last collection. */
+ word _mem_freed;
+ /* Number of explicitly deallocated words of memory */
+ /* since last collection. */
+
ptr_t _objfreelist[MAXOBJSZ+1];
/* free list for objects */
# ifdef MERGE_SIZES
@@ -913,6 +580,8 @@ extern struct _GC_arrays GC_arrays;
# define GC_last_heap_addr GC_arrays._last_heap_addr
# define GC_prev_heap_addr GC_arrays._prev_heap_addr
# define GC_words_allocd GC_arrays._words_allocd
+# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
+# define GC_mem_freed GC_arrays._mem_freed
# define GC_heapsize GC_arrays._heapsize
# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc
# ifdef GATHERSTATS
@@ -1031,7 +700,10 @@ void GC_mark_all_stack(/*b,t*/); /* Mark from everything in a range, */
void GC_remark(); /* Mark from all marked objects. Used */
/* only if we had to drop something. */
void GC_tl_mark(/*p*/); /* Mark from a single root. */
+void GC_clear_hdr_marks(/* hhdr */); /* Clear the mark bits in a header */
void GC_add_roots_inner();
+void GC_register_dynamic_libraries();
+ /* Add dynamic library data sections to the root set. */
/* Machine dependent startup routines */
ptr_t GC_get_stack_base();
@@ -1099,8 +771,16 @@ void GC_continue_reclaim(/*size, kind*/);
/* kind, as long as possible, and */
/* as long as the corr. free list is */
/* empty. */
-void GC_gcollect_inner(); /* Collect; caller must have acquired */
+bool GC_gcollect_inner(/* force */);
+ /* Collect; caller must have acquired */
/* lock and disabled signals. */
+ /* FALSE return indicates nothing was */
+ /* done due to insufficient allocation. */
+void GC_collect_or_expand(/* needed_blocks */);
+ /* Collect or expand heap in an attempt */
+ /* make the indicated number of free */
+ /* blocks available. Should be called */
+ /* until it succeeds or exits. */
void GC_init(); /* Initialize collector. */
ptr_t GC_generic_malloc(/* bytes, kind */);
@@ -1147,16 +827,41 @@ void GC_check_heap();
/* debugging info are intact. Print */
/* descriptions of any that are not. */
-void GC_printf(/* format, ... */);
+void GC_printf(/* format, a, b, c, d, e, f */);
/* A version of printf that doesn't allocate, */
/* is restricted to long arguments, and */
/* (unfortunately) doesn't use varargs for */
/* portability. Restricted to 6 args and */
/* 1K total output length. */
/* (We use sprintf. Hopefully that doesn't */
- /* allocate for long arguments. */
-void GC_err_printf(/* format, ... */);
+ /* allocate for long arguments.) */
+# define GC_printf0(f) GC_printf(f, 0l, 0l, 0l, 0l, 0l, 0l)
+# define GC_printf1(f,a) GC_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
+# define GC_printf2(f,a,b) GC_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
+# define GC_printf3(f,a,b,c) GC_printf(f, (long)a, (long)b, (long)c, 0l, 0l, 0l)
+# define GC_printf4(f,a,b,c,d) GC_printf(f, (long)a, (long)b, (long)c, \
+ (long)d, 0l, 0l)
+# define GC_printf5(f,a,b,c,d,e) GC_printf(f, (long)a, (long)b, (long)c, \
+ (long)d, (long)e, 0l)
+# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \
+ (long)d, (long)e, (long)g)
+
+void GC_err_printf(/* format, a, b, c, d, e, f */);
+# define GC_err_printf0(f) GC_err_puts(f)
+# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
+# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
+# define GC_err_printf3(f,a,b,c) GC_err_printf(f, (long)a, (long)b, (long)c, \
+ 0l, 0l, 0l)
+# define GC_err_printf4(f,a,b,c,d) GC_err_printf(f, (long)a, (long)b, \
+ (long)c, (long)d, 0l, 0l)
+# define GC_err_printf5(f,a,b,c,d,e) GC_err_printf(f, (long)a, (long)b, \
+ (long)c, (long)d, \
+ (long)e, 0l)
+# define GC_err_printf6(f,a,b,c,d,e,g) GC_err_printf(f, (long)a, (long)b, \
+ (long)c, (long)d, \
+ (long)e, (long)g)
/* Ditto, writes to stderr. */
+
void GC_err_puts(/* char *s */);
/* Write s to stderr, don't buffer, don't add */
/* newlines, don't ... */
diff --git a/headers.c b/headers.c
index 3873ee8f..15fda415 100644
--- a/headers.c
+++ b/headers.c
@@ -73,10 +73,10 @@ register word bytes;
scratch_free_ptr = (char *)GET_MEM(bytes_to_get);
if (scratch_free_ptr == 0) {
- GC_printf("Out of memory - trying to allocate less\n");
+ GC_err_printf0("Out of memory - trying to allocate less\n");
result = (char *)GET_MEM(bytes);
if (result == 0) {
- GC_printf("Out of memory - giving up\n");
+ GC_err_printf0("Out of memory - giving up\n");
} else {
scratch_free_ptr -= bytes;
return(result);
diff --git a/if_mach.c b/if_mach.c
new file mode 100644
index 00000000..7359a4f7
--- /dev/null
+++ b/if_mach.c
@@ -0,0 +1,22 @@
+/* Conditionally execute a command based on machine and OS from config.h */
+# include "config.h"
+# include <stdio.h>
+
+int main(argc, argv, envp)
+int argc;
+char ** argv;
+char ** envp;
+{
+ if (argc < 4) goto Usage;
+ if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
+ if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
+ && strcmp(OS_TYPE, argv[2]) != 0) return(0);
+ execvp(argv[3], argv+3);
+
+Usage:
+ fprintf(stderr, "Usage: %s mach_type os_type command\n", argv[0]);
+ fprintf(stderr, "Currently mach_type = %s, os_type = %s\n",
+ MACH_TYPE, OS_TYPE);
+ return(1);
+}
+
diff --git a/if_not_there.c b/if_not_there.c
new file mode 100644
index 00000000..806eed62
--- /dev/null
+++ b/if_not_there.c
@@ -0,0 +1,24 @@
+/* Conditionally execute a command based if the file argv[1] doesn't exist */
+/* Except for execvp, we stick to ANSI C. */
+# include "config.h"
+# include <stdio.h>
+
+int main(argc, argv, envp)
+int argc;
+char ** argv;
+char ** envp;
+{
+ FILE * f;
+ if (argc < 3) goto Usage;
+ if ((f = fopen(argv[1], "rb")) != 0
+ || (f = fopen(argv[1], "r")) != 0) {
+ fclose(f);
+ return(0);
+ }
+ execvp(argv[2], argv+2);
+
+Usage:
+ fprintf(stderr, "Usage: %s file_name command\n", argv[0]);
+ return(1);
+}
+
diff --git a/mach_dep.c b/mach_dep.c
index 670579d8..8e3ac078 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -27,8 +27,8 @@ GC_mark_regs()
asm("pushl r7"); asm("calls $1,_GC_tl_mark");
asm("pushl r6"); asm("calls $1,_GC_tl_mark");
# endif
-# ifdef M68K_SUN
- /* M68K_SUN - could be replaced by generic code */
+# if defined(M68K) && defined(SUNOS)
+ /* M68K SUNOS - could be replaced by generic code */
/* a0, a1 and d1 are caller save */
/* and therefore are on stack or dead. */
@@ -50,8 +50,8 @@ GC_mark_regs()
asm("addqw #0x4,sp"); /* put stack back where it was */
# endif
-# ifdef M68K_HP
- /* M68K_HP - could be replaced by generic code */
+# if defined(M68K) && defined(HP)
+ /* M68K HP - could be replaced by generic code */
/* a0, a1 and d1 are caller save. */
asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
@@ -70,9 +70,9 @@ GC_mark_regs()
asm("mov.l %d7,(%sp)"); asm("jsr _GC_tl_mark");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
-# endif /* M68K_HP */
+# endif /* M68K HP */
-# if defined(I386) && !defined(OS2)
+# if defined(I386) && !defined(OS2) && !defined(SUNOS5)
/* I386 code, generic code does not appear to work */
/* It does appear to work under OS2, and asms dont */
asm("pushl %eax"); asm("call _GC_tl_mark"); asm("addl $4,%esp");
@@ -83,6 +83,17 @@ GC_mark_regs()
asm("pushl %ebx"); asm("call _GC_tl_mark"); asm("addl $4,%esp");
# endif
+# if defined(I386) && defined(SUNOS5)
+ /* I386 code, generic code does not appear to work */
+ /* It does appear to work under OS2, and asms dont */
+ asm("pushl %eax"); asm("call GC_tl_mark"); asm("addl $4,%esp");
+ asm("pushl %ecx"); asm("call GC_tl_mark"); asm("addl $4,%esp");
+ asm("pushl %edx"); asm("call GC_tl_mark"); asm("addl $4,%esp");
+ asm("pushl %esi"); asm("call GC_tl_mark"); asm("addl $4,%esp");
+ asm("pushl %edi"); asm("call GC_tl_mark"); asm("addl $4,%esp");
+ asm("pushl %ebx"); asm("call GC_tl_mark"); asm("addl $4,%esp");
+# endif
+
# ifdef NS32K
asm ("movd r3, tos"); asm ("bsr ?_GC_tl_mark"); asm ("adjspb $-4");
asm ("movd r4, tos"); asm ("bsr ?_GC_tl_mark"); asm ("adjspb $-4");
@@ -111,7 +122,7 @@ GC_mark_regs()
asm("cas r11, r15, r0"); GC_tl_mark(TMP_SP);
# endif
-# ifdef M68K_SYSV
+# if defined(M68K) && defined(SYSV)
/* Once again similar to SUN and HP, though setjmp appears to work.
--Parag
*/
@@ -150,7 +161,7 @@ GC_mark_regs()
asm("addq.w &0x4,%sp"); /* put stack back where it was */
# endif /* !__GNUC__ */
-# endif /* M68K_SYSV */
+# endif /* M68K/SYSV */
# if defined(HP_PA) || (defined(I386) && defined(OS2))
@@ -174,9 +185,13 @@ GC_mark_regs()
# endif
/* other machines... */
-# if !(defined M68K_SUN) && !defined(M68K_HP) && !(defined VAX) && !(defined RT) && !(defined SPARC) && !(defined I386) &&!(defined NS32K) &&!defined(HP_PA) && !defined(M68K_SYSV)
+# if !(defined M68K) && !(defined VAX) && !(defined RT)
+# if !(defined SPARC) && !(defined I386) &&!(defined NS32K)
+# if !defined(HP_PA)
--> bad news <--
# endif
+# endif
+# endif
}
/* On register window machines, we need a way to force registers into */
diff --git a/mark.c b/mark.c
index aab8aa44..96935fb4 100644
--- a/mark.c
+++ b/mark.c
@@ -31,8 +31,7 @@
/*
* Limits of stack for GC_mark routine. Set by caller to GC_mark.
* All items between GC_mark_stack_top and GC_mark_stack_bottom-1 still need
- * to be marked. All items on the stack satisfy quicktest. They do
- * not necessarily reference real objects.
+ * to be marked.
*/
mse * GC_mark_stack;
@@ -88,9 +87,7 @@ register mse * msp, * msl;
/*
* Mark all objects pointed to by the regions described by
* mark stack entries between GC_mark_stack and GC_mark_stack_top,
- * inclusive. We assume and preserve the invariant
- * that everything on the mark stack points into a hblk that has an
- * allocated header. Assumes the upper limit of a mark stack entry
+ * inclusive. Assumes the upper limit of a mark stack entry
* is never 0.
*/
void GC_mark()
@@ -206,8 +203,8 @@ word n;
}
} else {
if (new_stack == 0) {
- GC_printf("No space for mark stack\n");
- exit(1);
+ GC_err_printf0("No space for mark stack\n");
+ EXIT();
}
GC_mark_stack = new_stack;
GC_mark_stack_size = n;
@@ -229,8 +226,8 @@ void GC_mark_reliable()
while (dropped_some) {
dropped_some = FALSE;
# ifdef PRINTSTATS
- GC_printf("Mark stack overflow; current size = %lu entries\n",
- GC_mark_stack_size);
+ GC_printf1("Mark stack overflow; current size = %lu entries\n",
+ GC_mark_stack_size);
# endif
alloc_mark_stack(2*GC_mark_stack_size);
GC_remark();
@@ -332,7 +329,7 @@ word dummy;
register word * lim;
register mse * GC_mark_stack_top_reg = GC_mark_stack_top;
- if (sz < 0) return;
+ if (hhdr -> hb_obj_kind == PTRFREE) return;
if (sz > MAXOBJSZ) {
lim = (word *)(h + 1);
} else {
@@ -348,6 +345,7 @@ word dummy;
GC_mark_stack_top_reg -> mse_end = p + sz;
}
}
+ GC_mark_stack_top = GC_mark_stack_top_reg;
GC_mark();
}
diff --git a/mark_roots.c b/mark_roots.c
index 5cc55649..132d59e3 100644
--- a/mark_roots.c
+++ b/mark_roots.c
@@ -1,20 +1,77 @@
# include <stdio.h>
# include "gc_private.h"
-# define MAX_ROOT_SETS 50
+
# ifdef PCR
+# define MAX_ROOT_SETS 1024
# include "pcr/il/PCR_IL.h"
# include "pcr/th/PCR_ThCtl.h"
# include "pcr/mm/PCR_MM.h"
+# else
+# define MAX_ROOT_SETS 64
# endif
+/* Data structure for list of root sets. */
+/* We keep a hash table, so that we can filter out duplicate additions. */
struct roots {
ptr_t r_start;
ptr_t r_end;
+ struct roots * r_next;
};
static struct roots static_roots[MAX_ROOT_SETS];
+
static n_root_sets = 0;
+ /* static_roots[0..n_root_sets) contains the valid root sets. */
+
+#define RT_SIZE 64 /* Power of 2, may be != MAX_ROOT_SETS */
+#define LOG_RT_SIZE 6
+
+static struct roots * root_index[RT_SIZE];
+ /* Hash table header. Used only to check whether a range is */
+ /* already present. */
+
+static int rt_hash(addr)
+char * addr;
+{
+ word result = (word) addr;
+# if CPP_WORDSZ > 8*LOG_RT_SIZE
+ result ^= result >> 8*LOG_RT_SIZE;
+# endif
+# if CPP_WORDSZ > 4*LOG_RT_SIZE
+ result ^= result >> 4*LOG_RT_SIZE;
+# endif
+ result ^= result >> 2*LOG_RT_SIZE;
+ result ^= result >> LOG_RT_SIZE;
+ result &= (RT_SIZE-1);
+ return(result);
+}
+
+/* Is a range starting at addr already in the table? */
+static bool roots_present(b, e)
+char *b, *e;
+{
+ register int h = rt_hash(b);
+ register struct roots *p = root_index[h];
+
+ while (p != 0) {
+ if (p -> r_start == (ptr_t)b && p -> r_end >= (ptr_t)e) return(TRUE);
+ p = p -> r_next;
+ }
+ return(FALSE);
+}
+
+/* Add the given root structure to the index. */
+static void add_roots_to_index(p)
+struct roots *p;
+{
+ register int h = rt_hash(p -> r_start);
+
+ p -> r_next = root_index[h];
+ root_index[h] = p;
+}
+
+
word GC_root_size = 0;
void GC_add_roots(b, e)
@@ -30,7 +87,10 @@ char * b; char * e;
}
-
+/* Add [b,e) to the root set. Adding the same interval a second time */
+/* is a moderately fast noop, and hence benign. We do not handle */
+/* different but overlapping intervals efficiently. (We do handle */
+/* them correctly.) */
void GC_add_roots_inner(b, e)
char * b; char * e;
{
@@ -47,11 +107,14 @@ char * b; char * e;
} else if ((ptr_t)b < endGC_arrays && (ptr_t)e > endGC_arrays) {
b = (char *)endGC_arrays;
}
+ if (roots_present(b,e)) return;
if (n_root_sets == MAX_ROOT_SETS) {
ABORT("Too many root sets\n");
}
static_roots[n_root_sets].r_start = (ptr_t)b;
static_roots[n_root_sets].r_end = (ptr_t)e;
+ static_roots[n_root_sets].r_next = 0;
+ add_roots_to_index(static_roots + n_root_sets);
GC_root_size += (ptr_t)e - (ptr_t)b;
n_root_sets++;
}
@@ -125,36 +188,19 @@ GC_mark_roots()
/* Add new static data areas of dynamically loaded modules. */
{
- PCR_IL_LoadedFile * p = PCR_IL_GetLoadedFiles();
- static PCR_IL_LoadedFile * last_already_added = NIL;
- /* Last file that was already added to the list of roots. */
- PCR_IL_LoadedFile * last_committed;
+ PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
PCR_IL_LoadedSegment * q;
- if (p != NIL && last_already_added == NIL) {
- /* Switch to obtaining roots from the dynamic loader. */
- /* Make sure the loader is properly initialized and that */
- /* it has a correct description of PCR static data. */
- PCR_IL_Lock(PCR_Bool_false,
- PCR_allSigsBlocked, PCR_waitForever);
- PCR_IL_Unlock();
- /* Discard old root sets. */
- n_root_sets = 0;
- GC_root_size = 0;
- /* We claim there are no dynamic libraries, or they */
- /* don't contain roots, since they allocate using the */
- /* system malloc, and they can't retain our pointers. */
- }
/* Skip uncommited files */
while (p != NIL && !(p -> lf_commitPoint)) {
/* The loading of this file has not yet been committed */
/* Hence its description could be inconsistent. */
- /* Furthermore, it hasn't yet been run. Hence it's data */
- /* segments can possibly reference heap allocated objects.*/
+ /* Furthermore, it hasn't yet been run. Hence its data */
+ /* segments can't possibly reference heap allocated */
+ /* objects. */
p = p -> lf_prev;
}
- last_committed = p;
- for (; p != last_already_added; p = p -> lf_prev) {
+ for (; p != NIL; p = p -> lf_prev) {
for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
== PCR_IL_SegFlags_Traced_on) {
@@ -164,7 +210,6 @@ GC_mark_roots()
}
}
}
- last_already_added = last_committed;
}
@@ -181,12 +226,15 @@ GC_mark_roots()
# else
GC_mark_all_stack( GC_stackbottom, GC_approx_sp() );
# endif
+
# endif
+ /* Reregister dynamic libraries, in case one got added. */
+ GC_register_dynamic_libraries();
/* Mark everything in static data areas */
- for (i = 0; i < n_root_sets; i++) {
+ for (i = 0; i < n_root_sets; i++) {
GC_mark_all(static_roots[i].r_start, static_roots[i].r_end);
- }
+ }
}
/*
diff --git a/misc.c b/misc.c
index a19e0dca..3179ef44 100644
--- a/misc.c
+++ b/misc.c
@@ -34,8 +34,10 @@ struct _GC_arrays GC_arrays = { 0 };
/* This must be done statically since they may be accessed before */
/* GC_init is called. */
struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
-/* PTRFREE */ { GC_aobjfreelist, GC_areclaim_list, GC_no_mark_proc, FALSE },
-/* NORMAL */ { GC_objfreelist, GC_reclaim_list, GC_normal_mark_proc, TRUE },
+/* PTRFREE */ { &GC_aobjfreelist[0], &GC_areclaim_list[0],
+ GC_no_mark_proc, FALSE },
+/* NORMAL */ { &GC_objfreelist[0], &GC_reclaim_list[0],
+ GC_normal_mark_proc, TRUE },
};
ptr_t GC_stackbottom = 0;
@@ -235,10 +237,9 @@ DCL_LOCK_STATE;
if (!GC_is_initialized) GC_init_inner();
lw = ROUNDED_UP_WORDS(lb);
- if (!GC_sufficient_hb(lw, k) && !GC_dont_gc) {
- GC_gcollect_inner(FALSE);
+ while ((h = GC_allochblk(lw, k)) == 0) {
+ GC_collect_or_expand(divHBLKSZ(lb) + 1);
}
- h = GC_allochblk(lw, k);
if (h == 0) {
op = 0;
} else {
@@ -505,6 +506,7 @@ int obj_kind;
h = HBLKPTR(p);
hhdr = HDR(h);
sz = hhdr -> hb_sz;
+ GC_mem_freed += sz;
ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
if (sz > MAXOBJSZ) {
@@ -546,56 +548,59 @@ void GC_init_inner()
}
# endif
if (sizeof (ptr_t) != sizeof(word)) {
- GC_printf("sizeof (ptr_t) != sizeof(word)\n");
+ GC_err_printf0("sizeof (ptr_t) != sizeof(word)\n");
ABORT("sizeof (ptr_t) != sizeof(word)\n");
}
if (sizeof (signed_word) != sizeof(word)) {
- GC_printf("sizeof (signed_word) != sizeof(word)\n");
+ GC_err_printf0("sizeof (signed_word) != sizeof(word)\n");
ABORT("sizeof (signed_word) != sizeof(word)\n");
}
if (sizeof (struct hblk) != HBLKSIZE) {
- GC_printf("sizeof (struct hblk) != HBLKSIZE\n");
+ GC_err_printf0("sizeof (struct hblk) != HBLKSIZE\n");
ABORT("sizeof (struct hblk) != HBLKSIZE\n");
}
# ifndef THREADS
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
- GC_printf(
+ GC_err_printf0(
"Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
ABORT("stack direction 1\n");
# endif
# if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
- GC_printf(
+ GC_err_printf0(
"One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
ABORT("stack direction 2\n");
# endif
# ifdef STACK_GROWS_DOWN
if ((word)(&dummy) > (word)GC_stackbottom) {
- GC_printf("STACK_GROWS_DOWN is defd, but stack appears to grow up\n");
- GC_printf("sp = 0x%lx, GC_stackbottom = 0x%lx\n",
- (unsigned long) (&dummy),
- (unsigned long) GC_stackbottom);
+ GC_err_printf0(
+ "STACK_GROWS_DOWN is defd, but stack appears to grow up\n");
+ GC_err_printf2("sp = 0x%lx, GC_stackbottom = 0x%lx\n",
+ (unsigned long) (&dummy),
+ (unsigned long) GC_stackbottom);
ABORT("stack direction 3\n");
}
# else
if ((word)(&dummy) < (word)GC_stackbottom) {
- GC_printf("STACK_GROWS_UP is defd, but stack appears to grow down\n");
- GC_printf("sp = 0x%lx, GC_stackbottom = 0x%lx\n",
- (unsigned long) (&dummy),
- (unsigned long) GC_stackbottom);
+ GC_err_printf0(
+ "STACK_GROWS_UP is defd, but stack appears to grow down\n");
+ GC_err_printf2("sp = 0x%lx, GC_stackbottom = 0x%lx\n",
+ (unsigned long) (&dummy),
+ (unsigned long) GC_stackbottom);
ABORT("stack direction 4");
}
# endif
# endif
# if !defined(_AUX_SOURCE) || defined(__GNUC__)
if ((word)(-1) < (word)0) {
- GC_printf("The type word should be an unsigned integer type\n");
- GC_printf("It appears to be signed\n");
+ GC_err_printf0("The type word should be an unsigned integer type\n");
+ GC_err_printf0("It appears to be signed\n");
ABORT("word");
}
# endif
if ((signed_word)(-1) >= (signed_word)0) {
- GC_printf("The type signed_word should be a signed integer type\n");
- GC_printf("It appears to be unsigned\n");
+ GC_err_printf0(
+ "The type signed_word should be a signed integer type\n");
+ GC_err_printf0("It appears to be unsigned\n");
ABORT("signed_word");
}
@@ -604,7 +609,7 @@ void GC_init_inner()
GC_bl_init();
GC_mark_init();
if (!GC_expand_hp_inner(GC_hincr)) {
- GC_printf("Can't start up: no memory\n");
+ GC_printf0("Can't start up: no memory\n");
EXIT();
}
GC_register_displacement_inner(0L);
@@ -614,11 +619,13 @@ void GC_init_inner()
/* Add initial guess of root sets */
GC_register_data_segments();
# ifdef PCR
+ PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever);
+ PCR_IL_Unlock();
GC_pcr_install();
# endif
/* Get black list set up */
- GC_gcollect_inner(TRUE);
- GC_gcollect_inner(TRUE);
+ (void)GC_gcollect_inner(TRUE);
+ (void)GC_gcollect_inner(TRUE);
/* Convince lint that some things are used */
{
extern char * GC_copyright[];
@@ -633,7 +640,6 @@ void GC_init_inner()
/* Assumes that all arguments have been converted to something of the */
/* same size as long, and that the format conversions expect something */
/* of that size. */
-/*VARARGS1*/
void GC_printf(format, a, b, c, d, e, f)
char * format;
long a, b, c, d, e, f;
@@ -652,7 +658,6 @@ long a, b, c, d, e, f;
# endif
}
-/*VARARGS1*/
void GC_err_printf(format, a, b, c, d, e, f)
char * format;
long a, b, c, d, e, f;
diff --git a/obj_map.c b/obj_map.c
index 6ea00763..fc3bfd99 100644
--- a/obj_map.c
+++ b/obj_map.c
@@ -100,7 +100,7 @@ word sz;
}
new_map = GC_scratch_alloc(MAP_SIZE);
# ifdef PRINTSTATS
- GC_printf("Adding block map for size %lu\n", (unsigned long)sz);
+ GC_printf1("Adding block map for size %lu\n", (unsigned long)sz);
# endif
for (displ = 0; displ < HBLKSIZE; displ++) {
MAP_ENTRY(new_map,displ) = OBJ_INVALID;
diff --git a/os_dep.c b/os_dep.c
index c1726d4c..9a8df5f8 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -1,7 +1,19 @@
+/*
+ * Copyright (c) 1991-1993 by Xerox Corporation. All rights reserved.
+ *
+ * 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 copy this garbage collector for any purpose,
+ * provided the above notices are retained on all copies.
+ */
# include "gc_private.h"
# include <stdio.h>
# include <signal.h>
+/* Blatantly OS dependent routines, except for those that are related */
+/* dynamic loading. */
+
/* Disable and enable signals during nontrivial allocations */
# ifdef OS2
@@ -43,40 +55,66 @@ void GC_enable_signals(void)
# else
-static int old_mask;
+# ifndef PCR
+
+# ifdef sigmask
+ /* Use the traditional BSD interface */
+# define SIGSET_T int
+# define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
+# define SIG_FILL(set) (set) = 0x7fffffff
+ /* Setting the leading bit appears to provoke a bug in some */
+ /* longjmp implementations. Most systems appear not to have */
+ /* a signal 32. */
+# define SIGSETMASK(old, new) (old) = sigsetmask(new)
+# else
+ /* Use POSIX/SYSV interface */
+# define SIGSET_T sigset_t
+# define SIG_DEL(set, signal) sigdelset(&(set), (signal))
+# define SIG_FILL(set) sigfillset(&set)
+# define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
+# endif
+
+static bool mask_initialized = FALSE;
+
+static SIGSET_T new_mask;
+
+static SIGSET_T old_mask;
+
+static SIGSET_T dummy;
void GC_disable_signals()
{
- int mask = 0x7fffffff;
- /* Setting the leading bit appears to provoke a bug in some */
- /* longjmp implementations. Most systems appear not to have */
- /* a signal 32. */
-
- mask &= ~(1<<(SIGSEGV-1));
- mask &= ~(1<<(SIGILL-1));
- mask &= ~(1<<(SIGQUIT-1));
-# ifdef SIGBUS
- mask &= ~(1<<(SIGBUS-1));
-# endif
-# ifdef SIGIOT
- mask &= ~(1<<(SIGIOT-1));
-# endif
-# ifdef SIGEMT
- mask &= ~(1<<(SIGEMT-1));
-# endif
-# ifdef SIGTRAP
- mask &= ~(1<<(SIGTRAP-1));
-# endif
- old_mask = sigsetmask(mask);
+ if (!mask_initialized) {
+ SIG_FILL(new_mask);
+
+ SIG_DEL(new_mask, SIGSEGV);
+ SIG_DEL(new_mask, SIGILL);
+ SIG_DEL(new_mask, SIGQUIT);
+# ifdef SIGBUS
+ SIG_DEL(new_mask, SIGBUS);
+# endif
+# ifdef SIGIOT
+ SIG_DEL(new_mask, SIGIOT);
+# endif
+# ifdef SIGEMT
+ SIG_DEL(new_mask, SIGEMT);
+# endif
+# ifdef SIGTRAP
+ SIG_DEL(new_mask, SIGTRAP);
+# endif
+ mask_initialized = TRUE;
+ }
+ SIGSETMASK(old_mask,new_mask);
}
void GC_enable_signals()
{
- (void)sigsetmask(old_mask);
+ SIGSETMASK(dummy,old_mask);
}
+# endif /* !PCR */
-# endif
+# endif /*!OS/2 */
/*
* Find the base of the stack.
@@ -93,7 +131,7 @@ ptr_t GC_get_stack_base()
PPIB ppib;
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
- fprintf(stderr, "DosGetInfoBlocks failed\n");
+ GC_err_printf0("DosGetInfoBlocks failed\n");
ABORT("DosGetInfoBlocks failed\n");
}
return((ptr_t)(ptib -> tib_pstacklimit));
@@ -172,8 +210,8 @@ ptr_t GC_get_stack_base()
result += MIN_PAGE_SIZE;
# endif
# endif /* HEURISTIC2 */
+ return(result);
# endif /* STACKBOTTOM */
- return(result);
}
# endif /* ! OS2 */
@@ -203,12 +241,12 @@ void GC_register_data_segments()
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
- fprintf(stderr, "DosGetInfoBlocks failed\n");
+ GC_err_printf0("DosGetInfoBlocks failed\n");
ABORT("DosGetInfoBlocks failed\n");
}
module_handle = ppib -> pib_hmte;
if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
- fprintf(stderr, "DosQueryModuleName failed\n");
+ GC_err_printf0("DosQueryModuleName failed\n");
ABORT("DosGetInfoBlocks failed\n");
}
myexefile = fopen(path, "rb");
@@ -269,7 +307,7 @@ void GC_register_data_segments()
if (!(flags & OBJWRITE)) continue;
if (!(flags & OBJREAD)) continue;
if (flags & OBJINVALID) {
- fprintf(stderr, "Object with invalid pages?\n");
+ GC_err_printf0("Object with invalid pages?\n");
continue;
}
GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg));
@@ -281,15 +319,12 @@ void GC_register_data_segments()
void GC_register_data_segments()
{
extern int end;
-
- GC_add_roots_inner(DATASTART, (char *)(&end));
-# ifdef DYNAMIC_LOADING
- {
- extern void GC_setup_dynamic_loading();
-
- GC_setup_dynamic_loading();
- }
+
+# ifndef PCR
+ GC_add_roots_inner(DATASTART, (char *)(&end));
# endif
+ /* Dynamic libraries are added at every collection, since they may */
+ /* change. */
}
# endif /* ! OS2 */
diff --git a/pcr_interface.c b/pcr_interface.c
index 85167804..573d34f7 100644
--- a/pcr_interface.c
+++ b/pcr_interface.c
@@ -36,8 +36,6 @@ void * GC_AllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear )
# define GC_FreeProc GC_free
-void GC_NoOpProc () {}
-
typedef struct {
PCR_ERes (*ed_proc)(void *p, size_t size, PCR_Any data);
bool ed_pointerfree;
@@ -92,14 +90,18 @@ PCR_ERes GC_EnumerateProc(
}
}
+void GC_DummyFreeProc(void *p) {};
+
+void GC_DummyShutdownProc(void) {};
+
struct PCR_MM_ProcsRep GC_Rep = {
MY_MAGIC,
GC_AllocProc,
GC_ReallocProc,
- GC_NoOpProc, /* mmp_free */
- GC_FreeProc, /* mmp_unsafeFree */
+ GC_DummyFreeProc, /* mmp_free */
+ GC_FreeProc, /* mmp_unsafeFree */
GC_EnumerateProc,
- GC_NoOpProc, /* mmp_shutdown */
+ GC_DummyShutdownProc /* mmp_shutdown */
};
void GC_pcr_install()
diff --git a/reclaim.c b/reclaim.c
index 357c0a67..9bf10158 100644
--- a/reclaim.c
+++ b/reclaim.c
@@ -21,14 +21,14 @@ ptr_t p;
word sz;
{
if (HDR(p) -> hb_obj_kind == PTRFREE) {
- GC_err_printf("Leaked atomic object at ");
+ GC_err_printf0("Leaked atomic object at ");
} else {
- GC_err_printf("Leaked composite object at ");
+ GC_err_printf0("Leaked composite object at ");
}
if (GC_debugging_started && GC_has_debug_info(p)) {
GC_print_obj(p);
} else {
- GC_err_printf("0x%lx (appr. size = %ld)\n",
+ GC_err_printf1("0x%lx (appr. size = %ld)\n",
(unsigned long)WORDS_TO_BYTES(sz));
}
}
@@ -434,13 +434,13 @@ int abort_if_found; /* Abort if a reclaimable object is found */
sz = hhdr -> hb_sz;
ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
# ifdef PRINTBLOCKS
- GC_printf("%ld(", (unsigned long)sz);
+ GC_printf1("%ld(", (unsigned long)sz);
if (hhdr -> hb_obj_kind == PTRFREE) {
- GC_printf("a");
+ GC_printf0("a");
} else if (hhdr -> hb_obj_kind == NORMAL){
- GC_printf("c");
+ GC_printf0("c");
} else {
- GC_printf("o");
+ GC_printf0("o");
}
# endif
@@ -472,7 +472,7 @@ int abort_if_found; /* Abort if a reclaimable object is found */
}
}
# ifdef PRINTBLOCKS
- if (empty) {GC_printf("e),");} else {GC_printf("n),");}
+ if (empty) {GC_printf0("e),");} else {GC_printf0("n),");}
# endif
}
@@ -507,7 +507,7 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */
}
# ifdef PRINTBLOCKS
- GC_printf("GC_reclaim: current block sizes:\n");
+ GC_printf0("GC_reclaim: current block sizes:\n");
# endif
/* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
@@ -515,7 +515,7 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */
GC_apply_to_all_blocks(GC_reclaim_block, abort_if_found);
# ifdef PRINTBLOCKS
- GC_printf("\n");
+ GC_printf0("\n");
# endif
}
diff --git a/setjmp_test.c b/setjmp_test.c
index 8426fd3d..6c2c8737 100644
--- a/setjmp_test.c
+++ b/setjmp_test.c
@@ -10,7 +10,7 @@
/* code.) */
#include <stdio.h>
#include <setjmp.h>
-#include "gc_private.h"
+#include "config.h"
#ifdef __hpux
/* X/OPEN PG3 defines "void* sbrk();" and this clashes with the definition */
@@ -26,6 +26,16 @@ getpagesize()
}
#endif
+#if defined(SUNOS5)
+#define _CLASSIC_XOPEN_TYPES
+#include <unistd.h>
+int
+getpagesize()
+{
+ return sysconf(_SC_PAGESIZE);
+}
+#endif
+
#ifdef _AUX_SOURCE
#include <sys/mmu.h>
int
@@ -95,7 +105,7 @@ main()
if (y == 1) {
if (x == 2) {
printf("Generic mark_regs code probably wont work\n");
-# if defined(SPARC) || defined(IBMRS6000)
+# if defined(SPARC) || defined(IBMRS6000) || defined(VAX) || defined(MIPS) || defined(M68K) || defined(I386) || defined(NS32K) || defined(RT)
printf("Assembly code supplied\n");
# else
printf("Need assembly code\n");
diff --git a/test.c b/test.c
index 027aa80c..be4fa067 100644
--- a/test.c
+++ b/test.c
@@ -69,6 +69,24 @@ sexpr y;
return(r);
}
+sexpr small_cons (x, y)
+sexpr x;
+sexpr y;
+{
+ register sexpr r;
+ register int *p;
+
+ r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
+ if (r == 0) {
+ (void)printf("Out of memory\n");
+ exit(1);
+ }
+ r -> sexpr_car = x;
+ r -> sexpr_cdr = y;
+ return(r);
+}
+
+
/* Return reverse(x) concatenated with y */
sexpr reverse1(x, y)
sexpr x, y;
@@ -92,7 +110,7 @@ int low, up;
if (low > up) {
return(nil);
} else {
- return(cons((sexpr)low, ints(low+1, up)));
+ return(small_cons(small_cons((sexpr)low, 0), ints(low+1, up)));
}
}
@@ -100,7 +118,7 @@ void check_ints(list, low, up)
sexpr list;
int low, up;
{
- if ((int)(car(list)) != low) {
+ if ((int)(car(car(list))) != low) {
(void)printf(
"List reversal produced incorrect list - collector is broken\n");
exit(1);
@@ -122,7 +140,7 @@ sexpr x;
if (is_nil(x)) {
(void)printf("NIL\n");
} else {
- (void)printf("%d", car(x));
+ (void)printf("(%d)", car(car(x)));
if (!is_nil(cdr(x))) {
(void)printf(", ");
(void)print_int_list(cdr(x));
@@ -147,9 +165,11 @@ reverse_test()
{
int i;
sexpr b;
+ sexpr c;
a = ints(1, 100);
b = ints(1, 50);
+ c = ints(1, 4500);
for (i = 0; i < 50; i++) {
b = reverse(reverse(b));
}
@@ -168,7 +188,8 @@ reverse_test()
}
check_ints(a,1,100);
check_ints(b,1,50);
- a = b = 0;
+ check_ints(c,1,4500);
+ a = b = c = 0;
}
/*