From dc5d3c40f99d052ff2b9ca6e670eaebe62606bdd Mon Sep 17 00:00:00 2001 From: Paolo Molaro Date: Tue, 24 Jan 2006 11:37:10 +0000 Subject: [PATCH] Tue Jan 24 12:34:06 CET 2006 Paolo Molaro * *: update from upstream changes. svn path=/trunk/mono/; revision=55979 --- ChangeLog | 5 + Makefile.am | 41 +++++- Makefile.direct | 23 +-- NT_STATIC_THREADS_MAKEFILE | 2 +- allchblk.c | 28 ++-- alloc.c | 36 +++-- alpha_mach_dep.S | 25 ++-- backgraph.c | 43 ++++-- configure.in | 63 ++++---- cord/cordprnt.c | 6 +- cord/cordtest.c | 2 +- darwin_stop_world.c | 124 ++++++++++++++-- doc/README | 2 +- doc/README.changes | 168 ++++++++++++++++++++++ doc/README.darwin | 13 ++ doc/README.environment | 1 + doc/README.linux | 4 +- doc/README.solaris2 | 4 +- dyn_load.c | 79 ++++++---- finalize.c | 33 ++--- headers.c | 2 +- include/gc.h | 35 ++++- include/gc_allocator.h | 12 +- include/gc_config_macros.h | 4 + include/gc_cpp.h | 2 +- include/new_gc_alloc.h | 8 +- include/private/gc_hdrs.h | 2 +- include/private/gc_locks.h | 126 +++++++++++----- include/private/gc_priv.h | 38 +++-- include/private/gcconfig.h | 223 +++++++++++++++++++++-------- include/private/pthread_support.h | 2 +- mach_dep.c | 137 +++++++++++------- mallocx.c | 3 +- mark.c | 12 +- mark_rts.c | 5 +- misc.c | 7 +- os_dep.c | 230 ++++++++++++++++++------------ powerpc_darwin_mach_dep.s | 9 +- pthread_support.c | 41 +++--- reclaim.c | 2 +- solaris_pthreads.c | 3 +- solaris_threads.c | 19 +-- specific.c | 3 +- threadlibs.c | 10 +- version.h | 4 +- win32_threads.c | 15 +- 46 files changed, 1174 insertions(+), 482 deletions(-) diff --git a/ChangeLog b/ChangeLog index bb89b2b2..ddc4befc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ + +Tue Jan 24 12:34:06 CET 2006 Paolo Molaro + + * *: update from upstream changes. + 2006-01-21 Martin Baulig * include/Makefile.am: Don't install libgc-mono-debugger.h. diff --git a/Makefile.am b/Makefile.am index 4850ba79..079e6cde 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,7 +41,7 @@ asm_libgc_sources = endif libmonogc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \ -dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \ +dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \ malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \ obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \ solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \ @@ -49,10 +49,9 @@ backgraph.c win32_threads.c \ pthread_support.c pthread_stop_world.c darwin_stop_world.c \ $(asm_libgc_sources) - -# Include THREADLIBS here to ensure that the correct versions of +# Include THREADDLLIBS here to ensure that the correct versions of # linuxthread semaphore functions get linked: -libmonogc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS) +libmonogc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) libmonogc_la_DEPENDENCIES = @addobjs@ libmonogc_la_LDFLAGS = -version-info 1:2:0 @@ -65,16 +64,48 @@ EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S AM_CFLAGS = @GC_CFLAGS@ +if CPLUSPLUS +extra_checks = test_cpp +else +extra_checks = +endif + +check_PROGRAMS = gctest $(extra_checks) + +test.o: $(srcdir)/tests/test.c + $(COMPILE) -c $(srcdir)/tests/test.c +# Using $< in the above seems to fail with the HP/UX on Itanium make. +test_cpp.o: $(srcdir)/tests/test_cpp.cc + $(CXXCOMPILE) -c $(srcdir)/tests/test_cpp.cc + +## FIXME: this is probably the reason why some files from BUILT_SOURCES +## are included in the distribution +# gctest_OBJECTS = test.o +gctest_SOURCES = tests/test.c +gctest_LDADD = ./libgc.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS) +test_cpp_SOURCES = tests/test_cpp.cc +test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS) + +TESTS = gctest $(extra_checks) + ## FIXME: relies on internal code generated by automake. all_objs = @addobjs@ $(libgc_la_OBJECTS) $(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \ include/private/gc_hdrs.h include/gc.h include/gc_gcj.h include/gc_mark.h ## FIXME: we shouldn't have to do this, but automake forces us to. +if COMPILER_XLC + ## XLC neither requires nor tolerates the unnecessary assembler goop + ASM_CPP_OPTIONS = +else + ## We use -Wp,-P to strip #line directives. Irix `as' chokes on + ## these. + ASM_CPP_OPTIONS = -Wp,-P -x assembler-with-cpp +endif .s.lo: ## We use -Wp,-P to strip #line directives. Irix `as' chokes on ## these. - $(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $< + $(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $< ## We have our own definition of LTCOMPILE because we want to use our ## CFLAGS, not those passed in from the top level make. diff --git a/Makefile.direct b/Makefile.direct index f2b32246..1f03b511 100644 --- a/Makefile.direct +++ b/Makefile.direct @@ -36,7 +36,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_ # -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC # To build the parallel collector in a static library on HP/UX, # add to the above: -# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L +# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt # To build the thread-safe collector on Tru64, add to the above: # -pthread -DGC_OSF1_THREADS @@ -70,10 +70,11 @@ HOSTCFLAGS=$(CFLAGS) # Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp. # -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads. # see README.linux. -D_REENTRANT may also be required. -# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested. -# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested. +# -DGC_OSF1_THREADS enables support for Tru64 pthreads. +# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. # Appeared to run into some underlying thread problems. -# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested. +# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. +# -DGC_AIX_THREADS enables support for IBM AIX threads. # -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads. # See README.DGUX386. # -DGC_WIN32_THREADS enables support for win32 threads. That makes sense @@ -233,8 +234,8 @@ HOSTCFLAGS=$(CFLAGS) # -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic() # and GC_local_gcj_malloc(). Needed for gc_gcj.h interface. These allocate # in a way that usually does not involve acquisition of a global lock. -# Currently requires -DGC_LINUX_THREADS, but should be easy to port to -# other pthreads environments. Recommended for multiprocessors. +# Currently works only on platforms such as Linux which use pthread_support.c. +# Recommended for multiprocessors. # -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported # "__thread" thread-local variables. This is the default in HP/UX. It # may help performance on recent Linux installations. (It failed for @@ -276,6 +277,10 @@ HOSTCFLAGS=$(CFLAGS) # -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers # by the indicated amount before trying to interpret them. Applied # after POINTER_MASK. EXPERIMENTAL. See also the preceding macro. +# -DDARWIN_DONT_PARSE_STACK Causes the Darwin port to discover thread +# stack bounds in the same way as other pthread ports, without trying to +# walk the frames onthe stack. This is recommended only as a fallback +# for applications that don't support proper stack unwinding. # CXXFLAGS= $(CFLAGS) @@ -283,9 +288,9 @@ AR= ar RANLIB= ranlib -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 aix_irix_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.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 pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_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 aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.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 pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC @@ -324,7 +329,7 @@ DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \ doc/simple_example.html TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \ - tests/leak_test.c tests/thread_leak_test.c + tests/leak_test.c tests/thread_leak_test.c tests/middle.c GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \ libtool.m4 install-sh configure.host Makefile.in \ diff --git a/NT_STATIC_THREADS_MAKEFILE b/NT_STATIC_THREADS_MAKEFILE index 7238c940..a7582af6 100644 --- a/NT_STATIC_THREADS_MAKEFILE +++ b/NT_STATIC_THREADS_MAKEFILE @@ -1,4 +1,4 @@ -# Makefile for Windows NT. Assumes Microsoft compiler, and a single thread. +# Makefile for Windows NT. Assumes Microsoft compiler. # DLLs are included in the root set under NT, but not under win32S. # Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor. diff --git a/allchblk.c b/allchblk.c index 1bd17da3..1a1efc6b 100644 --- a/allchblk.c +++ b/allchblk.c @@ -111,7 +111,7 @@ void GC_print_hblkfreelist() for (i = 0; i <= N_HBLK_FLS; ++i) { h = GC_hblkfreelist[i]; # ifdef USE_MUNMAP - if (0 != h) GC_printf1("Free list %ld (Total size %ld):\n", + if (0 != h) GC_printf1("Free list %ld:\n", (unsigned long)i); # else if (0 != h) GC_printf2("Free list %ld (Total size %ld):\n", @@ -133,10 +133,12 @@ void GC_print_hblkfreelist() h = hhdr -> hb_next; } } - if (total_free != GC_large_free_bytes) { +# ifndef USE_MUNMAP + if (total_free != GC_large_free_bytes) { GC_printf1("GC_large_free_bytes = %lu (INCONSISTENT!!)\n", (unsigned long) GC_large_free_bytes); - } + } +# endif GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free); } @@ -181,7 +183,7 @@ void GC_dump_regions() hhdr = HDR(p); GC_printf1("\t0x%lx ", (unsigned long)p); if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { - GC_printf1("Missing header!!\n", hhdr); + GC_printf1("Missing header!!(%ld)\n", hhdr); p += HBLKSIZE; continue; } @@ -283,8 +285,8 @@ int n; GET_HDR(hhdr -> hb_prev, phdr); phdr -> hb_next = hhdr -> hb_next; } + FREE_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz); INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz)); - FREE_ASSERT(GC_free_bytes[index] >= 0); if (0 != hhdr -> hb_next) { hdr * nhdr; GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr))); @@ -468,7 +470,11 @@ int index; if (total_size == bytes) return h; rest = (struct hblk *)((word)h + bytes); rest_hdr = GC_install_header(rest); - if (0 == rest_hdr) return(0); + if (0 == rest_hdr) { + /* This may be very bad news ... */ + WARN("Header allocation failed: Dropping block.\n", 0); + return(0); + } rest_hdr -> hb_sz = total_size - bytes; rest_hdr -> hb_flags = 0; # ifdef GC_ASSERTIONS @@ -584,8 +590,9 @@ int n; GET_HDR(hbp, hhdr); size_avail = hhdr->hb_sz; if (size_avail < size_needed) continue; - if (!GC_use_entire_heap - && size_avail != size_needed + if (size_avail != size_needed + && !GC_use_entire_heap + && !GC_dont_gc && USED_HEAP_SIZE >= GC_requested_heapsize && !TRUE_INCREMENTAL && GC_should_collect()) { # ifdef USE_MUNMAP @@ -602,7 +609,8 @@ int n; /* If we are deallocating lots of memory from */ /* finalizers, fail and collect sooner rather */ /* than later. */ - if (GC_finalizer_mem_freed > (GC_heapsize >> 4)) { + if (WORDS_TO_BYTES(GC_finalizer_mem_freed) + > (GC_heapsize >> 4)) { continue; } # endif /* !USE_MUNMAP */ @@ -692,7 +700,7 @@ int n; struct hblk * h; struct hblk * prev = hhdr -> hb_prev; - GC_words_wasted += total_size; + GC_words_wasted += BYTES_TO_WORDS(total_size); GC_large_free_bytes -= total_size; GC_remove_from_fl(hhdr, n); for (h = hbp; h < limit; h++) { diff --git a/alloc.c b/alloc.c index 99a61f6f..e8ab9ddf 100644 --- a/alloc.c +++ b/alloc.c @@ -92,6 +92,16 @@ char * GC_copyright[] = # include "version.h" +#if defined(SAVE_CALL_CHAIN) && \ + !(defined(REDIRECT_MALLOC) && defined(GC_HAVE_BUILTIN_BACKTRACE)) +# define SAVE_CALL_CHAIN_IN_GC + /* This is only safe if the call chain save mechanism won't end up */ + /* calling GC_malloc. The GNU C library documentation suggests */ + /* that backtrace doesn't use malloc, but at least the initial */ + /* call in some versions does seem to invoke the dynamic linker, */ + /* which uses malloc. */ +#endif + /* some more variables */ extern signed_word GC_mem_found; /* Number of reclaimed longwords */ @@ -104,8 +114,6 @@ word GC_free_space_divisor = 3; extern GC_bool GC_collection_in_progress(); /* Collection is in progress, or was abandoned. */ -extern GC_bool GC_print_back_height; - int GC_never_stop_func GC_PROTO((void)) { return(0); } unsigned long GC_time_limit = TIME_LIMIT; @@ -133,7 +141,7 @@ int GC_n_attempts = 0; /* Number of attempts at finishing */ if (GC_print_stats) { GC_printf0("Abandoning stopped marking after "); GC_printf1("%lu msecs", (unsigned long)time_diff); - GC_printf1("(attempt %d)\n", (unsigned long) GC_n_attempts); + GC_printf1("(attempt %ld)\n", (unsigned long) GC_n_attempts); } # endif return(1); @@ -198,7 +206,8 @@ word GC_adj_words_allocd() /* had been reallocated this round. Finalization is user */ /* visible progress. And if we don't count this, we have */ /* stability problems for programs that finalize all objects. */ - result += GC_words_wasted; + if ((GC_words_wasted >> 3) < result) + result += GC_words_wasted; /* This doesn't reflect useful work. But if there is lots of */ /* new fragmentation, the same is probably true of the heap, */ /* and the collection will be correspondingly cheaper. */ @@ -223,6 +232,8 @@ void GC_clear_a_few_frames() { # define NWORDS 64 word frames[NWORDS]; + /* Some compilers will warn that frames was set but never used. */ + /* That's the whole idea ... */ register int i; for (i = 0; i < NWORDS; i++) frames[i] = 0; @@ -299,7 +310,7 @@ void GC_maybe_gc() # endif if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED? GC_never_stop_func : GC_timeout_stop_func)) { -# ifdef SAVE_CALL_CHAIN +# ifdef SAVE_CALL_CHAIN_IN_GC GC_save_callers(GC_last_stack); # endif GC_finish_collection(); @@ -368,7 +379,7 @@ GC_stop_func stop_func; } GC_invalidate_mark_state(); /* Flush mark stack. */ GC_clear_marks(); -# ifdef SAVE_CALL_CHAIN +# ifdef SAVE_CALL_CHAIN_IN_GC GC_save_callers(GC_last_stack); # endif GC_is_full_gc = TRUE; @@ -423,7 +434,7 @@ int n; for (i = GC_deficit; i < GC_RATE*n; i++) { if (GC_mark_some((ptr_t)0)) { /* Need to finish a collection */ -# ifdef SAVE_CALL_CHAIN +# ifdef SAVE_CALL_CHAIN_IN_GC GC_save_callers(GC_last_stack); # endif # ifdef PARALLEL_MARK @@ -960,7 +971,7 @@ word n; # endif expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE; if (GC_last_heap_addr == 0 && !((word)space & SIGNB) - || GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) { + || (GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space)) { /* Assume the heap is growing up */ GC_greatest_plausible_heap_addr = (GC_PTR)GC_max((ptr_t)GC_greatest_plausible_heap_addr, @@ -1029,9 +1040,9 @@ word needed_blocks; GC_bool ignore_off_page; { if (!GC_incremental && !GC_dont_gc && - (GC_dont_expand && GC_words_allocd > 0 - || (GC_fo_entries > (last_fo_entries + 500) && (last_words_finalized || GC_words_finalized)) - || GC_should_collect())) { + ((GC_dont_expand && GC_words_allocd > 0) + || (GC_fo_entries > (last_fo_entries + 500) && (last_words_finalized || GC_words_finalized)) + || GC_should_collect())) { GC_gcollect_inner(); last_fo_entries = GC_fo_entries; last_words_finalized = GC_words_finalized; @@ -1042,6 +1053,9 @@ GC_bool ignore_off_page; if (blocks_to_get > MAXHINCR) { word slop; + /* Get the minimum required to make it likely that we */ + /* can satisfy the current request in the presence of black- */ + /* listing. This will probably be more than MAXHINCR. */ if (ignore_off_page) { slop = 4; } else { diff --git a/alpha_mach_dep.S b/alpha_mach_dep.S index bff64d35..d4def240 100644 --- a/alpha_mach_dep.S +++ b/alpha_mach_dep.S @@ -1,4 +1,3 @@ - # $Id$ .arch ev6 .text @@ -12,13 +11,13 @@ GC_push_regs: .mask 0x04000000, 0 .frame $sp, 16, $26, 0 - # $0 integer result - # $1-$8 temp regs - not preserved cross calls - # $9-$15 call saved regs - # $16-$21 argument regs - not preserved cross calls - # $22-$28 temp regs - not preserved cross calls - # $29 global pointer - not preserved cross calls - # $30 stack pointer +/* $0 integer result */ +/* $1-$8 temp regs - not preserved cross calls */ +/* $9-$15 call saved regs */ +/* $16-$21 argument regs - not preserved cross calls */ +/* $22-$28 temp regs - not preserved cross calls */ +/* $29 global pointer - not preserved cross calls */ +/* $30 stack pointer */ # define call_push(x) \ mov x, $16; \ @@ -33,12 +32,12 @@ GC_push_regs: call_push($14) call_push($15) - # $f0-$f1 floating point results - # $f2-$f9 call saved regs - # $f10-$f30 temp regs - not preserved cross calls +/* $f0-$f1 floating point results */ +/* $f2-$f9 call saved regs */ +/* $f10-$f30 temp regs - not preserved cross calls */ - # Use the most efficient transfer method for this hardware. - # Bit 1 detects the FIX extension, which includes ftoit. + /* Use the most efficient transfer method for this hardware. */ + /* Bit 1 detects the FIX extension, which includes ftoit. */ amask 2, $0 bne $0, $use_stack diff --git a/backgraph.c b/backgraph.c index 0fe1c8f7..0c512e2c 100644 --- a/backgraph.c +++ b/backgraph.c @@ -85,7 +85,7 @@ static back_edges * new_back_edges(void) { if (0 == back_edge_space) { back_edge_space = (back_edges *) - sbrk(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges)); + GET_MEM(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges)); } if (0 != avail_back_edges) { back_edges * result = avail_back_edges; @@ -113,17 +113,31 @@ static void deallocate_back_edges(back_edges *p) /* Table of objects that are currently on the depth-first search */ /* stack. Only objects with in-degree one are in this table. */ /* Other objects are identified using HEIGHT_IN_PROGRESS. */ -/* This data structure NEEDS IMPROVEMENT. */ -#define MAX_IN_PROGRESS 10000 +/* FIXME: This data structure NEEDS IMPROVEMENT. */ +#define INITIAL_IN_PROGRESS 10000 static ptr_t * in_progress_space = 0; -static int n_in_progress = 0; +static size_t in_progress_size = 0; +static size_t n_in_progress = 0; static void push_in_progress(ptr_t p) { + if (n_in_progress >= in_progress_size) + if (in_progress_size == 0) { + in_progress_size = INITIAL_IN_PROGRESS; + in_progress_space = (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t)); + } else { + ptr_t * new_in_progress_space; + in_progress_size *= 2; + new_in_progress_space = (ptr_t *) + GET_MEM(in_progress_size * sizeof(ptr_t)); + BCOPY(in_progress_space, new_in_progress_space, + n_in_progress * sizeof(ptr_t)); + in_progress_space = new_in_progress_space; + /* FIXME: This just drops the old space. */ + } if (in_progress_space == 0) - in_progress_space = sbrk(MAX_IN_PROGRESS * sizeof(ptr_t)); - if (n_in_progress == MAX_IN_PROGRESS) - ABORT("Exceeded MAX_IN_PROGRESS"); + ABORT("MAKE_BACK_GRAPH: Out of in-progress space: " + "Huge linear data structure?"); in_progress_space[n_in_progress++] = p; } @@ -318,8 +332,8 @@ static void add_back_edges(ptr_t p, word n_words, word gc_descr) } } -/* Rebuild the reprentation of the backward reachability graph. */ -/* Does not examine mark bits. Can be called before GC. */ +/* Rebuild the representation of the backward reachability graph. */ +/* Does not examine mark bits. Can be called before GC. */ void GC_build_back_graph(void) { GC_apply_to_each_object(add_back_edges); @@ -424,15 +438,20 @@ static void update_max_height(ptr_t p, word n_words, word gc_descr) } } +word GC_max_max_height = 0; + void GC_traverse_back_graph(void) { - static word max_max_height = 0; GC_max_height = 0; GC_apply_to_each_object(update_max_height); +} + +void GC_print_back_graph_stats(void) +{ GC_printf2("Maximum backwards height of reachable objects at GC %lu is %ld\n", (unsigned long) GC_gc_no, GC_max_height); - if (GC_max_height > max_max_height) { - max_max_height = GC_max_height; + if (GC_max_height > GC_max_max_height) { + GC_max_max_height = GC_max_height; GC_printf0("The following unreachable object is last in a longest chain " "of unreachable objects:\n"); GC_print_heap_obj(GC_deepest_obj); diff --git a/configure.in b/configure.in index 2e57f2a6..89467478 100644 --- a/configure.in +++ b/configure.in @@ -15,9 +15,9 @@ dnl Process this file with autoconf to produce configure. AC_PREREQ(2.53) -AC_INIT(libgc-mono, 6.3alpha6, Hans_Boehm@hp.com) +AC_INIT(libgc-mono, 6.6, Hans_Boehm@hp.com) -AM_INIT_AUTOMAKE(libgc-mono, 6.2, no-define) +AM_INIT_AUTOMAKE(libgc-mono, 6.6, no-define) AC_CONFIG_SRCDIR(gcj_mlc.c) AC_CANONICAL_HOST @@ -67,14 +67,15 @@ AC_ARG_ENABLE(cplusplus, ) INCLUDES=-I${srcdir}/include -THREADLIBS= +THREADDLLIBS= +## Libraries needed to support dynamic loading and/or threads. case "$THREADS" in no | none | single) THREADS=none ;; posix | pthreads) THREADS=posix - THREADLIBS=-lpthread + THREADDLLIBS=-lpthread case "$host" in x86-*-linux* | ia64-*-linux* | i386-*-linux* | i486-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux* | s390*-*-linux* | powerpc-*-linux*) AC_DEFINE(GC_LINUX_THREADS) @@ -100,7 +101,7 @@ case "$THREADS" in AC_DEFINE(PARALLEL_MARK) fi AC_DEFINE(THREAD_LOCAL_ALLOC) - THREADLIBS="-lpthread -lrt" + THREADDLLIBS="-lpthread -lrt" ;; *-*-freebsd4*) AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.") @@ -111,22 +112,16 @@ case "$THREADS" in INCLUDES="$INCLUDES $PTHREAD_CFLAGS" fi if test "x$PTHREAD_LIBS" = "x"; then - THREADLIBS=-pthread + THREADDLLIBS=-pthread else - THREADLIBS="$PTHREAD_LIBS" + THREADDLLIBS=$PTHREAD_LIBS fi ;; *-*-freebsd5*) AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.") AC_DEFINE(GC_FREEBSD_THREADS) - if test "x$PTHREAD_CFLAGS" != "x"; then - INCLUDES="$INCLUDES $PTHREAD_CFLAGS" - fi - if test "x$PTHREAD_LIBS" = "x"; then - THREADLIBS=-pthread - else - THREADLIBS="$PTHREAD_LIBS" - fi + INCLUDES="$INCLUDES -pthread" + THREADDLLIBS=-pthread ;; *-*-freebsd6*) AC_DEFINE(GC_FREEBSD_THREADS) @@ -134,9 +129,9 @@ case "$THREADS" in INCLUDES="$INCLUDES $PTHREAD_CFLAGS" fi if test "x$PTHREAD_LIBS" = "x"; then - THREADLIBS=-pthread + THREADDLLIBS=-pthread else - THREADLIBS="$PTHREAD_LIBS" + THREADDLLIBS="$PTHREAD_LIBS" fi ;; *-*-solaris*) @@ -165,7 +160,10 @@ case "$THREADS" in # Measurements havent yet been done. fi INCLUDES="$INCLUDES -pthread" - THREADLIBS="-lpthread -lrt" + THREADDLLIBS="-lpthread -lrt" + ;; + *) + AC_MSG_ERROR("Pthreads not supported by the GC on this platform.") ;; esac ;; @@ -179,9 +177,9 @@ case "$THREADS" in ;; dgux386) THREADS=dgux386 - AC_MSG_RESULT($THREADLIBS) + AC_MSG_RESULT($THREADDLLIBS) # Use pthread GCC switch - THREADLIBS=-pthread + THREADDLLIBS=-pthread if test "${enable_parallel_mark}" = yes; then AC_DEFINE(PARALLEL_MARK) fi @@ -193,7 +191,7 @@ case "$THREADS" in ;; aix) THREADS=posix - THREADLIBS=-lpthread + THREADDLLIBS=-lpthread AC_DEFINE(GC_AIX_THREADS) AC_DEFINE(_REENTRANT) ;; @@ -204,7 +202,7 @@ case "$THREADS" in AC_MSG_ERROR($THREADS is an unknown thread package) ;; esac -AC_SUBST(THREADLIBS) +AC_SUBST(THREADDLLIBS) case "$host" in powerpc-*-darwin*) @@ -213,12 +211,25 @@ case "$host" in esac AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue) +AC_MSG_CHECKING(for xlc) +AC_TRY_COMPILE([],[ + #ifndef __xlC__ + # error + #endif +], [compiler_xlc=yes], [compiler_xlc=no]) +AC_MSG_RESULT($compiler_xlc) +AM_CONDITIONAL(COMPILER_XLC,test $compiler_xlc = yes) +if test $compiler_xlc = yes -a "$powerpc_darwin" = true; then + # the darwin stack-frame-walking code is completely broken on xlc + AC_DEFINE(DARWIN_DONT_PARSE_STACK) +fi + # We never want libdl on darwin. It is a fake libdl that just ends up making # dyld calls anyway case "$host" in *-*-darwin*) ;; *) - AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl") + AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl") ;; esac @@ -319,7 +330,7 @@ case "$host" in machdep="sparc_mach_dep.lo" AC_DEFINE(SUNOS53_SHARED_LIB) ;; - sparc-sun-solaris2.*) + sparc*-sun-solaris2.*) machdep="sparc_mach_dep.lo" ;; ia64-*-*) @@ -381,10 +392,10 @@ AC_MSG_RESULT($THREADS) dnl As of 4.13a2, the collector will not properly work on Solaris when dnl built with gcc and -O. So we remove -O in the appropriate case. -dnl +dnl Not needed anymore on Solaris. AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary) case "$host" in - sparc-sun-solaris2*|*aix*) + *aix*) if test "$GCC" = yes; then AC_MSG_RESULT(yes) new_CFLAGS= diff --git a/cord/cordprnt.c b/cord/cordprnt.c index ad937b02..6d278fed 100644 --- a/cord/cordprnt.c +++ b/cord/cordprnt.c @@ -59,7 +59,7 @@ static int extract_conv_spec(CORD_pos source, char *buf, register int result = 0; register int current_number = 0; register int saw_period = 0; - register int saw_number; + register int saw_number = 0; register int chars_so_far = 0; register char current; @@ -243,7 +243,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) char * str = va_arg(args, char *); register char c; - while (c = *str++) { + while ((c = *str++)) { CORD_ec_append(result, c); } goto done; @@ -320,7 +320,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) if (buf != result[0].ec_bufptr) { register char c; - while (c = *buf++) { + while ((c = *buf++)) { CORD_ec_append(result, c); } } else { diff --git a/cord/cordtest.c b/cord/cordtest.c index 8f4836a2..08333ca0 100644 --- a/cord/cordtest.c +++ b/cord/cordtest.c @@ -221,7 +221,7 @@ void test_printf() if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5"); } -main() +int main() { # ifdef THINK_C printf("cordtest:\n"); diff --git a/darwin_stop_world.c b/darwin_stop_world.c index 60acd83c..692b18db 100644 --- a/darwin_stop_world.c +++ b/darwin_stop_world.c @@ -12,23 +12,33 @@ Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then it must set up a stack frame just like routines that call other routines." */ -#define PPC_RED_ZONE_SIZE 224 +#ifdef POWERPC +# if CPP_WORDSZ == 32 +# define PPC_RED_ZONE_SIZE 224 +# elif CPP_WORDSZ == 64 +# define PPC_RED_ZONE_SIZE 320 +# endif +#endif -/* Not 64-bit clean. Wait until Apple defines their 64-bit ABI */ typedef struct StackFrame { - unsigned int savedSP; - unsigned int savedCR; - unsigned int savedLR; - unsigned int reserved[2]; - unsigned int savedRTOC; + unsigned long savedSP; + unsigned long savedCR; + unsigned long savedLR; + unsigned long reserved[2]; + unsigned long savedRTOC; } StackFrame; - -unsigned int FindTopOfStack(unsigned int stack_start) { +unsigned long FindTopOfStack(unsigned int stack_start) { StackFrame *frame; if (stack_start == 0) { - __asm__ volatile("lwz %0,0(r1)" : "=r" (frame)); +# ifdef POWERPC +# if CPP_WORDSZ == 32 + __asm__ volatile("lwz %0,0(r1)" : "=r" (frame)); +# else + __asm__ volatile("ldz %0,0(r1)" : "=r" (frame)); +# endif +# endif } else { frame = (StackFrame *)stack_start; } @@ -37,7 +47,7 @@ unsigned int FindTopOfStack(unsigned int stack_start) { /* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */ # endif do { - if (frame->savedSP == NULL) break; + if (frame->savedSP == 0) break; /* if there are no more stack frames, stop */ frame = (StackFrame*)frame->savedSP; @@ -53,9 +63,88 @@ unsigned int FindTopOfStack(unsigned int stack_start) { /* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */ # endif - return (unsigned int)frame; + return (unsigned long)frame; } +#ifdef DARWIN_DONT_PARSE_STACK +void GC_push_all_stacks() { + int i; + kern_return_t r; + GC_thread p; + pthread_t me; + ptr_t lo, hi; + ppc_thread_state_t state; + mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT; + + me = pthread_self(); + if (!GC_thr_initialized) GC_thr_init(); + + for(i=0;inext) { + if(p -> flags & FINISHED) continue; + if(pthread_equal(p->id,me)) { + lo = GC_approx_sp(); + } else { + /* Get the thread state (registers, etc) */ + r = thread_get_state( + p->stop_info.mach_thread, + MACHINE_THREAD_STATE, + (natural_t*)&state, + &thread_state_count); + if(r != KERN_SUCCESS) ABORT("thread_get_state failed"); + + lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE); + + GC_push_one(state.r0); + GC_push_one(state.r2); + GC_push_one(state.r3); + GC_push_one(state.r4); + GC_push_one(state.r5); + GC_push_one(state.r6); + GC_push_one(state.r7); + GC_push_one(state.r8); + GC_push_one(state.r9); + GC_push_one(state.r10); + GC_push_one(state.r11); + GC_push_one(state.r12); + GC_push_one(state.r13); + GC_push_one(state.r14); + GC_push_one(state.r15); + GC_push_one(state.r16); + GC_push_one(state.r17); + GC_push_one(state.r18); + GC_push_one(state.r19); + GC_push_one(state.r20); + GC_push_one(state.r21); + GC_push_one(state.r22); + GC_push_one(state.r23); + GC_push_one(state.r24); + GC_push_one(state.r25); + GC_push_one(state.r26); + GC_push_one(state.r27); + GC_push_one(state.r28); + GC_push_one(state.r29); + GC_push_one(state.r30); + GC_push_one(state.r31); + } /* p != me */ + if(p->flags & MAIN_THREAD) + hi = GC_stackbottom; + else + hi = p->stack_end; +#if DEBUG_THREADS + GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n", + (unsigned long) p -> id, + (unsigned long) lo, + (unsigned long) hi + ); +#endif + GC_push_all_stack(lo,hi); + } /* for(p=GC_threads[i]...) */ + } /* for(i=0;i] - (Win32 only.) Try to avoid treating a mapped are never honored, eliminating this risk for most, but not all, applications. This feature is likely to disappear if/when we find a less disgusting "solution". + IN VERSION 6.4 AND LATER, THIS SHOULD BE UNNECESSARY. The following turn on runtime flags that are also program settable. Checked only during initialization. We expect that they will usually be set through diff --git a/doc/README.linux b/doc/README.linux index 1d0fd4c3..ec4e7e64 100644 --- a/doc/README.linux +++ b/doc/README.linux @@ -19,10 +19,10 @@ Linux threads. These should not be touched by the client program. To use threads, you need to abide by the following requirements: -1) You need to use LinuxThreads (which are included in libc6). +1) You need to use LinuxThreads or NPTL (which are included in libc6). The collector relies on some implementation details of the LinuxThreads - package. It is unlikely that this code will work on other + package. This code may not work on other pthread implementations (in particular it will *not* work with MIT pthreads). diff --git a/doc/README.solaris2 b/doc/README.solaris2 index 6ed61dc8..31e75003 100644 --- a/doc/README.solaris2 +++ b/doc/README.solaris2 @@ -43,9 +43,7 @@ can result in unpleasant heap growth. But it seems better than the race/deadlock issues we had before. If solaris_threads are used on an X86 processor with malloc redirected to -GC_malloc, it is necessary to call GC_thr_init explicitly before forking the -first thread. (This avoids a deadlock arising from calling GC_thr_init -with the allocation lock held.) +GC_malloc a deadlock is likely to result. It appears that there is a problem in using gc_cpp.h in conjunction with Solaris threads and Sun's C++ runtime. Apparently the overloaded new operator diff --git a/dyn_load.c b/dyn_load.c index 7111a874..62d3815b 100644 --- a/dyn_load.c +++ b/dyn_load.c @@ -96,7 +96,7 @@ /* Newer versions of GNU/Linux define this macro. We * define it similarly for any ELF systems that don't. */ # ifndef ElfW -# ifdef FREEBSD +# if defined(FREEBSD) # if __ELF_WORD_SIZE == 32 # define ElfW(type) Elf32_##type # else @@ -114,7 +114,7 @@ # define ElfW(type) Elf32_##type # else # define ElfW(type) Elf64_##type -# endif +# endif # endif # endif # endif @@ -493,7 +493,6 @@ static struct link_map * GC_FirstDLOpenedLinkMap() { ElfW(Dyn) *dp; - struct r_debug *r; static struct link_map *cachedResult = 0; if( _DYNAMIC == 0) { @@ -502,6 +501,12 @@ GC_FirstDLOpenedLinkMap() if( cachedResult == 0 ) { int tag; for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) { + /* FIXME: The DT_DEBUG header is not mandated by the */ + /* ELF spec. This code appears to be dependent on */ + /* idiosynchracies of older GNU tool chains. If this code */ + /* fails for you, the real problem is probably that it is */ + /* being used at all. You should be getting the */ + /* dl_iterate_phdr version. */ if( tag == DT_DEBUG ) { struct link_map *lm = ((struct r_debug *)(dp->d_un.d_ptr))->r_map; @@ -626,7 +631,8 @@ void GC_register_dynamic_libraries() } for (i = 0; i < needed_sz; i++) { flags = addr_map[i].pr_mflags; - if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant; + if ((flags & (MA_BREAK | MA_STACK | MA_PHYS + | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant; if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE)) goto irrelevant; /* The latter test is empirically useless in very old Irix */ @@ -748,6 +754,10 @@ void GC_register_dynamic_libraries() # define HAVE_REGISTER_MAIN_STATIC_DATA + /* The frame buffer testing code is dead in this version. */ + /* We leave it here temporarily in case the switch to just */ + /* testing for MEM_IMAGE sections causes un expected */ + /* problems. */ GC_bool GC_warn_fb = TRUE; /* Warn about traced likely */ /* graphics memory. */ GC_bool GC_disallow_ignore_fb = FALSE; @@ -762,25 +772,27 @@ void GC_register_dynamic_libraries() /* Should [start, start+len) be treated as a frame buffer */ /* and ignored? */ - /* Unfortunately, we currently have no real way to tell */ - /* automatically, and rely largely on user input. */ - /* FIXME: If we had more data on this phenomenon (e.g. */ - /* is start aligned to a MB multiple?) we should be able to */ - /* do better. */ + /* Unfortunately, we currently are not quite sure how to tell */ + /* this automatically, and rely largely on user input. */ + /* We expect that any mapping with type MEM_MAPPED (which */ + /* apparently excludes library data sections) can be safely */ + /* ignored. But we're too chicken to do that in this */ + /* version. */ /* Based on a very limited sample, it appears that: */ - /* - Frame buffer mappings appear as mappings of length */ - /* 2**n MB - 192K. (We guess the 192K can vary a bit.) */ - /* - Have a stating address at best 64K aligned. */ - /* I'd love more information about the mapping, since I */ - /* can't reproduce the problem. */ - static GC_bool is_frame_buffer(ptr_t start, size_t len) + /* - Frame buffer mappings appear as mappings of large */ + /* length, usually a bit less than a power of two. */ + /* - The definition of "a bit less" in the above cannot */ + /* be made more precise. */ + /* - Have a starting address at best 64K aligned. */ + /* - Have type == MEM_MAPPED. */ + static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp) { static GC_bool initialized = FALSE; # define MB (1024*1024) # define DEFAULT_FB_MB 15 # define MIN_FB_MB 3 - if (GC_disallow_ignore_fb) return FALSE; + if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE; if (!initialized) { char * ignore_fb_string = GETENV("GC_IGNORE_FB"); @@ -869,7 +881,11 @@ void GC_register_dynamic_libraries() && (protect == PAGE_EXECUTE_READWRITE || protect == PAGE_READWRITE) && !GC_is_heap_base(buf.AllocationBase) - && !is_frame_buffer(p, buf.RegionSize)) { + /* This used to check for + * !is_frame_buffer(p, buf.RegionSize, buf.Type) + * instead of just checking for MEM_IMAGE. + * If something breaks, change it back. */ + && buf.Type == MEM_IMAGE) { # ifdef DEBUG_VIRTUALQUERY GC_dump_meminfo(&buf); # endif @@ -1125,21 +1141,22 @@ static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) { static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) { unsigned long start,end,i; const struct section *sec; + if (GC_no_dls) return; for(i=0;isize == 0) continue; - start = slide + sec->addr; - end = start + sec->size; -# ifdef DARWIN_DEBUG - GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n", + if(sec == NULL || sec->size == 0) continue; + start = slide + sec->addr; + end = start + sec->size; +# ifdef DARWIN_DEBUG + GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n", start,end,sec->size,GC_dyld_name_for_hdr(hdr)); -# endif +# endif GC_add_roots((char*)start,(char*)end); - } -# ifdef DARWIN_DEBUG - GC_print_static_roots(); -# endif + } +# ifdef DARWIN_DEBUG + GC_print_static_roots(); +# endif } /* This should never be called by a thread holding the lock */ @@ -1152,15 +1169,15 @@ static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) { if(sec == NULL || sec->size == 0) continue; start = slide + sec->addr; end = start + sec->size; -# ifdef DARWIN_DEBUG +# ifdef DARWIN_DEBUG GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n", start,end,sec->size,GC_dyld_name_for_hdr(hdr)); # endif GC_remove_roots((char*)start,(char*)end); } -# ifdef DARWIN_DEBUG - GC_print_static_roots(); -# endif +# ifdef DARWIN_DEBUG + GC_print_static_roots(); +# endif } void GC_register_dynamic_libraries() { diff --git a/finalize.c b/finalize.c index e103228c..893f8259 100644 --- a/finalize.c +++ b/finalize.c @@ -807,24 +807,21 @@ void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0; static GC_word last_finalizer_notification = 0; -#ifdef KEEP_BACK_PTRS -void GC_generate_random_backtrace_no_gc(void); -#endif - void GC_notify_or_invoke_finalizers GC_PROTO((void)) { /* This is a convenient place to generate backtraces if appropriate, */ /* since that code is not callable with the allocation lock. */ -# ifdef KEEP_BACK_PTRS - if (GC_backtraces > 0) { - static word last_back_trace_gc_no = 3; /* Skip early ones. */ - long i; +# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) + static word last_back_trace_gc_no = 1; /* Skip first one. */ - LOCK(); - if (GC_gc_no > last_back_trace_gc_no) { + if (GC_gc_no > last_back_trace_gc_no) { + word i; + +# ifdef KEEP_BACK_PTRS + LOCK(); /* Stops when GC_gc_no wraps; that's OK. */ - last_back_trace_gc_no = (word)(-1); /* disable others. */ - for (i = 0; i < GC_backtraces; ++i) { + last_back_trace_gc_no = (word)(-1); /* disable others. */ + for (i = 0; i < GC_backtraces; ++i) { /* FIXME: This tolerates concurrent heap mutation, */ /* which may cause occasional mysterious results. */ /* We need to release the GC lock, since GC_print_callers */ @@ -832,10 +829,14 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void)) UNLOCK(); GC_generate_random_backtrace_no_gc(); LOCK(); - } - last_back_trace_gc_no = GC_gc_no; - } - UNLOCK(); + } + last_back_trace_gc_no = GC_gc_no; + UNLOCK(); +# endif +# ifdef MAKE_BACK_GRAPH + if (GC_print_back_height) + GC_print_back_graph_stats(); +# endif } # endif if (GC_finalize_now == 0) return; diff --git a/headers.c b/headers.c index 0aa51397..b7be1d84 100644 --- a/headers.c +++ b/headers.c @@ -206,7 +206,7 @@ register struct hblk * h; { hdr * result; - if (!get_index((word) h)) return(FALSE); + if (!get_index((word) h)) return(0); result = alloc_hdr(); SET_HDR(h, result); # ifdef USE_MUNMAP diff --git a/include/gc.h b/include/gc.h index 970c5b5b..84d5735a 100644 --- a/include/gc.h +++ b/include/gc.h @@ -32,7 +32,7 @@ # include "gc_config_macros.h" -# if defined(__STDC__) || defined(__cplusplus) +# if defined(__STDC__) || defined(__cplusplus) || defined(_AIX) # define GC_PROTO(args) args typedef void * GC_PTR; # define GC_CONST const @@ -207,7 +207,7 @@ GC_API GC_word GC_free_space_divisor; /* least N/GC_free_space_divisor bytes between */ /* collections, where N is the heap size plus */ /* a rough estimate of the root set size. */ - /* Initially, GC_free_space_divisor = 4. */ + /* Initially, GC_free_space_divisor = 3. */ /* Increasing its value will use less space */ /* but more collection time. Decreasing it */ /* will appreciably decrease collection time */ @@ -324,6 +324,9 @@ GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR)); /* the base of the user object. */ /* Return 0 if displaced_pointer doesn't point to within a valid */ /* object. */ +/* Note that a deallocated object in the garbage collected heap */ +/* may be considered valid, even if it has been deallocated with */ +/* GC_free. */ GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer)); /* Given a pointer to the base of an object, return its size in bytes. */ @@ -864,7 +867,7 @@ GC_API int GC_thread_is_registered GC_PROTO((void)); /* Safer assignment of a pointer to a nonstack location. */ #ifdef GC_DEBUG -# ifdef __STDC__ +# if defined(__STDC__) || defined(_AIX) # define GC_PTR_STORE(p, q) \ (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q)) # else @@ -955,7 +958,7 @@ extern void GC_thr_init(void); /* Needed for Solaris/X86 */ * no-op and the collector self-initializes. But a number of platforms * make that too hard. */ -#if defined(sparc) || defined(__sparc) +#if (defined(sparc) || defined(__sparc)) && defined(sun) /* * If you are planning on putting * the collector in a SunOS 5 dynamic library, you need to call GC_INIT() @@ -965,12 +968,32 @@ extern void GC_thr_init(void); /* Needed for Solaris/X86 */ # define GC_INIT() { extern end, etext; \ GC_noop(&end, &etext); } #else -# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX) +# if defined(__CYGWIN32__) || defined (_AIX) /* * Similarly gnu-win32 DLLs need explicit initialization from * the main program, as does AIX. */ -# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); } +# ifdef __CYGWIN32__ + extern int _data_start__[]; + extern int _data_end__[]; + extern int _bss_start__[]; + extern int _bss_end__[]; +# define GC_MAX(x,y) ((x) > (y) ? (x) : (y)) +# define GC_MIN(x,y) ((x) < (y) ? (x) : (y)) +# define GC_DATASTART ((GC_PTR) GC_MIN(_data_start__, _bss_start__)) +# define GC_DATAEND ((GC_PTR) GC_MAX(_data_end__, _bss_end__)) +# ifdef GC_DLL +# define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); } +# else +# define GC_INIT() +# endif +# endif +# if defined(_AIX) + extern int _data[], _end[]; +# define GC_DATASTART ((GC_PTR)((ulong)_data)) +# define GC_DATAEND ((GC_PTR)((ulong)_end)) +# define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); } +# endif # else # if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS) # define GC_INIT() { GC_init(); } diff --git a/include/gc_allocator.h b/include/gc_allocator.h index b0c188cd..200f181e 100644 --- a/include/gc_allocator.h +++ b/include/gc_allocator.h @@ -39,7 +39,13 @@ #define GC_ALLOCATOR_H -#include "gc.h" // For size_t +#include "gc.h" + +#if defined(__GNUC__) +# define GC_ATTR_UNUSED __attribute__((unused)) +#else +# define GC_ATTR_UNUSED +#endif /* First some helpers to allow us to dispatch on whether or not a type * is known to be pointerfree. @@ -122,7 +128,7 @@ public: } // __p is not permitted to be a null pointer. - void deallocate(pointer __p, size_type GC_n) + void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); } size_type max_size() const throw() @@ -198,7 +204,7 @@ public: } // __p is not permitted to be a null pointer. - void deallocate(pointer __p, size_type GC_n) + void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); } size_type max_size() const throw() diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h index d8d31141..4671864b 100644 --- a/include/gc_config_macros.h +++ b/include/gc_config_macros.h @@ -95,6 +95,10 @@ # define GC_DGUX386_THREADS # define GC_PTHREADS # endif +# if defined(_AIX) +# define GC_AIX_THREADS +# define GC_PTHREADS +# endif #endif /* GC_THREADS */ #if defined(GC_THREADS) && !defined(GC_PTHREADS) && \ diff --git a/include/gc_cpp.h b/include/gc_cpp.h index c4d8b50e..4f56f0d9 100644 --- a/include/gc_cpp.h +++ b/include/gc_cpp.h @@ -74,7 +74,7 @@ cycle, then that's considered a storage leak, and neither will be collectable. See the interface gc.h for low-level facilities for handling such cycles of objects with clean-up. -The collector cannot guarrantee that it will find all inaccessible +The collector cannot guarantee that it will find all inaccessible objects. In practice, it finds almost all of them. diff --git a/include/new_gc_alloc.h b/include/new_gc_alloc.h index f2219b77..7546638c 100644 --- a/include/new_gc_alloc.h +++ b/include/new_gc_alloc.h @@ -109,7 +109,7 @@ enum { GC_byte_alignment = 8 }; enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word }; inline void * &GC_obj_link(void * p) -{ return *(void **)p; } +{ return *reinterpret_cast(p); } // Compute a number of words >= n+1 bytes. // The +1 allows for pointers one past the end. @@ -228,7 +228,7 @@ class single_client_gc_alloc_template { } else { flh = GC_objfreelist_ptr + nwords; GC_obj_link(p) = *flh; - memset((char *)p + GC_bytes_per_word, 0, + memset(reinterpret_cast(p) + GC_bytes_per_word, 0, GC_bytes_per_word * (nwords - 1)); *flh = p; GC_aux::GC_mem_recently_freed += nwords; @@ -352,9 +352,9 @@ class simple_alloc { \ public: \ static T *allocate(size_t n) \ { return 0 == n? 0 : \ - (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \ + reinterpret_cast(alloc::ptr_free_allocate(n * sizeof (T))); } \ static T *allocate(void) \ - { return (T*) alloc::ptr_free_allocate(sizeof (T)); } \ + { return reinterpret_cast(alloc::ptr_free_allocate(sizeof (T))); } \ static void deallocate(T *p, size_t n) \ { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \ static void deallocate(T *p) \ diff --git a/include/private/gc_hdrs.h b/include/private/gc_hdrs.h index 96749ab1..70dfefe8 100644 --- a/include/private/gc_hdrs.h +++ b/include/private/gc_hdrs.h @@ -108,7 +108,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */ /* Analogous to GET_HDR, except that in the case of large objects, it */ /* Returns the header for the object beginning, and updates p. */ -/* Returns &GC_bad_header instead of 0. All of this saves a branch */ +/* Returns GC_invalid_header instead of 0. All of this saves a branch */ /* in the fast path. */ # define HC_GET_HDR(p, hhdr, source) \ { \ diff --git a/include/private/gc_locks.h b/include/private/gc_locks.h index 34e3daa4..d1ccf0ed 100644 --- a/include/private/gc_locks.h +++ b/include/private/gc_locks.h @@ -155,6 +155,25 @@ # define GC_TEST_AND_SET_DEFINED # endif # if defined(POWERPC) +# if CPP_WORDSZ == 64 + inline static int GC_test_and_set(volatile unsigned int *addr) { + unsigned long oldval; + unsigned long temp = 1; /* locked value */ + + __asm__ __volatile__( + "1:\tldarx %0,0,%3\n" /* load and reserve */ + "\tcmpdi %0, 0\n" /* if load is */ + "\tbne 2f\n" /* non-zero, return already set */ + "\tstdcx. %2,0,%1\n" /* else store conditional */ + "\tbne- 1b\n" /* retry if lost reservation */ + "\tsync\n" /* import barrier */ + "2:\t\n" /* oldval is zero if we set */ + : "=&r"(oldval), "=p"(addr) + : "r"(temp), "1"(addr) + : "cr0","memory"); + return (int)oldval; + } +# else inline static int GC_test_and_set(volatile unsigned int *addr) { int oldval; int temp = 1; /* locked value */ @@ -172,12 +191,13 @@ : "cr0","memory"); return oldval; } -# define GC_TEST_AND_SET_DEFINED - inline static void GC_clear(volatile unsigned int *addr) { - __asm__ __volatile__("eieio" : : : "memory"); - *(addr) = 0; - } -# define GC_CLEAR_DEFINED +# endif +# define GC_TEST_AND_SET_DEFINED + inline static void GC_clear(volatile unsigned int *addr) { + __asm__ __volatile__("lwsync" : : : "memory"); + *(addr) = 0; + } +# define GC_CLEAR_DEFINED # endif # if defined(ALPHA) inline static int GC_test_and_set(volatile unsigned int * addr) @@ -231,6 +251,30 @@ } # define GC_TEST_AND_SET_DEFINED # endif /* ARM32 */ +# ifdef CRIS + inline static int GC_test_and_set(volatile unsigned int *addr) { + /* Ripped from linuxthreads/sysdeps/cris/pt-machine.h. */ + /* Included with Hans-Peter Nilsson's permission. */ + register unsigned long int ret; + + /* Note the use of a dummy output of *addr to expose the write. + * The memory barrier is to stop *other* writes being moved past + * this code. + */ + __asm__ __volatile__("clearf\n" + "0:\n\t" + "movu.b [%2],%0\n\t" + "ax\n\t" + "move.b %3,[%2]\n\t" + "bwf 0b\n\t" + "clearf" + : "=&r" (ret), "=m" (*addr) + : "r" (addr), "r" ((int) 1), "m" (*addr) + : "memory"); + return ret; + } +# define GC_TEST_AND_SET_DEFINED +# endif /* CRIS */ # ifdef S390 inline static int GC_test_and_set(volatile unsigned int *addr) { int ret; @@ -274,6 +318,8 @@ # define GC_test_and_set(addr) test_and_set((void *)addr,1) # endif # else +# include +# include # define GC_test_and_set(addr) __test_and_set32((void *)addr,1) # define GC_clear(addr) __lock_release(addr); # define GC_CLEAR_DEFINED @@ -346,7 +392,7 @@ # endif # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ - && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) + && !defined(GC_WIN32_THREADS) # define NO_THREAD (pthread_t)(-1) # include # if defined(PARALLEL_MARK) @@ -393,6 +439,29 @@ # if defined(POWERPC) # if !defined(GENERIC_COMPARE_AND_SWAP) +# if CPP_WORDSZ == 64 + /* Returns TRUE if the comparison succeeded. */ + inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, + GC_word old, GC_word new_val) + { + unsigned long result, dummy; + __asm__ __volatile__( + "1:\tldarx %0,0,%5\n" + "\tcmpd %0,%4\n" + "\tbne 2f\n" + "\tstdcx. %3,0,%2\n" + "\tbne- 1b\n" + "\tsync\n" + "\tli %1, 1\n" + "\tb 3f\n" + "2:\tli %1, 0\n" + "3:\t\n" + : "=&r" (dummy), "=r" (result), "=p" (addr) + : "r" (new_val), "r" (old), "2"(addr) + : "cr0","memory"); + return (GC_bool) result; + } +# else /* Returns TRUE if the comparison succeeded. */ inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, GC_word old, GC_word new_val) @@ -414,6 +483,7 @@ : "cr0","memory"); return (GC_bool) result; } +# endif # endif /* !GENERIC_COMPARE_AND_SWAP */ inline static void GC_memory_barrier() { @@ -427,9 +497,18 @@ GC_word old, GC_word new_val) { unsigned long oldval; - __asm__ __volatile__("mov ar.ccv=%4 ;; cmpxchg8.rel %0=%1,%2,ar.ccv" - : "=r"(oldval), "=m"(*addr) - : "r"(new_val), "1"(*addr), "r"(old) : "memory"); +# if CPP_WORDSZ == 32 + __asm__ __volatile__( + "addp4 %0=0,%1\n" + "mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%0],%2,ar.ccv" + : "=&r"(oldval) + : "r"(addr), "r"(new_val), "r"(old) : "memory"); +# else + __asm__ __volatile__( + "mov ar.ccv=%3 ;; cmpxchg8.rel %0=[%1],%2,ar.ccv" + : "=r"(oldval) + : "r"(addr), "r"(new_val), "r"(old) : "memory"); +# endif return (oldval == old); } # endif /* !GENERIC_COMPARE_AND_SWAP */ @@ -593,33 +672,6 @@ extern pthread_t GC_mark_lock_holder; # endif # endif /* GC_PTHREADS with linux_threads.c implementation */ -# if defined(GC_IRIX_THREADS) -# include - /* This probably should never be included, but I can't test */ - /* on Irix anymore. */ -# include - - extern volatile unsigned int GC_allocate_lock; - /* This is not a mutex because mutexes that obey the (optional) */ - /* POSIX scheduling rules are subject to convoys in high contention */ - /* applications. This is basically a spin lock. */ - extern pthread_t GC_lock_holder; - extern void GC_lock(void); - /* Allocation lock holder. Only set if acquired by client through */ - /* GC_call_with_alloc_lock. */ -# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self() -# define NO_THREAD (pthread_t)(-1) -# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD -# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) -# define LOCK() { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } -# define UNLOCK() GC_clear(&GC_allocate_lock); - extern VOLATILE GC_bool GC_collecting; -# define ENTER_GC() \ - { \ - GC_collecting = 1; \ - } -# define EXIT_GC() GC_collecting = 0; -# endif /* GC_IRIX_THREADS */ # if defined(GC_WIN32_THREADS) # if defined(GC_PTHREADS) # include diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 3d7b4843..00c3187c 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -258,17 +258,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ /* */ /*********************************/ -#ifdef SAVE_CALL_CHAIN - -/* Fill in the pc and argument information for up to NFRAMES of my */ -/* callers. Ignore my frame and my callers frame. */ -struct callinfo; -void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES])); - -void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); - -#endif - #ifdef NEED_CALLINFO struct callinfo { word ci_pc; /* Caller, not callee, pc */ @@ -282,6 +271,16 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); }; #endif +#ifdef SAVE_CALL_CHAIN + +/* Fill in the pc and argument information for up to NFRAMES of my */ +/* callers. Ignore my frame and my callers frame. */ +void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES])); + +void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); + +#endif + /*********************************/ /* */ @@ -550,7 +549,7 @@ extern GC_warn_proc GC_current_warn_proc; #define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2) #define MAXOBJBYTES ((word)CPP_MAXOBJBYTES) -#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_HBLKSIZE/2) +#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_MAXOBJBYTES) #define MAXOBJSZ ((word)CPP_MAXOBJSZ) # define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE) @@ -938,11 +937,11 @@ struct _GC_arrays { char _valid_offsets[VALID_OFFSET_SZ]; /* GC_valid_offsets[i] == TRUE ==> i */ /* is registered as a displacement. */ -# define OFFSET_VALID(displ) \ - (GC_all_interior_pointers || GC_valid_offsets[displ]) char _modws_valid_offsets[sizeof(word)]; /* GC_valid_offsets[i] ==> */ /* GC_modws_valid_offsets[i%sizeof(word)] */ +# define OFFSET_VALID(displ) \ + (GC_all_interior_pointers || GC_valid_offsets[displ]) # ifdef STUBBORN_ALLOC page_hash_table _changed_pages; /* Stubborn object pages that were changes since last call to */ @@ -1632,6 +1631,10 @@ ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k)); /* are ignored. */ ptr_t GC_generic_malloc_inner GC_PROTO((word lb, int k)); /* Ditto, but I already hold lock, etc. */ +ptr_t GC_generic_malloc_words_small_inner GC_PROTO((word lw, int k)); + /* Analogous to the above, but assumes */ + /* a small object size, and bypasses */ + /* MERGE_SIZES mechanism. */ ptr_t GC_generic_malloc_words_small GC_PROTO((size_t lw, int k)); /* As above, but size in units of words */ /* Bypasses MERGE_SIZES. Assumes */ @@ -1725,6 +1728,13 @@ extern GC_bool GC_print_stats; /* Produce at least some logging output */ #ifdef KEEP_BACK_PTRS extern long GC_backtraces; + void GC_generate_random_backtrace_no_gc(void); +#endif + +extern GC_bool GC_print_back_height; + +#ifdef MAKE_BACK_GRAPH + void GC_print_back_graph_stats(void); #endif /* Macros used for collector internal allocation. */ diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index 2bbd38c4..4aeb31d8 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -55,7 +55,7 @@ # endif /* And one for FreeBSD: */ -# if defined(__FreeBSD__) +# if defined(__FreeBSD__) && !defined(FREEBSD) # define FREEBSD # endif @@ -97,6 +97,10 @@ # define ARM32 # define mach_type_known # endif +# if defined(NETBSD) && defined(__sh__) +# define SH +# define mach_type_known +# endif # if defined(vax) # define VAX # ifdef ultrix @@ -115,8 +119,8 @@ # if defined(nec_ews) || defined(_nec_ews) # define EWS4800 # endif -# if !defined(LINUX) && !defined(EWS4800) -# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__) +# if !defined(LINUX) && !defined(EWS4800) && !defined(NETBSD) +# if defined(ultrix) || defined(__ultrix) # define ULTRIX # else # if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) \ @@ -170,7 +174,7 @@ # define mach_type_known # endif # if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \ - && !defined(__OpenBSD__) && !(__NetBSD__) + && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__) # define SPARC # define DRSNX # define mach_type_known @@ -201,14 +205,16 @@ # if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \ || defined(hppa) || defined(__hppa__) # define HP_PA -# ifndef LINUX +# if !defined(LINUX) && !defined(HPUX) # define HPUX # endif # define mach_type_known # endif # if defined(__ia64) && defined(_HPUX_SOURCE) # define IA64 -# define HPUX +# ifndef HPUX +# define HPUX +# endif # define mach_type_known # endif # if defined(__BEOS__) && defined(_X86_) @@ -232,7 +238,18 @@ # define ARM32 # define mach_type_known # endif -# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__)) +# if defined(LINUX) && defined(__cris__) +# ifndef CRIS +# define CRIS +# endif +# define mach_type_known +# endif +# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || \ + defined(powerpc64) || defined(__powerpc64__)) +# define POWERPC +# define mach_type_known +# endif +# if defined(FREEBSD) && (defined(powerpc) || defined(__powerpc__)) # define POWERPC # define mach_type_known # endif @@ -252,6 +269,10 @@ # define SH # define mach_type_known # endif +# if defined(LINUX) && defined(__m32r__) +# define M32R +# define mach_type_known +# endif # if defined(__alpha) || defined(__alpha__) # define ALPHA # if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) && !defined(FREEBSD) @@ -276,16 +297,15 @@ # define MACOS # define mach_type_known # endif -# if defined(macosx) || \ - defined(__APPLE__) && defined(__MACH__) && defined(__ppc__) -# define DARWIN +# if defined(macosx) || (defined(__APPLE__) && defined(__MACH__)) +# define DARWIN +# if defined(__ppc__) || defined(__ppc64__) # define POWERPC # define mach_type_known -# endif -# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__) -# define DARWIN +# elif defined(__i386__) # define I386 --> Not really supported, but at least we recognize it. +# endif # endif # if defined(NeXT) && defined(mc68000) # define M68K @@ -314,6 +334,10 @@ # define X86_64 # define mach_type_known # endif +# if defined(FREEBSD) && defined(__sparc__) +# define SPARC +# define mach_type_known +#endif # if defined(bsdi) && (defined(i386) || defined(__i386__)) # define I386 # define BSDI @@ -474,17 +498,22 @@ /* POWERPC ==> IBM/Apple PowerPC */ /* (MACOS(<=9),DARWIN(incl.MACOSX),*/ /* LINUX, NETBSD, NOSYS variants) */ + /* Handles 32 and 64-bit variants. */ + /* AIX should be handled here, but */ + /* that's called an RS6000. */ + /* CRIS ==> Axis Etrax */ + /* M32R ==> Renesas M32R */ /* * For each architecture and OS, the following need to be defined: * - * CPP_WORD_SZ is a simple integer constant representing the word size. + * CPP_WORDSZ 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. + * We also assume CPP_WORDSZ is either 32 or 64. * (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. Default is 32.) + * 32 bit pointers should use CPP_WORDSZ of 32, not 64. Default is 32.) * * MACH_TYPE is a string representation of the machine type. * OS_TYPE is analogous for the OS. @@ -505,6 +534,9 @@ * DATAEND, if not `end' where `end' is defined as ``extern int end[];''. * RTH suggests gaining access to linker script synth'd values with * this idiom instead of `&end' where `end' is defined as ``extern int end;'' . + * Otherwise, ``GCC will assume these are in .sdata/.sbss'' and it will, e.g., + * cause failures on alpha*-*-* with ``-msmall-data or -fpic'' or mips-*-* + * without any special options. * * ALIGN_DOUBLE of GC_malloc should return blocks aligned to twice * the pointer size. @@ -598,7 +630,8 @@ */ # if defined(__GNUC__) && ((__GNUC__ >= 3) || \ (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \ - && !defined(__INTEL_COMPILER) + && !defined(__INTEL_COMPILER) \ + && !defined(__PATHCC__) # define HAVE_BUILTIN_UNWIND_INIT # endif @@ -722,7 +755,7 @@ # endif # endif -# ifdef POWERPC +# if defined(POWERPC) # define MACH_TYPE "POWERPC" # ifdef MACOS # define ALIGNMENT 2 /* Still necessary? Could it be 4? */ @@ -735,12 +768,14 @@ # define DATAEND /* not needed */ # endif # ifdef LINUX -# if (defined (powerpc64) || defined(__powerpc64__)) +# if defined(__powerpc64__) # define ALIGNMENT 8 # define CPP_WORDSZ 64 +# ifndef HBLKSIZE +# define HBLKSIZE 4096 +# endif # else -# define ALIGNMENT 4 /* Guess. Can someone verify? */ - /* This was 2, but that didn't sound right. */ +# define ALIGNMENT 4 # endif # define OS_TYPE "LINUX" /* HEURISTIC1 has been reliably reported to fail for a 32-bit */ @@ -752,7 +787,12 @@ # define DATAEND (_end) # endif # ifdef DARWIN -# define ALIGNMENT 4 +# ifdef __ppc64__ +# define ALIGNMENT 8 +# define CPP_WORDSZ 64 +# else +# define ALIGNMENT 4 +# endif # define OS_TYPE "DARWIN" # define DYNAMIC_LOADING /* XXX: see get_end(3), get_etext() and get_end() should not be used. @@ -764,8 +804,10 @@ # define USE_MMAP_ANON # define USE_ASM_PUSH_REGS /* This is potentially buggy. It needs more testing. See the comments in - os_dep.c */ -# define MPROTECT_VDB + os_dep.c. It relies on threads to track writes. */ +# ifdef GC_DARWIN_THREADS +/* # define MPROTECT_VDB -- diabled for now. May work for some apps. */ +# endif # include # define GETPAGESIZE() getpagesize() # if defined(USE_PPC_PREFETCH) && defined(__GNUC__) @@ -779,6 +821,22 @@ should be looked into some more */ # define NO_PTHREAD_TRYLOCK # endif +# ifdef FREEBSD +# define ALIGNMENT 4 +# define OS_TYPE "FREEBSD" +# ifndef GC_FREEBSD_THREADS +# define MPROTECT_VDB +# endif +# define SIG_SUSPEND SIGUSR1 +# define SIG_THR_RESTART SIGUSR2 +# define FREEBSD_STACKBOTTOM +# ifdef __ELF__ +# define DYNAMIC_LOADING +# endif + extern char etext[]; + extern char * GC_FreeBSDGetDataStart(); +# define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext) +# endif # ifdef NETBSD # define ALIGNMENT 4 # define OS_TYPE "NETBSD" @@ -918,12 +976,10 @@ extern ptr_t GC_SysVGetDataStart(); # ifdef __arch64__ # define DATASTART GC_SysVGetDataStart(0x100000, _etext) - /* libc_stack_end is not set reliably for sparc64 */ -# define STACKBOTTOM ((ptr_t) 0x80000000000ULL) # else # define DATASTART GC_SysVGetDataStart(0x10000, _etext) -# define LINUX_STACKBOTTOM # endif +# define LINUX_STACKBOTTOM # endif # ifdef OPENBSD # define OS_TYPE "OPENBSD" @@ -942,6 +998,23 @@ # define DATASTART ((ptr_t)(etext)) # endif # endif +# ifdef FREEBSD +# define OS_TYPE "FREEBSD" +# define SIG_SUSPEND SIGUSR1 +# define SIG_THR_RESTART SIGUSR2 +# define FREEBSD_STACKBOTTOM +# ifdef __ELF__ +# define DYNAMIC_LOADING +# endif + extern char etext[]; + extern char edata[]; + extern char end[]; +# define NEED_FIND_LIMIT +# define DATASTART ((ptr_t)(&etext)) +# define DATAEND (GC_find_limit (DATASTART, TRUE)) +# define DATASTART2 ((ptr_t)(&edata)) +# define DATAEND2 ((ptr_t)(&end)) +# endif # endif # ifdef I386 @@ -1126,26 +1199,8 @@ # endif # ifdef CYGWIN32 # define OS_TYPE "CYGWIN32" - extern int _data_start__[]; - extern int _data_end__[]; - extern int _bss_start__[]; - extern int _bss_end__[]; - /* For binutils 2.9.1, we have */ - /* DATASTART = _data_start__ */ - /* DATAEND = _bss_end__ */ - /* whereas for some earlier versions it was */ - /* DATASTART = _bss_start__ */ - /* DATAEND = _data_end__ */ - /* To get it right for both, we take the */ - /* minumum/maximum of the two. */ -# ifndef MAX -# define MAX(x,y) ((x) > (y) ? (x) : (y)) -# endif -# ifndef MIN -# define MIN(x,y) ((x) < (y) ? (x) : (y)) -# endif -# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__)) -# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__)) +# define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */ +# define DATAEND ((ptr_t)GC_DATAEND) # undef STACK_GRAN # define STACK_GRAN 0x10000 # define HEURISTIC1 @@ -1356,8 +1411,6 @@ # define DATAEND /* not needed */ # endif # if defined(NETBSD) - /* This also checked for __MIPSEL__ . Why? NETBSD recognition */ - /* should be handled at the top of the file. */ # define ALIGNMENT 4 # define OS_TYPE "NETBSD" # define HEURISTIC2 @@ -1391,6 +1444,8 @@ # define CPP_WORDSZ 32 # define STACKBOTTOM ((ptr_t)((ulong)&errno)) # endif +# define USE_MMAP +# define USE_MMAP_ANON /* From AIX linker man page: _text Specifies the first location of the program. _etext Specifies the first location after the program. @@ -1547,7 +1602,7 @@ # endif # ifdef LINUX # define OS_TYPE "LINUX" -# define STACKBOTTOM ((ptr_t) 0x120000000) +# define LINUX_STACKBOTTOM # ifdef __ELF__ # define SEARCH_FOR_DATA_START # define DYNAMIC_LOADING @@ -1698,7 +1753,7 @@ # define USE_GENERIC_PUSH_REGS # ifdef UTS4 # define OS_TYPE "UTS4" - extern int etext[]; + extern int etext[]; extern int _etext[]; extern int _end[]; extern ptr_t GC_SysVGetDataStart(); @@ -1712,18 +1767,20 @@ # define MACH_TYPE "S390" # define USE_GENERIC_PUSH_REGS # ifndef __s390x__ -# define ALIGNMENT 4 -# define CPP_WORDSZ 32 +# define ALIGNMENT 4 +# define CPP_WORDSZ 32 # else -# define ALIGNMENT 8 -# define CPP_WORDSZ 64 -# define HBLKSIZE 4096 +# define ALIGNMENT 8 +# define CPP_WORDSZ 64 +# endif +# ifndef HBLKSIZE +# define HBLKSIZE 4096 # endif # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM # define DYNAMIC_LOADING - extern int __data_start[]; + extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) extern int _end[]; # define DATAEND (_end) @@ -1800,6 +1857,19 @@ # endif #endif +# ifdef CRIS +# define MACH_TYPE "CRIS" +# define CPP_WORDSZ 32 +# define ALIGNMENT 1 +# define OS_TYPE "LINUX" +# define DYNAMIC_LOADING +# define LINUX_STACKBOTTOM +# define USE_GENERIC_PUSH_REGS +# define SEARCH_FOR_DATA_START + extern int _end[]; +# define DATAEND (_end) +# endif + # ifdef SH # define MACH_TYPE "SH" # define ALIGNMENT 4 @@ -1809,13 +1879,20 @@ # endif # ifdef LINUX # define OS_TYPE "LINUX" -# define STACKBOTTOM ((ptr_t) 0x7c000000) +# define LINUX_STACKBOTTOM # define USE_GENERIC_PUSH_REGS # define DYNAMIC_LOADING # define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND (_end) # endif +# ifdef NETBSD +# define OS_TYPE "NETBSD" +# define HEURISTIC2 +# define DATASTART GC_data_start +# define USE_GENERIC_PUSH_REGS +# define DYNAMIC_LOADING +# endif # endif # ifdef SH4 @@ -1825,6 +1902,23 @@ # define DATAEND /* not needed */ # endif +# ifdef M32R +# define CPP_WORDSZ 32 +# define MACH_TYPE "M32R" +# define ALIGNMENT 4 +# ifdef LINUX +# define OS_TYPE "LINUX" +# define LINUX_STACKBOTTOM +# undef STACK_GRAN +# define STACK_GRAN 0x10000000 +# define USE_GENERIC_PUSH_REGS +# define DYNAMIC_LOADING +# define SEARCH_FOR_DATA_START + extern int _end[]; +# define DATAEND (_end) +# endif +# endif + # ifdef X86_64 # define MACH_TYPE "X86_64" # define ALIGNMENT 8 @@ -2050,8 +2144,9 @@ # define THREADS # endif -# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \ - || defined(LINT) || defined(MSWINCE) || defined(ARM32) \ +# if defined(HP_PA) || defined(M88K) \ + || defined(POWERPC) && !defined(DARWIN) \ + || defined(LINT) || defined(MSWINCE) || defined(ARM32) || defined(CRIS) \ || (defined(I386) && defined(__LCC__)) /* Use setjmp based hack to mark from callee-save registers. */ /* The define should move to the individual platform */ @@ -2192,7 +2287,7 @@ # else # if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC) extern void *GC_amiga_get_mem(size_t size); - define GET_MEM(bytes) HBLKPTR((size_t) \ +# define GET_MEM(bytes) HBLKPTR((size_t) \ GC_amiga_get_mem((size_t)bytes + GC_page_size) \ + GC_page_size-1) # else @@ -2208,4 +2303,10 @@ #endif /* GC_PRIVATE_H */ +#if defined(_AIX) && !defined(__GNUC__) && !defined(__STDC__) + /* IBMs xlc compiler doesn't appear to follow the convention of */ + /* defining __STDC__ to be zero in extended mode. */ +# define __STDC__ 0 +#endif + # endif /* GCCONFIG_H */ diff --git a/include/private/pthread_support.h b/include/private/pthread_support.h index 8a3168da..c2c48c22 100644 --- a/include/private/pthread_support.h +++ b/include/private/pthread_support.h @@ -4,7 +4,7 @@ # include "private/gc_priv.h" # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ - && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) + && !defined(GC_WIN32_THREADS) #if defined(GC_DARWIN_THREADS) # include "private/darwin_stop_world.h" diff --git a/mach_dep.c b/mach_dep.c index 327e11ca..ba1e0b6f 100644 --- a/mach_dep.c +++ b/mach_dep.c @@ -27,6 +27,10 @@ # endif # endif +#if defined(RS6000) || defined(POWERPC) +# include +#endif + #if defined(__MWERKS__) && !defined(POWERPC) asm static void PushMacRegisters() @@ -400,64 +404,87 @@ void GC_push_regs() } #endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */ +void GC_with_callee_saves_pushed(fn, arg) +void (*fn)(); +ptr_t arg; +{ + word dummy; + +# if defined(USE_GENERIC_PUSH_REGS) +# ifdef HAVE_BUILTIN_UNWIND_INIT + /* This was suggested by Richard Henderson as the way to */ + /* force callee-save registers and register windows onto */ + /* the stack. */ + __builtin_unwind_init(); +# else /* !HAVE_BUILTIN_UNWIND_INIT */ +# if defined(RS6000) || defined(POWERPC) + /* FIXME: RS6000 means AIX. */ + /* This should probably be used in all Posix/non-gcc */ + /* settings. We defer that change to minimize risk. */ + ucontext_t ctxt; + getcontext(&ctxt); +# else + /* Generic code */ + /* The idea is due to Parag Patel at HP. */ + /* We're not sure whether he would like */ + /* to be he acknowledged for it or not. */ + jmp_buf regs; + register word * i = (word *) regs; + register ptr_t lim = (ptr_t)(regs) + (sizeof regs); + + /* Setjmp doesn't always clear all of the buffer. */ + /* That tends to preserve garbage. Clear it. */ + for (; (char *)i < lim; i++) { + *i = 0; + } +# if defined(MSWIN32) || defined(MSWINCE) \ + || defined(UTS4) || defined(LINUX) || defined(EWS4800) + (void) setjmp(regs); +# else + (void) _setjmp(regs); + /* We don't want to mess with signals. According to */ + /* SUSV3, setjmp() may or may not save signal mask. */ + /* _setjmp won't, but is less portable. */ +# endif +# endif /* !AIX ... */ +# endif /* !HAVE_BUILTIN_UNWIND_INIT */ +# else +# if defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */ + /* We may still need this to save thread contexts. */ + ucontext_t ctxt; + getcontext(&ctxt); +# else /* Shouldn't be needed */ + ABORT("Unexpected call to GC_with_callee_saves_pushed"); +# endif +# endif +# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \ + || defined(IA64) + /* On a register window machine, we need to save register */ + /* contents on the stack for this to work. The setjmp */ + /* is probably not needed on SPARC, since pointers are */ + /* only stored in windowed or scratch registers. It is */ + /* needed on IA64, since some non-windowed registers are */ + /* preserved. */ + { + GC_save_regs_ret_val = GC_save_regs_in_stack(); + /* On IA64 gcc, could use __builtin_ia64_flushrs() and */ + /* __builtin_ia64_flushrs(). The latter will be done */ + /* implicitly by __builtin_unwind_init() for gcc3.0.1 */ + /* and later. */ + } +# endif + fn(arg); + /* Strongly discourage the compiler from treating the above */ + /* as a tail-call, since that would pop the register */ + /* contents before we get a chance to look at them. */ + GC_noop1((word)(&dummy)); +} + #if defined(USE_GENERIC_PUSH_REGS) void GC_generic_push_regs(cold_gc_frame) ptr_t cold_gc_frame; { - { - word dummy; - -# ifdef HAVE_BUILTIN_UNWIND_INIT - /* This was suggested by Richard Henderson as the way to */ - /* force callee-save registers and register windows onto */ - /* the stack. */ - __builtin_unwind_init(); -# else /* !HAVE_BUILTIN_UNWIND_INIT */ - /* Generic code */ - /* The idea is due to Parag Patel at HP. */ - /* We're not sure whether he would like */ - /* to be he acknowledged for it or not. */ - jmp_buf regs; - register word * i = (word *) regs; - register ptr_t lim = (ptr_t)(regs) + (sizeof regs); - - /* Setjmp doesn't always clear all of the buffer. */ - /* That tends to preserve garbage. Clear it. */ - for (; (char *)i < lim; i++) { - *i = 0; - } -# if defined(POWERPC) || defined(MSWIN32) || defined(MSWINCE) \ - || defined(UTS4) || defined(LINUX) || defined(EWS4800) - (void) setjmp(regs); -# else - (void) _setjmp(regs); - /* We don't want to mess with signals. According to */ - /* SUSV3, setjmp() may or may not save signal mask. */ - /* _setjmp won't, but is less portable. */ -# endif -# endif /* !HAVE_BUILTIN_UNWIND_INIT */ -# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \ - || defined(IA64) - /* On a register window machine, we need to save register */ - /* contents on the stack for this to work. The setjmp */ - /* is probably not needed on SPARC, since pointers are */ - /* only stored in windowed or scratch registers. It is */ - /* needed on IA64, since some non-windowed registers are */ - /* preserved. */ - { - GC_save_regs_ret_val = GC_save_regs_in_stack(); - /* On IA64 gcc, could use __builtin_ia64_flushrs() and */ - /* __builtin_ia64_flushrs(). The latter will be done */ - /* implicitly by __builtin_unwind_init() for gcc3.0.1 */ - /* and later. */ - } -# endif - GC_push_current_stack(cold_gc_frame); - /* Strongly discourage the compiler from treating the above */ - /* as a tail-call, since that would pop the register */ - /* contents before we get a chance to look at them. */ - GC_noop1((word)(&dummy)); - } + GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame); } #endif /* USE_GENERIC_PUSH_REGS */ @@ -465,7 +492,7 @@ ptr_t cold_gc_frame; /* the stack. Return sp. */ # ifdef SPARC asm(" .seg \"text\""); -# if defined(SVR4) || defined(NETBSD) +# if defined(SVR4) || defined(NETBSD) || defined(FREEBSD) asm(" .globl GC_save_regs_in_stack"); asm("GC_save_regs_in_stack:"); asm(" .type GC_save_regs_in_stack,#function"); diff --git a/mallocx.c b/mallocx.c index d45f21e8..5ad593da 100644 --- a/mallocx.c +++ b/mallocx.c @@ -172,7 +172,8 @@ int obj_kind; # endif /* REDIRECT_REALLOC */ -/* The same thing, except caller does not hold allocation lock. */ +/* Allocate memory such that only pointers to near the */ +/* beginning of the object are considered. */ /* We avoid holding allocation lock while we clear memory. */ ptr_t GC_generic_malloc_ignore_off_page(lb, k) register size_t lb; diff --git a/mark.c b/mark.c index dd1fbd5f..09dfe92a 100644 --- a/mark.c +++ b/mark.c @@ -858,9 +858,9 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local, ++top; top -> mse_descr = descr; top -> mse_start = p -> mse_start; - GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH || - top -> mse_descr < GC_greatest_plausible_heap_addr - - GC_least_plausible_heap_addr); + GC_ASSERT( (top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH || + top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr + - (ptr_t)GC_least_plausible_heap_addr); /* If this is a big object, count it as */ /* size/256 + 1 objects. */ ++i; @@ -1450,8 +1450,8 @@ void GC_push_all_eager(bottom, top) ptr_t bottom; ptr_t top; { - word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1)); - word * t = (word *)(((long) top) & ~(ALIGNMENT-1)); + word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1)); + word * t = (word *)(((word) top) & ~(ALIGNMENT-1)); register word *p; register word q; register word *lim; @@ -1739,7 +1739,7 @@ register hdr * hhdr; { register int sz = hhdr -> hb_sz; - if (sz < MAXOBJSZ) { + if (sz <= MAXOBJSZ) { return(GC_page_was_dirty(h)); } else { register ptr_t p = (ptr_t)h; diff --git a/mark_rts.c b/mark_rts.c index 55eb5d54..4074879a 100644 --- a/mark_rts.c +++ b/mark_rts.c @@ -368,8 +368,11 @@ ptr_t p; ptr_t GC_approx_sp() { - word dummy; + VOLATILE word dummy; + dummy = 42; /* Force stack to grow if necessary. Otherwise the */ + /* later accesses might cause the kernel to think we're */ + /* doing something wrong. */ # ifdef _MSC_VER # pragma warning(disable:4172) # endif diff --git a/misc.c b/misc.c index 5b10feeb..52567b7d 100644 --- a/misc.c +++ b/misc.c @@ -246,7 +246,7 @@ void *arg2; byte_sz = WORDS_TO_BYTES(word_sz); if (GC_all_interior_pointers) { /* We need one extra byte; don't fill in GC_size_map[byte_sz] */ - byte_sz--; + byte_sz -= EXTRA_BYTES; } for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz; @@ -804,7 +804,10 @@ void GC_init_inner() void GC_enable_incremental GC_PROTO(()) { -# if !defined(SMALL_CONFIG) +# if !defined(SMALL_CONFIG) && !defined(KEEP_BACK_PTRS) + /* If we are keeping back pointers, the GC itself dirties all */ + /* pages on which objects have been marked, making */ + /* incremental GC pointless. */ if (!GC_find_leak) { DCL_LOCK_STATE; diff --git a/os_dep.c b/os_dep.c index e224af79..d7beb58d 100644 --- a/os_dep.c +++ b/os_dep.c @@ -60,6 +60,10 @@ # include # endif +#if defined(LINUX) || defined(LINUX_STACKBOTTOM) +# include +#endif + /* Blatantly OS dependent routines, except for those that are related */ /* to dynamic loading. */ @@ -80,7 +84,7 @@ # define NEED_FIND_LIMIT # endif -#if defined(FREEBSD) && defined(I386) +#if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__)) # include # if !defined(PCR) # define NEED_FIND_LIMIT @@ -250,30 +254,11 @@ word GC_apply_to_maps(word (*fn)(char *)) // XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n // ^^^^^^^^ ^^^^^^^^ ^^^^ ^^ // start end prot maj_dev -// 0 9 18 32 -// -// For 64 bit ABIs: -// 0 17 34 56 // -// The parser is called with a pointer to the entry and the return value -// is either NULL or is advanced to the next entry(the byte after the -// trailing '\n'.) +// Note that since about auguat 2003 kernels, the columns no longer have +// fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets +// anywhere, which is safer anyway. // -#if CPP_WORDSZ == 32 -# define OFFSET_MAP_START 0 -# define OFFSET_MAP_END 9 -# define OFFSET_MAP_PROT 18 -# define OFFSET_MAP_MAJDEV 32 -# define ADDR_WIDTH 8 -#endif - -#if CPP_WORDSZ == 64 -# define OFFSET_MAP_START 0 -# define OFFSET_MAP_END 17 -# define OFFSET_MAP_PROT 34 -# define OFFSET_MAP_MAJDEV 56 -# define ADDR_WIDTH 16 -#endif /* * Assign various fields of the first line in buf_ptr to *start, *end, @@ -282,37 +267,46 @@ word GC_apply_to_maps(word (*fn)(char *)) char *GC_parse_map_entry(char *buf_ptr, word *start, word *end, char *prot_buf, unsigned int *maj_dev) { - int i; - char *tok; + char *start_start, *end_start, *prot_start, *maj_dev_start; + char *p; + char *endp; if (buf_ptr == NULL || *buf_ptr == '\0') { return NULL; } - memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); - /* do the protections first. */ + p = buf_ptr; + while (isspace(*p)) ++p; + start_start = p; + GC_ASSERT(isxdigit(*start_start)); + *start = strtoul(start_start, &endp, 16); p = endp; + GC_ASSERT(*p=='-'); + + ++p; + end_start = p; + GC_ASSERT(isxdigit(*end_start)); + *end = strtoul(end_start, &endp, 16); p = endp; + GC_ASSERT(isspace(*p)); + + while (isspace(*p)) ++p; + prot_start = p; + GC_ASSERT(*prot_start == 'r' || *prot_start == '-'); + memcpy(prot_buf, prot_start, 4); prot_buf[4] = '\0'; - - if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */ - - tok = buf_ptr; - buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0'; - *start = strtoul(tok, NULL, 16); - - tok = buf_ptr+OFFSET_MAP_END; - buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0'; - *end = strtoul(tok, NULL, 16); - - buf_ptr += OFFSET_MAP_MAJDEV; - tok = buf_ptr; - while (*buf_ptr != ':') buf_ptr++; - *buf_ptr++ = '\0'; - *maj_dev = strtoul(tok, NULL, 16); + if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */ + /* Skip past protection field to offset field */ + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + GC_ASSERT(isxdigit(*p)); + /* Skip past offset field, which we ignore */ + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + maj_dev_start = p; + GC_ASSERT(isxdigit(*maj_dev_start)); + *maj_dev = strtoul(maj_dev_start, NULL, 16); } - while (*buf_ptr && *buf_ptr++ != '\n'); + while (*p && *p++ != '\n'); - return buf_ptr; + return p; } #endif /* Need to parse /proc/self/maps. */ @@ -704,8 +698,8 @@ ptr_t GC_get_stack_base() # if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \ || defined(HURD) || defined(NETBSD) || defined(FREEBSD) static struct sigaction old_segv_act; -# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \ - || defined(HURD) || defined(NETBSD) || defined(FREEBSD) +# if defined(IRIX5) || defined(HPUX) \ + || defined(HURD) || defined(NETBSD) static struct sigaction old_bus_act; # endif # else @@ -737,10 +731,12 @@ ptr_t GC_get_stack_base() /* and setting a handler at the same time. */ (void) sigaction(SIGSEGV, 0, &old_segv_act); (void) sigaction(SIGSEGV, &act, 0); + (void) sigaction(SIGBUS, 0, &old_bus_act); + (void) sigaction(SIGBUS, &act, 0); # else (void) sigaction(SIGSEGV, &act, &old_segv_act); -# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) || defined(HURD) || defined(NETBSD) || defined(FREEBSD) +# if defined(IRIX5) \ + || defined(HPUX) || defined(HURD) || defined(NETBSD) /* Under Irix 5.x or HP/UX, we may get SIGBUS. */ /* Pthreads doesn't exist under Irix 5.x, so we */ /* don't have to worry in the threads case. */ @@ -778,8 +774,8 @@ ptr_t GC_get_stack_base() # if defined(SUNOS5SIGS) || defined(IRIX5) \ || defined(OSF1) || defined(HURD) || defined(NETBSD) || defined(FREEBSD) (void) sigaction(SIGSEGV, &old_segv_act, 0); -# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) || defined(HURD) || defined(NETBSD) || defined(FREEBSD) +# if defined(IRIX5) \ + || defined(HPUX) || defined(HURD) || defined(NETBSD) (void) sigaction(SIGBUS, &old_bus_act, 0); # endif # else @@ -859,13 +855,14 @@ ptr_t GC_get_stack_base() #include #include -#include # define STAT_SKIP 27 /* Number of fields preceding startstack */ /* field in /proc/self/stat */ +#ifdef USE_LIBC_PRIVATES # pragma weak __libc_stack_end extern ptr_t __libc_stack_end; +#endif # ifdef IA64 /* Try to read the backing store base from /proc/self/maps. */ @@ -895,33 +892,38 @@ ptr_t GC_get_stack_base() return GC_apply_to_maps(backing_store_base_from_maps); } -# pragma weak __libc_ia64_register_backing_store_base - extern ptr_t __libc_ia64_register_backing_store_base; +# ifdef USE_LIBC_PRIVATES +# pragma weak __libc_ia64_register_backing_store_base + extern ptr_t __libc_ia64_register_backing_store_base; +# endif ptr_t GC_get_register_stack_base(void) { - if (0 != &__libc_ia64_register_backing_store_base - && 0 != __libc_ia64_register_backing_store_base) { - /* Glibc 2.2.4 has a bug such that for dynamically linked */ - /* executables __libc_ia64_register_backing_store_base is */ - /* defined but uninitialized during constructor calls. */ - /* Hence we check for both nonzero address and value. */ - return __libc_ia64_register_backing_store_base; - } else { - word result = backing_store_base_from_proc(); - if (0 == result) { +# ifdef USE_LIBC_PRIVATES + if (0 != &__libc_ia64_register_backing_store_base + && 0 != __libc_ia64_register_backing_store_base) { + /* Glibc 2.2.4 has a bug such that for dynamically linked */ + /* executables __libc_ia64_register_backing_store_base is */ + /* defined but uninitialized during constructor calls. */ + /* Hence we check for both nonzero address and value. */ + return __libc_ia64_register_backing_store_base; + } +# endif + word result = backing_store_base_from_proc(); + if (0 == result) { /* Use dumb heuristics. Works only for default configuration. */ result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT; result += BACKING_STORE_ALIGNMENT - 1; result &= ~(BACKING_STORE_ALIGNMENT - 1); /* Verify that it's at least readable. If not, we goofed. */ GC_noop1(*(word *)result); - } - return (ptr_t)result; } + return (ptr_t)result; } # endif +void *GC_set_stackbottom = NULL; + ptr_t GC_linux_stack_base(void) { /* We read the stack base value from /proc/self/stat. We do this */ @@ -941,7 +943,7 @@ ptr_t GC_get_stack_base() /* since the correct value of __libc_stack_end never */ /* becomes visible to us. The second test works around */ /* this. */ -#if USE_LIBC_PRIVATE_SYMBOLS +# ifdef USE_LIBC_PRIVATES if (0 != &__libc_stack_end && 0 != __libc_stack_end ) { # ifdef IA64 /* Some versions of glibc set the address 16 bytes too */ @@ -951,10 +953,19 @@ ptr_t GC_get_stack_base() } /* Otherwise it's not safe to add 16 bytes and we fall */ /* back to using /proc. */ # else +# ifdef SPARC + /* Older versions of glibc for 64-bit Sparc do not set + * this variable correctly, it gets set to either zero + * or one. + */ + if (__libc_stack_end != (ptr_t) (unsigned long)0x1) + return __libc_stack_end; +# else return __libc_stack_end; +# endif # endif } -#endif +# endif f = open("/proc/self/stat", O_RDONLY); if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) { ABORT("Couldn't read /proc/self/stat"); @@ -1385,7 +1396,7 @@ int * etext_addr; } # endif -# if defined(FREEBSD) && defined(I386) && !defined(PCR) +# if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__)) && !defined(PCR) /* Its unclear whether this should be identical to the above, or */ /* whether it should apply to non-X86 architectures. */ /* For now we don't assume that there is always an empty page after */ @@ -1506,7 +1517,7 @@ void GC_register_data_segments() # endif -# ifdef RS6000 +# if 0 && defined(RS6000) /* We now use mmap */ /* The compiler seems to generate speculative reads one past the end of */ /* an allocated object. Hence we need to make sure that the page */ /* following the last heap page is also mapped. */ @@ -2300,8 +2311,11 @@ GC_bool is_ptrfree; # if defined(ALPHA) || defined(M68K) typedef void (* REAL_SIG_PF)(int, int, s_c *); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *); + /* FIXME: */ + /* According to SUSV3, the last argument should have type */ + /* void * or ucontext_t * */ # else typedef void (* REAL_SIG_PF)(int, s_c); # endif @@ -2389,7 +2403,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif # ifdef FREEBSD # define SIG_OK (sig == SIGBUS) -# define CODE_OK (code == BUS_PAGE_FAULT) +# define CODE_OK TRUE # endif # endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */ @@ -2414,7 +2428,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ALPHA) || defined(M68K) void GC_write_fault_handler(int sig, int code, s_c * sc) # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp) # else # if defined(ARM32) @@ -2480,7 +2494,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ char * addr = (char *) (scp -> si_addr); # endif # ifdef LINUX -# if defined(I386) || defined (X86_64) +# if defined(I386) char * addr = (char *) (sc.cr2); # else # if defined(M68K) @@ -2515,7 +2529,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # ifdef ALPHA char * addr = get_fault_addr(sc); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) char * addr = si -> si_addr; /* I believe this is claimed to work on all platforms for */ /* Linux 2.3.47 and later. Hopefully we don't have to */ @@ -2527,7 +2541,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ARM32) char * addr = (char *)sc.fault_address; # else - --> architecture not supported +# if defined(CRIS) + char * addr = (char *)sc.regs.csraddr; +# else + --> architecture not supported +# endif # endif # endif # endif @@ -2596,7 +2614,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ALPHA) || defined(M68K) (*(REAL_SIG_PF)old_handler) (sig, code, sc); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) (*(REAL_SIG_PF)old_handler) (sig, si, scp); # else (*(REAL_SIG_PF)old_handler) (sig, sc); @@ -2690,7 +2708,8 @@ void GC_dirty_init() struct sigaction act, oldact; /* We should probably specify SA_SIGINFO for Linux, and handle */ /* the different architectures more uniformly. */ -# if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD) +# if defined(IRIX5) || defined(LINUX) && !defined(X86_64) \ + || defined(OSF1) || defined(HURD) act.sa_flags = SA_RESTART; act.sa_handler = (SIG_PF)GC_write_fault_handler; # else @@ -3068,7 +3087,7 @@ word n; #include #include -#define INITIAL_BUF_SZ 4096 +#define INITIAL_BUF_SZ 16384 word GC_proc_buf_size = INITIAL_BUF_SZ; char *GC_proc_buf; @@ -3403,8 +3422,6 @@ extern kern_return_t exception_raise_state_identity( #define MAX_EXCEPTION_PORTS 16 -static mach_port_t GC_task_self; - static struct { mach_msg_type_number_t count; exception_mask_t masks[MAX_EXCEPTION_PORTS]; @@ -3731,7 +3748,7 @@ static kern_return_t GC_forward_exception( exception_behavior_t behavior; thread_state_flavor_t flavor; - thread_state_data_t thread_state; + thread_state_t thread_state; mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX; for(i=0;i # else -# if defined(OPENBSD) || defined(NETBSD) +# if defined(OPENBSD) # include # else -# include +# if defined(FREEBSD) || defined(NETBSD) +# include +# else +# include +# endif # endif # endif # endif @@ -3990,6 +4017,16 @@ kern_return_t catch_exception_raise_state_identity( #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \ && defined(GC_HAVE_BUILTIN_BACKTRACE) +#ifdef REDIRECT_MALLOC + /* Deal with possible malloc calls in backtrace by omitting */ + /* the infinitely recursing backtrace. */ +# ifdef THREADS + __thread /* If your compiler doesn't understand this */ + /* you could use something like pthread_getspecific. */ +# endif + GC_in_save_callers = FALSE; +#endif + void GC_save_callers (info) struct callinfo info[NFRAMES]; { @@ -3999,15 +4036,26 @@ struct callinfo info[NFRAMES]; /* We retrieve NFRAMES+1 pc values, but discard the first, since it */ /* points to our own frame. */ +# ifdef REDIRECT_MALLOC + if (GC_in_save_callers) { + info[0].ci_pc = (word)(&GC_save_callers); + for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0; + return; + } + GC_in_save_callers = TRUE; +# endif GC_ASSERT(sizeof(struct callinfo) == sizeof(void *)); npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES); BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *)); for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0; +# ifdef REDIRECT_MALLOC + GC_in_save_callers = FALSE; +# endif } #else /* No builtin backtrace; do it ourselves */ -#if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC) +#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC) # define FR_SAVFP fr_fp # define FR_SAVPC fr_pc #else diff --git a/powerpc_darwin_mach_dep.s b/powerpc_darwin_mach_dep.s index 92f2c93c..fd23110b 100644 --- a/powerpc_darwin_mach_dep.s +++ b/powerpc_darwin_mach_dep.s @@ -1,7 +1,7 @@ ; GC_push_regs function. Under some optimization levels GCC will clobber ; some of the non-volatile registers before we get a chance to save them -; therefore, this can't be inline asm. +; therefore, this cannot be inline asm. .text .align 2 @@ -64,7 +64,8 @@ _GC_push_regs: ; PIC stuff, generated by GCC .data -.picsymbol_stub +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 2 L_GC_push_one$stub: .indirect_symbol _GC_push_one mflr r0 @@ -73,12 +74,12 @@ L0$_GC_push_one: mflr r11 addis r11,r11,ha16(L_GC_push_one$lazy_ptr-L0$_GC_push_one) mtlr r0 - lwz r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11) + lwzu r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11) mtctr r12 - addi r11,r11,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one) bctr .data .lazy_symbol_pointer L_GC_push_one$lazy_ptr: .indirect_symbol _GC_push_one .long dyld_stub_binding_helper + diff --git a/pthread_support.c b/pthread_support.c index 8c3c5aa1..ac8df854 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -2,7 +2,7 @@ * Copyright (c) 1994 by Xerox Corporation. All rights reserved. * Copyright (c) 1996 by Silicon Graphics. All rights reserved. * Copyright (c) 1998 by Fergus Henderson. All rights reserved. - * Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved. + * Copyright (c) 2000-2004 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -50,8 +50,7 @@ # include "private/pthread_support.h" # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ - && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \ - && !defined(GC_AIX_THREADS) + && !defined(GC_WIN32_THREADS) # if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \ && !defined(USE_COMPILER_TLS) @@ -68,7 +67,8 @@ # endif # if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \ - defined(GC_DARWIN_THREADS)) && !defined(USE_PTHREAD_SPECIFIC) + defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) \ + && !defined(USE_PTHREAD_SPECIFIC) # define USE_PTHREAD_SPECIFIC # endif @@ -116,7 +116,7 @@ # include #endif /* !GC_DARWIN_THREADS */ -#if defined(GC_DARWIN_THREADS) +#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) # include #endif /* GC_DARWIN_THREADS */ @@ -896,9 +896,9 @@ int GC_get_nprocs() /* We hold the allocation lock. */ void GC_thr_init() { -# ifndef GC_DARWIN_THREADS - int dummy; -# endif +# ifndef GC_DARWIN_THREADS + int dummy; +# endif GC_thread t; if (GC_thr_initialized) return; @@ -930,14 +930,15 @@ void GC_thr_init() # if defined(GC_HPUX_THREADS) GC_nprocs = pthread_num_processors_np(); # endif -# if defined(GC_OSF1_THREADS) +# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1; # endif -# if defined(GC_FREEBSD_THREADS) - GC_nprocs = 1; +# if defined(GC_IRIX_THREADS) + GC_nprocs = sysconf(_SC_NPROC_ONLN); + if (GC_nprocs <= 0) GC_nprocs = 1; # endif -# if defined(GC_DARWIN_THREADS) +# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) int ncpus = 1; size_t len = sizeof(ncpus); sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0); @@ -984,6 +985,8 @@ void GC_thr_init() /* Disable true incremental collection, but generational is OK. */ GC_time_limit = GC_TIME_UNLIMITED; } + /* If we are using a parallel marker, actually start helper threads. */ + if (GC_parallel) start_mark_threads(); # endif } @@ -1000,10 +1003,6 @@ void GC_init_parallel() /* GC_init() calls us back, so set flag first. */ if (!GC_is_initialized) GC_init(); - /* If we are using a parallel marker, start the helper threads. */ -# ifdef PARALLEL_MARK - if (GC_parallel) start_mark_threads(); -# endif /* Initialize thread local free lists if used. */ # if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL) LOCK(); @@ -1317,7 +1316,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread, if (!GC_thr_initialized) GC_thr_init(); # ifdef GC_ASSERTIONS { - int stack_size; + size_t stack_size; if (NULL == attr) { pthread_attr_t my_attr; pthread_attr_init(&my_attr); @@ -1325,7 +1324,13 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread, } else { pthread_attr_getstacksize(attr, &stack_size); } - GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word))); +# ifdef PARALLEL_MARK + GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word))); +# else + /* FreeBSD-5.3/Alpha: default pthread stack is 64K, */ + /* HBLKSIZE=8192, sizeof(word)=8 */ + GC_ASSERT(stack_size >= 65536); +# endif /* Our threads may need to do some work for the GC. */ /* Ridiculously small threads won't work, and they */ /* probably wouldn't work anyway. */ diff --git a/reclaim.c b/reclaim.c index 323d420f..864c0cad 100644 --- a/reclaim.c +++ b/reclaim.c @@ -888,7 +888,7 @@ void GC_print_block_list() { struct Print_stats pstats; - GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n"); + GC_printf1("(kind(0=ptrfree,1=normal,2=unc.,%lu=stubborn):size_in_bytes, #_marks_set)\n", STUBBORN); pstats.number_of_blocks = 0; pstats.total_bytes = 0; GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats); diff --git a/solaris_pthreads.c b/solaris_pthreads.c index 819454b4..08c45e7c 100644 --- a/solaris_pthreads.c +++ b/solaris_pthreads.c @@ -16,8 +16,9 @@ * Modified by Peter C. for Solaris Posix Threads. */ -# if defined(GC_SOLARIS_PTHREADS) # include "private/gc_priv.h" + +# if defined(GC_SOLARIS_PTHREADS) # include # include # include diff --git a/solaris_threads.c b/solaris_threads.c index 20c76003..5c49c120 100644 --- a/solaris_threads.c +++ b/solaris_threads.c @@ -16,9 +16,9 @@ */ /* Boehm, September 14, 1994 4:44 pm PDT */ -# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) - # include "private/gc_priv.h" + +# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) # include "private/solaris_threads.h" # include # include @@ -248,8 +248,8 @@ static void stop_all_lwps() for (i = 0; i < max_lwps; i++) last_ids[i] = 0; for (;;) { - if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0) - ABORT("Main PIOCSTATUS failed"); + if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0) + ABORT("Main PIOCSTATUS failed"); if (status.pr_nlwp < 1) ABORT("Invalid number of lwps returned by PIOCSTATUS"); if (status.pr_nlwp >= max_lwps) { @@ -262,7 +262,7 @@ static void stop_all_lwps() for (i = 0; i < max_lwps; i++) last_ids[i] = 0; continue; - } + } if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0) ABORT("PIOCLWPIDS failed"); changed = FALSE; @@ -803,6 +803,7 @@ void GC_thr_init(void) { GC_thread t; thread_t tid; + int ret; if (GC_thr_initialized) return; @@ -820,9 +821,11 @@ void GC_thr_init(void) t = GC_new_thread(thr_self()); t -> stack_size = 0; t -> flags = DETACHED | CLIENT_OWNS_STACK; - if (thr_create(0 /* stack */, 0 /* stack_size */, GC_thr_daemon, - 0 /* arg */, THR_DETACHED | THR_DAEMON, - &tid /* thread_id */) != 0) { + ret = thr_create(0 /* stack */, 0 /* stack_size */, GC_thr_daemon, + 0 /* arg */, THR_DETACHED | THR_DAEMON, + &tid /* thread_id */); + if (ret != 0) { + GC_err_printf1("Thr_create returned %ld\n", ret); ABORT("Cant fork daemon"); } thr_setprio(tid, 126); diff --git a/specific.c b/specific.c index 2c40c2b4..7d5d8894 100644 --- a/specific.c +++ b/specific.c @@ -11,9 +11,10 @@ * modified is included with the above copyright notice. */ +#include "private/gc_priv.h" /* For GC_compare_and_exchange, GC_memory_barrier */ + #if defined(GC_LINUX_THREADS) -#include "private/gc_priv.h" /* For GC_compare_and_exchange, GC_memory_barrier */ #include "private/specific.h" static tse invalid_tse = {INVALID_QTID, 0, 0, INVALID_THREADID}; diff --git a/threadlibs.c b/threadlibs.c index 247d3c65..9078c8d8 100644 --- a/threadlibs.c +++ b/threadlibs.c @@ -1,3 +1,4 @@ +# include "gc_config_macros.h" # include "private/gcconfig.h" # include @@ -10,10 +11,17 @@ int main() "-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n"); # endif # if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \ - || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \ + || defined(GC_SOLARIS_PTHREADS) \ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) printf("-lpthread\n"); # endif +# if defined(GC_FREEBSD_THREADS) +# if (__FREEBSD_version >= 500000) + printf("-lpthread\n"); +# else + printf("-pthread\n"); +# endif +# endif # if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) printf("-lpthread -lrt\n"); # endif diff --git a/version.h b/version.h index e8f1a3ab..e1fe24bd 100644 --- a/version.h +++ b/version.h @@ -2,8 +2,8 @@ /* Eventually this one may become unnecessary. For now we need */ /* it to keep the old-style build process working. */ #define GC_TMP_VERSION_MAJOR 6 -#define GC_TMP_VERSION_MINOR 3 -#define GC_TMP_ALPHA_VERSION 6 +#define GC_TMP_VERSION_MINOR 6 +#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA #ifndef GC_NOT_ALPHA # define GC_NOT_ALPHA 0xff diff --git a/win32_threads.c b/win32_threads.c index 3195094c..87944dc3 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -1,6 +1,7 @@ +#include "private/gc_priv.h" + #if defined(GC_WIN32_THREADS) -#include "private/gc_priv.h" #include #ifdef CYGWIN32 @@ -10,6 +11,7 @@ # undef pthread_create # undef pthread_sigmask # undef pthread_join +# undef pthread_detach # undef dlopen # define DEBUG_CYGWIN_THREADS 0 @@ -195,7 +197,7 @@ static void GC_delete_thread(DWORD thread_id) { /* Must still be in_use, since nobody else can store our thread_id. */ i++) {} if (i > my_max) { - WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id); + WARN("Removing nonexistent thread %ld\n", (GC_word)thread_id); } else { GC_delete_gc_thread(thread_table+i); } @@ -242,6 +244,9 @@ void GC_push_thread_structures GC_PROTO((void)) # endif } +/* Defined in misc.c */ +extern CRITICAL_SECTION GC_write_cs; + void GC_stop_world() { DWORD thread_id = GetCurrentThreadId(); @@ -250,6 +255,9 @@ void GC_stop_world() if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()"); GC_please_stop = TRUE; +# ifndef CYGWIN32 + EnterCriticalSection(&GC_write_cs); +# endif /* !CYGWIN32 */ for (i = 0; i <= GC_get_max_thread_index(); i++) if (thread_table[i].stack_base != 0 && thread_table[i].id != thread_id) { @@ -280,6 +288,9 @@ void GC_stop_world() # endif thread_table[i].suspended = TRUE; } +# ifndef CYGWIN32 + LeaveCriticalSection(&GC_write_cs); +# endif /* !CYGWIN32 */ } void GC_start_world() -- 2.40.0