summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Totz <jtotz@ic.ac.uk>2012-03-18 22:33:08 +0000
committerIvan Maidanski <ivmai@mail.ru>2012-11-14 14:17:32 +0400
commit31876d79fb6237e6d71932e48770e4ec1c4df064 (patch)
tree2d93659520a88a332892637d76830008876fa630
parenta8367cbf87badcc04d303dd801568c3e8d95cb3d (diff)
parent6859feb53580bb4ae6f558767a0e7572cbf72a69 (diff)
downloadbdwgc-jtotz_bdwgc.tar.gz
update to new version. not entirely sure if it works correctly, only did a quick test.jtotz_bdwgc
Conflicts: .hgtags include/gc.h include/gc_cpp.h include/private/gcconfig.h
-rw-r--r--.cvsignore39
-rw-r--r--.hgtags1
-rw-r--r--ChangeLog1152
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.direct1
-rw-r--r--Makefile.in124
-rw-r--r--NT_MAKEFILE2
-rw-r--r--NT_STATIC_THREADS_MAKEFILE2
-rw-r--r--NT_X64_STATIC_THREADS_MAKEFILE2
-rw-r--r--NT_X64_THREADS_MAKEFILE2
-rw-r--r--allchblk.c4
-rw-r--r--alloc.c123
-rw-r--r--backgraph.c16
-rw-r--r--blacklst.c3
-rw-r--r--checksums.c36
-rwxr-xr-xconfigure70
-rw-r--r--configure.ac54
-rw-r--r--configure.host4
-rwxr-xr-xconfigure_atomic_ops.sh4
-rw-r--r--cord/cordbscs.c718
-rw-r--r--cord/cordtest.c110
-rw-r--r--cord/cordxtra.c243
-rw-r--r--darwin_stop_world.c47
-rw-r--r--dbg_mlc.c429
-rw-r--r--doc/README4
-rw-r--r--doc/README.autoconf6
-rw-r--r--doc/README.environment37
-rw-r--r--doc/README.macros54
-rw-r--r--doc/README.solaris224
-rw-r--r--doc/README.win3210
-rw-r--r--dyn_load.c338
-rw-r--r--extra/setjmp_t.c177
-rw-r--r--finalize.c9
-rw-r--r--gc_dlopen.c20
-rw-r--r--gcj_mlc.c13
-rw-r--r--headers.c2
-rw-r--r--include/gc.h61
-rw-r--r--include/gc_config_macros.h4
-rw-r--r--include/gc_cpp.h59
-rw-r--r--include/gc_inline.h12
-rw-r--r--include/gc_typed.h6
-rw-r--r--include/gc_version.h2
-rw-r--r--[-rwxr-xr-x]include/private/config.h.in7
-rw-r--r--include/private/darwin_stop_world.h13
-rw-r--r--include/private/dbg_mlc.h192
-rw-r--r--include/private/gc_hdrs.h4
-rw-r--r--include/private/gc_locks.h61
-rw-r--r--include/private/gc_pmark.h106
-rw-r--r--include/private/gc_priv.h311
-rw-r--r--include/private/gcconfig.h780
-rw-r--r--include/private/pthread_stop_world.h2
-rw-r--r--include/private/pthread_support.h26
-rw-r--r--include/private/specific.h14
-rw-r--r--include/private/thread_local_alloc.h179
-rw-r--r--mach_dep.c21
-rw-r--r--malloc.c140
-rw-r--r--mallocx.c119
-rw-r--r--mark.c159
-rw-r--r--mark_rts.c20
-rw-r--r--misc.c305
-rw-r--r--new_hblk.c10
-rw-r--r--os_dep.c899
-rw-r--r--pthread_start.c10
-rw-r--r--pthread_stop_world.c136
-rw-r--r--pthread_support.c257
-rw-r--r--ptr_chck.c2
-rw-r--r--reclaim.c91
-rw-r--r--specific.c145
-rw-r--r--stubborn.c2
-rw-r--r--tests/huge_test.c2
-rwxr-xr-xtests/initsecondarythread.c55
-rw-r--r--tests/realloc_test.c34
-rw-r--r--tests/smash_test.c2
-rw-r--r--[-rwxr-xr-x]tests/staticrootslib.c6
-rw-r--r--tests/test.c328
-rw-r--r--tests/test_cpp.cc60
-rw-r--r--tests/tests.am15
-rw-r--r--tests/threadkey_test.c92
-rw-r--r--thread_local_alloc.c10
-rw-r--r--vc9/test_cpp_libgc.vcproj16
-rw-r--r--vc9/test_libgc.vcproj16
-rw-r--r--[-rwxr-xr-x]win32_threads.c334
82 files changed, 5389 insertions, 3618 deletions
diff --git a/.cvsignore b/.cvsignore
index d1ce9d22..b7324ef5 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,17 +1,50 @@
+*.bsc
+*.csm
+*.dll
+*.err
+*.exe
+*.exp
+*.la
+*.lb1
+*.lib
+*.lnk
*.lo
+*.map
+*.o
+*.obj
+*.out
+*.pdb
+*.rbj
+*.res
+*.sbr
+*.stackdump
+*.sym
+*.tmp
+.deps
.libs
Makefile
+add_gc_prefix
bdw-gc.pc
config.log
config.status
+cordtest
+core
+de
+gc-*
+gcname
gctest
hugetest
+if_mach
+if_not_there
+initsecondarythread
leaktest
-libcord.la
-libgc.la
-libstaticrootslib.la
libtool
middletest
+realloc_test
+setjmp_test
smashtest
staticrootstest
+test_cpp
+threadkey_test
threadleaktest
+threadlibs
diff --git a/.hgtags b/.hgtags
index 80479691..7902ded5 100644
--- a/.hgtags
+++ b/.hgtags
@@ -2,6 +2,7 @@
24a2e5b43a289dc9ba38fbde2b602c79c632ce03 gc7_2alpha6
3c239e80bee0341c7834b5c5f85738c26da09f87 gc7_0
43c85b2e652869da9de1058eb3e94b79c755941a gc7_0alpha7
+24a2e5b43a289dc9ba38fbde2b602c79c632ce03 gc7_2alpha6
664dc1f702d2a4665b13964252fb63df0c58c93e start
813e2af7cb1f3bffc43c54350847fa634b9a7e6a gc7_1alpha2
de9672597e74978f9220b7b54c618b33a6d5c507 gc7_0alpha9
diff --git a/ChangeLog b/ChangeLog
index 02b53a8f..a96ab000 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1140 @@
+2011-07-26 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/realloc_test.c: New file.
+ * tests/tests.am (TESTS, check_PROGRAMS): Add realloc_test.
+ * .cvsignore: Add realloc_test.
+ * configure: Regenerate.
+ * Makefile.in: Ditto.
+
+2011-07-14 Ivan Maidanski <ivmai@mail.ru>
+
+ * .cvsignore: Add more auto-generated files.
+
+2011-07-14 Ivan Maidanski <ivmai@mail.ru>
+
+ * new_hblk.c (GC_build_fl): Adjust "h" local variable cast type
+ when setting obj_link (to prevent compiler warning); reformat the
+ comment.
+ * tests/test.c (reverse_test_inner): Use proper type when touching
+ "b" and "c" local variables (to prevent compiler warning).
+
+2011-07-05 Ivan Maidanski <ivmai@mail.ru>
+
+ * misc.c (GC_init): Use HOTTER_THAN (instead of STACK_GROWS_DOWN)
+ for GC_stackbottom assertion.
+ * os_dep.c (GC_enclosing_mapping): Define only if IA64 or
+ INCLUDE_LINUX_THREAD_DESCR; make GC_INNER.
+ * pthread_support.c (GC_enclosing_mapping): Declare (only if
+ INCLUDE_LINUX_THREAD_DESCR).
+ * os_dep.c (GC_get_main_stack_base): Don't call pthread_getattr_np
+ if REDIRECT_MALLOC as the former is observed to call redirected
+ malloc (while GC is not initialized yet) on some Linux platforms.
+ * include/private/gc_priv.h (MAX_HEAP_SECTS): Don't use a smaller
+ value for SMALL_CONFIG if USE_PROC_FOR_LIBRARIES defined.
+
+2011-07-05 Ivan Maidanski <ivmai@mail.ru>
+
+ * malloc.c (GC_init_lib_bounds): Call GC_init (to ensure GC is
+ initialized before doing GC_text_mapping).
+ * misc.c (GC_init): Add a check for GC_init recursion in case of
+ malloc is redirected (abort with the corresponding message).
+ * pthread.c (GC_thr_init): Place GC_add_roots_inner call into
+ "else" branch to prevent "local variable might be uninitialized"
+ compiler warning; add comment.
+
+2011-07-05 Ivan Maidanski <ivmai@mail.ru>
+
+ * dyn_load.c (GC_register_dynamic_libraries): Remove duplicate
+ call of GC_FirstDLOpenedLinkMap (twice).
+ * dyn_load.c (GC_register_main_static_data): Add comment.
+ * cord/cordbscs.c (CORD_riter): Check for empty string passed (do
+ not call CORD_riter4 if CORD_len() returned zero).
+ * cord/cordbscs.c (CORD_init_min_len): Replace the K&R-style
+ function definition with the ANSI C one.
+ * cord/cordbscs.c: Expand all tabs to spaces; remove
+ trailing spaces at EOLn.
+ * tests/threadkey_test.c (on_thread_exit_inner): Check
+ GC_pthread_create() result.
+
+2011-07-04 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gcconfig.h (etext): Don't define if unused
+ (NetBSD).
+ * include/private/gcconfig.h (GC_data_start, DATASTART): Define
+ for NetBSD/amd64 if ELF.
+ * include/private/gcconfig.h (SEARCH_FOR_DATA_START): Don't define
+ for NetBSD/amd64 if ELF.
+
+2011-07-04 Ivan Maidanski <ivmai@mail.ru> (mostly really Andy Wingo)
+
+ * configure.ac (GC_THREADS): Refine the comment.
+ * configure.ac (GC_WIN32_PTHREADS): Add template.
+ * configure.ac (cygwin, win32): Define GC_WIN32_THREADS instead of
+ GC_THREADS.
+ * configure.ac (pthreads): Add mingw target (GC_WIN32_PTHREADS).
+ * configure: Regenerate.
+ * include/private/config.h.in: Ditto.
+ * include/private/gc_locks.h (GC_WIN32_PTHREADS): Remove nested
+ test for the macro; add comment.
+
+2011-07-01 Ivan Maidanski <ivmai@mail.ru>
+
+ * win32_threads.c (CHECK_LOOKUP_MY_THREAD): New macro definition.
+ * win32_threads.c (GC_reset_finalizer_nested,
+ GC_check_finalizer_nested, GC_unregister_my_thread,
+ GC_do_blocking_inner, GC_call_with_gc_active, GC_init_parallel):
+ Insert CHECK_LOOKUP_MY_THREAD before dereferencing thread
+ descriptor pointer (to instruct a LINT-like tool that it is ok to
+ dereference the pointer).
+ * win32_threads.c (GC_get_next_stack): Assert plast_stack_min is
+ non-NULL if current_min is not ADDR_LIMIT (for a LINT-like tool).
+ * win32_threads.c (GC_init_parallel): Define and use "me" local
+ variable.
+ * cord/cordtest.c (test_basics): Test CORD_substr() result is
+ non-NULL.
+ * cord/cordtest.c (test_extras): Test fopen() result is non-NULL.
+ * cord/cordtest.c (test_basics, test_extras, test_printf, main):
+ Replace the K&R-style function definition with the ANSI C one.
+ * cord/cordtest.c: Expand all tabs to spaces; remove
+ trailing spaces at EOLn.
+ * include/private/gc_priv.h (ABORT): Define as abort() when
+ checking the code with a LINT-like tool (Win32 only).
+ * tests/test.c (FAIL): Ditto.
+ * tests/test.c (CHECH_GCLIB_VERSION): New macro (to check that the
+ version of libgc.so used at runtime matches that at compile time).
+ * tests/test.c (GC_COND_INIT): Use CHECH_GCLIB_VERSION.
+ * tests/test.c (CHECK_OUT_OF_MEMORY): New macro (to test malloc
+ result for out of memory).
+ * tests/test.c (cons, small_cons, small_cons_uncollectable,
+ gcj_cons, reverse_test_inner, mktree, alloc8bytes, typed_test,
+ run_one_test): Use CHECK_OUT_OF_MEMORY.
+
+2011-06-30 Ivan Maidanski <ivmai@mail.ru>
+
+ * dyn_load.c (GC_register_map_entries): Remove "count" local
+ variable as unused.
+ * gc_dlopen.c (disable_gc_for_dlopen): Define only if not
+ USE_PROC_FOR_LIBRARIES.
+ * malloc.c (calloc): Add parentheses around '&&' operator.
+ * mark.c (GC_noop_sink): New global variable (instead of a static
+ local variable inside GC_noop1).
+ * mark.c (GC_noop1): Use GC_noop_sink variable (to prevent
+ "variable set but not used" compiler warning).
+ * include/private/gcconfig.h (USE_PROC_FOR_LIBRARIES): Define only
+ if undefined yet.
+ * tests/smash_test.c (main): Don't dereference "p" local variable
+ if it is NULL.
+ * tests/staticrootslib.c (main): Ditto.
+
+2011-06-30 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (GC_segment_is_thread_stack): Replace '&'
+ operator with '&&' one in conditional expressions.
+ * specific.c (remove_specific): Dereference "entry" local variable
+ only if it is non-NULL.
+ * include/gc.h (GC_NEW): Refine the comment (about the returned
+ value).
+
+2011-06-15 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/gc_version.h, configure.ac, doc/README: Change to
+ version 7.2alpha7.
+ * configure: Regenerate.
+
+[7.2alpha6]
+
+2011-06-14 Ivan Maidanski <ivmai@mail.ru>
+
+ * configure_atomic_ops.sh: Remove.
+ * Makefile.direct (dist gc.tar): Remove configure_atomic_ops.sh.
+ * Makefile.am (EXTRA_DIST): Add autogen.sh.
+ * Makefile.in: Regenerate.
+ * configure: Ditto.
+
+2011-06-14 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/gc_version.h, configure.ac, doc/README: Change to
+ version 7.2alpha6.
+ * configure: Regenerate.
+
+2011-05-31 Ivan Maidanski <ivmai@mail.ru>
+
+ * NT_STATIC_THREADS_MAKEFILE (.cpp.obj): Remove duplicate .cpp
+ filename passed.
+ * NT_X64_THREADS_MAKEFILE (.cpp.obj): Use lowercase file
+ extension.
+ * NT_X64_STATIC_THREADS_MAKEFILE (.cpp.obj): Ditto.
+ * NT_MAKEFILE (.cpp.obj): Ditto.
+
+2011-05-31 Ivan Maidanski <ivmai@mail.ru>
+
+ * alloc.c (GC_add_current_malloc_heap, GC_build_back_graph,
+ GC_traverse_back_graph): Move prototype to gc_priv.h.
+ * checksums.c (GC_page_was_ever_dirty): Ditto.
+ * dbg_mlc.c (GC_default_print_heap_obj_proc): Ditto.
+ * dyn_load.c (GC_parse_map_entry, GC_get_maps,
+ GC_segment_is_thread_stack, GC_roots_present, GC_is_heap_base,
+ GC_get_next_stack): Ditto.
+ * finalize.c (GC_reset_finalizer_nested,
+ GC_check_finalizer_nested): Ditto.
+ * gcj_mlc.c (GC_start_debugging, GC_store_debug_info): Ditto.
+ * malloc.c (GC_extend_size_map, GC_text_mapping): Ditto.
+ * mark_rts.c (GC_mark_thread_local_free_lists): Ditto.
+ * misc.c (GC_register_main_static_data, GC_init_win32,
+ GC_setpagesize, GC_init_linux_data_start,
+ GC_set_and_save_fault_handler, GC_init_dyld, GC_init_netbsd_elf,
+ GC_initialize_offsets, GC_bl_init, GC_do_blocking_inner,
+ GC_bl_init_no_interiors): Ditto.
+ * os_dep.c (GC_greatest_stack_base_below, GC_push_all_stacks):
+ Ditto.
+ * reclaim.c (GC_check_leaked): Ditto.
+ * win32_threads.c (GC_gww_dirty_init): Ditto.
+ * darwin_stop_world.c (GC_is_mach_marker, GC_mprotect_stop,
+ GC_mprotect_resume): Move prototype to darwin_stop_world.h.
+ * pthread_support.c (GC_FindTopOfStack): Ditto.
+ * dyn_load.c (GC_cond_add_roots): Merge adjacent definitions.
+ * mark.c (GC_page_was_ever_dirty): Remove (as already declared).
+ * mark_rts.c (GC_roots_present): Change return type to void
+ pointer (to match the prototype); return NULL instead of FALSE.
+ * mark_rts.c (GC_add_roots_inner): Cast GC_roots_present() result.
+ * os_dep.c (NEED_PROC_MAPS): Move definition to gcconfig.h.
+ * os_dep.c (GC_write_fault_handler): Make STATIC.
+ * os_dep.c (GC_set_write_fault_handler): New function (only if
+ GC_WIN32_THREADS).
+ * pthread_start.c (GC_start_rtn_prepare_thread,
+ GC_thread_exit_proc): Move prototype to pthread_support.h.
+ * pthread_support.c (GC_nacl_initialize_gc_thread,
+ GC_nacl_shutdown_gc_thread, GC_unblock_gc_signals):
+ Ditto.
+ * pthread_support.c (GC_stop_init): Move prototype to
+ pthread_stop_world.h.
+ * thread_local_alloc.c (GC_check_tls_for): Reformat comment.
+ * win32_threads.c (GC_write_fault_handler): Remove prototype.
+ * win32_threads.c (GC_register_my_thread_inner): Call
+ GC_set_write_fault_handler instead of SetUnhandledExceptionFilter
+ (only if MPROTECT_VDB).
+ * doc/README.win32: Add information about DMC.
+ * include/private/gc_priv.h (GC_set_write_fault_handler): New
+ prototype (only if GC_WIN32_THREADS and MPROTECT_VDB).
+
+2011-05-31 Ivan Maidanski <ivmai@mail.ru>
+
+ * misc.c (vsnprintf): Redirect to vsprintf() if NO_VSNPRINTF.
+
+2011-05-31 Ivan Maidanski <ivmai@mail.ru>
+
+ * win32_threads.c (GC_unregister_my_thread): Use KNOWN_FINISHED()
+ instead of FINISHED macro.
+ * tests/test.c (check_heap_stats): Round up max_heap_sz value for
+ Win32 (same as for USE_MMAP).
+
+2011-05-31 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/test.c (check_heap_stats): Adjust printf format specifier
+ for max_heap_sz; cast max_heap_sz accordingly.
+
+2011-05-30 Ivan Maidanski <ivmai@mail.ru>
+
+ * doc/README.solaris2: Add note.
+
+2011-05-30 Ivan Maidanski <ivmai@mail.ru>
+
+ * configure.ac (SOLARIS25_PROC_VDB_BUG_FIXED): Don't define for
+ Solaris/x86 2.10+.
+ * configure: Regenerate.
+
+2011-05-23 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/threadkey_test.c (SKIP_THREADKEY_TEST): Skip the test if
+ defined; explicitly define for some targets.
+
+2011-05-23 Ivan Maidanski <ivmai@mail.ru>
+
+ * mark.c (GC_dirty): Add prototype (only if MANUAL_VDB).
+ * stubborn.c (GC_dirty): Ditto.
+ * include/private/gcconfig.h (GWW_VDB, MPROTECT_VDB, PCR_VDB,
+ PROC_VDB): Undefine if MANUAL_VDB.
+ * include/private/gcconfig.h (DEFAULT_VDB): Don't define if
+ MANUAL_VDB.
+ * os_dep.c (async_set_pht_entry_from_index): Define for
+ MANUAL_VDB.
+ * os_dep.c (GC_read_dirty): Set GC_dirty_maintained only if
+ success; if ioctl() failed then just print warning instead of
+ aborting.
+
+2011-05-23 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gc_priv.h (GC_ASSERT): Use "%d" (instead of %ld)
+ for line number printing.
+
+2011-05-23 Ivan Maidanski <ivmai@mail.ru>
+
+ * os_dep.c (GC_read_dirty): Add debug logging if DEBUG_DIRTY_BITS
+ (for PROC_VDB only); print errors via GC_err_printf; rename "ps"
+ and "np" local variables to npages and pagesize, respectively;
+ remove "current_addr" local variable.
+ * os_dep.c: Reformat comments.
+
+2011-05-22 Ivan Maidanski <ivmai@mail.ru>
+
+ * os_dep.c (GC_get_main_stack_base): Convert to GC_get_stack_base
+ for BeOS and OS/2; define HAVE_GET_STACK_BASE.
+ * os_dep.c (GET_MAIN_STACKBASE_SPECIAL): Define when a specific
+ GC_get_main_stack_base implementation is defined.
+ * os_dep.c (GC_get_main_stack_base): Define that based on
+ GC_get_stack_base() in a single place (only if
+ GET_MAIN_STACKBASE_SPECIAL is unset); check GC_get_stack_base()
+ result.
+
+2011-05-20 Ivan Maidanski <ivmai@mail.ru>
+
+ * mark.c (GC_push_selected): Remove "push_fn" argument (use
+ GC_push_all directly); update the documentation; reformat the
+ comment.
+ * mark.c (GC_push_conditional): Simplify the code (for better
+ readability).
+
+2011-05-20 Ivan Maidanski <ivmai@mail.ru>
+
+ * mark.c (alloc_mark_stack): Use FALSE/TRUE (instead of 0/1) for
+ boolean local variables.
+ * doc/README.macros (GC_PREFER_MPROTECT_VDB): Update.
+ * os_dep.c (GC_page_was_dirty, GC_page_was_ever_dirty,
+ GC_remove_protection): Define for GWW_VDB and PROC_VDB in a single
+ place.
+ * os_dep.c (GC_page_was_dirty, GC_page_was_ever_dirty): Compute
+ PHT_HASH(h) only once (store result to a local variable).
+
+2011-05-20 Ivan Maidanski <ivmai@mail.ru>
+
+ * doc/README.solaris2: Update.
+
+2011-05-19 Ivan Maidanski <ivmai@mail.ru> (really Jie Liu)
+
+ * include/private/gcconfig.h (end, InitStackBottom): Declare
+ extern variable for RTEMS.
+ * include/private/gcconfig.h (DATASTART, DATAEND, STACKBOTTOM):
+ Update (for RTEMS).
+ * include/private/gcconfig.h (DATAEND): Fix a typo in the macro
+ name (for RTEMS).
+ * tests/test.c (CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER):
+ Replace with CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER (for RTEMS).
+
+2011-05-18 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gcconfig.h (MPROTECT_VDB): Enable for Solaris in
+ single-threaded environment.
+
+2011-05-18 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gcconfig.h (MPROTECT_VDB): Undefine if PROC_VDB.
+ * tests/test.c (NUMBER_ROUND_UP): New macro.
+ * tests/test.c (check_heap_stats): Round up total expected heap
+ size to the nearest 4 MiB bound.
+ * tests/test.c (check_heap_stats): Print the current and expected
+ heap sizes in case of failure.
+
+2011-05-18 Ivan Maidanski <ivmai@mail.ru>
+
+ * checksums.c (GC_check_blocks, GC_check_dirty): Do log printing
+ only if GC_print_stats; print errors using GC_err_printf.
+ * checksums.c (GC_check_blocks): Join adjacent printf() calls into
+ a single one.
+
+2011-05-17 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (pthread_join): Add assertion (check thread is
+ finished).
+ * pthread_support.c (GC_register_my_thread): Don't detach the
+ thread if invoked from the thread destructor.
+ * win32_threads.c (GC_register_my_thread): Ditto.
+ * win32_threads.c (GC_unregister_my_thread): Don't delete the
+ thread (just set FINISHED) if the thread is not detached (only if
+ GC_PTHREADS); add assertion (check the thread is not finished).
+ * tests/threadkey_test.c (main): Join some created threads.
+
+2011-05-17 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (GC_delete_gc_thread): Rename "gc_id" local
+ variable to "t".
+ * win32_threads.c (GC_delete_gc_thread): Ditto.
+ * pthread_support.c (pthread_join, pthread_detach,
+ pthread_cancel): Rename "thread_gc_id" local variable to "t".
+ * win32_threads.c (GC_pthread_detach): Ditto.
+ * win32_threads.c (GC_delete_gc_thread): Remove "gc_nvid" local
+ variable.
+ * win32_threads.c (GC_pthread_join): Rename "joinee" local
+ variable to "t".
+
+2011-05-16 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_stop_world.c (pthread_sigmask): Undefine even if not
+ DEBUG_THREADS.
+ * pthread_stop_world.c (GC_unblock_gc_signals): New function (only
+ if GC_EXPLICIT_SIGNALS_UNBLOCK).
+ * pthread_support.c (GC_unblock_gc_signals): New prototype.
+ * pthread_support.c (GC_register_my_thread_inner,
+ GC_register_my_thread): Call GC_unblock_gc_signals (only if
+ GC_EXPLICIT_SIGNALS_UNBLOCK); add comment.
+ * include/private/gcconfig.h (GC_EXPLICIT_SIGNALS_UNBLOCK): New
+ macro.
+
+2011-05-16 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_stop_world.c (GC_suspend_handler_inner): Remove "dummy",
+ "sig" local variables; rename my_thread local variable to "self".
+
+2011-05-13 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/threadkey_test.c (LIMIT): Use smaller value (don't create
+ more than 30 in parallel by default).
+
+2011-05-13 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/threadkey_test.c (key_once, main): Work around for Solaris
+ PTHREAD_ONCE_INIT.
+ * tests/threadkey_test.c (LIMIT): Use smaller value for Solaris.
+
+2011-05-13 Ivan Maidanski <ivmai@mail.ru>
+
+ * dyn_load.c (GC_FirstDLOpenedLinkMap): Remove unused "r" local
+ variable.
+ * pthread_support.c (GC_unregister_my_thread_inner): Revert back
+ GC_remove_specific invocation; add a comment.
+ * include/private/thread_local_alloc.h (GC_remove_specific):
+ Revert back.
+ * specific.c: Expand all tabs to spaces.
+ * specific.c (slow_getspecific): Cast qtid to AO_t.
+ * include/private/specific.h (quick_thread_id): Reformat comment.
+ * include/private/specific.h (key_create, setspecific,
+ remove_specific): Remove "extern" keyword.
+ * include/private/specific.h (getspecific): Change type of "qtid"
+ local variable to unsigned long.
+
+2011-05-11 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (GC_check_tls): Fix "#endif" comment.
+ * include/gc.h (GC_REDIRECT_TO_LOCAL): Remove deprecated comment.
+ * include/private/thread_local_alloc.h (THREAD_LOCAL_ALLOC):
+ Remove redundant test of the macro.
+ * include/private/thread_local_alloc.h: Reformat the code.
+
+2011-05-11 Ivan Maidanski <ivmai@mail.ru>
+
+ * backgraph.c (add_edge): Recognize DEBUG_PRINT_BIG_N_EDGES macro.
+ * os_dep.c (GC_set_and_save_fault_handler): Recognize
+ SIGACTION_FLAGS_NODEFER_HACK macro.
+ * pthread_support.c (mark_mutex): Recognize GLIBC_2_1_MUTEX_HACK
+ macro.
+ * pthread_support.c (GC_acquire_mark_lock): Remove commented out
+ code.
+ * include/gc_inline.h (GC_MALLOC_WORDS, GC_MALLOC_ATOMIC_WORDS,
+ GC_CONS): Remove trailing space (before back-slash).
+ * include/private/gc_hdrs.h (GET_BI, GET_HDR_ADDR): Ditto.
+ * include/private/gc_pmark.h (PUSH_OBJ, PUSH_CONTENTS,
+ SET_MARK_BIT_EXIT_IF_SET, LONG_MULT, PUSH_CONTENTS_HDR,
+ GC_PUSH_ONE_STACK, GC_PUSH_ONE_HEAP): Ditto.
+ * include/private/thread_local_alloc.h (GC_key_create): Ditto.
+ * include/private/gc_priv.h (SUNOS5SIGS): Don't include
+ sys/siginfo.h on Linux.
+ * include/private/gcconfig.h: Reformat comments (and some code).
+ * include/private/gcconfig.h (FORCE_WRITE_PREFETCH): New macro
+ recognized, force PREFETCH_FOR_WRITE to be defined on x86.
+ * include/private/gcconfig.h (USE_HPUX_FIXED_STACKBOTTOM): New
+ macro recognized (for HP/UX).
+
+2011-05-11 Ivan Maidanski <ivmai@mail.ru>
+
+ * os_dep.c (GC_gww_page_was_ever_dirty): Fix comment (for
+ GWW_VDB).
+ * os_dep.c (GC_dirty_init): Use memset() for GC_written_pages
+ resetting (for PROC_VDB).
+
+2011-05-11 Ivan Maidanski <ivmai@mail.ru> (mostly really Ludovic Courtes)
+
+ * tests/threadkey_test.c: New file.
+ * .cvsignore (threadkey_test): Add.
+ * tests/tests.am (TESTS, check_PROGRAMS): Add 'threadkey_test'.
+ * tests/tests.am (threadkey_test_SOURCES, threadkey_test_LDADD):
+ New variable.
+ * Makefile.in: Regenerate.
+
+2011-05-11 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (GC_unregister_my_thread_inner): Don't call
+ GC_remove_specific.
+ * include/private/thread_local_alloc.h (GC_remove_specific):
+ Remove (since it is empty for all targets).
+ * pthread_support.c (GC_record_stack_base): New inline function.
+ * win32_threads.c (GC_record_stack_base): Ditto.
+ * pthread_support.c (GC_register_my_thread_inner): Invoke
+ GC_record_stack_base.
+ * win32_threads.c (GC_register_my_thread_inner): Ditto.
+ * pthread_support.c (GC_register_my_thread): If thread is FINISHED
+ then call GC_record_stack_base, clear FINISHED, initialize
+ thread-local list and return success.
+ * win32_threads.c (GC_register_my_thread): Ditto.
+ * include/gc.h (GC_register_my_thread): Update documentation.
+ * include/private/thread_local_alloc.h (GC_thread_key): Ditto.
+
+2011-05-10 Ivan Maidanski <ivmai@mail.ru>
+
+ * thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Join
+ adjacent "#ifdef".
+ * thread_local_alloc.c (GC_malloc_atomic): Call
+ GC_core_malloc_atomic (instead of GC_core_malloc).
+
+2011-05-10 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_start.c (GC_start_rtn_prepare_thread): Change return
+ type to GC_thread.
+ * pthread_start.c (GC_inner_start_routine): Pass the current
+ thread descriptor to pthread_cleanup_push (same as in
+ win32_threads.c).
+ * pthread_stop_world.c (GC_push_all_stacks): Rename "me" local
+ variable to "self".
+ * win32_threads.c (GC_push_all_stacks): Ditto.
+ * pthread_stop_world.c (GC_suspend_all, GC_start_world): Rename
+ "my_thread" local variable to "self".
+ * pthread_support.c (GC_unregister_my_thread_inner): New static
+ function.
+ * pthread_support.c (GC_unregister_my_thread,
+ GC_thread_exit_proc): Use GC_unregister_my_thread_inner.
+ * win32_threads.c (GC_register_my_thread, GC_unregister_my_thread,
+ GC_do_blocking_inner): Rename "t" local variable to "thread_id".
+ * win32_threads.c (GC_wait_marker, GC_notify_all_marker): Rename
+ "id" local variable to "thread_id".
+
+2011-05-10 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (GC_unregister_my_thread): Call pthread_self
+ only once.
+ * win32_threads.c (GC_pthread_start_inner): Ditto.
+ * pthread_support.c (GC_unregister_my_thread): Add debug output.
+ * win32_threads.c (GC_unregister_my_thread): Ditto.
+ * pthread_support.c (GC_register_my_thread,
+ GC_start_rtn_prepare_thread): Rename "my_pthread" local variable
+ to "self".
+
+2011-05-10 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/gc.h (GC_HIDE_POINTER, GC_REVEAL_POINTER): Define
+ unconditionally (do not test GC_I_HIDE_POINTERS); update the
+ comment.
+ * include/gc.h (HIDE_POINTER, REVEAL_POINTER): Define as alias to
+ GC_HIDE/REVEAL_POINTER, respectively.
+ * include/private/gc_pmark.h (GC_I_HIDE_POINTERS): Do not define.
+ * include/private/gc_priv.h (GC_I_HIDE_POINTERS): Ditto.
+
+2011-05-10 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/gc.h (GC_register_my_thread): Refine the comment.
+
+2011-05-08 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/gc_inline.h (GC_MALLOC_WORDS, GC_CONS): Add missing
+ parentheses.
+ * include/gc_typed.h (GC_get_bit, GC_set_bit,
+ GC_CALLOC_EXPLICITLY_TYPED): Ditto.
+
+2011-05-07 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gcconfig.h (NO_GETCONTEXT): Add missing ')'.
+
+2011-05-07 Ivan Maidanski <ivmai@mail.ru> (really Thorsten Glaser)
+
+ * include/private/gcconfig.h (NO_GETCONTEXT): Do not use
+ getcontext(2) on m68k because it is not implemented there.
+
+2011-05-07 Ivan Maidanski <ivmai@mail.ru>
+
+ * alloc.c (GC_clear_a_few_frames): Use BZERO().
+ * mark_rts.c (GC_clear_roots, GC_rebuild_root_index): Ditto.
+ * reclaim.c (GC_start_reclaim): Ditto.
+ * blacklst.c (total_stack_black_listed): Remove "len" local
+ variable.
+ * dbg_mlc.c (GC_generate_random_valid_address): Replace "for"
+ statement with "do-while" one.
+ * dyn_load.c (GC_register_dynamic_libraries,
+ GC_register_dynlib_callback): Remove redundant parentheses.
+
+2011-05-06 Ivan Maidanski <ivmai@mail.ru>
+
+ * cord/cordxtra.c (CORD_from_file_lazy_inner): Suppress
+ "unused result" compiler warning for fread().
+ * cord/cordxtra.c: Expand all tabs to spaces.
+
+2011-05-06 Ivan Maidanski <ivmai@mail.ru>
+
+ * os_dep.c (GC_write_fault_handler): Break when in_allocd_block
+ is set to true.
+
+2011-05-06 Ivan Maidanski <ivmai@mail.ru>
+
+ * dbg_mlc.c (GC_has_other_debug_info): Change return type to int;
+ return -1 if the object has (or had) debugging info but was
+ marked deallocated.
+ * include/private/dbg_mlc.h (GC_has_other_debug_info): Ditto.
+ * dbg_mlc.c (GC_has_other_debug_info): Update documentation;
+ remove "ohdr" local variable.
+ * dbg_mlc.c (GC_debug_free): Don't call GC_free if the object has
+ probably been deallocated.
+ * dbg_mlc.c (GC_debug_free): Don't actually free the object even
+ in the leak-finding mode if GC_findleak_delay_free.
+ * dbg_mlc.c (GC_print_all_smashed_proc): Print a trailing blank
+ line.
+ * dbg_mlc.c (GC_check_leaked): New function (only unless
+ SHORT_DBG_HDRS).
+ * doc/README.environment (GC_FINDLEAK_DELAY_FREE): Document.
+ * doc/README.macros (GC_FINDLEAK_DELAY_FREE): Ditto.
+ * include/private/dbg_mlc.h (START_FLAG, END_FLAG): Use GC_WORD_C
+ on 64-bit architectures.
+ * include/private/dbg_mlc.h (NOT_MARKED): Remove redundant
+ parentheses.
+ * include/private/dbg_mlc.h (GC_HAS_DEBUG_INFO): Update (due to
+ GC_has_other_debug_info change).
+ * include/private/gc_priv.h (GC_findleak_delay_free): New global
+ variable declaration (unless SHORT_DBG_HDRS).
+ * misc.c (GC_findleak_delay_free): New global variable; recognize
+ GC_FINDLEAK_DELAY_FREE.
+ * misc.c (GC_init): Recognize GC_FINDLEAK_DELAY_FREE environment
+ variable (unless SHORT_DBG_HDRS).
+ * reclaim.c (GC_check_leaked): Declare (unless SHORT_DBG_HDRS).
+ * reclaim.c (GC_add_leaked): Don't add the object to leaked list
+ if marked as deallocated.
+
+2011-05-05 Ivan Maidanski <ivmai@mail.ru>
+
+ * dbg_mlc.c (GC_has_other_debug_info): Fix punctuation in the
+ comment.
+ * dbg_mlc.c (GC_FREED_MEM_MARKER): New macro.
+ * dbg_mlc.c (GC_debug_free): Use GC_FREED_MEM_MARKER.
+ * dbg_mlc.c (GC_smashed): Refine documentation.
+ * mark.c (GC_push_selected): Change dirty_fn return type to
+ GC_bool.
+ * os_dep.c (GC_page_was_ever_dirty): Make GC_INNER.
+ * reclaim.c (GC_reclaim_small_nonempty_block): Remove "kind"
+ local variable.
+ * reclaim.c (GC_reclaim_block): Pass true constant to
+ GC_reclaim_small_nonempty_block (instead of report_if_found).
+ * doc/README.autoconf: Update; fix a typo.
+ * include/private/gcconfig.h (GC_WORD_C): New macro.
+
+2011-05-03 Ivan Maidanski <ivmai@mail.ru>
+
+ * dbg_mlc.c (GC_store_debug_info_inner): Cast "linenum".
+ * dbg_mlc.c (GC_check_annotated_obj): Fix punctuation in the
+ comment.
+ * dbg_mlc.c (GC_print_smashed_obj): Add (and print) "msg"
+ argument.
+ * dbg_mlc.c (GC_debug_free, GC_print_all_smashed_proc): Pass
+ message to GC_print_smashed_obj.
+ * dbg_mlc.c (GC_debug_free): Call GC_size once.
+ * dbg_mlc.c (GC_debug_realloc): Calculate old_sz only if
+ allocation succeeded; remove unnecessary check for object is
+ smashed (since this is done in GC_debug_free); remove "clobbered"
+ local variable.
+
+2011-05-03 Ivan Maidanski <ivmai@mail.ru>
+
+ * dbg_mlc.c (GC_store_debug_info_inner, GC_store_debug_info):
+ Rename "integer" argument to "linenum"; change the type of the
+ argument to int.
+ * gcj_mlc.c (GC_store_debug_info): Ditto.
+ * dbg_mlc.c (GET_OH_LINENUM): New macro.
+ * dbg_mlc.c (GC_print_obj, GC_print_smashed_obj): Use
+ GET_OH_LINENUM; adjust print format specifier.
+ * dbg_mlc.c (GC_debug_malloc, GC_debug_malloc_ignore_off_page,
+ GC_debug_malloc_atomic_ignore_off_page,
+ GC_debug_generic_malloc_inner,
+ GC_debug_generic_malloc_inner_ignore_off_page,
+ GC_debug_malloc_stubborn, GC_debug_malloc_atomic,
+ GC_debug_malloc_uncollectable,
+ GC_debug_malloc_atomic_uncollectable): Remove unnecessary cast of
+ "i".
+ * gcj_mlc.c (GC_debug_gcj_malloc): Ditto.
+
+2011-04-26 Ivan Maidanski <ivmai@mail.ru>
+
+ * .cvsignore (initsecondarythread, test_cpp): Add.
+ * os_dep.c (GC_linux_stack_base): Rename to
+ GC_linux_main_stack_base.
+ * os_dep.c (GC_freebsd_stack_base): Rename to
+ GC_freebsd_main_stack_base; adjust error message.
+ * pthread_stop_world.c (GC_stop_init): Use GC_SEM_INIT_PSHARED
+ as an argument for sem_init().
+ * pthread_support.c (pthread_create): Ditto.
+ * pthread_support.c (pthread_create): Abort in case sem_init()
+ fails.
+ * include/private/gc_priv.h (GC_SEM_INIT_PSHARED): Define.
+ * tests/initsecondarythread.c: Include gcconfig.h; call GC_INIT
+ from main() if it should be done from the primordial thread only.
+
+2011-04-26 Ivan Maidanski <ivmai@mail.ru>
+
+ * alloc.c: Don't include sys/types.h for ArmCC.
+ * dyn_load.c: Ditto.
+ * os_dep.c: Ditto.
+ * mach_dep.c (_setjmp, _longjmp): Redirect to setjmp/longjmp for
+ ArmCC.
+ * mark.c (GC_noop): Define specially for ArmCC.
+ * include/private/gc_priv.h (GC_noop): Ditto.
+ * misc.c (GC_init): Don't test pointers comparison for ArmCC.
+ * misc.c: Don't include unistd.h for ArmCC.
+ * os_dep.c (pages_executable): Rename to GC_pages_executable;
+ make STATIC.
+ * os_dep.c (GC_unix_mmap_get_mem): Don't define for ArmCC.
+ * ptr_chck.c (GC_is_visible): Explicitly cast
+ (GC_DS_PER_OBJECT-GC_INDIR_PER_OBJ_BIAS) to word (to suppress
+ a compiler warning).
+ * include/private/gcconfig.h: Recognize __arm.
+ * include/private/gcconfig.h (HBLKPTR): Define for ArmCC.
+ * include/private/gcconfig.h (HBLKPTR): Add parentheses for
+ "bytes" argument.
+
+2011-04-24 Ivan Maidanski <ivmai@mail.ru>
+
+ * pthread_support.c (GC_get_nprocs): Don't define for Android.
+ * pthread_support.c (GC_dummy_thread_local): Don't test
+ GC_LINUX_THREADS.
+ * include/gc_config_macros.h (GC_ADD_CALLER, GC_RETURN_ADDR):
+ Define for Android.
+
+2011-04-24 Ivan Maidanski <ivmai@mail.ru>
+
+ * mach_dep.c (NO_GETCONTEXT): Move to gcconfig.h.
+ * os_dep.c (GC_write_fault_handler): Don't include ucontext.h if
+ NO_GETCONTEXT.
+ * include/private/gcconfig.h (GETPAGESIZE): Define as a sysconf
+ call for Android.
+
+2011-04-23 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gc_locks.h (WIN32_LEAN_AND_MEAN, NOSERVICE):
+ Define before including windows.h.
+ * include/private/gc_priv.h (WIN32_LEAN_AND_MEAN, NOSERVICE):
+ Ditto.
+ * include/private/thread_local_alloc.h (WIN32_LEAN_AND_MEAN,
+ NOSERVICE): Ditto.
+ * include/private/gc_priv.h (CLOCKS_PER_SEC): Reformat the
+ comment.
+ * include/private/gc_priv.h (MS_TIME_DIFF): Avoid floating-point
+ arithmetics; add a comment.
+
+2011-04-23 Ivan Maidanski <ivmai@mail.ru>
+
+ * mark.c (GC_clear_hdr_marks): Don't test USE_MARK_BYTES.
+ * extra/setjmp_t.c (main): Don't test USE_MARK_BITS.
+ * include/private/gc_pmark.h (SET_MARK_BIT_EXIT_IF_SET): Ditto.
+ * include/private/gc_pmark.h (SET_MARK_BIT_EXIT_IF_SET): Remove
+ "mark_byte" local variable.
+ * include/private/gc_pmark.h (OR_WORD_EXIT_IF_SET): Add a comment
+ about that AO_or() is not used by GC unless USE_MARK_BITS
+ explicitly set.
+ * include/private/gc_priv.h (OR_WORD): Ditto.
+ * include/private/gc_pmark.h (INCR_MARKS): Remove trailing ';',
+ add parentheses.
+ * include/private/gc_priv.h (ONES): Define before use by
+ MAKE_COOLER.
+ * include/private/gc_priv.h (MARK_BITS_SZ): Define where used.
+ * include/private/gc_priv.h (OR_WORD): Don't define if
+ USE_MARK_BYTES.
+ * include/private/gcconfig.h (USE_MARK_BYTES); Remove duplicate
+ definition; simplify expression.
+
+2011-04-22 Ivan Maidanski <ivmai@mail.ru>
+
+ * os_dep.c (GC_get_maps): Always close the file.
+ * pthread_support.c (GC_get_nprocs): Ditto.
+ * os_dep.c (READ): Define similarly across the file (without
+ parameters).
+ * pthread_support.c (GC_get_nprocs): Use signed int type for "i"
+ and "len" local variables (since read() may return -1).
+ * include/private/gc_pmark.h (LONG_MULT): Add prefix/suffix
+ double underscore; add "volatile" for asm.
+ * include/private/gc_pmark.h (LONG_MULT): Add missing
+ parentheses.
+ * include/private/gc_priv.h (OR_WORD): Ditto.
+ * include/private/gc_priv.h (OR_WORD): Remove unnecessary brackets
+ and ';' symbol.
+
+2011-04-22 Ivan Maidanski <ivmai@mail.ru>
+
+ * os_dep.c (GC_get_stack_base): Implement for Android (same as
+ for Linux).
+ * pthread_support.c (GC_get_nprocs): Return 1 (instead of -1) if
+ failed to open "stat" file (not to issue a warning twice); update
+ the comment.
+ * pthread_support.c (GC_thr_init): Call sysconf() on Android to
+ get the number of CPUs.
+
+2011-04-21 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gc_priv.h (_GNU_SOURCE): Revert one of the
+ recent patches regarding this macro as the macro should be set
+ (to 1) before including any other system header.
+
+2011-04-21 Ivan Maidanski <ivmai@mail.ru>
+
+ * doc/README.environment (GC_INITIAL_HEAP_SIZE,
+ GC_MAXIMUM_HEAP_SIZE): Update.
+
+2011-04-20 Ivan Maidanski <ivmai@mail.ru>
+
+ * misc.c (GC_parse_mem_size_arg): Allow 'k', 'M', 'G' suffixes in
+ heap size specifier; return 0 if not a valid one.
+ * include/gc_cpp.h: Explicitly define inline one-argument delete
+ operator for Cygwin (as a workaround).
+ * include/gc_cpp.h: Reformat the code.
+ * tests/test_cpp.cc: Ditto.
+ * tests/test_cpp.cc (main): Suppress compiler warnings about
+ "assigned value is unused".
+
+2011-04-19 Ivan Maidanski <ivmai@mail.ru>
+
+ * misc.c (GC_parse_mem_size_arg): New function.
+ * misc.c (GC_init): Use GC_parse_mem_size_arg().
+ * pthread_stop_world.c (tkill): Declare for Android.
+
+2011-04-19 Ivan Maidanski <ivmai@mail.ru>
+
+ * include/private/gc_priv.h (_GNU_SOURCE): Include features.h
+ first (except for NaCl) and then define the macro to 1 if not yet.
+
+2011-04-18 Ivan Maidanski <ivmai@mail.ru> (really Ludovic Courtes)
+
+ * tests/tests.am (TESTS, check_PROGRAMS): Add
+ 'initsecondarythread'.
+ * tests/tests.am (initsecondarythread_SOURCES,
+ initsecondarythread_LDADD): New variable.
+ * Makefile.in: Regenerate.
+ * configure: Ditto.
+
+2011-04-18 Ivan Maidanski <ivmai@mail.ru>
+
+ * dbg_mlc.c (GC_store_debug_info_inner): Always define; add
+ "const" to its string argument.
+ * dbg_mlc.c (GC_store_debug_info): Call GC_store_debug_info_inner.
+ * dbg_mlc.c (GC_debug_free): Set GC_have_errors in case of
+ smashed or previously deallocated found.
+ * dbg_mlc.c (GC_check_heap_block): Replace while loop with a for
+ one.
+ * reclaim.c (GC_reclaim_check): Ditto.
+ * dbg_mlc.c (GC_check_heap_proc): Remove redundant cast to word.
+ * os_dep.c (GC_get_stack_base): Don't initialize
+ stackbase_main_self/ss_sp on Solaris if thr_main() is zero (thus
+ calling GC_INIT() from a non-primordial thread is possible now).
+ * reclaim.c (GC_add_leaked): Turn into an inline one.
+ * reclaim.c (GC_reclaim_small_nonempty_block):
+ Change report_if_found type from int/word to boolean.
+ * include/private/gc_priv.h (GC_start_reclaim): Ditto.
+ * include/private/gc_priv.h (set_mark_bit_from_hdr,
+ clear_mark_bit_from_hdr): Place closing parenthesis properly;
+ reformat the code.
+
+2011-04-16 Ivan Maidanski <ivmai@mail.ru>
+
+ * os_dep.c (GC_get_main_stack_base): Try to use
+ pthread_attr_getstack first for Linux if THREADS.
+ * doc/README.macros (USE_GET_STACKBASE_FOR_MAIN): Adjust text
+ alignment.
+
+2011-04-13 Ivan Maidanski <ivmai@mail.ru>
+
+ * dbg_mlc.c (GC_generate_random_backtrace_no_gc): Fix a message
+ typo.
+ * dbg_mlc.c (GC_debug_malloc): Add a comment (about zero size).
+ * dbg_mlc.c (GC_debug_generic_malloc_inner): Reformat the comment.
+ * dbg_mlc.c (GC_strdup): Call GC_err_printf instead of WARN (in
+ case of NULL argument).
+ * dbg_mlc.c (GC_free): In case of NULL argument, just return
+ (without any warning printed); eliminate "uncollectable" local
+ variable.
+
+2011-04-13 Ivan Maidanski <ivmai@mail.ru> (mostly really Rainer Orth)
+
+ * configure.ac (THREADDLLIBS): Use alternate thread library on
+ Solaris 8.
+ * configure.ac (need_atomic_ops_asm): Set to true only for Sparc
+ Solaris.
+ * configure.ac: Don't use libdl on mips-sgi-irix6.
+ * configure: Regenerate.
+
+2011-04-11 Ivan Maidanski <ivmai@mail.ru> (really Jie Liu)
+
+ * mach_dep.c (NO_GETCONTEXT); Define for RTEMS.
+ * mach_dep.c (GC_with_callee_saves_pushed): Don't call
+ __builtin_unwind_init() for RTEMS; use setjmp() without the
+ leading underscore (for RTEMS).
+ * tests/test.c (BIG): Use smaller value for RTEMS.
+ * tests/test.c (main): Customize for RTEMS.
+
+2011-04-11 Ivan Maidanski <ivmai@mail.ru> (mostly really Jim Meyering)
+
+ * configure.host: Remove doubled words in comments.
+ * os_dep.c: Ditto.
+ * doc/README: Ditto.
+ * extra/setjmp_t.c: Ditto.
+ * tests/huge_test.c: Ditto.
+ * extra/setjmp_t.c (getpagesize, nested_sp, main, g): Replace the
+ K&R-style function definition with the ANSI C one.
+ * extra/setjmp_t.c: Expand all tabs to spaces.
+ * extra/setjmp_t.c (nested_sp): Implement in the same way as
+ GC_approx_sp.
+
+2011-04-10 Ivan Maidanski <ivmai@mail.ru> (really Iain Sandoe, Mike Stump)
+
+ * dyn_load.c (GC_dyld_sections): Add more sctions.
+ * dyn_load.c (GC_dyld_add_sect_fmts): New static varaible.
+ * dyn_load.c (L2_MAX_OFILE_ALIGNMENT): New macro.
+ * dyn_load.c (GC_dyld_image_add, GC_dyld_image_remove): Improve
+ logging; add support for on-demand sections.
+ * dyn_load.c (GC_dyld_image_add, GC_dyld_image_remove): Reformat
+ the code.
+
+2011-04-10 Ivan Maidanski <ivmai@mail.ru>
+
+ * gcj_mlc.c (GC_gcj_malloc_initialized): Use STATIC unless
+ GC_ASSERTIONS.
+ * include/private/gc_priv.h (GC_gcj_malloc_initialized): Don't
+ declare (as external) unless GC_ASSERTIONS.
+ * os_dep.c (GC_win32_free_heap): Clear GC_heap_bases[] also for
+ Cygwin; add FIXME.
+ * include/private/gcconfig.h: Include <sys/unistd.h> for RTEMS.
+ * include/private/gcconfig.h: Add "#error" for every "-->" mark.
+ * include/private/gcconfig.h (CLEAR_DOUBLE): Turn the code into
+ an expression.
+ * include/private/pthread_support.h (SUSPENDED_EXT): Add new flag
+ (which existed previously as SUSPENDED and still exists in GCJ).
+ * include/private/pthread_support.h (DISABLED_GC): Change the
+ value (as it is already used by SUSPENDED_EXT).
+
+2011-04-10 Ivan Maidanski <ivmai@mail.ru> (mostly really Iain Sandoe)
+
+ * tests/test.c (reverse_test): Modify count (BIG) for
+ ppc64-darwin.
+
+2011-04-09 Ivan Maidanski <ivmai@mail.ru>
+
+ * reclaim.c (GC_print_all_errors): Recognize new GC_ABORT_ON_LEAK
+ macro and environment variable; abort if any error has been
+ printed provided the environment variable (or macro) is set.
+ * doc/README.environment (GC_ABORT_ON_LEAK): Document.
+ * doc/README.macros (GC_ABORT_ON_LEAK): Ditto.
+ * doc/README.macros (FIND_LEAK, SUNOS5SIGS, PCR,
+ USE_COMPILER_TLS): Reformat the text.
+
+2011-04-09 Ivan Maidanski <ivmai@mail.ru> (really Jie Liu)
+
+ * os_dep.c (GC_unix_sbrk_get_mem, GC_unix_get_mem): Don't define
+ for RTEMS.
+ * include/private/gcconfig.h (RTEMS): Add support for.
+ * include/private/gcconfig.h (GET_MEM): Use calloc() for RTEMS.
+
+2011-04-09 Ivan Maidanski <ivmai@mail.ru>
+
+ * mallocx.c (GC_malloc_uncollectable): Move to malloc.c (since
+ it is used internally in some places).
+
+2011-04-09 Ivan Maidanski <ivmai@mail.ru>
+
+ * dbg_mlc.c (GC_register_finalizer_no_order): Remove redundant
+ declaration.
+ * dbg_mlc.c (GC_debug_malloc_replacement,
+ GC_debug_realloc_replacement): Rename RA to GC_DBG_RA.
+ * malloc.c (GC_debug_malloc_replacement): Ditto.
+ * mallocx.c (GC_debug_realloc_replacement): Ditto.
+ * dbg_mlc.c (GC_store_debug_info): Move proto from dbg_mlc.h.
+ * malloc.c (GC_strdup, GC_strndup, GC_wcsdup): Move to mallocx.c.
+ * malloc.c: Include errno.h only REDIRECT_MALLOC; remove redundant
+ includes of string.h.
+ * mallocx.c: Include string.h (for GC_strdup).
+ * include/private/dbg_mlc.h (GC_store_debug_info): Move declaration
+ to dbg_mlc.c.
+ * include/private/gc_locks.h (UNCOND_LOCK, UNCOND_UNLOCK): Remove
+ redundant trailing ';'.
+ * include/private/gc_priv.h (START_WORLD, COND_DUMP): Ditto.
+ * include/private/gc_locks.h (LOCK, UNLOCK): Place opening '{'
+ properly.
+ * include/private/gc_priv.h (GC_DBG_RA): Move from dbg_mlc.c,
+ malloc.c, mallocx.c.
+
+2011-04-07 Ivan Maidanski <ivmai@mail.ru>
+
+ * alloc.c (GC_check_heap, GC_print_all_smashed): Move the
+ definition from misc.c.
+ * dbg_mlc.c (GC_debug_malloc_atomic_uncollectable): Define as
+ public.
+ * include/gc.h (GC_debug_malloc_atomic_uncollectable): Declare.
+ * include/gc.h (GC_MALLOC_ATOMIC_UNCOLLECTABLE): Define new public
+ macro.
+ * dbg_mlc.c (MAX_SMASHED): Don't define if already set.
+ * reclaim.c (MAX_LEAKED): Ditto.
+ * dbg_mlc.c (GC_add_smashed): Add FIXME about the concurrent
+ access to the global array.
+ * reclaim.c (GC_add_leaked): Ditto.
+ * misc.c (GC_print_back_height): Set on if GC_PRINT_BACK_HEIGHT
+ (new macro) is defined.
+ * doc/README.macros (GC_PRINT_BACK_HEIGHT): Document.
+ * misc.c (GC_dump_regularly, GC_init): Replace 0/1 for
+ GC_dump_regularly and GC_print_back_height variables with
+ FALSE/TRUE.
+ * reclaim.c (GC_print_all_errors): Refine the comment.
+
+2011-04-04 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/test.c (reverse_test_inner): Undo one of the previous
+ patches which shifts "c" and "d" pointers only if
+ ALL_INTERIOR_POINTERS (since interior pointers are always
+ recognized in stacks).
+
+2011-04-03 Ivan Maidanski <ivmai@mail.ru>
+
+ * misc.c (GC_stdout, GC_stderr): Move the definition to the place
+ where GC_log is defined (Unix only).
+ * misc.c (GC_init): Recognize "GC_ONLY_LOG_TO_FILE" environment
+ variable and the similar macro; redirect GC_stdout and GC_stderr
+ to GC_log if "GC_LOG_FILE" environment variable is set unless
+ prohibited by GC_ONLY_LOG_TO_FILE (Unix only).
+ * doc/README.environment (GC_ONLY_LOG_TO_FILE): Document.
+ * doc/README.macros (GC_ONLY_LOG_TO_FILE): Ditto.
+
+2011-04-03 Ivan Maidanski <ivmai@mail.ru>
+
+ * misc.c (GC_stdout, GC_write): Rename GC_stdout to GC_log (Win32
+ only).
+ * misc.c (GC_write): Add for MacOS (and OS/2); change WRITE()
+ accordingly.
+ * misc.c (GC_write): Reformat code (Unix only).
+ * misc.c (GC_printf): Check GC_quiet before va_start().
+
+2011-04-03 Ivan Maidanski <ivmai@mail.ru>
+
+ * allchblk.c (GC_freehblk): Use GC_log_printf instead of GC_printf
+ inside "if (GC_print_stats)" branch.
+ * alloc.c (GC_collect_or_expand): Ditto.
+ * dyn_load.c (GC_register_dynamic_libraries): Ditto.
+ * headers.c (GC_scratch_alloc): Ditto.
+ * os_dep.c (GC_get_maps, GC_remap, PROTECT,
+ GC_write_fault_handler, GC_dirty_init, GC_mprotect_thread): Ditto.
+ * alloc.c (min_bytes_allocd): Use GC_log_printf instead of
+ GC_printf for DEBUG_THREADS output.
+ * darwin_stop_world.c (GC_stack_range_for, GC_suspend_thread_list,
+ GC_stop_world, GC_thread_resume, GC_start_world): Ditto.
+ * pthread_start.c (GC_inner_start_routine): Ditto.
+ * pthread_stop_world.c (GC_suspend_handler, GC_restart_handler,
+ GC_push_all_stacks, GC_suspend_all, GC_stop_world,
+ GC_start_world): Ditto.
+ * pthread_support.c (GC_mark_thread, GC_get_nprocs,
+ GC_start_rtn_prepare_thread, pthread_create): Ditto.
+ * alloc.c (GC_adj_bytes_allocd, GC_maybe_gc, GC_stopped_mark,
+ GC_finish_collection): Reformat code.
+ * pthread_stop_world.c (GC_print_sig_mask): Ditto.
+ * pthread_support.c (GC_thr_init): Ditto.
+ * checksums.c (GC_update_check_page): Use GC_printf() instead of
+ GC_err_printf() for error printing.
+ * checksums.c (GC_check_blocks, GC_check_dirty): Use GC_log_printf
+ instead of GC_printf for logging purposes.
+ * dyn_load.c (sys_errlist, sys_nerr, errno): Move declaration of
+ external variable outside from GC_register_dynamic_libraries.
+ * dyn_load.c (GC_register_dynamic_libraries): Don't use
+ sys_errlist value if errno equals to sys_nerr.
+ * dyn_load.c (GC_register_dynamic_libraries): Use GC_log_printf
+ instead of GC_printf for DL_VERBOSE output.
+ * dyn_load.c (GC_dyld_image_add, GC_dyld_image_remove,
+ GC_init_dyld): Use GC_log_printf instead of GC_printf for
+ DARWIN_DEBUG output.
+ * os_dep.c (catch_exception_raise): Use GC_log_printf
+ instead of GC_printf for DEBUG_EXCEPTION_HANDLING output.
+ * reclaim.c (GC_print_free_list): Move "n" increment out of
+ GC_printf() call.
+
+2011-04-03 Ivan Maidanski <ivmai@mail.ru>
+
+ * win32_threads.c (DEBUG_CYGWIN_THREADS, DEBUG_WIN32_PTHREADS,
+ DEBUG_WIN32_THREADS): Remove.
+ * win32_threads.c (GC_register_my_thread_inner,
+ GC_win32_start_inner): Use GC_log_printf instead of GC_printf
+ inside "if (GC_print_stats)" branch.
+ * win32_threads.c (GC_PTHREAD_PTRVAL): New macro (defined only if
+ GC_PTHREADS).
+ * win32_threads.c (GC_delete_gc_thread, NUMERIC_THREAD_ID,
+ GC_pthread_join, GC_pthread_create): Use GC_PTHREAD_PTRVAL
+ macro.
+ * win32_threads.c (GC_push_stack_for, GC_mark_thread,
+ GC_CreateThread, GC_beginthreadex, GC_pthread_join,
+ GC_pthread_create, GC_pthread_start_inner, GC_thread_exit_proc,
+ GC_mark_thread_local_free_lists): Use GC_log_printf instead of
+ GC_printf for DEBUG_THREADS output.
+ * win32_threads.c (GC_win32_start_inner, GC_CreateThread,
+ GC_beginthreadex, GC_pthread_join, GC_pthread_create,
+ GC_pthread_start_inner, GC_thread_exit_proc): Cast
+ GetCurrentThreadId result to long; don't cast value of pthread_t
+ type to int; adjust printf format specifiers.
+ * doc/README.win32 (DEBUG_WIN32_PTHREADS): Remove obsolete
+ information.
+
+2011-04-03 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/test.c (cons, small_cons, gcj_cons, check_ints,
+ check_uncollectable_ints, print_int_list, check_marks_int_list,
+ fork_a_thread, finalizer, mktree, chktree, alloc8bytes,
+ alloc_small, tree_test, typed_test, check_heap_stats, WinMain,
+ test, main): Remove unnecessary casts of GC_printf calls to void.
+
+2011-04-02 Ivan Maidanski <ivmai@mail.ru>
+
+ * allchblk.c (GC_print_hblkfreelist): Adjust (make uniform across
+ BDWGC) printed message (adjust letters case, terminating dot and
+ new line symbols).
+ * alloc.c (GC_check_fl_marks): Ditto.
+ * backgraph.c (new_back_edges): Ditto.
+ * checksums.c (GC_check_dirty): Ditto.
+ * darwin_stop_world.c (GC_push_all_stacks,
+ GC_suspend_thread_list): Ditto.
+ * dbg_mlc.c (GC_print_type, GC_debug_free, GC_debug_realloc,
+ store_old): Ditto.
+ * dyn_load.c (GC_register_dynamic_libraries): Ditto.
+ * mark.c (GC_initiate_gc, GC_mark_some, GC_mark_from, GC_push_all,
+ GC_push_selected, GC_push_next_marked_dirty): Ditto.
+ * mark_rts.c (GC_exclude_static_roots_inner): Ditto.
+ * os_dep.c (GC_remap, GC_default_push_other_roots,
+ GC_push_thread_structures, GC_dirty_init, GC_read_dirty,
+ catch_exception_raise_state, catch_exception_raise_state_identity,
+ GC_mprotect_thread_notify, GC_mprotect_thread,
+ catch_exception_raise): Ditto.
+ * pthread_stop_world.c (GC_print_sig_mask, GC_push_all_stacks,
+ GC_stop_world, GC_stop_init): Ditto.
+ * pthread_support.c (GC_thr_init, GC_register_my_thread_inner,
+ GC_start_routine): Ditto.
+ * win32_threads.c (GC_register_my_thread_inner,
+ GC_push_all_stacks, GC_win32_start_inner, GC_pthread_join,
+ GC_pthread_start_inner): Ditto.
+ * alloc.c (GC_expand_hp_inner): Realign the code.
+ * mark.c (GC_mark_from, GC_mark_local, GC_do_parallel_mark):
+ Ditto.
+ * misc.c (GC_init): Ditto.
+ * os_dep.c (GC_dirty_init, GC_read_dirty): Ditto.
+ * include/private/gc_pmark.h (PUSH_CONTENTS_HDR): Ditto.
+ * tests/test.c (run_one_test): Ditto.
+ * misc.c (GC_err_puts): Document.
+ * misc.c (GC_err_write): Remove.
+ * os_dep.c (dump_maps): Ditto.
+ * include/private/gc_priv.h (GC_err_write): Ditto.
+ * os_dep.c (GC_print_address_map): Call GC_err_puts() instead of
+ dump_maps() and GC_err_write().
+ * os_dep.c (GC_read_dirty): Remove redundant brackets.
+
+2011-04-02 Ivan Maidanski <ivmai@mail.ru>
+
+ * tests/test.c (reverse_test_inner): Test interior pointer
+ recognition only if ALL_INTERIOR_POINTERS.
+ * tests/test.c (run_one_test): Replace GC_all_interior_pointers
+ with GC_get_all_interior_pointers(); simplify the expression.
+ * tests/test.c (check_heap_stats): Replace GC_bytes_allocd and
+ GC_bytes_allocd_before_gc with GC_get_total_bytes().
+ * tests/test.c (main): Replace GC_gc_no with GC_get_gc_no().
+
2011-03-27 Ivan Maidanski <ivmai@mail.ru>
* dbg_mlc.c (GC_debug_strdup, GC_debug_free): Output a portability
@@ -49,12 +1186,13 @@
2011-03-22 Ivan Maidanski <ivmai@mail.ru>
- * misc.c (GC_abort): Use _exit() (instead of DebugBreak) on Win32 when
- doing code static analysis (to inform the tool that the function is
- a no-return one).
- * os_dep.c (GC_linux_stack_base): Remove a duplicate validation of the
- length of "stat" file; use signed int type for "i", "buf_offset" and
- "len" local variables (since read() may return -1).
+ * misc.c (GC_abort): Use _exit() (instead of DebugBreak) on Win32
+ when doing code static analysis (to inform the tool that the
+ function is a no-return one).
+ * os_dep.c (GC_linux_stack_base): Remove a duplicate validation
+ of the length of "stat" file; use signed int type for "i",
+ "buf_offset" and "len" local variables (since read() may
+ return -1).
2011-03-20 Ivan Maidanski <ivmai@mail.ru>
@@ -584,7 +1722,7 @@
type).
* os_dep.c (GC_dirty_init): Print a message about SIG_IGN detected
(for SIGSEGV/BUS) only if GC_print_stats.
- * os_dep.c (catch_exception_raise): Join 2 adjucent GC_err_printf
+ * os_dep.c (catch_exception_raise): Join 2 adjacent GC_err_printf
calls.
2010-11-25 Ivan Maidanski <ivmai@mail.ru>
diff --git a/Makefile.am b/Makefile.am
index 319e116d..4de6e46f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -172,7 +172,7 @@ EXTRA_DIST += README.QUICK
EXTRA_DIST += BCC_MAKEFILE NT_MAKEFILE \
OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE \
Makefile.direct Makefile.dj Makefile.DLLs SMakefile.amiga \
- WCC_MAKEFILE build_atomic_ops.sh build_atomic_ops.sh.cygwin \
+ WCC_MAKEFILE autogen.sh build_atomic_ops.sh build_atomic_ops.sh.cygwin \
NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
NT_X64_THREADS_MAKEFILE CMakeLists.txt tests/CMakeLists.txt
diff --git a/Makefile.direct b/Makefile.direct
index 99075fcd..707a94e2 100644
--- a/Makefile.direct
+++ b/Makefile.direct
@@ -418,7 +418,6 @@ gcname: $(srcdir)/extra/gcname.c $(srcdir)/include/gc_version.h
dist gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
cp Makefile Makefile.old
cp Makefile.direct Makefile
- CC=$(CC) ./configure_atomic_ops.sh
cd $(AO_SRC_DIR); $(MAKE) dist
if test $(srcdir)/libatomic_ops = $(AO_SRC_DIR); \
then \
diff --git a/Makefile.in b/Makefile.in
index 27163860..29d41ea0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -96,8 +96,9 @@ target_triplet = @target@
@USE_INTERNAL_LIBATOMIC_OPS_TRUE@ -I$(top_srcdir)/libatomic_ops/src
check_PROGRAMS = gctest$(EXEEXT) leaktest$(EXEEXT) middletest$(EXEEXT) \
- smashtest$(EXEEXT) hugetest$(EXEEXT) staticrootstest$(EXEEXT) \
- $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+ smashtest$(EXEEXT) hugetest$(EXEEXT) realloc_test$(EXEEXT) \
+ staticrootstest$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \
+ $(am__EXEEXT_3)
# C Library: Architecture Dependent
# ---------------------------------
@@ -121,8 +122,11 @@ DIST_COMMON = $(am__configure_deps) $(am__pkginclude_HEADERS_DIST) \
mkinstalldirs
@KEEP_BACK_PTRS_TRUE@am__append_7 = tracetest$(EXEEXT)
@KEEP_BACK_PTRS_TRUE@am__append_8 = tracetest
-@THREADS_TRUE@am__append_9 = threadleaktest$(EXEEXT)
-@THREADS_TRUE@am__append_10 = threadleaktest
+@THREADS_TRUE@am__append_9 = threadleaktest$(EXEEXT) \
+@THREADS_TRUE@ threadkey_test$(EXEEXT) \
+@THREADS_TRUE@ initsecondarythread$(EXEEXT)
+@THREADS_TRUE@am__append_10 = threadleaktest threadkey_test \
+@THREADS_TRUE@ initsecondarythread
@CPLUSPLUS_TRUE@am__append_11 = test_cpp$(EXEEXT)
@CPLUSPLUS_TRUE@am__append_12 = test_cpp
subdir = .
@@ -213,19 +217,30 @@ libstaticrootslib_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libstaticrootslib_la_LDFLAGS) $(LDFLAGS) -o $@
@KEEP_BACK_PTRS_TRUE@am__EXEEXT_1 = tracetest$(EXEEXT)
-@THREADS_TRUE@am__EXEEXT_2 = threadleaktest$(EXEEXT)
+@THREADS_TRUE@am__EXEEXT_2 = threadleaktest$(EXEEXT) \
+@THREADS_TRUE@ threadkey_test$(EXEEXT) \
+@THREADS_TRUE@ initsecondarythread$(EXEEXT)
@CPLUSPLUS_TRUE@am__EXEEXT_3 = test_cpp$(EXEEXT)
am_gctest_OBJECTS = test.$(OBJEXT)
gctest_OBJECTS = $(am_gctest_OBJECTS)
am_hugetest_OBJECTS = huge_test.$(OBJEXT)
hugetest_OBJECTS = $(am_hugetest_OBJECTS)
hugetest_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am__initsecondarythread_SOURCES_DIST = tests/initsecondarythread.c
+@THREADS_TRUE@am_initsecondarythread_OBJECTS = \
+@THREADS_TRUE@ initsecondarythread.$(OBJEXT)
+initsecondarythread_OBJECTS = $(am_initsecondarythread_OBJECTS)
+@THREADS_TRUE@initsecondarythread_DEPENDENCIES = \
+@THREADS_TRUE@ $(am__DEPENDENCIES_2)
am_leaktest_OBJECTS = leak_test.$(OBJEXT)
leaktest_OBJECTS = $(am_leaktest_OBJECTS)
leaktest_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_middletest_OBJECTS = middle.$(OBJEXT)
middletest_OBJECTS = $(am_middletest_OBJECTS)
middletest_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_realloc_test_OBJECTS = realloc_test.$(OBJEXT)
+realloc_test_OBJECTS = $(am_realloc_test_OBJECTS)
+realloc_test_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_smashtest_OBJECTS = smash_test.$(OBJEXT)
smashtest_OBJECTS = $(am_smashtest_OBJECTS)
smashtest_DEPENDENCIES = $(am__DEPENDENCIES_2)
@@ -241,6 +256,10 @@ test_cpp_OBJECTS = $(am_test_cpp_OBJECTS)
@AVOID_CPP_LIB_FALSE@@CPLUSPLUS_TRUE@ $(am__DEPENDENCIES_2)
@AVOID_CPP_LIB_TRUE@@CPLUSPLUS_TRUE@test_cpp_DEPENDENCIES = gc_cpp.o \
@AVOID_CPP_LIB_TRUE@@CPLUSPLUS_TRUE@ $(am__DEPENDENCIES_2)
+am__threadkey_test_SOURCES_DIST = tests/threadkey_test.c
+@THREADS_TRUE@am_threadkey_test_OBJECTS = threadkey_test.$(OBJEXT)
+threadkey_test_OBJECTS = $(am_threadkey_test_OBJECTS)
+@THREADS_TRUE@threadkey_test_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__threadleaktest_SOURCES_DIST = tests/thread_leak_test.c
@THREADS_TRUE@am_threadleaktest_OBJECTS = thread_leak_test.$(OBJEXT)
threadleaktest_OBJECTS = $(am_threadleaktest_OBJECTS)
@@ -283,16 +302,20 @@ LTCCASCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
SOURCES = $(libcord_la_SOURCES) $(libgc_la_SOURCES) \
$(EXTRA_libgc_la_SOURCES) $(nodist_libgc_la_SOURCES) \
$(libgccpp_la_SOURCES) $(libstaticrootslib_la_SOURCES) \
- $(gctest_SOURCES) $(hugetest_SOURCES) $(leaktest_SOURCES) \
- $(middletest_SOURCES) $(smashtest_SOURCES) \
- $(staticrootstest_SOURCES) $(test_cpp_SOURCES) \
+ $(gctest_SOURCES) $(hugetest_SOURCES) \
+ $(initsecondarythread_SOURCES) $(leaktest_SOURCES) \
+ $(middletest_SOURCES) $(realloc_test_SOURCES) \
+ $(smashtest_SOURCES) $(staticrootstest_SOURCES) \
+ $(test_cpp_SOURCES) $(threadkey_test_SOURCES) \
$(threadleaktest_SOURCES) $(tracetest_SOURCES)
DIST_SOURCES = $(libcord_la_SOURCES) $(am__libgc_la_SOURCES_DIST) \
$(EXTRA_libgc_la_SOURCES) $(am__libgccpp_la_SOURCES_DIST) \
$(libstaticrootslib_la_SOURCES) $(gctest_SOURCES) \
- $(hugetest_SOURCES) $(leaktest_SOURCES) $(middletest_SOURCES) \
- $(smashtest_SOURCES) $(staticrootstest_SOURCES) \
- $(am__test_cpp_SOURCES_DIST) \
+ $(hugetest_SOURCES) $(am__initsecondarythread_SOURCES_DIST) \
+ $(leaktest_SOURCES) $(middletest_SOURCES) \
+ $(realloc_test_SOURCES) $(smashtest_SOURCES) \
+ $(staticrootstest_SOURCES) $(am__test_cpp_SOURCES_DIST) \
+ $(am__threadkey_test_SOURCES_DIST) \
$(am__threadleaktest_SOURCES_DIST) \
$(am__tracetest_SOURCES_DIST)
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
@@ -538,13 +561,13 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \
EXTRA_DIST = gc_cpp.cpp README.QUICK BCC_MAKEFILE NT_MAKEFILE \
OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE \
Makefile.direct Makefile.dj Makefile.DLLs SMakefile.amiga \
- WCC_MAKEFILE build_atomic_ops.sh build_atomic_ops.sh.cygwin \
- NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
- NT_X64_THREADS_MAKEFILE CMakeLists.txt tests/CMakeLists.txt \
- extra/add_gc_prefix.c extra/gc.c extra/gcname.c \
- extra/if_mach.c extra/if_not_there.c hpux_test_and_clear.s \
- gc.mak extra/MacOS.c MacProjects.sit.hqx mach_dep.c \
- extra/setjmp_t.c extra/threadlibs.c extra/AmigaOS.c \
+ WCC_MAKEFILE autogen.sh build_atomic_ops.sh \
+ build_atomic_ops.sh.cygwin NT_STATIC_THREADS_MAKEFILE \
+ NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE \
+ CMakeLists.txt tests/CMakeLists.txt extra/add_gc_prefix.c \
+ extra/gc.c extra/gcname.c extra/if_mach.c extra/if_not_there.c \
+ hpux_test_and_clear.s gc.mak extra/MacOS.c MacProjects.sit.hqx \
+ mach_dep.c extra/setjmp_t.c extra/threadlibs.c extra/AmigaOS.c \
Mac_files/datastart.c Mac_files/dataend.c \
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
include/private/msvc_dbg.h extra/msvc_dbg.c libatomic_ops \
@@ -583,8 +606,9 @@ dist_noinst_HEADERS = include/private/gc_hdrs.h \
include/ec.h include/javaxfc.h
check_LTLIBRARIES = libstaticrootslib.la
TESTS = gctest$(EXEEXT) leaktest$(EXEEXT) middletest$(EXEEXT) \
- smashtest$(EXEEXT) hugetest$(EXEEXT) staticrootstest$(EXEEXT) \
- $(am__append_7) $(am__append_9) $(am__append_11)
+ smashtest$(EXEEXT) hugetest$(EXEEXT) realloc_test$(EXEEXT) \
+ staticrootstest$(EXEEXT) $(am__append_7) $(am__append_9) \
+ $(am__append_11)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = bdw-gc.pc
libgc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
@@ -652,6 +676,8 @@ smashtest_SOURCES = tests/smash_test.c
smashtest_LDADD = $(test_ldadd)
hugetest_SOURCES = tests/huge_test.c
hugetest_LDADD = $(test_ldadd)
+realloc_test_SOURCES = tests/realloc_test.c
+realloc_test_LDADD = $(test_ldadd)
staticrootstest_SOURCES = tests/staticrootstest.c
staticrootstest_LDADD = $(test_ldadd) libstaticrootslib.la
libstaticrootslib_la_SOURCES = tests/staticrootslib.c
@@ -662,6 +688,10 @@ libstaticrootslib_la_DEPENDENCIES = $(top_builddir)/libgc.la
@KEEP_BACK_PTRS_TRUE@tracetest_LDADD = $(test_ldadd)
@THREADS_TRUE@threadleaktest_SOURCES = tests/thread_leak_test.c
@THREADS_TRUE@threadleaktest_LDADD = $(test_ldadd)
+@THREADS_TRUE@threadkey_test_SOURCES = tests/threadkey_test.c
+@THREADS_TRUE@threadkey_test_LDADD = $(test_ldadd)
+@THREADS_TRUE@initsecondarythread_SOURCES = tests/initsecondarythread.c
+@THREADS_TRUE@initsecondarythread_LDADD = $(test_ldadd)
@CPLUSPLUS_TRUE@test_cpp_SOURCES = tests/test_cpp.cc
@AVOID_CPP_LIB_FALSE@@CPLUSPLUS_TRUE@test_cpp_LDADD = libgccpp.la $(test_ldadd)
@AVOID_CPP_LIB_TRUE@@CPLUSPLUS_TRUE@test_cpp_LDADD = gc_cpp.o $(test_ldadd)
@@ -826,12 +856,18 @@ gctest$(EXEEXT): $(gctest_OBJECTS) $(gctest_DEPENDENCIES)
hugetest$(EXEEXT): $(hugetest_OBJECTS) $(hugetest_DEPENDENCIES)
@rm -f hugetest$(EXEEXT)
$(LINK) $(hugetest_OBJECTS) $(hugetest_LDADD) $(LIBS)
+initsecondarythread$(EXEEXT): $(initsecondarythread_OBJECTS) $(initsecondarythread_DEPENDENCIES)
+ @rm -f initsecondarythread$(EXEEXT)
+ $(LINK) $(initsecondarythread_OBJECTS) $(initsecondarythread_LDADD) $(LIBS)
leaktest$(EXEEXT): $(leaktest_OBJECTS) $(leaktest_DEPENDENCIES)
@rm -f leaktest$(EXEEXT)
$(LINK) $(leaktest_OBJECTS) $(leaktest_LDADD) $(LIBS)
middletest$(EXEEXT): $(middletest_OBJECTS) $(middletest_DEPENDENCIES)
@rm -f middletest$(EXEEXT)
$(LINK) $(middletest_OBJECTS) $(middletest_LDADD) $(LIBS)
+realloc_test$(EXEEXT): $(realloc_test_OBJECTS) $(realloc_test_DEPENDENCIES)
+ @rm -f realloc_test$(EXEEXT)
+ $(LINK) $(realloc_test_OBJECTS) $(realloc_test_LDADD) $(LIBS)
smashtest$(EXEEXT): $(smashtest_OBJECTS) $(smashtest_DEPENDENCIES)
@rm -f smashtest$(EXEEXT)
$(LINK) $(smashtest_OBJECTS) $(smashtest_LDADD) $(LIBS)
@@ -841,6 +877,9 @@ staticrootstest$(EXEEXT): $(staticrootstest_OBJECTS) $(staticrootstest_DEPENDENC
test_cpp$(EXEEXT): $(test_cpp_OBJECTS) $(test_cpp_DEPENDENCIES)
@rm -f test_cpp$(EXEEXT)
$(CXXLINK) $(test_cpp_OBJECTS) $(test_cpp_LDADD) $(LIBS)
+threadkey_test$(EXEEXT): $(threadkey_test_OBJECTS) $(threadkey_test_DEPENDENCIES)
+ @rm -f threadkey_test$(EXEEXT)
+ $(LINK) $(threadkey_test_OBJECTS) $(threadkey_test_LDADD) $(LIBS)
threadleaktest$(EXEEXT): $(threadleaktest_OBJECTS) $(threadleaktest_DEPENDENCIES)
@rm -f threadleaktest$(EXEEXT)
$(LINK) $(threadleaktest_OBJECTS) $(threadleaktest_LDADD) $(LIBS)
@@ -875,6 +914,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gcj_mlc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/headers.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huge_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initsecondarythread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/leak_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mallocx.Plo@am__quote@
@@ -891,6 +931,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pthread_support.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptr_chck.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/real_malloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/realloc_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reclaim.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smash_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sparc_mach_dep.Plo@am__quote@
@@ -902,6 +943,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cpp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_leak_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_local_alloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/threadkey_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/typd_mlc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32_threads.Plo@am__quote@
@@ -1018,6 +1060,20 @@ huge_test.obj: tests/huge_test.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o huge_test.obj `if test -f 'tests/huge_test.c'; then $(CYGPATH_W) 'tests/huge_test.c'; else $(CYGPATH_W) '$(srcdir)/tests/huge_test.c'; fi`
+initsecondarythread.o: tests/initsecondarythread.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT initsecondarythread.o -MD -MP -MF $(DEPDIR)/initsecondarythread.Tpo -c -o initsecondarythread.o `test -f 'tests/initsecondarythread.c' || echo '$(srcdir)/'`tests/initsecondarythread.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/initsecondarythread.Tpo $(DEPDIR)/initsecondarythread.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/initsecondarythread.c' object='initsecondarythread.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o initsecondarythread.o `test -f 'tests/initsecondarythread.c' || echo '$(srcdir)/'`tests/initsecondarythread.c
+
+initsecondarythread.obj: tests/initsecondarythread.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT initsecondarythread.obj -MD -MP -MF $(DEPDIR)/initsecondarythread.Tpo -c -o initsecondarythread.obj `if test -f 'tests/initsecondarythread.c'; then $(CYGPATH_W) 'tests/initsecondarythread.c'; else $(CYGPATH_W) '$(srcdir)/tests/initsecondarythread.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/initsecondarythread.Tpo $(DEPDIR)/initsecondarythread.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/initsecondarythread.c' object='initsecondarythread.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o initsecondarythread.obj `if test -f 'tests/initsecondarythread.c'; then $(CYGPATH_W) 'tests/initsecondarythread.c'; else $(CYGPATH_W) '$(srcdir)/tests/initsecondarythread.c'; fi`
+
leak_test.o: tests/leak_test.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT leak_test.o -MD -MP -MF $(DEPDIR)/leak_test.Tpo -c -o leak_test.o `test -f 'tests/leak_test.c' || echo '$(srcdir)/'`tests/leak_test.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/leak_test.Tpo $(DEPDIR)/leak_test.Po
@@ -1046,6 +1102,20 @@ middle.obj: tests/middle.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o middle.obj `if test -f 'tests/middle.c'; then $(CYGPATH_W) 'tests/middle.c'; else $(CYGPATH_W) '$(srcdir)/tests/middle.c'; fi`
+realloc_test.o: tests/realloc_test.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT realloc_test.o -MD -MP -MF $(DEPDIR)/realloc_test.Tpo -c -o realloc_test.o `test -f 'tests/realloc_test.c' || echo '$(srcdir)/'`tests/realloc_test.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/realloc_test.Tpo $(DEPDIR)/realloc_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/realloc_test.c' object='realloc_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o realloc_test.o `test -f 'tests/realloc_test.c' || echo '$(srcdir)/'`tests/realloc_test.c
+
+realloc_test.obj: tests/realloc_test.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT realloc_test.obj -MD -MP -MF $(DEPDIR)/realloc_test.Tpo -c -o realloc_test.obj `if test -f 'tests/realloc_test.c'; then $(CYGPATH_W) 'tests/realloc_test.c'; else $(CYGPATH_W) '$(srcdir)/tests/realloc_test.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/realloc_test.Tpo $(DEPDIR)/realloc_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/realloc_test.c' object='realloc_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o realloc_test.obj `if test -f 'tests/realloc_test.c'; then $(CYGPATH_W) 'tests/realloc_test.c'; else $(CYGPATH_W) '$(srcdir)/tests/realloc_test.c'; fi`
+
smash_test.o: tests/smash_test.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT smash_test.o -MD -MP -MF $(DEPDIR)/smash_test.Tpo -c -o smash_test.o `test -f 'tests/smash_test.c' || echo '$(srcdir)/'`tests/smash_test.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/smash_test.Tpo $(DEPDIR)/smash_test.Po
@@ -1074,6 +1144,20 @@ staticrootstest.obj: tests/staticrootstest.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o staticrootstest.obj `if test -f 'tests/staticrootstest.c'; then $(CYGPATH_W) 'tests/staticrootstest.c'; else $(CYGPATH_W) '$(srcdir)/tests/staticrootstest.c'; fi`
+threadkey_test.o: tests/threadkey_test.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT threadkey_test.o -MD -MP -MF $(DEPDIR)/threadkey_test.Tpo -c -o threadkey_test.o `test -f 'tests/threadkey_test.c' || echo '$(srcdir)/'`tests/threadkey_test.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/threadkey_test.Tpo $(DEPDIR)/threadkey_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/threadkey_test.c' object='threadkey_test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o threadkey_test.o `test -f 'tests/threadkey_test.c' || echo '$(srcdir)/'`tests/threadkey_test.c
+
+threadkey_test.obj: tests/threadkey_test.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT threadkey_test.obj -MD -MP -MF $(DEPDIR)/threadkey_test.Tpo -c -o threadkey_test.obj `if test -f 'tests/threadkey_test.c'; then $(CYGPATH_W) 'tests/threadkey_test.c'; else $(CYGPATH_W) '$(srcdir)/tests/threadkey_test.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/threadkey_test.Tpo $(DEPDIR)/threadkey_test.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/threadkey_test.c' object='threadkey_test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o threadkey_test.obj `if test -f 'tests/threadkey_test.c'; then $(CYGPATH_W) 'tests/threadkey_test.c'; else $(CYGPATH_W) '$(srcdir)/tests/threadkey_test.c'; fi`
+
thread_leak_test.o: tests/thread_leak_test.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_leak_test.o -MD -MP -MF $(DEPDIR)/thread_leak_test.Tpo -c -o thread_leak_test.o `test -f 'tests/thread_leak_test.c' || echo '$(srcdir)/'`tests/thread_leak_test.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread_leak_test.Tpo $(DEPDIR)/thread_leak_test.Po
diff --git a/NT_MAKEFILE b/NT_MAKEFILE
index f9077a3d..809d9f77 100644
--- a/NT_MAKEFILE
+++ b/NT_MAKEFILE
@@ -18,7 +18,7 @@ all: gctest.exe cord\de.exe test_cpp.exe
$(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj
.cpp.obj:
- $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.CPP /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
diff --git a/NT_STATIC_THREADS_MAKEFILE b/NT_STATIC_THREADS_MAKEFILE
index 6892d291..9a003478 100644
--- a/NT_STATIC_THREADS_MAKEFILE
+++ b/NT_STATIC_THREADS_MAKEFILE
@@ -25,7 +25,7 @@ all: gctest.exe cord\de.exe test_cpp.exe
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -DPARALLEL_MARK -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj
.cpp.obj:
- $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
diff --git a/NT_X64_STATIC_THREADS_MAKEFILE b/NT_X64_STATIC_THREADS_MAKEFILE
index 7b31bfd5..93de9727 100644
--- a/NT_X64_STATIC_THREADS_MAKEFILE
+++ b/NT_X64_STATIC_THREADS_MAKEFILE
@@ -28,7 +28,7 @@ all: gctest.exe cord\de.exe test_cpp.exe
# of safe uses of strncpy. It would be nice to leave the rest enabled.
.cpp.obj:
- $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.CPP /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
diff --git a/NT_X64_THREADS_MAKEFILE b/NT_X64_THREADS_MAKEFILE
index eadd6163..e0a252b7 100644
--- a/NT_X64_THREADS_MAKEFILE
+++ b/NT_X64_THREADS_MAKEFILE
@@ -35,7 +35,7 @@ all: gc64.dll gctest.exe cord\de.exe test_cpp.exe
# Disable crt security warnings, since unfortunately they warn about all sorts # of safe uses of strncpy. It would be nice to leave the rest enabled.
.cpp.obj:
- $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DALL_INTERIOR_POINTERS -DGC_DLL -DGC_THREADS -D_CRT_SECURE_NO_DEPRECATE $*.CPP /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DALL_INTERIOR_POINTERS -DGC_DLL -DGC_THREADS -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
diff --git a/allchblk.c b/allchblk.c
index 440b0510..efcc00ab 100644
--- a/allchblk.c
+++ b/allchblk.c
@@ -120,7 +120,7 @@ void GC_print_hblkfreelist(void)
# ifdef USE_MUNMAP
if (0 != h) GC_printf("Free list %u:\n", i);
# else
- if (0 != h) GC_printf("Free list %u (Total size %lu):\n",
+ if (0 != h) GC_printf("Free list %u (total size %lu):\n",
i, (unsigned long)GC_free_bytes[i]);
# endif
while (h != 0) {
@@ -848,7 +848,7 @@ GC_INNER void GC_freehblk(struct hblk *hbp)
/* Check for duplicate deallocation in the easy case */
if (HBLK_IS_FREE(hhdr)) {
if (GC_print_stats)
- GC_printf("Duplicate large block deallocation of %p\n", hbp);
+ GC_log_printf("Duplicate large block deallocation of %p\n", hbp);
ABORT("Duplicate large block deallocation");
}
diff --git a/alloc.c b/alloc.c
index d18b7710..a41cb1db 100644
--- a/alloc.c
+++ b/alloc.c
@@ -20,7 +20,9 @@
#include <stdio.h>
#if !defined(MACOS) && !defined(MSWINCE)
# include <signal.h>
-# include <sys/types.h>
+# if !defined(__CC_ARM)
+# include <sys/types.h>
+# endif
#endif
/*
@@ -180,7 +182,7 @@ GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
time_diff = MS_TIME_DIFF(current_time,GC_start_time);
if (time_diff >= GC_time_limit) {
if (GC_print_stats) {
- GC_log_printf(
+ GC_log_printf(
"Abandoning stopped marking after %lu msecs (attempt %d)\n",
time_diff, GC_n_attempts);
}
@@ -217,7 +219,8 @@ static word min_bytes_allocd(void)
stack_size = GC_total_stacksize;
/* For now, we just use the value computed during the latest GC. */
# ifdef DEBUG_THREADS
- GC_printf("Total stacks size: %lu\n", (unsigned long)stack_size);
+ GC_log_printf("Total stacks size: %lu\n",
+ (unsigned long)stack_size);
# endif
}
# endif
@@ -238,9 +241,8 @@ static word min_bytes_allocd(void)
STATIC word GC_adj_bytes_allocd(void)
{
signed_word result;
- signed_word expl_managed =
- (signed_word)GC_non_gc_bytes
- - (signed_word)GC_non_gc_bytes_at_gc;
+ signed_word expl_managed = (signed_word)GC_non_gc_bytes
+ - (signed_word)GC_non_gc_bytes_at_gc;
/* Don't count what was explicitly freed, or newly allocated for */
/* explicit management. Note that deallocating an explicitly */
@@ -283,9 +285,7 @@ STATIC void GC_clear_a_few_frames(void)
# define CLEAR_NWORDS 64
# endif
volatile word frames[CLEAR_NWORDS];
- int i;
-
- for (i = 0; i < CLEAR_NWORDS; i++) frames[i] = 0;
+ BZERO((word *)frames, CLEAR_NWORDS * sizeof(word));
}
/* Heap size at which we need a collection to avoid expanding past */
@@ -364,10 +364,9 @@ STATIC void GC_maybe_gc(void)
# endif
if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) {
if (GC_print_stats) {
- GC_log_printf(
+ GC_log_printf(
"***>Full mark for collection %lu after %ld allocd bytes\n",
- (unsigned long)GC_gc_no+1,
- (long)GC_bytes_allocd);
+ (unsigned long)GC_gc_no + 1, (long)GC_bytes_allocd);
}
GC_promote_black_lists();
(void)GC_reclaim_all((GC_stop_func)0, TRUE);
@@ -471,7 +470,7 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
if (GC_print_stats) {
GET_TIME(current_time);
GC_log_printf("Complete collection took %lu msecs\n",
- MS_TIME_DIFF(current_time,start_time));
+ MS_TIME_DIFF(current_time,start_time));
}
# endif
return(TRUE);
@@ -542,6 +541,9 @@ GC_INNER void GC_collect_a_little_inner(int n)
RESTORE_CANCEL(cancel_state);
}
+GC_INNER void (*GC_check_heap)(void) = 0;
+GC_INNER void (*GC_print_all_smashed)(void) = 0;
+
GC_API int GC_CALL GC_collect_a_little(void)
{
int result;
@@ -555,14 +557,6 @@ GC_API int GC_CALL GC_collect_a_little(void)
return(result);
}
-#if !defined(REDIRECT_MALLOC) && (defined(MSWIN32) || defined(MSWINCE))
- GC_INNER void GC_add_current_malloc_heap(void);
-#endif
-
-#ifdef MAKE_BACK_GRAPH
- GC_INNER void GC_build_back_graph(void);
-#endif
-
#ifndef SMALL_CONFIG
/* Variables for world-stop average delay time statistic computation. */
/* "divisor" is incremented every world-stop and halved when reached */
@@ -624,20 +618,20 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
GC_clear_a_few_frames();
GC_noop(0,0,0,0,0,0);
GC_initiate_gc();
- for(i = 0;;i++) {
- if ((*stop_func)()) {
- if (GC_print_stats) {
- GC_log_printf("Abandoned stopped marking after "
- "%u iterations\n", i);
- }
- GC_deficit = i; /* Give the mutator a chance. */
-# ifdef THREAD_LOCAL_ALLOC
- GC_world_stopped = FALSE;
-# endif
- START_WORLD();
- return(FALSE);
+ for (i = 0;;i++) {
+ if ((*stop_func)()) {
+ if (GC_print_stats) {
+ GC_log_printf("Abandoned stopped marking after %u iterations\n",
+ i);
}
- if (GC_mark_some((ptr_t)(&dummy))) break;
+ GC_deficit = i; /* Give the mutator a chance. */
+# ifdef THREAD_LOCAL_ALLOC
+ GC_world_stopped = FALSE;
+# endif
+ START_WORLD();
+ return(FALSE);
+ }
+ if (GC_mark_some((ptr_t)(&dummy))) break;
}
GC_gc_no++;
@@ -731,7 +725,7 @@ GC_INNER void GC_set_fl_marks(ptr_t q)
for (p = q; p != 0; p = obj_link(p)) {
if (!GC_is_marked(p)) {
GC_err_printf("Unmarked object %p on list %p\n", p, q);
- ABORT("Unmarked local free list entry.");
+ ABORT("Unmarked local free list entry");
}
}
}
@@ -786,10 +780,6 @@ STATIC void GC_clear_fl_marks(ptr_t q)
void GC_check_tls(void);
#endif
-#ifdef MAKE_BACK_GRAPH
- GC_INNER void GC_traverse_back_graph(void);
-#endif
-
/* Finish up a collection. Assumes mark bits are consistent, lock is */
/* held, but the world is otherwise running. */
STATIC void GC_finish_collection(void)
@@ -876,7 +866,7 @@ STATIC void GC_finish_collection(void)
if (GC_print_stats == VERBOSE)
GC_log_printf("Bytes recovered before sweep - f.l. count = %ld\n",
- (long)GC_bytes_found);
+ (long)GC_bytes_found);
/* Reconstruct free lists to contain everything not marked */
GC_start_reclaim(FALSE);
@@ -895,16 +885,16 @@ STATIC void GC_finish_collection(void)
}
if (GC_print_stats == VERBOSE) {
-# ifdef USE_MUNMAP
- GC_log_printf("Immediately reclaimed %ld bytes in heap"
- " of size %lu bytes (%lu unmapped)\n",
- (long)GC_bytes_found, (unsigned long)GC_heapsize,
- (unsigned long)GC_unmapped_bytes);
-# else
- GC_log_printf("Immediately reclaimed %ld bytes in heap"
- " of size %lu bytes\n",
- (long)GC_bytes_found, (unsigned long)GC_heapsize);
-# endif
+# ifdef USE_MUNMAP
+ GC_log_printf("Immediately reclaimed %ld bytes in heap"
+ " of size %lu bytes (%lu unmapped)\n",
+ (long)GC_bytes_found, (unsigned long)GC_heapsize,
+ (unsigned long)GC_unmapped_bytes);
+# else
+ GC_log_printf(
+ "Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
+ (long)GC_bytes_found, (unsigned long)GC_heapsize);
+# endif
}
/* Reset or increment counters for next cycle */
@@ -928,7 +918,7 @@ STATIC void GC_finish_collection(void)
/* A convenient place to output finalization statistics. */
GC_print_finalization_stats();
- GC_log_printf("Finalize + initiate sweep took %lu + %lu msecs\n",
+ GC_log_printf("Finalize plus initiate sweep took %lu + %lu msecs\n",
MS_TIME_DIFF(finalize_time,start_time),
MS_TIME_DIFF(done_time,finalize_time));
}
@@ -1075,19 +1065,19 @@ GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes)
{
unsigned i;
- GC_printf("Total heap size: %lu\n", (unsigned long) GC_heapsize);
+ GC_printf("Total heap size: %lu\n", (unsigned long)GC_heapsize);
for (i = 0; i < GC_n_heap_sects; i++) {
- ptr_t start = GC_heap_sects[i].hs_start;
- size_t len = GC_heap_sects[i].hs_bytes;
- struct hblk *h;
- unsigned nbl = 0;
+ ptr_t start = GC_heap_sects[i].hs_start;
+ size_t len = GC_heap_sects[i].hs_bytes;
+ struct hblk *h;
+ unsigned nbl = 0;
- for (h = (struct hblk *)start; h < (struct hblk *)(start + len); h++) {
- if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
- }
- GC_printf("Section %d from %p to %p %lu/%lu blacklisted\n",
- i, start, start + len,
- (unsigned long)nbl, (unsigned long)(len/HBLKSIZE));
+ for (h = (struct hblk *)start; h < (struct hblk *)(start + len); h++) {
+ if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
+ }
+ GC_printf("Section %d from %p to %p %lu/%lu blacklisted\n",
+ i, start, start + len,
+ (unsigned long)nbl, (unsigned long)(len/HBLKSIZE));
}
}
#endif
@@ -1141,7 +1131,7 @@ GC_INNER GC_bool GC_expand_hp_inner(word n)
}
space = GET_MEM(bytes);
GC_add_to_our_memory((ptr_t)space, bytes);
- if( space == 0 ) {
+ if (space == 0) {
if (GC_print_stats) {
GC_log_printf("Failed to expand heap by %ld bytes\n",
(unsigned long)bytes);
@@ -1149,9 +1139,8 @@ GC_INNER GC_bool GC_expand_hp_inner(word n)
return(FALSE);
}
if (GC_print_stats) {
- GC_log_printf("Increasing heap size by %lu after %lu allocated bytes\n",
- (unsigned long)bytes,
- (unsigned long)GC_bytes_allocd);
+ GC_log_printf("Increasing heap size by %lu after %lu allocated bytes\n",
+ (unsigned long)bytes, (unsigned long)GC_bytes_allocd);
}
/* Adjust heap limits generously for blacklisting to work better. */
/* GC_add_to_heap performs minimal adjustment needed for */
@@ -1273,7 +1262,7 @@ GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
return(FALSE);
}
} else if (GC_fail_count && GC_print_stats) {
- GC_printf("Memory available again ...\n");
+ GC_log_printf("Memory available again...\n");
}
RESTORE_CANCEL(cancel_state);
return(TRUE);
diff --git a/backgraph.c b/backgraph.c
index c496e003..60a9e0f9 100644
--- a/backgraph.c
+++ b/backgraph.c
@@ -98,7 +98,7 @@ static back_edges * new_back_edges(void)
return result;
}
if (GC_n_back_edge_structs >= MAX_BACK_EDGE_STRUCTS - 1) {
- ABORT("needed too much space for back edges: adjust "
+ ABORT("Needed too much space for back edges: adjust "
"MAX_BACK_EDGE_STRUCTS");
}
return back_edge_space + (GC_n_back_edge_structs++);
@@ -254,14 +254,12 @@ static void add_edge(ptr_t p, ptr_t q)
}
be_cont -> edges[i] = p;
be -> n_edges++;
- if (be -> n_edges == 100) {
-# if 0
- if (GC_print_stats) {
- GC_err_printf("The following object has in-degree >= 100:\n");
- GC_print_heap_obj(q);
- }
-# endif
- }
+# ifdef DEBUG_PRINT_BIG_N_EDGES
+ if (GC_print_stats == VERBOSE && be -> n_edges == 100) {
+ GC_err_printf("The following object has big in-degree:\n");
+ GC_print_heap_obj(q);
+ }
+# endif
}
typedef void (*per_object_func)(ptr_t p, size_t n_bytes, word gc_descr);
diff --git a/blacklst.c b/blacklst.c
index a6df6933..9fd00167 100644
--- a/blacklst.c
+++ b/blacklst.c
@@ -281,8 +281,7 @@ static word total_stack_black_listed(void)
for (i = 0; i < GC_n_heap_sects; i++) {
struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
- size_t len = (word) GC_heap_sects[i].hs_bytes;
- struct hblk * endp1 = start + len/HBLKSIZE;
+ struct hblk * endp1 = start + GC_heap_sects[i].hs_bytes/HBLKSIZE;
total += GC_number_stack_black_listed(start, endp1);
}
diff --git a/checksums.c b/checksums.c
index e2e5a69f..3f2af938 100644
--- a/checksums.c
+++ b/checksums.c
@@ -97,8 +97,6 @@ int GC_n_changed_errors = 0;
int GC_n_clean = 0;
int GC_n_dirty = 0;
-GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h);
-
STATIC void GC_update_check_page(struct hblk *h, int index)
{
page_entry *pe = GC_sums + index;
@@ -110,7 +108,7 @@ STATIC void GC_update_check_page(struct hblk *h, int index)
pe -> new_sum = GC_checksum(h);
# if !defined(MSWIN32) && !defined(MSWINCE)
if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) {
- GC_printf("GC_page_was_ever_dirty(%p) is wrong\n", h);
+ GC_err_printf("GC_page_was_ever_dirty(%p) is wrong\n", h);
}
# endif
if (GC_page_was_dirty(h)) {
@@ -165,12 +163,14 @@ STATIC void GC_check_blocks(void)
GC_bytes_in_used_blocks = 0;
GC_apply_to_all_blocks(GC_add_block, (word)0);
- GC_printf("GC_bytes_in_used_blocks = %lu, bytes_in_free_blocks = %lu ",
- (unsigned long)GC_bytes_in_used_blocks,
- (unsigned long)bytes_in_free_blocks);
- GC_printf("GC_heapsize = %lu\n", (unsigned long)GC_heapsize);
+ if (GC_print_stats)
+ GC_log_printf("GC_bytes_in_used_blocks = %lu,"
+ " bytes_in_free_blocks = %lu, heapsize = %lu\n",
+ (unsigned long)GC_bytes_in_used_blocks,
+ (unsigned long)bytes_in_free_blocks,
+ (unsigned long)GC_heapsize);
if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) {
- GC_printf("LOST SOME BLOCKS!!\n");
+ GC_err_printf("LOST SOME BLOCKS!!\n");
}
}
@@ -202,19 +202,21 @@ void GC_check_dirty(void)
}
}
out:
- GC_printf("Checked %lu clean and %lu dirty pages\n",
- (unsigned long) GC_n_clean, (unsigned long) GC_n_dirty);
+ if (GC_print_stats)
+ GC_log_printf("Checked %lu clean and %lu dirty pages\n",
+ (unsigned long)GC_n_clean, (unsigned long)GC_n_dirty);
if (GC_n_dirty_errors > 0) {
- GC_printf("Found %d dirty bit errors (%d were faulted)\n",
- GC_n_dirty_errors, GC_n_faulted_dirty_errors);
+ GC_err_printf("Found %d dirty bit errors (%d were faulted)\n",
+ GC_n_dirty_errors, GC_n_faulted_dirty_errors);
}
if (GC_n_changed_errors > 0) {
- GC_printf("Found %lu changed bit errors\n",
- (unsigned long)GC_n_changed_errors);
- GC_printf("These may be benign (provoked by nonpointer changes)\n");
+ GC_err_printf("Found %lu changed bit errors\n",
+ (unsigned long)GC_n_changed_errors);
+ GC_err_printf(
+ "These may be benign (provoked by nonpointer changes)\n");
# ifdef THREADS
- GC_printf(
- "Also expect 1 per thread currently allocating a stubborn obj.\n");
+ GC_err_printf(
+ "Also expect 1 per thread currently allocating a stubborn obj\n");
# endif
}
for (i = 0; i < GC_n_faulted; ++i) {
diff --git a/configure b/configure
index a06db048..7f975b40 100755
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
#! /bin/sh
-# From configure.ac Revision: 1.64 .
+# From configure.ac Revision: 1.69 .
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for gc 7.2alpha5.
+# Generated by GNU Autoconf 2.68 for gc 7.2alpha7.
#
# Report bugs to <Hans.Boehm@hp.com>.
#
@@ -571,8 +571,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='gc'
PACKAGE_TARNAME='gc'
-PACKAGE_VERSION='7.2alpha5'
-PACKAGE_STRING='gc 7.2alpha5'
+PACKAGE_VERSION='7.2alpha7'
+PACKAGE_STRING='gc 7.2alpha7'
PACKAGE_BUGREPORT='Hans.Boehm@hp.com'
PACKAGE_URL=''
@@ -1368,7 +1368,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures gc 7.2alpha5 to adapt to many kinds of systems.
+\`configure' configures gc 7.2alpha7 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1439,7 +1439,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of gc 7.2alpha5:";;
+ short | recursive ) echo "Configuration of gc 7.2alpha7:";;
esac
cat <<\_ACEOF
@@ -1567,7 +1567,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-gc configure 7.2alpha5
+gc configure 7.2alpha7
generated by GNU Autoconf 2.68
Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2057,7 +2057,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by gc $as_me 7.2alpha5, which was
+It was created by gc $as_me 7.2alpha7, which was
generated by GNU Autoconf 2.68. Invocation command line was
$ $0 $@
@@ -3031,7 +3031,7 @@ fi
# Define the identity of the package.
PACKAGE='gc'
- VERSION='7.2alpha5'
+ VERSION='7.2alpha7'
cat >>confdefs.h <<_ACEOF
@@ -4969,6 +4969,7 @@ fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
$as_echo_n "checking for inline... " >&6; }
if ${ac_cv_c_inline+:} false; then :
@@ -5062,7 +5063,8 @@ if test "x$ac_cv_lib_pthread_pthread_self" = xyes; then :
fi
case "$host" in
- x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux* | sparc*-*-linux*)
+ x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* \
+ | x86_64-*-linux* | alpha-*-linux* | sparc*-*-linux*)
$as_echo "#define GC_LINUX_THREADS 1" >>confdefs.h
$as_echo "#define _REENTRANT 1" >>confdefs.h
@@ -5167,18 +5169,18 @@ $as_echo "$as_me: WARNING: \"Only on NetBSD 2.0 or later.\"" >&2;}
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
- THREADDLLIBS="-lpthread -lrt"
- if test "$GCC" != yes; then
- CFLAGS="$CFLAGS -O"
- need_atomic_ops_asm=true
- fi
+ # Need to use alternate thread library, otherwise gctest hangs
+ # on Solaris 8.
+ multi_os_directory=`$CC -print-multi-os-directory`
+ THREADDLLIBS="-L/usr/lib/lwp/$multi_os_directory \
+ -R/usr/lib/lwp/$multi_os_directory -lpthread -lrt"
;;
*-*-irix*)
$as_echo "#define GC_IRIX_THREADS 1" >>confdefs.h
;;
*-*-cygwin*)
- $as_echo "#define GC_THREADS 1" >>confdefs.h
+ $as_echo "#define GC_WIN32_THREADS 1" >>confdefs.h
if test "${enable_parallel_mark}" = yes; then
$as_echo "#define PARALLEL_MARK 1" >>confdefs.h
@@ -5191,6 +5193,18 @@ $as_echo "$as_me: WARNING: \"Only on NetBSD 2.0 or later.\"" >&2;}
THREADDLLIBS=""
win32_threads=true
;;
+ *-*-mingw*)
+ $as_echo "#define GC_WIN32_PTHREADS 1" >>confdefs.h
+
+ # Using win32-pthreads
+ if test "${enable_parallel_mark}" = yes; then
+ $as_echo "#define PARALLEL_MARK 1" >>confdefs.h
+
+ fi
+ $as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
+
+ THREADDLLIBS="-lpthread"
+ ;;
*-*-darwin*)
$as_echo "#define GC_DARWIN_THREADS 1" >>confdefs.h
@@ -5225,9 +5239,17 @@ $as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
as_fn_error $? "\"Pthreads not supported by the GC on this platform.\"" "$LINENO" 5
;;
esac
+ case "$host" in
+ sparc*-*-solaris*)
+ if test "$GCC" != yes; then
+ CFLAGS="$CFLAGS -O"
+ need_atomic_ops_asm=true
+ fi
+ ;;
+ esac
;;
win32)
- $as_echo "#define GC_THREADS 1" >>confdefs.h
+ $as_echo "#define GC_WIN32_THREADS 1" >>confdefs.h
if test "${enable_parallel_mark}" = yes; then
$as_echo "#define PARALLEL_MARK 1" >>confdefs.h
@@ -5244,7 +5266,7 @@ $as_echo "#define EMPTY_GETENV_RESULTS 1" >>confdefs.h
THREADS=dgux386
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $THREADDLLIBS" >&5
$as_echo "$THREADDLLIBS" >&6; }
- # Use pthread GCC switch
+ # Use pthread GCC switch
THREADDLLIBS=-pthread
if test "${enable_parallel_mark}" = yes; then
$as_echo "#define PARALLEL_MARK 1" >>confdefs.h
@@ -5366,9 +5388,12 @@ $as_echo "#define DARWIN_DONT_PARSE_STACK 1" >>confdefs.h
fi
+case "$host" in
+# While IRIX 6 has libdl for the O32 and N32 ABIs, it's missing for N64
+# and unnecessary everywhere.
+ mips-sgi-irix6*) ;;
# We never want libdl on darwin. It is a fake libdl that just ends up making
# dyld calls anyway. The same applies to Cygwin.
-case "$host" in
*-*-darwin*) ;;
*-*-cygwin*) ;;
*)
@@ -5545,7 +5570,8 @@ $as_echo "$as_me: WARNING: OpenBSD/Alpha without dlopen(). Shared library suppor
alpha*-*-linux*)
machdep="mach_dep.lo"
;;
- i?86-*-solaris2.[89] | i?86-*-solaris2.1?)
+ i?86-*-solaris2.[89])
+ # PROC_VDB appears to work in 2.8 and 2.9 but not in 2.10+ (for now).
$as_echo "#define SOLARIS25_PROC_VDB_BUG_FIXED 1" >>confdefs.h
@@ -17216,7 +17242,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by gc $as_me 7.2alpha5, which was
+This file was extended by gc $as_me 7.2alpha7, which was
generated by GNU Autoconf 2.68. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -17282,7 +17308,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-gc config.status 7.2alpha5
+gc config.status 7.2alpha7
configured by $0, generated by GNU Autoconf 2.68,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 6df2ea87..f66ce6bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,12 +17,12 @@ dnl Process this file with autoconf to produce configure.
# Initialization
# ==============
-AC_INIT(gc,7.2alpha5,Hans.Boehm@hp.com)
+AC_INIT(gc,7.2alpha7,Hans.Boehm@hp.com)
## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_TARGET
-AC_PREREQ(2.53)
+AC_PREREQ(2.64)
AC_REVISION($Revision$)
GC_SET_VERSION
AM_INIT_AUTOMAKE([foreign dist-bzip2 nostdinc])
@@ -78,7 +78,8 @@ AH_TEMPLATE([USE_COMPILER_TLS],
[Define to use of compiler-support for thread-local variables.])
dnl Thread selection macros.
-AH_TEMPLATE([GC_THREADS], [Define to support threads.])
+AH_TEMPLATE([GC_THREADS], [Define to support platform-specific \
+ threads.])
AH_TEMPLATE([GC_AIX_THREADS], [Define to support IBM AIX threads.])
AH_TEMPLATE([GC_DARWIN_THREADS], [Define to support Darwin pthreads.])
AH_TEMPLATE([GC_FREEBSD_THREADS], [Define to support FreeBSD pthreads.])
@@ -90,7 +91,8 @@ AH_TEMPLATE([GC_NETBSD_THREADS], [Define to support NetBSD pthreads.])
AH_TEMPLATE([GC_OPENBSD_THREADS], [Define to support OpenBSD pthreads.])
AH_TEMPLATE([GC_OSF1_THREADS], [Define to support Tru64 pthreads.])
AH_TEMPLATE([GC_SOLARIS_THREADS], [Define to support Solaris pthreads.])
-AH_TEMPLATE([GC_WIN32_THREADS], [Define to support win32 threads.])
+AH_TEMPLATE([GC_WIN32_THREADS], [Define to support Win32 threads.])
+AH_TEMPLATE([GC_WIN32_PTHREADS], [Define to support win32-pthreads.])
dnl System header feature requests.
AH_TEMPLATE([_POSIX_C_SOURCE], [The POSIX feature macro.])
@@ -110,7 +112,8 @@ case "$THREADS" in
THREADS=posix
AC_CHECK_LIB(pthread, pthread_self, THREADDLLIBS="-lpthread",,)
case "$host" in
- x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux* | sparc*-*-linux*)
+ x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* \
+ | x86_64-*-linux* | alpha-*-linux* | sparc*-*-linux*)
AC_DEFINE(GC_LINUX_THREADS)
AC_DEFINE(_REENTRANT)
if test "${enable_parallel_mark}" = yes; then
@@ -180,17 +183,17 @@ case "$THREADS" in
*-*-solaris*)
AC_DEFINE(GC_SOLARIS_THREADS)
AC_DEFINE(THREAD_LOCAL_ALLOC)
- THREADDLLIBS="-lpthread -lrt"
- if test "$GCC" != yes; then
- CFLAGS="$CFLAGS -O"
- need_atomic_ops_asm=true
- fi
+ # Need to use alternate thread library, otherwise gctest hangs
+ # on Solaris 8.
+ multi_os_directory=`$CC -print-multi-os-directory`
+ THREADDLLIBS="-L/usr/lib/lwp/$multi_os_directory \
+ -R/usr/lib/lwp/$multi_os_directory -lpthread -lrt"
;;
*-*-irix*)
AC_DEFINE(GC_IRIX_THREADS)
;;
*-*-cygwin*)
- AC_DEFINE(GC_THREADS)
+ AC_DEFINE(GC_WIN32_THREADS)
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
fi
@@ -200,6 +203,15 @@ case "$THREADS" in
THREADDLLIBS=""
win32_threads=true
;;
+ *-*-mingw*)
+ AC_DEFINE(GC_WIN32_PTHREADS)
+ # Using win32-pthreads
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ THREADDLLIBS="-lpthread"
+ ;;
*-*-darwin*)
AC_DEFINE(GC_DARWIN_THREADS)
AC_DEFINE(THREAD_LOCAL_ALLOC)
@@ -226,9 +238,17 @@ case "$THREADS" in
AC_MSG_ERROR("Pthreads not supported by the GC on this platform.")
;;
esac
+ case "$host" in
+ sparc*-*-solaris*)
+ if test "$GCC" != yes; then
+ CFLAGS="$CFLAGS -O"
+ need_atomic_ops_asm=true
+ fi
+ ;;
+ esac
;;
win32)
- AC_DEFINE(GC_THREADS)
+ AC_DEFINE(GC_WIN32_THREADS)
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
AC_DEFINE(THREAD_LOCAL_ALLOC)
@@ -240,7 +260,7 @@ case "$THREADS" in
dgux386)
THREADS=dgux386
AC_MSG_RESULT($THREADDLLIBS)
- # Use pthread GCC switch
+ # Use pthread GCC switch
THREADDLLIBS=-pthread
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
@@ -293,9 +313,12 @@ if test $compiler_xlc = yes -a "$powerpc_darwin" = true; then
AC_DEFINE([DARWIN_DONT_PARSE_STACK], 1, [See doc/README.macros.])
fi
+case "$host" in
+# While IRIX 6 has libdl for the O32 and N32 ABIs, it's missing for N64
+# and unnecessary everywhere.
+ mips-sgi-irix6*) ;;
# We never want libdl on darwin. It is a fake libdl that just ends up making
# dyld calls anyway. The same applies to Cygwin.
-case "$host" in
*-*-darwin*) ;;
*-*-cygwin*) ;;
*)
@@ -384,7 +407,8 @@ case "$host" in
alpha*-*-linux*)
machdep="mach_dep.lo"
;;
- i?86-*-solaris2.[[89]] | i?86-*-solaris2.1?)
+ i?86-*-solaris2.[[89]])
+ # PROC_VDB appears to work in 2.8 and 2.9 but not in 2.10+ (for now).
AC_DEFINE([SOLARIS25_PROC_VDB_BUG_FIXED], 1,
[See the comment in gcconfig.h.])
;;
diff --git a/configure.host b/configure.host
index a98a0a7c..898c9236 100644
--- a/configure.host
+++ b/configure.host
@@ -2,7 +2,7 @@
# This shell script handles all host based configuration for the garbage
# collector.
-# It sets various shell variables based on the the host and the
+# It sets various shell variables based on the host and the
# configuration options. You can modify this shell script without
# needing to rerun autoconf.
@@ -26,7 +26,7 @@ gc_cflags=""
if test :"$GCC": = :yes: ; then
gc_cflags="${gc_cflags} -fexceptions"
else
- case "$host" in
+ case "$host" in
hppa*-*-hpux* )
if test :$GCC: != :"yes": ; then
gc_cflags="${gc_flags} +ESdbgasm"
diff --git a/configure_atomic_ops.sh b/configure_atomic_ops.sh
deleted file mode 100755
index 932579f1..00000000
--- a/configure_atomic_ops.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-P=`pwd`/libatomic_ops-install
-cd libatomic_ops
-./configure --prefix=$P
diff --git a/cord/cordbscs.c b/cord/cordbscs.c
index d83f4067..924bf445 100644
--- a/cord/cordbscs.c
+++ b/cord/cordbscs.c
@@ -19,64 +19,64 @@
# include <stdio.h>
# include <string.h>
-/* An implementation of the cord primitives. These are the only */
-/* Functions that understand the representation. We perform only */
-/* minimal checks on arguments to these functions. Out of bounds */
-/* arguments to the iteration functions may result in client functions */
-/* invoked on garbage data. In most cases, client functions should be */
-/* programmed defensively enough that this does not result in memory */
-/* smashes. */
+/* An implementation of the cord primitives. These are the only */
+/* Functions that understand the representation. We perform only */
+/* minimal checks on arguments to these functions. Out of bounds */
+/* arguments to the iteration functions may result in client functions */
+/* invoked on garbage data. In most cases, client functions should be */
+/* programmed defensively enough that this does not result in memory */
+/* smashes. */
typedef void (* oom_fn)(void);
oom_fn CORD_oom_fn = (oom_fn) 0;
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
- ABORT("Out of memory\n"); }
+ ABORT("Out of memory\n"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
typedef unsigned long word;
typedef union {
struct Concatenation {
- char null;
- char header;
- char depth; /* concatenation nesting depth. */
- unsigned char left_len;
- /* Length of left child if it is sufficiently */
- /* short; 0 otherwise. */
-# define MAX_LEFT_LEN 255
- word len;
- CORD left; /* length(left) > 0 */
- CORD right; /* length(right) > 0 */
+ char null;
+ char header;
+ char depth; /* concatenation nesting depth. */
+ unsigned char left_len;
+ /* Length of left child if it is sufficiently */
+ /* short; 0 otherwise. */
+# define MAX_LEFT_LEN 255
+ word len;
+ CORD left; /* length(left) > 0 */
+ CORD right; /* length(right) > 0 */
} concatenation;
struct Function {
- char null;
- char header;
- char depth; /* always 0 */
- char left_len; /* always 0 */
- word len;
- CORD_fn fn;
- void * client_data;
+ char null;
+ char header;
+ char depth; /* always 0 */
+ char left_len; /* always 0 */
+ word len;
+ CORD_fn fn;
+ void * client_data;
} function;
struct Generic {
- char null;
- char header;
- char depth;
- char left_len;
- word len;
+ char null;
+ char header;
+ char depth;
+ char left_len;
+ word len;
} generic;
char string[1];
} CordRep;
# define CONCAT_HDR 1
-
+
# define FN_HDR 4
# define SUBSTR_HDR 6
- /* Substring nodes are a special case of function nodes. */
- /* The client_data field is known to point to a substr_args */
- /* structure, and the function is either CORD_apply_access_fn */
- /* or CORD_index_access_fn. */
+ /* Substring nodes are a special case of function nodes. */
+ /* The client_data field is known to point to a substr_args */
+ /* structure, and the function is either CORD_apply_access_fn */
+ /* or CORD_index_access_fn. */
/* The following may be applied only to function and concatenation nodes: */
#define IS_CONCATENATION(s) (((CordRep *)s)->generic.header == CONCAT_HDR)
@@ -90,26 +90,26 @@ typedef union {
#define GEN_LEN(s) (CORD_IS_STRING(s) ? strlen(s) : LEN(s))
#define LEFT_LEN(c) ((c) -> left_len != 0? \
- (c) -> left_len \
- : (CORD_IS_STRING((c) -> left) ? \
- (c) -> len - GEN_LEN((c) -> right) \
- : LEN((c) -> left)))
+ (c) -> left_len \
+ : (CORD_IS_STRING((c) -> left) ? \
+ (c) -> len - GEN_LEN((c) -> right) \
+ : LEN((c) -> left)))
#define SHORT_LIMIT (sizeof(CordRep) - 1)
- /* Cords shorter than this are C strings */
+ /* Cords shorter than this are C strings */
-/* Dump the internal representation of x to stdout, with initial */
-/* indentation level n. */
+/* Dump the internal representation of x to stdout, with initial */
+/* indentation level n. */
void CORD_dump_inner(CORD x, unsigned n)
{
register size_t i;
-
+
for (i = 0; i < (size_t)n; i++) {
fputs(" ", stdout);
}
if (x == 0) {
- fputs("NIL\n", stdout);
+ fputs("NIL\n", stdout);
} else if (CORD_IS_STRING(x)) {
for (i = 0; i <= SHORT_LIMIT; i++) {
if (x[i] == '\0') break;
@@ -119,14 +119,14 @@ void CORD_dump_inner(CORD x, unsigned n)
putchar('\n');
} else if (IS_CONCATENATION(x)) {
register struct Concatenation * conc =
- &(((CordRep *)x) -> concatenation);
+ &(((CordRep *)x) -> concatenation);
printf("Concatenation: %p (len: %d, depth: %d)\n",
x, (int)(conc -> len), (int)(conc -> depth));
CORD_dump_inner(conc -> left, n+1);
CORD_dump_inner(conc -> right, n+1);
} else /* function */{
register struct Function * func =
- &(((CordRep *)x) -> function);
+ &(((CordRep *)x) -> function);
if (IS_SUBSTR(x)) printf("(Substring) ");
printf("Function: %p (len: %d): ", x, (int)(func -> len));
for (i = 0; i < 20 && i < func -> len; i++) {
@@ -137,7 +137,7 @@ void CORD_dump_inner(CORD x, unsigned n)
}
}
-/* Dump the internal representation of x to stdout */
+/* Dump the internal representation of x to stdout */
void CORD_dump(CORD x)
{
CORD_dump_inner(x, 0);
@@ -149,7 +149,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
register size_t result_len;
register size_t lenx;
register int depth;
-
+
if (x == CORD_EMPTY) return(y);
if (leny == 0) return(x);
if (CORD_IS_STRING(x)) {
@@ -157,7 +157,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
result_len = lenx + leny;
if (result_len <= SHORT_LIMIT) {
register char * result = GC_MALLOC_ATOMIC(result_len+1);
-
+
if (result == 0) OUT_OF_MEMORY;
memcpy(result, x, lenx);
memcpy(result + lenx, y, leny);
@@ -167,35 +167,35 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
depth = 1;
}
} else {
- register CORD right;
- register CORD left;
- register char * new_right;
- register size_t right_len;
-
- lenx = LEN(x);
-
+ register CORD right;
+ register CORD left;
+ register char * new_right;
+ register size_t right_len;
+
+ lenx = LEN(x);
+
if (leny <= SHORT_LIMIT/2
- && IS_CONCATENATION(x)
+ && IS_CONCATENATION(x)
&& CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
/* Merge y into right part of x. */
if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
- right_len = lenx - LEN(left);
+ right_len = lenx - LEN(left);
} else if (((CordRep *)x) -> concatenation.left_len != 0) {
right_len = lenx - ((CordRep *)x) -> concatenation.left_len;
} else {
- right_len = strlen(right);
+ right_len = strlen(right);
}
result_len = right_len + leny; /* length of new_right */
if (result_len <= SHORT_LIMIT) {
- new_right = GC_MALLOC_ATOMIC(result_len + 1);
- memcpy(new_right, right, right_len);
- memcpy(new_right + right_len, y, leny);
- new_right[result_len] = '\0';
- y = new_right;
- leny = result_len;
- x = left;
- lenx -= right_len;
- /* Now fall through to concatenate the two pieces: */
+ new_right = GC_MALLOC_ATOMIC(result_len + 1);
+ memcpy(new_right, right, right_len);
+ memcpy(new_right + right_len, y, leny);
+ new_right[result_len] = '\0';
+ y = new_right;
+ leny = result_len;
+ x = left;
+ lenx -= right_len;
+ /* Now fall through to concatenate the two pieces: */
}
if (CORD_IS_STRING(x)) {
depth = 1;
@@ -209,21 +209,21 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
}
{
/* The general case; lenx, result_len is known: */
- register struct Concatenation * result;
-
- result = GC_NEW(struct Concatenation);
- if (result == 0) OUT_OF_MEMORY;
- result->header = CONCAT_HDR;
- result->depth = depth;
- if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
- result->len = result_len;
- result->left = x;
- result->right = y;
- if (depth >= MAX_DEPTH) {
- return(CORD_balance((CORD)result));
- } else {
- return((CORD) result);
- }
+ register struct Concatenation * result;
+
+ result = GC_NEW(struct Concatenation);
+ if (result == 0) OUT_OF_MEMORY;
+ result->header = CONCAT_HDR;
+ result->depth = depth;
+ if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
+ result->len = result_len;
+ result->left = x;
+ result->right = y;
+ if (depth >= MAX_DEPTH) {
+ return(CORD_balance((CORD)result));
+ } else {
+ return((CORD) result);
+ }
}
}
@@ -233,7 +233,7 @@ CORD CORD_cat(CORD x, CORD y)
register size_t result_len;
register int depth;
register size_t lenx;
-
+
if (x == CORD_EMPTY) return(y);
if (y == CORD_EMPTY) return(x);
if (CORD_IS_STRING(y)) {
@@ -243,28 +243,28 @@ CORD CORD_cat(CORD x, CORD y)
depth = DEPTH(y) + 1;
} else {
register int depthy = DEPTH(y);
-
+
lenx = LEN(x);
depth = DEPTH(x) + 1;
if (depthy >= depth) depth = depthy + 1;
}
result_len = lenx + LEN(y);
{
- register struct Concatenation * result;
-
- result = GC_NEW(struct Concatenation);
- if (result == 0) OUT_OF_MEMORY;
- result->header = CONCAT_HDR;
- result->depth = depth;
- if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
- result->len = result_len;
- result->left = x;
- result->right = y;
- if (depth >= MAX_DEPTH) {
- return(CORD_balance((CORD)result));
- } else {
- return((CORD) result);
- }
+ register struct Concatenation * result;
+
+ result = GC_NEW(struct Concatenation);
+ if (result == 0) OUT_OF_MEMORY;
+ result->header = CONCAT_HDR;
+ result->depth = depth;
+ if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
+ result->len = result_len;
+ result->left = x;
+ result->right = y;
+ if (depth >= MAX_DEPTH) {
+ return(CORD_balance((CORD)result));
+ } else {
+ return((CORD) result);
+ }
}
}
@@ -278,7 +278,7 @@ CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
register size_t i;
char buf[SHORT_LIMIT+1];
register char c;
-
+
for (i = 0; i < len; i++) {
c = (*fn)(i, client_data);
if (c == '\0') goto gen_case;
@@ -293,25 +293,25 @@ CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
}
gen_case:
{
- register struct Function * result;
-
- result = GC_NEW(struct Function);
- if (result == 0) OUT_OF_MEMORY;
- result->header = FN_HDR;
- /* depth is already 0 */
- result->len = len;
- result->fn = fn;
- result->client_data = client_data;
- return((CORD) result);
+ register struct Function * result;
+
+ result = GC_NEW(struct Function);
+ if (result == 0) OUT_OF_MEMORY;
+ result->header = FN_HDR;
+ /* depth is already 0 */
+ result->len = len;
+ result->fn = fn;
+ result->client_data = client_data;
+ return((CORD) result);
}
}
size_t CORD_len(CORD x)
{
if (x == 0) {
- return(0);
+ return(0);
} else {
- return(GEN_LEN(x));
+ return(GEN_LEN(x));
}
}
@@ -323,7 +323,7 @@ struct substr_args {
char CORD_index_access_fn(size_t i, void * client_data)
{
register struct substr_args *descr = (struct substr_args *)client_data;
-
+
return(((char *)(descr->sa_cord))[i + descr->sa_index]);
}
@@ -331,19 +331,19 @@ char CORD_apply_access_fn(size_t i, void * client_data)
{
register struct substr_args *descr = (struct substr_args *)client_data;
register struct Function * fn_cord = &(descr->sa_cord->function);
-
+
return((*(fn_cord->fn))(i + descr->sa_index, fn_cord->client_data));
}
-/* A version of CORD_substr that simply returns a function node, thus */
-/* postponing its work. The fourth argument is a function that may */
-/* be used for efficient access to the ith character. */
-/* Assumes i >= 0 and i + n < length(x). */
+/* A version of CORD_substr that simply returns a function node, thus */
+/* postponing its work. The fourth argument is a function that may */
+/* be used for efficient access to the ith character. */
+/* Assumes i >= 0 and i + n < length(x). */
CORD CORD_substr_closure(CORD x, size_t i, size_t n, CORD_fn f)
{
register struct substr_args * sa = GC_NEW(struct substr_args);
CORD result;
-
+
if (sa == 0) OUT_OF_MEMORY;
sa->sa_cord = (CordRep *)x;
sa->sa_index = i;
@@ -353,9 +353,9 @@ CORD CORD_substr_closure(CORD x, size_t i, size_t n, CORD_fn f)
}
# define SUBSTR_LIMIT (10 * SHORT_LIMIT)
- /* Substrings of function nodes and flat strings shorter than */
- /* this are flat strings. Othewise we use a functional */
- /* representation, which is significantly slower to access. */
+ /* Substrings of function nodes and flat strings shorter than */
+ /* this are flat strings. Othewise we use a functional */
+ /* representation, which is significantly slower to access. */
/* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/
CORD CORD_substr_checked(CORD x, size_t i, size_t n)
@@ -365,56 +365,56 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
return(CORD_substr_closure(x, i, n, CORD_index_access_fn));
} else {
register char * result = GC_MALLOC_ATOMIC(n+1);
-
+
if (result == 0) OUT_OF_MEMORY;
strncpy(result, x+i, n);
result[n] = '\0';
return(result);
}
} else if (IS_CONCATENATION(x)) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
- register size_t left_len;
- register size_t right_len;
-
- left_len = LEFT_LEN(conc);
- right_len = conc -> len - left_len;
- if (i >= left_len) {
- if (n == right_len) return(conc -> right);
- return(CORD_substr_checked(conc -> right, i - left_len, n));
- } else if (i+n <= left_len) {
- if (n == left_len) return(conc -> left);
- return(CORD_substr_checked(conc -> left, i, n));
- } else {
- /* Need at least one character from each side. */
- register CORD left_part;
- register CORD right_part;
- register size_t left_part_len = left_len - i;
-
- if (i == 0) {
- left_part = conc -> left;
- } else {
- left_part = CORD_substr_checked(conc -> left, i, left_part_len);
- }
- if (i + n == right_len + left_len) {
- right_part = conc -> right;
- } else {
- right_part = CORD_substr_checked(conc -> right, 0,
- n - left_part_len);
- }
- return(CORD_cat(left_part, right_part));
- }
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+ register size_t left_len;
+ register size_t right_len;
+
+ left_len = LEFT_LEN(conc);
+ right_len = conc -> len - left_len;
+ if (i >= left_len) {
+ if (n == right_len) return(conc -> right);
+ return(CORD_substr_checked(conc -> right, i - left_len, n));
+ } else if (i+n <= left_len) {
+ if (n == left_len) return(conc -> left);
+ return(CORD_substr_checked(conc -> left, i, n));
+ } else {
+ /* Need at least one character from each side. */
+ register CORD left_part;
+ register CORD right_part;
+ register size_t left_part_len = left_len - i;
+
+ if (i == 0) {
+ left_part = conc -> left;
+ } else {
+ left_part = CORD_substr_checked(conc -> left, i, left_part_len);
+ }
+ if (i + n == right_len + left_len) {
+ right_part = conc -> right;
+ } else {
+ right_part = CORD_substr_checked(conc -> right, 0,
+ n - left_part_len);
+ }
+ return(CORD_cat(left_part, right_part));
+ }
} else /* function */ {
if (n > SUBSTR_LIMIT) {
if (IS_SUBSTR(x)) {
- /* Avoid nesting substring nodes. */
- register struct Function * f = &(((CordRep *)x) -> function);
- register struct substr_args *descr =
- (struct substr_args *)(f -> client_data);
-
- return(CORD_substr_closure((CORD)descr->sa_cord,
- i + descr->sa_index,
- n, f -> fn));
+ /* Avoid nesting substring nodes. */
+ register struct Function * f = &(((CordRep *)x) -> function);
+ register struct substr_args *descr =
+ (struct substr_args *)(f -> client_data);
+
+ return(CORD_substr_closure((CORD)descr->sa_cord,
+ i + descr->sa_index,
+ n, f -> fn));
} else {
return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
}
@@ -426,13 +426,13 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
register char c;
register int j;
register int lim = i + n;
-
+
for (j = i; j < lim; j++) {
- c = (*(f -> fn))(j, f -> client_data);
- if (c == '\0') {
- return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
- }
- *p++ = c;
+ c = (*(f -> fn))(j, f -> client_data);
+ if (c == '\0') {
+ return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
+ }
+ *p++ = c;
}
*p = '\0';
result = GC_MALLOC_ATOMIC(n+1);
@@ -446,59 +446,59 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
CORD CORD_substr(CORD x, size_t i, size_t n)
{
register size_t len = CORD_len(x);
-
+
if (i >= len || n <= 0) return(0);
- /* n < 0 is impossible in a correct C implementation, but */
- /* quite possible under SunOS 4.X. */
+ /* n < 0 is impossible in a correct C implementation, but */
+ /* quite possible under SunOS 4.X. */
if (i + n > len) n = len - i;
# ifndef __STDC__
if (i < 0) ABORT("CORD_substr: second arg. negative");
- /* Possible only if both client and C implementation are buggy. */
- /* But empirically this happens frequently. */
+ /* Possible only if both client and C implementation are buggy. */
+ /* But empirically this happens frequently. */
# endif
return(CORD_substr_checked(x, i, n));
}
-/* See cord.h for definition. We assume i is in range. */
+/* See cord.h for definition. We assume i is in range. */
int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
- CORD_batched_iter_fn f2, void * client_data)
+ CORD_batched_iter_fn f2, void * client_data)
{
if (x == 0) return(0);
if (CORD_IS_STRING(x)) {
- register const char *p = x+i;
-
- if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big");
+ register const char *p = x+i;
+
+ if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big");
if (f2 != CORD_NO_FN) {
return((*f2)(p, client_data));
} else {
- while (*p) {
+ while (*p) {
if ((*f1)(*p, client_data)) return(1);
p++;
- }
- return(0);
+ }
+ return(0);
}
} else if (IS_CONCATENATION(x)) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
-
-
- if (i > 0) {
- register size_t left_len = LEFT_LEN(conc);
-
- if (i >= left_len) {
- return(CORD_iter5(conc -> right, i - left_len, f1, f2,
- client_data));
- }
- }
- if (CORD_iter5(conc -> left, i, f1, f2, client_data)) {
- return(1);
- }
- return(CORD_iter5(conc -> right, 0, f1, f2, client_data));
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+
+
+ if (i > 0) {
+ register size_t left_len = LEFT_LEN(conc);
+
+ if (i >= left_len) {
+ return(CORD_iter5(conc -> right, i - left_len, f1, f2,
+ client_data));
+ }
+ }
+ if (CORD_iter5(conc -> left, i, f1, f2, client_data)) {
+ return(1);
+ }
+ return(CORD_iter5(conc -> right, 0, f1, f2, client_data));
} else /* function */ {
register struct Function * f = &(((CordRep *)x) -> function);
register size_t j;
register size_t lim = f -> len;
-
+
for (j = i; j < lim; j++) {
if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
return(1);
@@ -507,7 +507,7 @@ int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
return(0);
}
}
-
+
#undef CORD_iter
int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data)
{
@@ -518,36 +518,36 @@ int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
{
if (x == 0) return(0);
if (CORD_IS_STRING(x)) {
- register const char *p = x + i;
- register char c;
-
- for(;;) {
- c = *p;
- if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
+ register const char *p = x + i;
+ register char c;
+
+ for(;;) {
+ c = *p;
+ if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
if ((*f1)(c, client_data)) return(1);
- if (p == x) break;
+ if (p == x) break;
p--;
- }
- return(0);
+ }
+ return(0);
} else if (IS_CONCATENATION(x)) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
- register CORD left_part = conc -> left;
- register size_t left_len;
-
- left_len = LEFT_LEN(conc);
- if (i >= left_len) {
- if (CORD_riter4(conc -> right, i - left_len, f1, client_data)) {
- return(1);
- }
- return(CORD_riter4(left_part, left_len - 1, f1, client_data));
- } else {
- return(CORD_riter4(left_part, i, f1, client_data));
- }
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+ register CORD left_part = conc -> left;
+ register size_t left_len;
+
+ left_len = LEFT_LEN(conc);
+ if (i >= left_len) {
+ if (CORD_riter4(conc -> right, i - left_len, f1, client_data)) {
+ return(1);
+ }
+ return(CORD_riter4(left_part, left_len - 1, f1, client_data));
+ } else {
+ return(CORD_riter4(left_part, i, f1, client_data));
+ }
} else /* function */ {
register struct Function * f = &(((CordRep *)x) -> function);
register size_t j;
-
+
for (j = i; ; j--) {
if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
return(1);
@@ -559,7 +559,9 @@ int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data)
{
- return(CORD_riter4(x, CORD_len(x) - 1, f1, client_data));
+ size_t len = CORD_len(x);
+ if (len == 0) return(0);
+ return(CORD_riter4(x, len - 1, f1, client_data));
}
/*
@@ -579,7 +581,7 @@ int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data)
typedef struct {
CORD c;
- size_t len; /* Actual length of c */
+ size_t len; /* Actual length of c */
} ForestElement;
static size_t min_len [ MAX_DEPTH ];
@@ -589,24 +591,24 @@ static int min_len_init = 0;
int CORD_max_len;
typedef ForestElement Forest [ MAX_DEPTH ];
- /* forest[i].len >= fib(i+1) */
- /* The string is the concatenation */
- /* of the forest in order of DECREASING */
- /* indices. */
+ /* forest[i].len >= fib(i+1) */
+ /* The string is the concatenation */
+ /* of the forest in order of DECREASING */
+ /* indices. */
void CORD_init_min_len()
{
register int i;
register size_t last, previous, current;
-
+
min_len[0] = previous = 1;
min_len[1] = last = 2;
for (i = 2; i < MAX_DEPTH; i++) {
- current = last + previous;
- if (current < last) /* overflow */ current = last;
- min_len[i] = current;
- previous = last;
- last = current;
+ current = last + previous;
+ if (current < last) /* overflow */ current = last;
+ min_len[i] = current;
+ previous = last;
+ last = current;
}
CORD_max_len = last - 1;
min_len_init = 1;
@@ -616,48 +618,48 @@ void CORD_init_min_len()
void CORD_init_forest(ForestElement * forest, size_t max_len)
{
register int i;
-
+
for (i = 0; i < MAX_DEPTH; i++) {
- forest[i].c = 0;
- if (min_len[i] > max_len) return;
+ forest[i].c = 0;
+ if (min_len[i] > max_len) return;
}
ABORT("Cord too long");
}
-/* Add a leaf to the appropriate level in the forest, cleaning */
-/* out lower levels as necessary. */
-/* Also works if x is a balanced tree of concatenations; however */
-/* in this case an extra concatenation node may be inserted above x; */
-/* This node should not be counted in the statement of the invariants. */
+/* Add a leaf to the appropriate level in the forest, cleaning */
+/* out lower levels as necessary. */
+/* Also works if x is a balanced tree of concatenations; however */
+/* in this case an extra concatenation node may be inserted above x; */
+/* This node should not be counted in the statement of the invariants. */
void CORD_add_forest(ForestElement * forest, CORD x, size_t len)
{
register int i = 0;
register CORD sum = CORD_EMPTY;
register size_t sum_len = 0;
-
+
while (len > min_len[i + 1]) {
- if (forest[i].c != 0) {
- sum = CORD_cat(forest[i].c, sum);
- sum_len += forest[i].len;
- forest[i].c = 0;
- }
+ if (forest[i].c != 0) {
+ sum = CORD_cat(forest[i].c, sum);
+ sum_len += forest[i].len;
+ forest[i].c = 0;
+ }
i++;
}
- /* Sum has depth at most 1 greter than what would be required */
- /* for balance. */
+ /* Sum has depth at most 1 greter than what would be required */
+ /* for balance. */
sum = CORD_cat(sum, x);
sum_len += len;
- /* If x was a leaf, then sum is now balanced. To see this */
- /* consider the two cases in which forest[i-1] either is or is */
- /* not empty. */
+ /* If x was a leaf, then sum is now balanced. To see this */
+ /* consider the two cases in which forest[i-1] either is or is */
+ /* not empty. */
while (sum_len >= min_len[i]) {
- if (forest[i].c != 0) {
- sum = CORD_cat(forest[i].c, sum);
- sum_len += forest[i].len;
- /* This is again balanced, since sum was balanced, and has */
- /* allowable depth that differs from i by at most 1. */
- forest[i].c = 0;
- }
+ if (forest[i].c != 0) {
+ sum = CORD_cat(forest[i].c, sum);
+ sum_len += forest[i].len;
+ /* This is again balanced, since sum was balanced, and has */
+ /* allowable depth that differs from i by at most 1. */
+ forest[i].c = 0;
+ }
i++;
}
i--;
@@ -670,37 +672,37 @@ CORD CORD_concat_forest(ForestElement * forest, size_t expected_len)
register int i = 0;
CORD sum = 0;
size_t sum_len = 0;
-
+
while (sum_len != expected_len) {
- if (forest[i].c != 0) {
- sum = CORD_cat(forest[i].c, sum);
- sum_len += forest[i].len;
- }
+ if (forest[i].c != 0) {
+ sum = CORD_cat(forest[i].c, sum);
+ sum_len += forest[i].len;
+ }
i++;
}
return(sum);
}
-/* Insert the frontier of x into forest. Balanced subtrees are */
-/* treated as leaves. This potentially adds one to the depth */
-/* of the final tree. */
+/* Insert the frontier of x into forest. Balanced subtrees are */
+/* treated as leaves. This potentially adds one to the depth */
+/* of the final tree. */
void CORD_balance_insert(CORD x, size_t len, ForestElement * forest)
{
register int depth;
-
+
if (CORD_IS_STRING(x)) {
CORD_add_forest(forest, x, len);
} else if (IS_CONCATENATION(x)
&& ((depth = DEPTH(x)) >= MAX_DEPTH
|| len < min_len[depth])) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
- size_t left_len = LEFT_LEN(conc);
-
- CORD_balance_insert(conc -> left, left_len, forest);
- CORD_balance_insert(conc -> right, len - left_len, forest);
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+ size_t left_len = LEFT_LEN(conc);
+
+ CORD_balance_insert(conc -> left, left_len, forest);
+ CORD_balance_insert(conc -> right, len - left_len, forest);
} else /* function or balanced */ {
- CORD_add_forest(forest, x, len);
+ CORD_add_forest(forest, x, len);
}
}
@@ -709,7 +711,7 @@ CORD CORD_balance(CORD x)
{
Forest forest;
register size_t len;
-
+
if (x == 0) return(0);
if (CORD_IS_STRING(x)) return(x);
if (!min_len_init) CORD_init_min_len();
@@ -720,13 +722,13 @@ CORD CORD_balance(CORD x)
}
-/* Position primitives */
+/* Position primitives */
/* Private routines to deal with the hard cases only: */
-/* P contains a prefix of the path to cur_pos. Extend it to a full */
-/* path and set up leaf info. */
-/* Return 0 if past the end of cord, 1 o.w. */
+/* P contains a prefix of the path to cur_pos. Extend it to a full */
+/* path and set up leaf info. */
+/* Return 0 if past the end of cord, 1 o.w. */
void CORD__extend_path(register CORD_pos p)
{
register struct CORD_pe * current_pe = &(p[0].path[p[0].path_len]);
@@ -734,25 +736,25 @@ void CORD__extend_path(register CORD_pos p)
register size_t pos = p[0].cur_pos;
register size_t top_pos = current_pe -> pe_start_pos;
register size_t top_len = GEN_LEN(top);
-
+
/* Fill in the rest of the path. */
while(!CORD_IS_STRING(top) && IS_CONCATENATION(top)) {
- register struct Concatenation * conc =
- &(((CordRep *)top) -> concatenation);
- register size_t left_len;
-
- left_len = LEFT_LEN(conc);
- current_pe++;
- if (pos >= top_pos + left_len) {
- current_pe -> pe_cord = top = conc -> right;
- current_pe -> pe_start_pos = top_pos = top_pos + left_len;
- top_len -= left_len;
- } else {
- current_pe -> pe_cord = top = conc -> left;
- current_pe -> pe_start_pos = top_pos;
- top_len = left_len;
- }
- p[0].path_len++;
+ register struct Concatenation * conc =
+ &(((CordRep *)top) -> concatenation);
+ register size_t left_len;
+
+ left_len = LEFT_LEN(conc);
+ current_pe++;
+ if (pos >= top_pos + left_len) {
+ current_pe -> pe_cord = top = conc -> right;
+ current_pe -> pe_start_pos = top_pos = top_pos + left_len;
+ top_len -= left_len;
+ } else {
+ current_pe -> pe_cord = top = conc -> left;
+ current_pe -> pe_start_pos = top_pos;
+ top_len = left_len;
+ }
+ p[0].path_len++;
}
/* Fill in leaf description for fast access. */
if (CORD_IS_STRING(top)) {
@@ -771,7 +773,7 @@ char CORD__pos_fetch(register CORD_pos p)
struct CORD_pe * pe = &((p)[0].path[(p)[0].path_len]);
CORD leaf = pe -> pe_cord;
register struct Function * f = &(((CordRep *)leaf) -> function);
-
+
if (!IS_FUNCTION(leaf)) ABORT("CORD_pos_fetch: bad leaf");
return ((*(f -> fn))(p[0].cur_pos - pe -> pe_start_pos, f -> client_data));
}
@@ -781,48 +783,48 @@ void CORD__next(register CORD_pos p)
register size_t cur_pos = p[0].cur_pos + 1;
register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
register CORD leaf = current_pe -> pe_cord;
-
+
/* Leaf is not a string or we're at end of leaf */
p[0].cur_pos = cur_pos;
if (!CORD_IS_STRING(leaf)) {
- /* Function leaf */
- register struct Function * f = &(((CordRep *)leaf) -> function);
- register size_t start_pos = current_pe -> pe_start_pos;
- register size_t end_pos = start_pos + f -> len;
-
- if (cur_pos < end_pos) {
- /* Fill cache and return. */
- register size_t i;
- register size_t limit = cur_pos + FUNCTION_BUF_SZ;
- register CORD_fn fn = f -> fn;
- register void * client_data = f -> client_data;
-
- if (limit > end_pos) {
- limit = end_pos;
- }
- for (i = cur_pos; i < limit; i++) {
- p[0].function_buf[i - cur_pos] =
- (*fn)(i - start_pos, client_data);
- }
- p[0].cur_start = cur_pos;
- p[0].cur_leaf = p[0].function_buf;
- p[0].cur_end = limit;
- return;
- }
+ /* Function leaf */
+ register struct Function * f = &(((CordRep *)leaf) -> function);
+ register size_t start_pos = current_pe -> pe_start_pos;
+ register size_t end_pos = start_pos + f -> len;
+
+ if (cur_pos < end_pos) {
+ /* Fill cache and return. */
+ register size_t i;
+ register size_t limit = cur_pos + FUNCTION_BUF_SZ;
+ register CORD_fn fn = f -> fn;
+ register void * client_data = f -> client_data;
+
+ if (limit > end_pos) {
+ limit = end_pos;
+ }
+ for (i = cur_pos; i < limit; i++) {
+ p[0].function_buf[i - cur_pos] =
+ (*fn)(i - start_pos, client_data);
+ }
+ p[0].cur_start = cur_pos;
+ p[0].cur_leaf = p[0].function_buf;
+ p[0].cur_end = limit;
+ return;
+ }
}
- /* End of leaf */
- /* Pop the stack until we find two concatenation nodes with the */
- /* same start position: this implies we were in left part. */
+ /* End of leaf */
+ /* Pop the stack until we find two concatenation nodes with the */
+ /* same start position: this implies we were in left part. */
{
- while (p[0].path_len > 0
- && current_pe[0].pe_start_pos != current_pe[-1].pe_start_pos) {
- p[0].path_len--;
- current_pe--;
- }
- if (p[0].path_len == 0) {
- p[0].path_len = CORD_POS_INVALID;
+ while (p[0].path_len > 0
+ && current_pe[0].pe_start_pos != current_pe[-1].pe_start_pos) {
+ p[0].path_len--;
+ current_pe--;
+ }
+ if (p[0].path_len == 0) {
+ p[0].path_len = CORD_POS_INVALID;
return;
- }
+ }
}
p[0].path_len--;
CORD__extend_path(p);
@@ -831,26 +833,26 @@ void CORD__next(register CORD_pos p)
void CORD__prev(register CORD_pos p)
{
register struct CORD_pe * pe = &(p[0].path[p[0].path_len]);
-
+
if (p[0].cur_pos == 0) {
p[0].path_len = CORD_POS_INVALID;
return;
}
p[0].cur_pos--;
if (p[0].cur_pos >= pe -> pe_start_pos) return;
-
- /* Beginning of leaf */
-
- /* Pop the stack until we find two concatenation nodes with the */
- /* different start position: this implies we were in right part. */
+
+ /* Beginning of leaf */
+
+ /* Pop the stack until we find two concatenation nodes with the */
+ /* different start position: this implies we were in right part. */
{
- register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
-
- while (p[0].path_len > 0
- && current_pe[0].pe_start_pos == current_pe[-1].pe_start_pos) {
- p[0].path_len--;
- current_pe--;
- }
+ register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
+
+ while (p[0].path_len > 0
+ && current_pe[0].pe_start_pos == current_pe[-1].pe_start_pos) {
+ p[0].path_len--;
+ current_pe--;
+ }
}
p[0].path_len--;
CORD__extend_path(p);
@@ -866,7 +868,7 @@ void CORD__prev(register CORD_pos p)
char CORD_pos_fetch(register CORD_pos p)
{
if (p[0].cur_start <= p[0].cur_pos && p[0].cur_pos < p[0].cur_end) {
- return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
+ return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
} else {
return(CORD__pos_fetch(p));
}
@@ -875,18 +877,18 @@ char CORD_pos_fetch(register CORD_pos p)
void CORD_next(CORD_pos p)
{
if (p[0].cur_pos < p[0].cur_end - 1) {
- p[0].cur_pos++;
+ p[0].cur_pos++;
} else {
- CORD__next(p);
+ CORD__next(p);
}
}
void CORD_prev(CORD_pos p)
{
if (p[0].cur_end != 0 && p[0].cur_pos > p[0].cur_start) {
- p[0].cur_pos--;
+ p[0].cur_pos--;
} else {
- CORD__prev(p);
+ CORD__prev(p);
}
}
@@ -908,8 +910,8 @@ int CORD_pos_valid(CORD_pos p)
void CORD_set_pos(CORD_pos p, CORD x, size_t i)
{
if (x == CORD_EMPTY) {
- p[0].path_len = CORD_POS_INVALID;
- return;
+ p[0].path_len = CORD_POS_INVALID;
+ return;
}
p[0].path[0].pe_cord = x;
p[0].path[0].pe_start_pos = 0;
diff --git a/cord/cordtest.c b/cord/cordtest.c
index 08333ca0..42c1fe61 100644
--- a/cord/cordtest.c
+++ b/cord/cordtest.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -10,18 +10,18 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, August 24, 1994 11:58 am PDT */
-# include "gc.h" /* For GC_INIT() only */
+
+# include "gc.h" /* For GC_INIT() only */
# include "cord.h"
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
-/* This is a very incomplete test of the cord package. It knows about */
-/* a few internals of the package (e.g. when C strings are returned) */
-/* that real clients shouldn't rely on. */
+/* This is a very incomplete test of the cord package. It knows about */
+/* a few internals of the package (e.g. when C strings are returned) */
+/* that real clients shouldn't rely on. */
# define ABORT(string) \
-{ int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
+ { int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
int count;
@@ -48,60 +48,64 @@ char id_cord_fn(size_t i, void * client_data)
return((char)i);
}
-void test_basics()
+void test_basics(void)
{
CORD x = CORD_from_char_star("ab");
register int i;
char c;
CORD y;
CORD_pos p;
-
+
x = CORD_cat(x,x);
if (!CORD_IS_STRING(x)) ABORT("short cord should usually be a string");
if (strcmp(x, "abab") != 0) ABORT("bad CORD_cat result");
-
+
for (i = 1; i < 16; i++) {
x = CORD_cat(x,x);
}
x = CORD_cat(x,"c");
if (CORD_len(x) != 128*1024+1) ABORT("bad length");
-
+
count = 0;
if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
ABORT("CORD_iter5 failed");
}
if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
-
+
count = 0;
CORD_set_pos(p, x, 64*1024-1);
while(CORD_pos_valid(p)) {
- (void) test_fn(CORD_pos_fetch(p), (void *)13);
- CORD_next(p);
+ (void) test_fn(CORD_pos_fetch(p), (void *)13);
+ CORD_next(p);
}
if (count != 64*1024 + 2) ABORT("Position based iteration failed");
-
+
y = CORD_substr(x, 1023, 5);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
-
+
y = CORD_substr(x, 1024, 8);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "abababab") != 0) ABORT("bad CORD_substr result");
-
+
y = CORD_substr(x, 128*1024-1, 8);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "bc") != 0) ABORT("bad CORD_substr result");
-
+
x = CORD_balance(x);
if (CORD_len(x) != 128*1024+1) ABORT("bad length");
-
+
count = 0;
if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
ABORT("CORD_iter5 failed");
}
if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
-
+
y = CORD_substr(x, 1023, 5);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
y = CORD_from_fn(id_cord_fn, 0, 13);
@@ -109,23 +113,23 @@ void test_basics()
CORD_set_pos(p, y, i);
while(CORD_pos_valid(p)) {
c = CORD_pos_fetch(p);
- if(c != i) ABORT("Traversal of function node failed");
- CORD_next(p); i++;
+ if(c != i) ABORT("Traversal of function node failed");
+ CORD_next(p); i++;
}
if (i != 13) ABORT("Bad apparent length for function node");
}
-void test_extras()
+void test_extras(void)
{
# if defined(__OS2__) || defined(__DJGPP__)
-# define FNAME1 "tmp1"
-# define FNAME2 "tmp2"
+# define FNAME1 "tmp1"
+# define FNAME2 "tmp2"
# elif defined(AMIGA)
-# define FNAME1 "T:tmp1"
-# define FNAME2 "T:tmp2"
+# define FNAME1 "T:tmp1"
+# define FNAME2 "T:tmp2"
# else
-# define FNAME1 "/tmp/cord_test"
-# define FNAME2 "/tmp/cord_test2"
+# define FNAME1 "/tmp/cord_test"
+# define FNAME2 "/tmp/cord_test2"
# endif
register int i;
CORD y = "abcdefghijklmnopqrstuvwxyz0123456789";
@@ -133,7 +137,7 @@ void test_extras()
CORD w, z;
FILE *f;
FILE *f1a, *f1b, *f2;
-
+
w = CORD_cat(CORD_cat(y,y),y);
z = CORD_catn(3,y,y,y);
if (CORD_cmp(w,z) != 0) ABORT("CORD_catn comparison wrong");
@@ -148,12 +152,16 @@ void test_extras()
if ((f = fopen(FNAME1, "w")) == 0) ABORT("open failed");
if (CORD_put(z,f) == EOF) ABORT("CORD_put failed");
if (fclose(f) == EOF) ABORT("fclose failed");
- w = CORD_from_file(f1a = fopen(FNAME1, "rb"));
+ f1a = fopen(FNAME1, "rb");
+ if (!f1a) ABORT("Unable to open " FNAME1);
+ w = CORD_from_file(f1a);
if (CORD_len(w) != CORD_len(z)) ABORT("file length wrong");
if (CORD_cmp(w,z) != 0) ABORT("file comparison wrong");
if (CORD_cmp(CORD_substr(w, 50*36+2, 36), y) != 0)
- ABORT("file substr wrong");
- z = CORD_from_file_lazy(f1b = fopen(FNAME1, "rb"));
+ ABORT("file substr wrong");
+ f1b = fopen(FNAME1, "rb");
+ if (!f1b) ABORT("2nd open failed: " FNAME1);
+ z = CORD_from_file_lazy(f1b);
if (CORD_cmp(w,z) != 0) ABORT("File conversions differ");
if (CORD_chr(w, 0, '9') != 37) ABORT("CORD_chr failed 1");
if (CORD_chr(w, 3, 'a') != 38) ABORT("CORD_chr failed 2");
@@ -169,46 +177,48 @@ void test_extras()
# endif
if (CORD_put(x,f) == EOF) ABORT("CORD_put failed");
if (fclose(f) == EOF) ABORT("fclose failed");
- w = CORD_from_file(f2 = fopen(FNAME2, "rb"));
+ f2 = fopen(FNAME2, "rb");
+ if (!f2) ABORT("Unable to open " FNAME2);
+ w = CORD_from_file(f2);
if (CORD_len(w) != CORD_len(x)) ABORT("file length wrong");
if (CORD_cmp(w,x) != 0) ABORT("file comparison wrong");
if (CORD_cmp(CORD_substr(w, 1000*36, 36), y) != 0)
- ABORT("file substr wrong");
+ ABORT("file substr wrong");
if (strcmp(CORD_to_char_star(CORD_substr(w, 1000*36, 36)), y) != 0)
- ABORT("char * file substr wrong");
+ ABORT("char * file substr wrong");
if (strcmp(CORD_substr(w, 1000*36, 2), "ab") != 0)
- ABORT("short file substr wrong");
+ ABORT("short file substr wrong");
if (CORD_str(x,1,"9a") != 35) ABORT("CORD_str failed 1");
if (CORD_str(x,0,"9abcdefghijk") != 35) ABORT("CORD_str failed 2");
if (CORD_str(x,0,"9abcdefghijx") != CORD_NOT_FOUND)
- ABORT("CORD_str failed 3");
+ ABORT("CORD_str failed 3");
if (CORD_str(x,0,"9>") != CORD_NOT_FOUND) ABORT("CORD_str failed 4");
if (remove(FNAME1) != 0) {
- /* On some systems, e.g. OS2, this may fail if f1 is still open. */
- if ((fclose(f1a) == EOF) & (fclose(f1b) == EOF))
- ABORT("fclose(f1) failed");
- if (remove(FNAME1) != 0) ABORT("remove 1 failed");
+ /* On some systems, e.g. OS2, this may fail if f1 is still open. */
+ if ((fclose(f1a) == EOF) & (fclose(f1b) == EOF))
+ ABORT("fclose(f1) failed");
+ if (remove(FNAME1) != 0) ABORT("remove 1 failed");
}
if (remove(FNAME2) != 0) {
- if (fclose(f2) == EOF) ABORT("fclose(f2) failed");
- if (remove(FNAME2) != 0) ABORT("remove 2 failed");
+ if (fclose(f2) == EOF) ABORT("fclose(f2) failed");
+ if (remove(FNAME2) != 0) ABORT("remove 2 failed");
}
}
-void test_printf()
+void test_printf(void)
{
CORD result;
char result2[200];
long l;
short s;
CORD x;
-
+
if (CORD_sprintf(&result, "%7.2f%ln", 3.14159F, &l) != 7)
- ABORT("CORD_sprintf failed 1");
+ ABORT("CORD_sprintf failed 1");
if (CORD_cmp(result, " 3.14") != 0)ABORT("CORD_sprintf goofed 1");
if (l != 7) ABORT("CORD_sprintf goofed 2");
if (CORD_sprintf(&result, "%-7.2s%hn%c%s", "abcd", &s, 'x', "yz") != 10)
- ABORT("CORD_sprintf failed 2");
+ ABORT("CORD_sprintf failed 2");
if (CORD_cmp(result, "ab xyz") != 0)ABORT("CORD_sprintf goofed 3");
if (s != 7) ABORT("CORD_sprintf goofed 4");
x = "abcdefghij";
@@ -216,12 +226,12 @@ void test_printf()
x = CORD_cat(x,x);
x = CORD_cat(x,x);
if (CORD_sprintf(&result, "->%-120.78r!\n", x) != 124)
- ABORT("CORD_sprintf failed 3");
+ ABORT("CORD_sprintf failed 3");
(void) sprintf(result2, "->%-120.78s!\n", CORD_to_char_star(x));
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
}
-int main()
+int main(void)
{
# ifdef THINK_C
printf("cordtest:\n");
diff --git a/cord/cordxtra.c b/cord/cordxtra.c
index b0a74622..d5394dba 100644
--- a/cord/cordxtra.c
+++ b/cord/cordxtra.c
@@ -24,17 +24,17 @@
# include <stdarg.h>
# include "cord.h"
# include "ec.h"
-# define I_HIDE_POINTERS /* So we get access to allocation lock. */
- /* We use this for lazy file reading, */
- /* so that we remain independent */
- /* of the threads primitives. */
+# define I_HIDE_POINTERS /* So we get access to allocation lock. */
+ /* We use this for lazy file reading, */
+ /* so that we remain independent */
+ /* of the threads primitives. */
# include "gc.h"
-/* For now we assume that pointer reads and writes are atomic, */
-/* i.e. another thread always sees the state before or after */
-/* a write. This might be false on a Motorola M68K with */
-/* pointers that are not 32-bit aligned. But there probably */
-/* aren't too many threads packages running on those. */
+/* For now we assume that pointer reads and writes are atomic, */
+/* i.e. another thread always sees the state before or after */
+/* a write. This might be false on a Motorola M68K with */
+/* pointers that are not 32-bit aligned. But there probably */
+/* aren't too many threads packages running on those. */
# define ATOMIC_WRITE(x,y) (x) = (y)
# define ATOMIC_READ(x) (*(x))
@@ -46,19 +46,19 @@
# define SEEK_END 2
# endif
-# define BUFSZ 2048 /* Size of stack allocated buffers when */
- /* we want large buffers. */
+# define BUFSZ 2048 /* Size of stack allocated buffers when */
+ /* we want large buffers. */
typedef void (* oom_fn)(void);
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
- ABORT("Out of memory\n"); }
+ ABORT("Out of memory\n"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
CORD CORD_cat_char(CORD x, char c)
{
register char * string;
-
+
if (c == '\0') return(CORD_cat(x, CORD_nul(1)));
string = GC_MALLOC_ATOMIC(2);
if (string == 0) OUT_OF_MEMORY;
@@ -83,22 +83,22 @@ CORD CORD_catn(int nargs, ...)
}
typedef struct {
- size_t len;
- size_t count;
- char * buf;
+ size_t len;
+ size_t count;
+ char * buf;
} CORD_fill_data;
int CORD_fill_proc(char c, void * client_data)
{
register CORD_fill_data * d = (CORD_fill_data *)client_data;
register size_t count = d -> count;
-
+
(d -> buf)[count] = c;
d -> count = ++count;
if (count >= d -> len) {
- return(1);
+ return(1);
} else {
- return(0);
+ return(0);
}
}
@@ -109,7 +109,7 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
register size_t max = d -> len;
register char * buf = d -> buf;
register const char * t = s;
-
+
while((buf[count] = *t++) != '\0') {
count++;
if (count >= max) {
@@ -121,12 +121,12 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
return(0);
}
-/* Fill buf with len characters starting at i. */
-/* Assumes len characters are available. */
+/* Fill buf with len characters starting at i. */
+/* Assumes len characters are available. */
void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
{
CORD_fill_data fd;
-
+
fd.len = len;
fd.buf = buf;
fd.count = 0;
@@ -138,7 +138,7 @@ int CORD_cmp(CORD x, CORD y)
CORD_pos xpos;
CORD_pos ypos;
register size_t avail, yavail;
-
+
if (y == CORD_EMPTY) return(x != CORD_EMPTY);
if (x == CORD_EMPTY) return(-1);
if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
@@ -147,7 +147,7 @@ int CORD_cmp(CORD x, CORD y)
for(;;) {
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
- return(-1);
+ return(-1);
} else {
return(0);
}
@@ -163,12 +163,12 @@ int CORD_cmp(CORD x, CORD y)
CORD_next(xpos);
CORD_next(ypos);
} else {
- /* process as many characters as we can */
+ /* process as many characters as we can */
register int result;
-
+
if (avail > yavail) avail = yavail;
result = strncmp(CORD_pos_cur_char_addr(xpos),
- CORD_pos_cur_char_addr(ypos), avail);
+ CORD_pos_cur_char_addr(ypos), avail);
if (result != 0) return(result);
CORD_pos_advance(xpos, avail);
CORD_pos_advance(ypos, avail);
@@ -182,13 +182,13 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
CORD_pos ypos;
register size_t count;
register long avail, yavail;
-
+
CORD_set_pos(xpos, x, x_start);
CORD_set_pos(ypos, y, y_start);
for(count = 0; count < len;) {
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
- return(-1);
+ return(-1);
} else {
return(0);
}
@@ -205,14 +205,14 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
CORD_next(ypos);
count++;
} else {
- /* process as many characters as we can */
+ /* process as many characters as we can */
register int result;
-
+
if (avail > yavail) avail = yavail;
count += avail;
if (count > len) avail -= (count - len);
result = strncmp(CORD_pos_cur_char_addr(xpos),
- CORD_pos_cur_char_addr(ypos), (size_t)avail);
+ CORD_pos_cur_char_addr(ypos), (size_t)avail);
if (result != 0) return(result);
CORD_pos_advance(xpos, (size_t)avail);
CORD_pos_advance(ypos, (size_t)avail);
@@ -225,7 +225,7 @@ char * CORD_to_char_star(CORD x)
{
register size_t len = CORD_len(x);
char * result = GC_MALLOC_ATOMIC(len + 1);
-
+
if (result == 0) OUT_OF_MEMORY;
CORD_fill_buf(x, 0, len, result);
result[len] = '\0';
@@ -254,7 +254,7 @@ const char * CORD_to_const_char_star(CORD x)
char CORD_fetch(CORD x, size_t i)
{
CORD_pos xpos;
-
+
CORD_set_pos(xpos, x, i);
if (!CORD_pos_valid(xpos)) ABORT("bad index?");
return(CORD_pos_fetch(xpos));
@@ -264,36 +264,36 @@ char CORD_fetch(CORD x, size_t i)
int CORD_put_proc(char c, void * client_data)
{
register FILE * f = (FILE *)client_data;
-
+
return(putc(c, f) == EOF);
}
int CORD_batched_put_proc(const char * s, void * client_data)
{
register FILE * f = (FILE *)client_data;
-
+
return(fputs(s, f) == EOF);
}
-
+
int CORD_put(CORD x, FILE * f)
{
if (CORD_iter5(x, 0, CORD_put_proc, CORD_batched_put_proc, f)) {
return(EOF);
} else {
- return(1);
+ return(1);
}
}
typedef struct {
- size_t pos; /* Current position in the cord */
- char target; /* Character we're looking for */
+ size_t pos; /* Current position in the cord */
+ char target; /* Character we're looking for */
} chr_data;
int CORD_chr_proc(char c, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
-
+
if (c == d -> target) return(1);
(d -> pos) ++;
return(0);
@@ -302,7 +302,7 @@ int CORD_chr_proc(char c, void * client_data)
int CORD_rchr_proc(char c, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
-
+
if (c == d -> target) return(1);
(d -> pos) --;
return(0);
@@ -312,48 +312,48 @@ int CORD_batched_chr_proc(const char *s, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
register char * occ = strchr(s, d -> target);
-
+
if (occ == 0) {
- d -> pos += strlen(s);
- return(0);
+ d -> pos += strlen(s);
+ return(0);
} else {
- d -> pos += occ - s;
- return(1);
+ d -> pos += occ - s;
+ return(1);
}
}
size_t CORD_chr(CORD x, size_t i, int c)
{
chr_data d;
-
+
d.pos = i;
d.target = c;
if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
return(d.pos);
} else {
- return(CORD_NOT_FOUND);
+ return(CORD_NOT_FOUND);
}
}
size_t CORD_rchr(CORD x, size_t i, int c)
{
chr_data d;
-
+
d.pos = i;
d.target = c;
if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
return(d.pos);
} else {
- return(CORD_NOT_FOUND);
+ return(CORD_NOT_FOUND);
}
}
-/* Find the first occurrence of s in x at position start or later. */
-/* This uses an asymptotically poor algorithm, which should typically */
-/* perform acceptably. We compare the first few characters directly, */
-/* and call CORD_ncmp whenever there is a partial match. */
-/* This has the advantage that we allocate very little, or not at all. */
-/* It's very fast if there are few close misses. */
+/* Find the first occurrence of s in x at position start or later. */
+/* This uses an asymptotically poor algorithm, which should typically */
+/* perform acceptably. We compare the first few characters directly, */
+/* and call CORD_ncmp whenever there is a partial match. */
+/* This has the advantage that we allocate very little, or not at all. */
+/* It's very fast if there are few close misses. */
size_t CORD_str(CORD x, size_t start, CORD s)
{
CORD_pos xpos;
@@ -361,14 +361,14 @@ size_t CORD_str(CORD x, size_t start, CORD s)
size_t slen;
register size_t start_len;
const char * s_start;
- unsigned long s_buf = 0; /* The first few characters of s */
- unsigned long x_buf = 0; /* Start of candidate substring. */
- /* Initialized only to make compilers */
- /* happy. */
+ unsigned long s_buf = 0; /* The first few characters of s */
+ unsigned long x_buf = 0; /* Start of candidate substring. */
+ /* Initialized only to make compilers */
+ /* happy. */
unsigned long mask = 0;
register size_t i;
register size_t match_pos;
-
+
if (s == CORD_EMPTY) return(start);
if (CORD_IS_STRING(s)) {
s_start = s;
@@ -391,17 +391,17 @@ size_t CORD_str(CORD x, size_t start, CORD s)
CORD_next(xpos);
}
for (match_pos = start; ; match_pos++) {
- if ((x_buf & mask) == s_buf) {
- if (slen == start_len ||
- CORD_ncmp(x, match_pos + start_len,
- s, start_len, slen - start_len) == 0) {
- return(match_pos);
- }
- }
- if ( match_pos == xlen - slen ) {
- return(CORD_NOT_FOUND);
- }
- x_buf <<= 8;
+ if ((x_buf & mask) == s_buf) {
+ if (slen == start_len ||
+ CORD_ncmp(x, match_pos + start_len,
+ s, start_len, slen - start_len) == 0) {
+ return(match_pos);
+ }
+ }
+ if ( match_pos == xlen - slen ) {
+ return(CORD_NOT_FOUND);
+ }
+ x_buf <<= 8;
x_buf |= (unsigned char)CORD_pos_fetch(xpos);
CORD_next(xpos);
}
@@ -442,16 +442,16 @@ CORD CORD_from_file_eager(FILE * f)
{
register int c;
CORD_ec ecord;
-
+
CORD_ec_init(ecord);
for(;;) {
c = getc(f);
if (c == 0) {
- /* Append the right number of NULs */
- /* Note that any string of NULs is rpresented in 4 words, */
- /* independent of its length. */
+ /* Append the right number of NULs */
+ /* Note that any string of NULs is rpresented in 4 words, */
+ /* independent of its length. */
register size_t count = 1;
-
+
CORD_ec_flush_buf(ecord);
while ((c = getc(f)) == 0) count++;
ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
@@ -463,18 +463,18 @@ CORD CORD_from_file_eager(FILE * f)
return(CORD_balance(CORD_ec_to_cord(ecord)));
}
-/* The state maintained for a lazily read file consists primarily */
-/* of a large direct-mapped cache of previously read values. */
-/* We could rely more on stdio buffering. That would have 2 */
-/* disadvantages: */
-/* 1) Empirically, not all fseek implementations preserve the */
-/* buffer whenever they could. */
-/* 2) It would fail if 2 different sections of a long cord */
-/* were being read alternately. */
-/* We do use the stdio buffer for read ahead. */
-/* To guarantee thread safety in the presence of atomic pointer */
-/* writes, cache lines are always replaced, and never modified in */
-/* place. */
+/* The state maintained for a lazily read file consists primarily */
+/* of a large direct-mapped cache of previously read values. */
+/* We could rely more on stdio buffering. That would have 2 */
+/* disadvantages: */
+/* 1) Empirically, not all fseek implementations preserve the */
+/* buffer whenever they could. */
+/* 2) It would fail if 2 different sections of a long cord */
+/* were being read alternately. */
+/* We do use the stdio buffer for read ahead. */
+/* To guarantee thread safety in the presence of atomic pointer */
+/* writes, cache lines are always replaced, and never modified in */
+/* place. */
# define LOG_CACHE_SZ 14
# define CACHE_SZ (1 << LOG_CACHE_SZ)
@@ -484,12 +484,12 @@ CORD CORD_from_file_eager(FILE * f)
typedef struct {
size_t tag;
char data[LINE_SZ];
- /* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ */
+ /* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ */
} cache_line;
typedef struct {
FILE * lf_file;
- size_t lf_current; /* Current file pointer value */
+ size_t lf_current; /* Current file pointer value */
cache_line * volatile lf_cache[CACHE_SZ/LINE_SZ];
} lf_state;
@@ -501,7 +501,7 @@ typedef struct {
typedef struct {
lf_state * state;
- size_t file_pos; /* Position of needed character. */
+ size_t file_pos; /* Position of needed character. */
cache_line * new_cache;
} refill_data;
@@ -515,14 +515,14 @@ refill_data * client_data;
size_t line_start = LINE_START(file_pos);
size_t line_no = DIV_LINE_SZ(MOD_CACHE_SZ(file_pos));
cache_line * new_cache = client_data -> new_cache;
-
+
if (line_start != state -> lf_current
&& fseek(f, line_start, SEEK_SET) != 0) {
- ABORT("fseek failed");
+ ABORT("fseek failed");
}
if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
- <= file_pos - line_start) {
- ABORT("fread failed");
+ <= file_pos - line_start) {
+ ABORT("fread failed");
}
new_cache -> tag = DIV_LINE_SZ(file_pos);
/* Store barrier goes here. */
@@ -535,47 +535,50 @@ char CORD_lf_func(size_t i, void * client_data)
{
register lf_state * state = (lf_state *)client_data;
register cache_line * volatile * cl_addr =
- &(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
+ &(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
register cache_line * cl = (cache_line *)ATOMIC_READ(cl_addr);
-
+
if (cl == 0 || cl -> tag != DIV_LINE_SZ(i)) {
- /* Cache miss */
- refill_data rd;
-
+ /* Cache miss */
+ refill_data rd;
+
rd.state = state;
rd.file_pos = i;
rd.new_cache = GC_NEW_ATOMIC(cache_line);
if (rd.new_cache == 0) OUT_OF_MEMORY;
return((char)(GC_word)
- GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
+ GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
}
return(cl -> data[MOD_LINE_SZ(i)]);
-}
+}
/*ARGSUSED*/
-void CORD_lf_close_proc(void * obj, void * client_data)
+void CORD_lf_close_proc(void * obj, void * client_data)
{
if (fclose(((lf_state *)obj) -> lf_file) != 0) {
- ABORT("CORD_lf_close_proc: fclose failed");
+ ABORT("CORD_lf_close_proc: fclose failed");
}
-}
+}
CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
{
register lf_state * state = GC_NEW(lf_state);
register int i;
-
+
if (state == 0) OUT_OF_MEMORY;
if (len != 0) {
- /* Dummy read to force buffer allocation. */
- /* This greatly increases the probability */
- /* of avoiding deadlock if buffer allocation */
- /* is redirected to GC_malloc and the */
- /* world is multithreaded. */
- char buf[1];
-
- (void) fread(buf, 1, 1, f);
- rewind(f);
+ /* Dummy read to force buffer allocation. */
+ /* This greatly increases the probability */
+ /* of avoiding deadlock if buffer allocation */
+ /* is redirected to GC_malloc and the */
+ /* world is multithreaded. */
+ char buf[1];
+
+ if (fread(buf, 1, 1, f) > 1) {
+ /* Just to suppress "unused result" compiler warning. */
+ ABORT("fread unexpected result");
+ }
+ rewind(f);
}
state -> lf_file = f;
for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
@@ -589,7 +592,7 @@ CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
CORD CORD_from_file_lazy(FILE * f)
{
register long len;
-
+
if (fseek(f, 0l, SEEK_END) != 0) {
ABORT("Bad fd argument - fseek failed");
}
@@ -605,7 +608,7 @@ CORD CORD_from_file_lazy(FILE * f)
CORD CORD_from_file(FILE * f)
{
register long len;
-
+
if (fseek(f, 0l, SEEK_END) != 0) {
ABORT("Bad fd argument - fseek failed");
}
diff --git a/darwin_stop_world.c b/darwin_stop_world.c
index db462295..f05dc685 100644
--- a/darwin_stop_world.c
+++ b/darwin_stop_world.c
@@ -145,7 +145,7 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
(natural_t *)&state,
&thread_state_count);
# ifdef DEBUG_THREADS
- GC_printf("thread_get_state return value = %d\n", kern_result);
+ GC_log_printf("thread_get_state returns value = %d\n", kern_result);
# endif
if (kern_result != KERN_SUCCESS)
ABORT("thread_get_state failed");
@@ -255,8 +255,8 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
*phi = (p->flags & MAIN_THREAD) != 0 ? GC_stackbottom : p->stack_end;
# endif
# ifdef DEBUG_THREADS
- GC_printf("Darwin: Stack for thread 0x%lx = [%p,%p)\n",
- (unsigned long) thread, lo, *phi);
+ GC_log_printf("Darwin: Stack for thread 0x%lx = [%p,%p)\n",
+ (unsigned long)thread, lo, *phi);
# endif
return lo;
}
@@ -322,7 +322,7 @@ GC_INNER void GC_push_all_stacks(void)
if (GC_print_stats == VERBOSE)
GC_log_printf("Pushed %d thread stacks\n", nthreads);
if (!found_me && !GC_in_thread_creation)
- ABORT("Collecting from unknown thread.");
+ ABORT("Collecting from unknown thread");
GC_total_stacksize = total_size;
}
@@ -352,10 +352,6 @@ GC_INNER void GC_push_all_stacks(void)
STATIC int GC_mach_threads_count = 0;
/* FIXME: it is better to implement GC_mach_threads as a hash set. */
-# ifdef PARALLEL_MARK
- GC_INNER GC_bool GC_is_mach_marker(thread_act_t thread);
-# endif
-
/* returns true if there's a thread in act_list that wasn't in old_list */
STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
thread_act_array_t old_list,
@@ -386,8 +382,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
# endif
# ifdef DEBUG_THREADS
- GC_printf("Attempting to suspend thread 0x%lx\n",
- (unsigned long)thread);
+ GC_log_printf("Attempting to suspend thread 0x%lx\n",
+ (unsigned long)thread);
# endif
/* find the current thread in the old list */
found = FALSE;
@@ -411,7 +407,7 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
if (!found) {
/* add it to the GC_mach_threads list */
if (GC_mach_threads_count == GC_MAX_MACH_THREADS)
- ABORT("too many threads");
+ ABORT("Too many threads");
GC_mach_threads[GC_mach_threads_count].thread = thread;
/* default is not suspended */
GC_mach_threads[GC_mach_threads_count].already_suspended = FALSE;
@@ -431,8 +427,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
continue;
}
# ifdef DEBUG_THREADS
- GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
- info.run_state);
+ GC_log_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
+ info.run_state);
# endif
if (info.suspend_count != 0) {
/* thread is already suspended. */
@@ -442,7 +438,7 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
}
# ifdef DEBUG_THREADS
- GC_printf("Suspending 0x%lx\n", (unsigned long)thread);
+ GC_log_printf("Suspending 0x%lx\n", (unsigned long)thread);
# endif
kern_result = thread_suspend(thread);
if (kern_result != KERN_SUCCESS) {
@@ -460,11 +456,6 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
#endif /* !GC_NO_THREADS_DISCOVERY */
-#ifdef MPROTECT_VDB
- GC_INNER void GC_mprotect_stop(void);
- GC_INNER void GC_mprotect_resume(void);
-#endif
-
/* Caller holds allocation lock. */
GC_INNER void GC_stop_world(void)
{
@@ -474,8 +465,8 @@ GC_INNER void GC_stop_world(void)
kern_return_t kern_result;
# ifdef DEBUG_THREADS
- GC_printf("Stopping the world from thread 0x%lx\n",
- (unsigned long)my_thread);
+ GC_log_printf("Stopping the world from thread 0x%lx\n",
+ (unsigned long)my_thread);
# endif
# ifdef PARALLEL_MARK
if (GC_parallel) {
@@ -564,7 +555,7 @@ GC_INNER void GC_stop_world(void)
# endif
# ifdef DEBUG_THREADS
- GC_printf("World stopped from 0x%lx\n", (unsigned long)my_thread);
+ GC_log_printf("World stopped from 0x%lx\n", (unsigned long)my_thread);
# endif
mach_port_deallocate(my_task, my_thread);
}
@@ -581,8 +572,8 @@ GC_INLINE void GC_thread_resume(thread_act_t thread)
ABORT("thread_info failed");
# endif
# ifdef DEBUG_THREADS
- GC_printf("Resuming thread 0x%lx with state %d\n",
- (unsigned long)thread, info.run_state);
+ GC_log_printf("Resuming thread 0x%lx with state %d\n",
+ (unsigned long)thread, info.run_state);
# endif
/* Resume the thread */
kern_result = thread_resume(thread);
@@ -597,7 +588,7 @@ GC_INNER void GC_start_world(void)
task_t my_task = current_task();
int i;
# ifdef DEBUG_THREADS
- GC_printf("World starting\n");
+ GC_log_printf("World starting\n");
# endif
# ifdef MPROTECT_VDB
if(GC_incremental) {
@@ -639,8 +630,8 @@ GC_INNER void GC_start_world(void)
/* The thread is found in GC_mach_threads. */
if (GC_mach_threads[j].already_suspended) {
# ifdef DEBUG_THREADS
- GC_printf("Not resuming already suspended thread 0x%lx\n",
- (unsigned long)thread);
+ GC_log_printf("Not resuming already suspended thread 0x%lx\n",
+ (unsigned long)thread);
# endif
} else {
GC_thread_resume(thread);
@@ -669,7 +660,7 @@ GC_INNER void GC_start_world(void)
}
# ifdef DEBUG_THREADS
- GC_printf("World started\n");
+ GC_log_printf("World started\n");
# endif
}
diff --git a/dbg_mlc.c b/dbg_mlc.c
index d4db3b3b..6f51c030 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -22,43 +22,37 @@
#endif
#include <string.h>
-GC_INNER void GC_default_print_heap_obj_proc(ptr_t p);
-
-GC_API void GC_CALL GC_register_finalizer_no_order(void * obj,
- GC_finalization_proc fn, void * cd,
- GC_finalization_proc *ofn, void * *ocd);
-
#ifndef SHORT_DBG_HDRS
- /* Check whether object with base pointer p has debugging info */
+ /* Check whether object with base pointer p has debugging info. */
/* p is assumed to point to a legitimate object in our part */
/* of the heap. */
/* This excludes the check as to whether the back pointer is */
/* odd, which is added by the GC_HAS_DEBUG_INFO macro. */
/* Note that if DBG_HDRS_ALL is set, uncollectable objects */
/* on free lists may not have debug information set. Thus it's */
- /* not always safe to return TRUE, even if the client does */
- /* its part. */
- GC_INNER GC_bool GC_has_other_debug_info(ptr_t p)
+ /* not always safe to return TRUE (1), even if the client does */
+ /* its part. Return -1 if the object with debug info has been */
+ /* marked as deallocated. */
+ GC_INNER int GC_has_other_debug_info(ptr_t p)
{
- oh * ohdr = (oh *)p;
- ptr_t body = (ptr_t)(ohdr + 1);
- word sz = GC_size((ptr_t) ohdr);
+ ptr_t body = (ptr_t)((oh *)p + 1);
+ word sz = GC_size(p);
- if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
+ if (HBLKPTR(p) != HBLKPTR((ptr_t)body)
|| sz < DEBUG_BYTES + EXTRA_BYTES) {
- return(FALSE);
+ return 0;
}
- if (ohdr -> oh_sz == sz) {
- /* Object may have had debug info, but has been deallocated */
- return(FALSE);
+ if (((oh *)p) -> oh_sf != (START_FLAG ^ (word)body)
+ && ((word *)p)[BYTES_TO_WORDS(sz)-1] != (END_FLAG ^ (word)body)) {
+ return 0;
}
- if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
- if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
- return(TRUE);
+ if (((oh *)p)->oh_sz == sz) {
+ /* Object may have had debug info, but has been deallocated */
+ return -1;
}
- return(FALSE);
+ return 1;
}
-#endif
+#endif /* !SHORT_DBG_HDRS */
#ifdef KEEP_BACK_PTRS
@@ -175,13 +169,11 @@ GC_API void GC_CALL GC_register_finalizer_no_order(void * obj,
{
ptr_t result;
ptr_t base;
- for (;;) {
- result = GC_generate_random_heap_address();
- base = GC_base(result);
- if (0 == base) continue;
- if (!GC_is_marked(base)) continue;
- return result;
- }
+ do {
+ result = GC_generate_random_heap_address();
+ base = GC_base(result);
+ } while (base == 0 || !GC_is_marked(base));
+ return result;
}
/* Print back trace for p */
@@ -237,7 +229,7 @@ GC_API void GC_CALL GC_register_finalizer_no_order(void * obj,
{
void * current;
current = GC_generate_random_valid_address();
- GC_printf("\n****Chose address %p in object\n", current);
+ GC_printf("\n****Chosen address %p in object\n", current);
GC_print_backtrace(current);
}
@@ -255,15 +247,14 @@ GC_API void GC_CALL GC_register_finalizer_no_order(void * obj,
# define CROSSES_HBLK(p, sz) \
(((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
-/* Store debugging info into p. Return displaced pointer. */
-/* Assumes we don't hold allocation lock. */
-GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string,
- word integer)
+
+/* Store debugging info into p. Return displaced pointer. */
+/* This version assumes we do hold the allocation lock. */
+STATIC ptr_t GC_store_debug_info_inner(ptr_t p, word sz, const char *string,
+ int linenum)
{
word * result = (word *)((oh *)p + 1);
- DCL_LOCK_STATE;
- LOCK();
GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
# ifdef KEEP_BACK_PTRS
@@ -273,48 +264,31 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string,
((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
# endif
((oh *)p) -> oh_string = string;
- ((oh *)p) -> oh_int = integer;
+ ((oh *)p) -> oh_int = (word)linenum;
# ifndef SHORT_DBG_HDRS
((oh *)p) -> oh_sz = sz;
((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
# endif
- UNLOCK();
return((ptr_t)result);
}
-#ifdef DBG_HDRS_ALL
-/* Store debugging info into p. Return displaced pointer. */
-/* This version assumes we do hold the allocation lock. */
-STATIC ptr_t GC_store_debug_info_inner(ptr_t p, word sz, char *string,
- word integer)
+GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string,
+ int linenum)
{
- word * result = (word *)((oh *)p + 1);
+ ptr_t result;
+ DCL_LOCK_STATE;
- GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
- GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
-# ifdef KEEP_BACK_PTRS
- ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
-# endif
-# ifdef MAKE_BACK_GRAPH
- ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
-# endif
- ((oh *)p) -> oh_string = string;
- ((oh *)p) -> oh_int = integer;
-# ifndef SHORT_DBG_HDRS
- ((oh *)p) -> oh_sz = sz;
- ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
- ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
- result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
-# endif
- return((ptr_t)result);
+ LOCK();
+ result = GC_store_debug_info_inner(p, sz, string, linenum);
+ UNLOCK();
+ return result;
}
-#endif
#ifndef SHORT_DBG_HDRS
- /* Check the object with debugging info at ohdr */
- /* return NULL if it's OK. Else return clobbered */
+ /* Check the object with debugging info at ohdr. */
+ /* Return NULL if it's OK. Else return clobbered */
/* address. */
STATIC ptr_t GC_check_annotated_obj(oh *ohdr)
{
@@ -380,12 +354,14 @@ STATIC void GC_print_type(ptr_t p)
GC_err_puts("STUBBORN");
break;
default:
- GC_err_printf("kind %d, descr 0x%lx", kind,
+ GC_err_printf("kind=%d descr=0x%lx", kind,
(unsigned long)(hhdr -> hb_descr));
}
}
}
+#define GET_OH_LINENUM(ohdr) ((int)(ohdr)->oh_int)
+
/* Print a human-readable description of the object to stderr. p points */
/* to somewhere inside an object with the debugging info. */
STATIC void GC_print_obj(ptr_t p)
@@ -399,10 +375,10 @@ STATIC void GC_print_obj(ptr_t p)
GC_err_printf("%p (", ((ptr_t)ohdr + sizeof(oh)));
GC_err_puts(ohdr -> oh_string);
# ifdef SHORT_DBG_HDRS
- GC_err_printf(":%ld, ", (unsigned long)(ohdr -> oh_int));
+ GC_err_printf(":%d, ", GET_OH_LINENUM(ohdr));
# else
- GC_err_printf(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
- (unsigned long)(ohdr -> oh_sz));
+ GC_err_printf(":%d, sz=%lu, ",
+ GET_OH_LINENUM(ohdr), (unsigned long)(ohdr -> oh_sz));
# endif
GC_print_type((ptr_t)(ohdr + 1));
GC_err_puts(")\n");
@@ -423,7 +399,8 @@ STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
/* Use GC_err_printf and friends to print a description of the object */
/* whose client-visible address is p, and which was smashed at */
/* clobbered_addr. */
- STATIC void GC_print_smashed_obj(ptr_t p, ptr_t clobbered_addr)
+ STATIC void GC_print_smashed_obj(const char *msg, ptr_t p,
+ ptr_t clobbered_addr)
{
oh * ohdr = (oh *)GC_base(p);
@@ -434,17 +411,16 @@ STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
|| ohdr -> oh_string == 0) {
GC_err_printf(
- "%p in or near object at %p(<smashed>, appr. sz = %lu)\n",
- clobbered_addr, p,
+ "%s %p in or near object at %p(<smashed>, appr. sz = %lu)\n",
+ msg, clobbered_addr, p,
(unsigned long)(GC_size((ptr_t)ohdr) - DEBUG_BYTES));
} else {
- GC_err_printf("%p in or near object at %p(%s:%lu, sz=%lu)\n",
- clobbered_addr, p,
+ GC_err_printf("%s %p in or near object at %p (%s:%d, sz=%lu)\n",
+ msg, clobbered_addr, p,
(word)(ohdr -> oh_string) < HBLKSIZE ? "(smashed string)" :
ohdr -> oh_string[0] == '\0' ? "EMPTY(smashed?)" :
ohdr -> oh_string,
- (unsigned long)(ohdr -> oh_int),
- (unsigned long)(ohdr -> oh_sz));
+ GET_OH_LINENUM(ohdr), (unsigned long)(ohdr -> oh_sz));
PRINT_CALL_CHAIN(ohdr);
}
}
@@ -459,16 +435,16 @@ STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
GC_INNER void GC_start_debugging(void)
{
-# ifndef SHORT_DBG_HDRS
- GC_check_heap = GC_check_heap_proc;
- GC_print_all_smashed = GC_print_all_smashed_proc;
-# else
- GC_check_heap = GC_do_nothing;
- GC_print_all_smashed = GC_do_nothing;
-# endif
- GC_print_heap_obj = GC_debug_print_heap_obj_proc;
- GC_debugging_started = TRUE;
- GC_register_displacement((word)sizeof(oh));
+# ifndef SHORT_DBG_HDRS
+ GC_check_heap = GC_check_heap_proc;
+ GC_print_all_smashed = GC_print_all_smashed_proc;
+# else
+ GC_check_heap = GC_do_nothing;
+ GC_print_all_smashed = GC_do_nothing;
+# endif
+ GC_print_heap_obj = GC_debug_print_heap_obj_proc;
+ GC_debugging_started = TRUE;
+ GC_register_displacement((word)sizeof(oh));
}
size_t GC_debug_header_size = sizeof(oh);
@@ -481,7 +457,11 @@ GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
GC_API void * GC_CALL GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
{
- void * result = GC_malloc(lb + DEBUG_BYTES);
+ void * result;
+ /* Note that according to malloc() specification, if size is 0 then */
+ /* malloc() returns either NULL, or a unique pointer value that can */
+ /* later be successfully passed to free(). We always do the latter. */
+ result = GC_malloc(lb + DEBUG_BYTES);
if (result == 0) {
GC_err_printf("GC_debug_malloc(%lu) returning NULL (",
@@ -494,7 +474,7 @@ GC_API void * GC_CALL GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
GC_API void * GC_CALL GC_debug_malloc_ignore_off_page(size_t lb,
@@ -513,7 +493,7 @@ GC_API void * GC_CALL GC_debug_malloc_ignore_off_page(size_t lb,
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
@@ -523,7 +503,7 @@ GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
if (result == 0) {
GC_err_printf("GC_debug_malloc_atomic_ignore_off_page(%lu)"
- " returning NULL (", (unsigned long) lb);
+ " returning NULL (", (unsigned long)lb);
GC_err_puts(s);
GC_err_printf(":%lu)\n", (unsigned long)i);
return(0);
@@ -532,18 +512,15 @@ GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
#ifdef DBG_HDRS_ALL
- /*
- * An allocation function for internal use.
- * Normally internally allocated objects do not have debug information.
- * But in this case, we need to make sure that all objects have debug
- * headers.
- * We assume debugging was started in collector initialization,
- * and we already hold the GC lock.
- */
+ /* An allocation function for internal use. Normally internally */
+ /* allocated objects do not have debug information. But in this */
+ /* case, we need to make sure that all objects have debug headers. */
+ /* We assume debugging was started in collector initialization, and */
+ /* we already hold the GC lock. */
GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k)
{
void * result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
@@ -554,7 +531,7 @@ GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
return(0);
}
ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
- return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
+ return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
}
GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
@@ -569,13 +546,13 @@ GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
return(0);
}
ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
- return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
+ return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
}
-#endif
+#endif /* DBG_HDRS_ALL */
#ifdef STUBBORN_ALLOC
-GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
-{
+ GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
+ {
void * result = GC_malloc_stubborn(lb + DEBUG_BYTES);
if (result == 0) {
@@ -589,11 +566,11 @@ GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
-}
+ return (GC_store_debug_info(result, (word)lb, s, i));
+ }
-GC_API void GC_CALL GC_debug_change_stubborn(void *p)
-{
+ GC_API void GC_CALL GC_debug_change_stubborn(void *p)
+ {
void * q = GC_base(p);
hdr * hhdr;
@@ -607,10 +584,10 @@ GC_API void GC_CALL GC_debug_change_stubborn(void *p)
ABORT("GC_debug_change_stubborn: arg not stubborn");
}
GC_change_stubborn(q);
-}
+ }
-GC_API void GC_CALL GC_debug_end_stubborn_change(void *p)
-{
+ GC_API void GC_CALL GC_debug_end_stubborn_change(void *p)
+ {
void * q = GC_base(p);
hdr * hhdr;
@@ -624,21 +601,20 @@ GC_API void GC_CALL GC_debug_end_stubborn_change(void *p)
ABORT("GC_debug_end_stubborn_change: arg not stubborn");
}
GC_end_stubborn_change(q);
-}
+ }
#else /* !STUBBORN_ALLOC */
-GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
-{
+ GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
+ {
return GC_debug_malloc(lb, OPT_RA s, i);
-}
-
-/*ARGSUSED*/
-GC_API void GC_CALL GC_debug_change_stubborn(void *p) {}
+ }
-/*ARGSUSED*/
-GC_API void GC_CALL GC_debug_end_stubborn_change(void *p) {}
+ /*ARGSUSED*/
+ GC_API void GC_CALL GC_debug_change_stubborn(void *p) {}
+ /*ARGSUSED*/
+ GC_API void GC_CALL GC_debug_end_stubborn_change(void *p) {}
#endif /* !STUBBORN_ALLOC */
GC_API void * GC_CALL GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
@@ -656,7 +632,7 @@ GC_API void * GC_CALL GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
GC_API char * GC_CALL GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
@@ -665,9 +641,10 @@ GC_API char * GC_CALL GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
size_t lb;
if (str == NULL) {
if (GC_find_leak)
- WARN("strdup(NULL) behavior is undefined\n", 0);
+ GC_err_printf("strdup(NULL) behavior is undefined\n");
return NULL;
}
+
lb = strlen(str) + 1;
copy = GC_debug_malloc_atomic(lb, OPT_RA s, i);
if (copy == NULL) {
@@ -738,11 +715,12 @@ GC_API void * GC_CALL GC_debug_malloc_uncollectable(size_t lb,
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
#ifdef ATOMIC_UNCOLLECTABLE
- void * GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
+ GC_API void * GC_CALL GC_debug_malloc_atomic_uncollectable(size_t lb,
+ GC_EXTRA_PARAMS)
{
void * result =
GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
@@ -759,69 +737,73 @@ GC_API void * GC_CALL GC_debug_malloc_uncollectable(size_t lb,
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
#endif /* ATOMIC_UNCOLLECTABLE */
+#ifndef GC_FREED_MEM_MARKER
+# if CPP_WORDSZ == 32
+# define GC_FREED_MEM_MARKER 0xdeadbeef
+# else
+# define GC_FREED_MEM_MARKER GC_WORD_C(0xEFBEADDEdeadbeef)
+# endif
+#endif
+
GC_API void GC_CALL GC_debug_free(void * p)
{
ptr_t base;
-# ifndef SHORT_DBG_HDRS
- ptr_t clobbered;
-# endif
+ if (0 == p) return;
- if (0 == p) {
- if (GC_find_leak)
- WARN("free(NULL) is non-portable\n", 0);
- return;
- }
base = GC_base(p);
if (base == 0) {
- GC_err_printf("Attempt to free invalid pointer %p\n", p);
- ABORT("free(invalid pointer)");
+ GC_err_printf("Attempt to free invalid pointer %p\n", p);
+ ABORT("Invalid pointer passed to free()");
}
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
- GC_err_printf(
- "GC_debug_free called on pointer %p w/o debugging info\n", p);
+ GC_err_printf(
+ "GC_debug_free called on pointer %p w/o debugging info\n", p);
} else {
# ifndef SHORT_DBG_HDRS
- clobbered = GC_check_annotated_obj((oh *)base);
+ ptr_t clobbered = GC_check_annotated_obj((oh *)base);
+ word sz = GC_size(base);
if (clobbered != 0) {
- if (((oh *)base) -> oh_sz == GC_size(base)) {
- GC_err_printf(
- "GC_debug_free: found previously deallocated (?) object at ");
+ GC_have_errors = TRUE;
+ if (((oh *)base) -> oh_sz == sz) {
+ GC_print_smashed_obj(
+ "GC_debug_free: found previously deallocated (?) object at",
+ p, clobbered);
+ return; /* ignore double free */
} else {
- GC_err_printf("GC_debug_free: found smashed location at ");
+ GC_print_smashed_obj("GC_debug_free: found smashed location at",
+ p, clobbered);
}
- GC_print_smashed_obj(p, clobbered);
}
- /* Invalidate size */
- ((oh *)base) -> oh_sz = GC_size(base);
+ /* Invalidate size (mark the object as deallocated) */
+ ((oh *)base) -> oh_sz = sz;
# endif /* SHORT_DBG_HDRS */
}
- if (GC_find_leak) {
- GC_free(base);
- } else {
- hdr * hhdr = HDR(p);
- GC_bool uncollectable = FALSE;
-
- if (hhdr -> hb_obj_kind == UNCOLLECTABLE) {
- uncollectable = TRUE;
- }
-# ifdef ATOMIC_UNCOLLECTABLE
- if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) {
- uncollectable = TRUE;
- }
+ if (GC_find_leak
+# ifndef SHORT_DBG_HDRS
+ && ((ptr_t)p - (ptr_t)base != sizeof(oh) || !GC_findleak_delay_free)
# endif
- if (uncollectable) {
- GC_free(base);
- } else {
- size_t i;
- size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh));
+ ) {
+ GC_free(base);
+ } else {
+ hdr * hhdr = HDR(p);
+ if (hhdr -> hb_obj_kind == UNCOLLECTABLE
+# ifdef ATOMIC_UNCOLLECTABLE
+ || hhdr -> hb_obj_kind == AUNCOLLECTABLE
+# endif
+ ) {
+ GC_free(base);
+ } else {
+ size_t i;
+ size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh));
- for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef;
- GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz));
- }
+ for (i = 0; i < obj_sz; ++i)
+ ((word *)p)[i] = GC_FREED_MEM_MARKER;
+ GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz));
+ }
} /* !GC_find_leak */
}
@@ -845,19 +827,15 @@ GC_API void GC_CALL GC_debug_free(void * p)
GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
{
void * base;
-# ifndef SHORT_DBG_HDRS
- ptr_t clobbered;
-# endif
void * result;
- size_t copy_sz = lb;
- size_t old_sz;
hdr * hhdr;
+ if (p == 0)
+ return(GC_debug_malloc(lb, OPT_RA s, i));
- if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i));
base = GC_base(p);
if (base == 0) {
GC_err_printf("Attempt to reallocate invalid pointer %p\n", p);
- ABORT("realloc(invalid pointer)");
+ ABORT("Invalid pointer passed to realloc()");
}
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
GC_err_printf(
@@ -888,38 +866,38 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
default:
result = NULL; /* initialized to prevent warning. */
GC_err_printf("GC_debug_realloc: encountered bad kind\n");
- ABORT("bad kind");
+ ABORT("Bad kind");
+ }
+
+ if (result != NULL) {
+ size_t old_sz;
+# ifdef SHORT_DBG_HDRS
+ old_sz = GC_size(base) - sizeof(oh);
+# else
+ old_sz = ((oh *)base) -> oh_sz;
+# endif
+ BCOPY(p, result, old_sz < lb ? old_sz : lb);
+ GC_debug_free(p);
}
-# ifdef SHORT_DBG_HDRS
- old_sz = GC_size(base) - sizeof(oh);
-# else
- clobbered = GC_check_annotated_obj((oh *)base);
- if (clobbered != 0) {
- GC_err_printf("GC_debug_realloc: found smashed location at ");
- GC_print_smashed_obj(p, clobbered);
- }
- old_sz = ((oh *)base) -> oh_sz;
-# endif
- if (old_sz < copy_sz) copy_sz = old_sz;
- if (result == 0) return(0);
- BCOPY(p, result, copy_sz);
- GC_debug_free(p);
return(result);
}
#ifndef SHORT_DBG_HDRS
-/* List of smashed objects. We defer printing these, since we can't */
-/* always print them nicely with the allocation lock held. */
-/* We put them here instead of in GC_arrays, since it may be useful to */
-/* be able to look at them with the debugger. */
-#define MAX_SMASHED 20
+/* List of smashed (clobbered) locations. We defer printing these, */
+/* since we can't always print them nicely with the allocation lock */
+/* held. We put them here instead of in GC_arrays, since it may be */
+/* useful to be able to look at them with the debugger. */
+#ifndef MAX_SMASHED
+# define MAX_SMASHED 20
+#endif
STATIC ptr_t GC_smashed[MAX_SMASHED] = {0};
STATIC unsigned GC_n_smashed = 0;
STATIC void GC_add_smashed(ptr_t smashed)
{
GC_ASSERT(GC_is_marked(GC_base(smashed)));
+ /* FIXME: Prevent adding an object while printing smashed list. */
GC_smashed[GC_n_smashed] = smashed;
if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
/* In case of overflow, we keep the first MAX_SMASHED-1 */
@@ -936,11 +914,12 @@ STATIC void GC_print_all_smashed_proc(void)
if (GC_n_smashed == 0) return;
GC_err_printf("GC_check_heap_block: found smashed heap objects:\n");
for (i = 0; i < GC_n_smashed; ++i) {
- GC_print_smashed_obj((ptr_t)GC_base(GC_smashed[i]) + sizeof(oh),
+ GC_print_smashed_obj("", (ptr_t)GC_base(GC_smashed[i]) + sizeof(oh),
GC_smashed[i]);
GC_smashed[i] = 0;
}
GC_n_smashed = 0;
+ GC_err_printf("\n");
}
/* Check all marked objects in the given block for validity */
@@ -954,23 +933,19 @@ STATIC void GC_check_heap_block(struct hblk *hbp, word dummy)
char *p, *plim;
p = hbp->hb_body;
- bit_no = 0;
if (sz > MAXOBJBYTES) {
- plim = p;
+ plim = p;
} else {
- plim = hbp->hb_body + HBLKSIZE - sz;
+ plim = hbp->hb_body + HBLKSIZE - sz;
}
/* go through all words in block */
- while( p <= plim ) {
- if( mark_bit_from_hdr(hhdr, bit_no)
- && GC_HAS_DEBUG_INFO((ptr_t)p)) {
- ptr_t clobbered = GC_check_annotated_obj((oh *)p);
-
- if (clobbered != 0) GC_add_smashed(clobbered);
- }
- bit_no += MARK_BIT_OFFSET(sz);
- p += sz;
- }
+ for (bit_no = 0; p <= plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) {
+ if (mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) {
+ ptr_t clobbered = GC_check_annotated_obj((oh *)p);
+ if (clobbered != 0)
+ GC_add_smashed(clobbered);
+ }
+ }
}
/* This assumes that all accessible objects are marked, and that */
@@ -979,7 +954,33 @@ STATIC void GC_check_heap_proc(void)
{
GC_STATIC_ASSERT((sizeof(oh) & (GRANULE_BYTES - 1)) == 0);
/* FIXME: Should we check for twice that alignment? */
- GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
+ GC_apply_to_all_blocks(GC_check_heap_block, 0);
+}
+
+GC_INNER GC_bool GC_check_leaked(ptr_t base)
+{
+ size_t i;
+ size_t obj_sz;
+ word *p;
+
+ if (
+# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
+ (*(word *)base & 1) != 0 &&
+# endif
+ GC_has_other_debug_info(base) >= 0)
+ return TRUE; /* object has leaked */
+
+ /* Validate freed object's content. */
+ p = (word *)(base + sizeof(oh));
+ obj_sz = BYTES_TO_WORDS(HDR(base)->hb_sz - sizeof(oh));
+ for (i = 0; i < obj_sz; ++i)
+ if (p[i] != GC_FREED_MEM_MARKER) {
+ GC_set_mark_bit(base); /* do not reclaim it in this cycle */
+ GC_add_smashed((ptr_t)(&p[i])); /* alter-after-free detected */
+ break; /* don't report any other smashed locations in the object */
+ }
+
+ return FALSE; /* GC_debug_free() has been called */
}
#endif /* !SHORT_DBG_HDRS */
@@ -1027,7 +1028,7 @@ static void store_old(void *obj, GC_finalization_proc my_old_fn,
return;
}
if (my_old_fn != GC_debug_invoke_finalizer) {
- GC_err_printf("Debuggable object at %p had non-debug finalizer.\n",
+ GC_err_printf("Debuggable object at %p had a non-debug finalizer\n",
obj);
/* This should probably be fatal. */
} else {
@@ -1162,18 +1163,12 @@ GC_API void GC_CALL GC_debug_register_finalizer_ignore_self
store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
}
-#ifdef GC_ADD_CALLER
-# define RA GC_RETURN_ADDR,
-#else
-# define RA
-#endif
-
GC_API void * GC_CALL GC_debug_malloc_replacement(size_t lb)
{
- return GC_debug_malloc(lb, RA "unknown", 0);
+ return GC_debug_malloc(lb, GC_DBG_RA "unknown", 0);
}
GC_API void * GC_CALL GC_debug_realloc_replacement(void *p, size_t lb)
{
- return GC_debug_realloc(p, lb, RA "unknown", 0);
+ return GC_debug_realloc(p, lb, GC_DBG_RA "unknown", 0);
}
diff --git a/doc/README b/doc/README
index 5ca93f09..8ca035bd 100644
--- a/doc/README
+++ b/doc/README
@@ -36,7 +36,7 @@ Public License, but is not needed by, nor linked into the collector library.
It is included here only becuase the atomic_ops distribution is, for
simplicity, included in its entirety.
-This is version 7.2alpha5 of a conservative garbage collector for C and C++.
+This is version 7.2alpha7 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
@@ -129,7 +129,7 @@ ALL_INTERIOR_POINTERS defined, or GC_all_interior_pointers is otherwise
set, as is now the default.
Compiling without ALL_INTERIOR_POINTERS may reduce accidental retention
-of garbage objects, by requiring pointers from the heap to to the beginning
+of garbage objects, by requiring pointers from the heap to the beginning
of an object. But this no longer appears to be a significant
issue for most programs occupying a small fraction of the possible
address space.
diff --git a/doc/README.autoconf b/doc/README.autoconf
index f8640bec..94833f65 100644
--- a/doc/README.autoconf
+++ b/doc/README.autoconf
@@ -1,4 +1,4 @@
-As of GC6.0alpha8, we attempt to support GNU-style builds based on automake,
+Starting from GC v6.0, we support GNU-style builds based on automake,
autoconf and libtool. This is based almost entirely on Tom Tromey's work
with gcj.
@@ -36,7 +36,7 @@ as well as the sources needed to regenerate the derived files. (If I missed
some, please let me know.)
Note that the distribution comes with a "Makefile" which will be overwritten
-by "configure" with one that is not at all equiavelent to the original. The
+by "configure" with one that is not at all equivalent to the original. The
distribution contains a copy of the original "Makefile" in "Makefile.direct".
Important options to configure:
@@ -48,7 +48,7 @@ Important options to configure:
--enable-threads=TYPE choose threading package
--enable-parallel-mark parallelize marking and free list construction
--enable-gc-debug (--enable-full-debug before about 7.0)
- include full support for pointer backtracing etc.
+ include full support for pointer back-tracing etc.
Unless --prefix is set (or --exec-prefix or one of the more obscure options),
diff --git a/doc/README.environment b/doc/README.environment
index 07a4ebf3..866e9055 100644
--- a/doc/README.environment
+++ b/doc/README.environment
@@ -1,15 +1,17 @@
-The garbage collector looks at a number of environment variables which are
-then used to affect its operation. These are examined only on Un*x-like
-platforms and win32.
+The garbage collector looks at a number of environment variables which are,
+then, used to affect its operation.
GC_INITIAL_HEAP_SIZE=<bytes> - Initial heap size in bytes. May speed up
- process start-up.
+ process start-up. Optionally, may be
+ specified with a multiplier ('k', 'M' or 'G')
+ suffix.
-GC_MAXIMUM_HEAP_SIZE=<bytes> - Maximum collected heap size.
+GC_MAXIMUM_HEAP_SIZE=<bytes> - Maximum collected heap size. Allows
+ a multiplier suffix.
GC_LOOP_ON_ABORT - Causes the collector abort routine to enter a tight loop.
This may make it easier to debug, such a process, especially
- for multithreaded platforms that don't produce usable core
+ for multi-threaded platforms that don't produce usable core
files, or if a core file would be too large. On some
platforms, this also causes SIGSEGV to be caught and
result in an infinite loop in a handler, allowing
@@ -20,6 +22,10 @@ GC_PRINT_STATS - Turn on GC logging. Not functional with SMALL_CONFIG.
GC_LOG_FILE - The name of the log file. Stderr by default. Not functional
with SMALL_CONFIG.
+GC_ONLY_LOG_TO_FILE - Turns off redirection of GC stdout and stderr to the log
+ file specified by GC_LOG_FILE. Has no effect unless
+ GC_LOG_FILE is set. Not functional with SMALL_CONFIG.
+
GC_PRINT_VERBOSE_STATS - Turn on even more logging. Not functional with
SMALL_CONFIG.
@@ -28,7 +34,7 @@ GC_DUMP_REGULARLY - Generate a GC debugging dump GC_dump() on startup
if you have a bug to report, but please include only the
last complete dump.
-GC_BACKTRACES=<n> - Generate n random backtraces (for heap profiling) after
+GC_BACKTRACES=<n> - Generate n random back-traces (for heap profiling) after
each GC. Collector must have been built with
KEEP_BACK_PTRS. This won't generate useful output unless
most objects in the heap were allocated through debug
@@ -70,7 +76,7 @@ GC_IGNORE_GCJ_INFO - Ignore the type descriptors implicitly supplied by
descriptor generation problems, and possibly for
temporarily working around such problems. It forces a
fully conservative scan of all heap objects except
- those known to be pointerfree, and may thus have other
+ those known to be pointer-free, and may thus have other
adverse effects.
GC_PRINT_BACK_HEIGHT - Print max length of chain through unreachable objects
@@ -114,10 +120,10 @@ other means, but this may help with debugging and testing:
GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
depending on platform and collector configuration, this
may involve write protecting pieces of the heap to
- track modifications. These pieces may include pointerfree
- objects or not. Although this is intended to be
- transparent, it may cause unintended system call failures.
- Use with caution.
+ track modifications. These pieces may include
+ pointer-free objects or not. Although this is intended
+ to be transparent, it may cause unintended system call
+ failures. Use with caution.
GC_PAUSE_TIME_TARGET - Set the desired garbage collector pause time in msecs.
This only has an effect if incremental collection is
@@ -154,6 +160,13 @@ GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection. Forces a
collection at program termination to detect leaks that would
otherwise occur after the last GC.
+GC_FINDLEAK_DELAY_FREE - Turns on deferred freeing of objects in the
+ leak-finding mode (see the corresponding macro
+ description for more information).
+
+GC_ABORT_ON_LEAK - Causes the application to be terminated once leaked or
+ smashed objects are found.
+
GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
pointer recognition.
diff --git a/doc/README.macros b/doc/README.macros
index ac788971..a6291baf 100644
--- a/doc/README.macros
+++ b/doc/README.macros
@@ -81,23 +81,32 @@ GC_REQUIRE_WCSDUP Force GC to export GC_wcsdup() (the Unicode version
These define arguments influence the collector configuration:
-FIND_LEAK causes GC_find_leak to be initially set.
- This causes the collector to assume that all inaccessible
- objects should have been explicitly deallocated, and reports exceptions.
- Finalization and the test program are not usable in this mode.
+
+FIND_LEAK Causes GC_find_leak to be initially set. This causes the
+ collector to assume that all inaccessible objects should have been
+ explicitly deallocated, and reports exceptions. Finalization and the test
+ program are not usable in this mode.
+
+GC_FINDLEAK_DELAY_FREE Turns on deferred freeing of objects in the
+ leak-finding mode letting the collector to detect alter-object-after-free
+ errors as well as detect leaked objects sooner (instead of only when program
+ terminates). Has no effect if SHORT_DBG_HDRS.
+
+GC_ABORT_ON_LEAK Causes the application to be terminated once leaked or
+ smashed (corrupted on use-after-free) objects are found (after printing the
+ information about that objects).
SUNOS5SIGS Solaris-like signal handling. This is probably misnamed,
- since it really doesn't guarantee much more than Posix.
- Currently set only for Solaris2.X, HPUX, and DRSNX. Should
- probably be set for some other platforms.
+ since it really doesn't guarantee much more than POSIX. Currently set only
+ for Solaris2.X, HPUX, and DRSNX. Should probably be set for some other
+ platforms.
-PCR Set if the collector is being built as part of the Xerox
- Portable Common Runtime.
+PCR Set if the collector is being built as part of the Xerox Portable
+ Common Runtime.
-USE_COMPILER_TLS Assume the existence of __thread-style thread-local
- storage. Set automatically for thread-local allocation with
- the HP/UX vendor compiler. Usable with gcc on sufficiently
- up-to-date ELF platforms.
+USE_COMPILER_TLS Assume the existence of __thread-style thread-local storage.
+ Set automatically for thread-local allocation with the HP/UX vendor
+ compiler. Usable with gcc on sufficiently up-to-date ELF platforms.
IMPORTANT: Any of the _THREADS options must normally also be defined in
the client before including gc.h. This redefines thread primitives to
@@ -416,6 +425,10 @@ MAKE_BACK_GRAPH Enable GC_PRINT_BACK_HEIGHT environment variable.
support. Implies DBG_HDRS_ALL. All allocation should be done using
the debug interface.
+GC_PRINT_BACK_HEIGHT Permanently turn on back-height printing mode
+ (useful when NO_GETENV). See the similar environment variable description
+ in README.environment. Requires MAKE_BACK_GRAPH defined.
+
STUBBORN_ALLOC Allows allocation of "hard to change" objects, and thus
makes incremental collection easier. Was enabled by default until 6.0.
Rarely used, to my knowledge.
@@ -493,8 +506,9 @@ DONT_USE_USER32_DLL (Win32 only) Don't use "user32" DLL import library
(containing MessageBox() entry); useful for a static GC library.
GC_PREFER_MPROTECT_VDB Choose MPROTECT_VDB manually in case of multiple
- virtual dirty bit strategies are implemented (at present useful on Win32
- to force MPROTECT_VDB strategy instead of the default GWW_VDB one).
+ virtual dirty bit strategies are implemented (at present useful on Win32 and
+ Solaris to force MPROTECT_VDB strategy instead of the default GWW_VDB or
+ PROC_VDB ones).
GC_IGNORE_GCJ_INFO Disable GCJ-style type information (useful for
debugging on WinCE).
@@ -502,6 +516,10 @@ GC_IGNORE_GCJ_INFO Disable GCJ-style type information (useful for
GC_PRINT_VERBOSE_STATS Permanently turn on verbose logging (useful for
debugging and profiling on WinCE).
+GC_ONLY_LOG_TO_FILE Don't redirect GC stdout and stderr to the log file
+ specified by GC_LOG_FILE environment variable. Has effect only when the
+ variable is set (to anything other than "0").
+
GC_DONT_EXPAND Don't expand the heap unless explicitly requested or forced to.
GC_USE_ENTIRE_HEAP Causes the non-incremental collector to use the
@@ -539,6 +557,6 @@ PLATFORM_ANDROID Compile for Android NDK platform.
SN_TARGET_PS3 Compile for Sony PS/3.
USE_GET_STACKBASE_FOR_MAIN (Linux only) Use pthread_attr_getstack() instead
-of __libc_stack_end (or instead of any hard-coded value) for getting the
-primordial thread stack base (useful if the client modifies the program's
-address space).
+ of __libc_stack_end (or instead of any hard-coded value) for getting the
+ primordial thread stack base (useful if the client modifies the program's
+ address space).
diff --git a/doc/README.solaris2 b/doc/README.solaris2
index f9141063..d46fe262 100644
--- a/doc/README.solaris2
+++ b/doc/README.solaris2
@@ -13,10 +13,14 @@ not safe: "Many library routines use malloc() internally, so use brk()
and sbrk() only when you know that malloc() definitely will not be used by
any library routine." This doesn't make a lot of sense to me, since there
seems to be no documentation as to which routines can transitively call malloc.
-Nonetheless, under Solaris2, the collector now (since 4.12) allocates
+Nonetheless, under Solaris2, the collector now allocates
memory using mmap by default. (It defines USE_MMAP in gcconfig.h.)
You may want to reverse this decisions if you use -DREDIRECT_MALLOC=...
+Note:
+Before you run "make check", you need to set your LD_LIBRARY_PATH correctly
+(eg., to "/usr/local/lib") so that tests can find the shared library
+libgcc_s.so.1. Alternatively, you can configure with --disable-shared.
SOLARIS THREADS:
@@ -24,21 +28,19 @@ The collector must be compiled with -DGC_THREADS to be thread safe.
This assumes use of the pthread_ interface. Old style Solaris threads
are no longer supported.
-It is also essential that gc.h be included in files that call thr_create,
-thr_join, thr_suspend, thr_continue, or dlopen. Gc.h macro defines
-these to also do GC bookkeeping, etc. Gc.h must be included with
-one or both of these macros defined, otherwise
-these replacements are not visible.
-A collector built in this way way only be used by programs that are
-linked with the threads library.
+It is also essential that gc.h be included in files that call pthread_create,
+pthread_join, pthread_detach, or dlopen. gc.h macro defines these to also do
+GC bookkeeping, etc. gc.h must be included with one or both of these macros
+defined, otherwise these replacements are not visible. A collector built in
+this way way only be used by programs that are linked with the threads library.
Since 5.0 alpha5, dlopen disables collection temporarily,
unless USE_PROC_FOR_LIBRARIES is defined. In some unlikely cases, this
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
+If threads are used on an X86 processor with malloc redirected to
+GC_malloc, it is necessary to call GC_INIT explicitly before forking the
first thread. (This avoids a deadlock arising from calling GC_thr_init
with the allocation lock held.)
@@ -46,7 +48,7 @@ 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
is invoked by some iostream initialization code before threads are correctly
initialized. As a result, call to thr_self() in garbage collector
-initialization segfaults. Currently the only known workaround is to not
+initialization SEGV faults. Currently the only known workaround is to not
invoke the garbage collector from a user defined global operator new, or to
have it invoke the garbage-collector's allocators only after main has started.
(Note that the latter requires a moderately expensive test in operator
diff --git a/doc/README.win32 b/doc/README.win32
index 2e43b63e..4a030cf3 100644
--- a/doc/README.win32
+++ b/doc/README.win32
@@ -107,6 +107,12 @@ version, change the line near the top. By default, it does not
require the assembler. If you do have the assembler, I recommend
removing the -DUSE_GENERIC.
+Digital Mars compiler
+---------------------
+
+Same as MS Visual C++ but might require
+-DAO_OLD_STYLE_INTERLOCKED_COMPARE_EXCHANGE option to compile with the
+parallel marker enabled.
Watcom compiler
---------------
@@ -225,6 +231,4 @@ correctly track threads.
To build the collector for Mingw32 Pthreads, use Makefile.direct and
explicitly set GC_WIN32_PTHREADS. Use -DPTW32_STATIC_LIB for the static
-threads library. Note that the DEBUG_WIN32_PTHREADS support in
-win32_threads.c is currently broken and looking for someone to debug it.
-(This information and the port came from Romano Paolo Tenca).
+threads library.
diff --git a/dyn_load.c b/dyn_load.c
index 49448a1d..982ec379 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -29,7 +29,7 @@
* But then not much of anything is safe in the presence of dlclose.
*/
-#if !defined(MACOS) && !defined(_WIN32_WCE)
+#if !defined(MACOS) && !defined(_WIN32_WCE) && !defined(__CC_ARM)
# include <sys/types.h>
#endif
@@ -135,7 +135,6 @@ GC_FirstDLOpenedLinkMap(void)
{
extern ElfW(Dyn) _DYNAMIC;
ElfW(Dyn) *dp;
- struct r_debug *r;
static struct link_map * cachedResult = 0;
static ElfW(Dyn) *dynStructureAddr = 0;
/* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
@@ -186,12 +185,9 @@ GC_FirstDLOpenedLinkMap(void)
# ifndef USE_PROC_FOR_LIBRARIES
GC_INNER void GC_register_dynamic_libraries(void)
{
- struct link_map *lm = GC_FirstDLOpenedLinkMap();
-
+ struct link_map *lm;
- for (lm = GC_FirstDLOpenedLinkMap();
- lm != (struct link_map *) 0; lm = lm->l_next)
- {
+ for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next) {
ElfW(Ehdr) * e;
ElfW(Phdr) * p;
unsigned long offset;
@@ -205,7 +201,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
# endif
p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
offset = ((unsigned long)(lm->l_addr));
- for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
+ for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
switch( p->p_type ) {
case PT_LOAD:
{
@@ -242,11 +238,6 @@ GC_INNER void GC_register_dynamic_libraries(void)
#define MAPS_BUF_SIZE (32*1024)
-GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
- char **prot, unsigned int *maj_dev,
- char **mapping_name);
-GC_INNER char *GC_get_maps(void); /* from os_dep.c */
-
/* Sort an array of HeapSects by start address. */
/* Unfortunately at least some versions of */
/* Linux qsort end up calling malloc by way of sysconf, and hence can't */
@@ -277,15 +268,10 @@ static void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
}
}
-#ifdef THREADS
- GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi);
-#endif
-
STATIC word GC_register_map_entries(char *maps)
{
char *prot;
char *buf_ptr = maps;
- int count;
ptr_t start, end;
unsigned int maj_dev;
ptr_t least_ha, greatest_ha;
@@ -383,7 +369,7 @@ STATIC word GC_register_map_entries(char *maps)
GC_INNER void GC_register_dynamic_libraries(void)
{
if (!GC_register_map_entries(GC_get_maps()))
- ABORT("Failed to read /proc for library registration.");
+ ABORT("Failed to read /proc for library registration");
}
/* We now take care of the main data segment ourselves: */
@@ -454,7 +440,7 @@ STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
return -1;
p = info->dlpi_phdr;
- for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
+ for( i = 0; i < (int)info->dlpi_phnum; i++, p++ ) {
switch( p->p_type ) {
# ifdef PT_GNU_RELRO
case PT_GNU_RELRO:
@@ -534,7 +520,7 @@ GC_INNER GC_bool GC_register_main_static_data(void)
/* zero (otherwise a compiler might issue a warning). */
return FALSE;
# else
- return (dl_iterate_phdr == 0);
+ return (dl_iterate_phdr == 0); /* implicit conversion to function ptr */
# endif
}
@@ -680,9 +666,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
return;
}
# endif
- lm = GC_FirstDLOpenedLinkMap();
- for (lm = GC_FirstDLOpenedLinkMap();
- lm != (struct link_map *) 0; lm = lm->l_next)
+ for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next)
{
ElfW(Ehdr) * e;
ElfW(Phdr) * p;
@@ -697,7 +681,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
# endif
p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
offset = ((unsigned long)(lm->l_addr));
- for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
+ for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
switch( p->p_type ) {
case PT_LOAD:
{
@@ -729,10 +713,6 @@ GC_INNER void GC_register_dynamic_libraries(void)
# define IRIX6
#endif
-GC_INNER void * GC_roots_present(ptr_t);
- /* The type is a lie, since the real type doesn't make sense here, */
- /* and we only test for NULL. */
-
/* We use /proc to track down all parts of the address space that are */
/* mapped by the process, and throw out regions we know we shouldn't */
/* worry about. This may also work under other SVR4 variants. */
@@ -858,15 +838,9 @@ GC_INNER void GC_register_dynamic_libraries(void)
/* We traverse the entire address space and register all segments */
/* that could possibly have been written to. */
-
- GC_INNER GC_bool GC_is_heap_base(ptr_t p);
-
-# ifdef GC_WIN32_THREADS
- GC_INNER void GC_get_next_stack(char *start, char * limit, char **lo,
- char **hi);
-
- STATIC void GC_cond_add_roots(char *base, char * limit)
- {
+ STATIC void GC_cond_add_roots(char *base, char * limit)
+ {
+# ifdef GC_WIN32_THREADS
char * curr_base = base;
char * next_stack_lo;
char * next_stack_hi;
@@ -880,10 +854,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
curr_base = next_stack_hi;
}
if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
- }
-# else
- STATIC void GC_cond_add_roots(char *base, char * limit)
- {
+# else
char dummy;
char * stack_top
= (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
@@ -893,8 +864,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
return;
}
GC_add_roots_inner(base, limit, TRUE);
- }
-# endif
+# endif
+ }
#ifdef DYNAMIC_LOADING
/* GC_register_main_static_data is not needed unless DYNAMIC_LOADING. */
@@ -998,6 +969,10 @@ GC_INNER void GC_register_dynamic_libraries(void)
#include <loader.h>
+extern char *sys_errlist[];
+extern int sys_nerr;
+extern int errno;
+
GC_INNER void GC_register_dynamic_libraries(void)
{
int status;
@@ -1031,18 +1006,15 @@ GC_INNER void GC_register_dynamic_libraries(void)
/* Check status AFTER checking moduleid because */
/* of a bug in the non-shared ldr_next_module stub */
if (status != 0) {
- if (GC_print_stats) {
- extern char *sys_errlist[];
- extern int sys_nerr;
- extern int errno;
- GC_printf("dynamic_load: status = %d\n", status);
- if (errno <= sys_nerr) {
- GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
- } else {
- GC_printf("dynamic_load: err_code = %d\n", errno);
- }
+ if (GC_print_stats) {
+ GC_log_printf("dynamic_load: status = %d\n", status);
+ if (errno < sys_nerr) {
+ GC_log_printf("dynamic_load: %s\n", sys_errlist[errno]);
+ } else {
+ GC_log_printf("dynamic_load: err_code = %d\n", errno);
}
- ABORT("ldr_next_module failed");
+ }
+ ABORT("ldr_next_module failed");
}
/* Get the module information */
@@ -1056,16 +1028,15 @@ GC_INNER void GC_register_dynamic_libraries(void)
continue; /* skip the main module */
# ifdef DL_VERBOSE
- GC_printf("---Module---\n");
- GC_printf("Module ID = %16ld\n", moduleinfo.lmi_modid);
- GC_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
- GC_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
- GC_printf("pathname of module = \"%s\"\n", moduleinfo.lmi_name);
+ GC_log_printf("---Module---\n");
+ GC_log_printf("Module ID\t = %16ld\n", moduleinfo.lmi_modid);
+ GC_log_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
+ GC_log_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
+ GC_log_printf("module pathname\t = \"%s\"\n", moduleinfo.lmi_name);
# endif
/* For each region in this module */
for (region = 0; region < moduleinfo.lmi_nregion; region++) {
-
/* Get the region information */
status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
regioninfosize, &regionreturnsize);
@@ -1077,21 +1048,21 @@ GC_INNER void GC_register_dynamic_libraries(void)
continue;
# ifdef DL_VERBOSE
- GC_printf("--- Region ---\n");
- GC_printf("Region number = %16ld\n",
- regioninfo.lri_region_no);
- GC_printf("Protection flags = %016x\n", regioninfo.lri_prot);
- GC_printf("Virtual address = %16p\n", regioninfo.lri_vaddr);
- GC_printf("Mapped address = %16p\n", regioninfo.lri_mapaddr);
- GC_printf("Region size = %16ld\n", regioninfo.lri_size);
- GC_printf("Region name = \"%s\"\n", regioninfo.lri_name);
+ GC_log_printf("--- Region ---\n");
+ GC_log_printf("Region number\t = %16ld\n",
+ regioninfo.lri_region_no);
+ GC_log_printf("Protection flags = %016x\n", regioninfo.lri_prot);
+ GC_log_printf("Virtual address\t = %16p\n", regioninfo.lri_vaddr);
+ GC_log_printf("Mapped address\t = %16p\n",
+ regioninfo.lri_mapaddr);
+ GC_log_printf("Region size\t = %16ld\n", regioninfo.lri_size);
+ GC_log_printf("Region name\t = \"%s\"\n", regioninfo.lri_name);
# endif
/* register region as a garbage collection root */
- GC_add_roots_inner (
- (char *)regioninfo.lri_mapaddr,
- (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
- TRUE);
+ GC_add_roots_inner((char *)regioninfo.lri_mapaddr,
+ (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
+ TRUE);
}
}
@@ -1129,10 +1100,10 @@ GC_INNER void GC_register_dynamic_libraries(void)
break; /* Moved past end of shared library list --> finished */
} else {
if (GC_print_stats) {
- if (errno <= sys_nerr) {
- GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
+ if (errno < sys_nerr) {
+ GC_log_printf("dynamic_load: %s\n", sys_errlist[errno]);
} else {
- GC_printf("dynamic_load: err_code = %d\n", errno);
+ GC_log_printf("dynamic_load: err_code = %d\n", errno);
}
}
ABORT("shl_get failed");
@@ -1141,16 +1112,16 @@ GC_INNER void GC_register_dynamic_libraries(void)
}
# ifdef DL_VERBOSE
- GC_printf("---Shared library---\n");
- GC_printf("\tfilename = \"%s\"\n", shl_desc->filename);
- GC_printf("\tindex = %d\n", index);
- GC_printf("\thandle = %08x\n",
- (unsigned long) shl_desc->handle);
- GC_printf("\ttext seg. start = %08x\n", shl_desc->tstart);
- GC_printf("\ttext seg. end = %08x\n", shl_desc->tend);
- GC_printf("\tdata seg. start = %08x\n", shl_desc->dstart);
- GC_printf("\tdata seg. end = %08x\n", shl_desc->dend);
- GC_printf("\tref. count = %lu\n", shl_desc->ref_count);
+ GC_log_printf("---Shared library---\n");
+ GC_log_printf("\tfilename\t= \"%s\"\n", shl_desc->filename);
+ GC_log_printf("\tindex\t\t= %d\n", index);
+ GC_log_printf("\thandle\t\t= %08x\n",
+ (unsigned long) shl_desc->handle);
+ GC_log_printf("\ttext seg.start\t= %08x\n", shl_desc->tstart);
+ GC_log_printf("\ttext seg.end\t= %08x\n", shl_desc->tend);
+ GC_log_printf("\tdata seg.start\t= %08x\n", shl_desc->dstart);
+ GC_log_printf("\tdata seg.end\t= %08x\n", shl_desc->dend);
+ GC_log_printf("\tref.count\t= %lu\n", shl_desc->ref_count);
# endif
/* register shared library's data segment as a garbage collection root */
@@ -1209,15 +1180,44 @@ GC_INNER void GC_register_dynamic_libraries(void)
/*#define DARWIN_DEBUG*/
+/* Writable sections generally available on Darwin. */
STATIC const struct {
- const char *seg;
- const char *sect;
+ const char *seg;
+ const char *sect;
} GC_dyld_sections[] = {
- { SEG_DATA, SECT_DATA },
- { SEG_DATA, SECT_BSS },
- { SEG_DATA, SECT_COMMON }
+ { SEG_DATA, SECT_DATA },
+ /* Used by FSF GCC, but not by OS X system tools, so far. */
+ { SEG_DATA, "__static_data" },
+ { SEG_DATA, SECT_BSS },
+ { SEG_DATA, SECT_COMMON },
+ /* FSF GCC - zero-sized object sections for targets */
+ /*supporting section anchors. */
+ { SEG_DATA, "__zobj_data" },
+ { SEG_DATA, "__zobj_bss" }
+};
+
+/* Additional writable sections: */
+/* GCC on Darwin constructs aligned sections "on demand", where */
+/* the alignment size is embedded in the section name. */
+/* Furthermore, there are distinctions between sections */
+/* containing private vs. public symbols. It also constructs */
+/* sections specifically for zero-sized objects, when the */
+/* target supports section anchors. */
+STATIC const char * GC_dyld_add_sect_fmts[] =
+{
+ "__bss%u",
+ "__pu_bss%u",
+ "__zo_bss%u",
+ "__zo_pu_bss%u",
+ NULL
};
+/* Currently, mach-o will allow up to the max of 2^15 alignment */
+/* in an object file. */
+#ifndef L2_MAX_OFILE_ALIGNMENT
+# define L2_MAX_OFILE_ALIGNMENT 15
+#endif
+
STATIC const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr)
{
unsigned long i, c;
@@ -1228,63 +1228,119 @@ STATIC const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr)
return NULL;
}
-/* This should never be called by a thread holding the lock */
-STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr, intptr_t slide)
+/* This should never be called by a thread holding the lock. */
+STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
+ intptr_t slide)
{
- unsigned long start,end,i;
- const struct GC_MACH_SECTION *sec;
- const char *name;
- GC_has_static_roots_func callback = GC_has_static_roots;
- DCL_LOCK_STATE;
- if (GC_no_dls) return;
-# ifdef DARWIN_DEBUG
- name = GC_dyld_name_for_hdr(hdr);
-# else
- name = callback != 0 ? GC_dyld_name_for_hdr(hdr) : NULL;
-# endif
- for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
- sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
- GC_dyld_sections[i].sect);
- if(sec == NULL || sec->size < sizeof(word)) continue;
+ unsigned long start, end;
+ int i, j;
+ const struct GC_MACH_SECTION *sec;
+ const char *name;
+ GC_has_static_roots_func callback = GC_has_static_roots;
+ char secnam[16];
+ const char *fmt;
+ DCL_LOCK_STATE;
+
+ if (GC_no_dls) return;
+# ifdef DARWIN_DEBUG
+ name = GC_dyld_name_for_hdr(hdr);
+# else
+ name = callback != 0 ? GC_dyld_name_for_hdr(hdr) : NULL;
+# endif
+ for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
+ sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
+ GC_dyld_sections[i].sect);
+ if (sec == NULL || sec->size < sizeof(word))
+ continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+ LOCK();
+ /* The user callback is called holding the lock. */
+ if (callback == 0 || callback(name, (void*)start, (size_t)sec->size)) {
+# ifdef DARWIN_DEBUG
+ GC_log_printf(
+ "Adding section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
+ GC_dyld_sections[i].sect, (void*)start, (void*)end,
+ (unsigned long)sec->size, name);
+# endif
+ GC_add_roots_inner((ptr_t)start, (ptr_t)end, FALSE);
+ }
+ UNLOCK();
+ }
+
+ /* Sections constructed on demand. */
+ for (j = 0; (fmt = GC_dyld_add_sect_fmts[j]) != NULL; j++) {
+ /* Add our manufactured aligned BSS sections. */
+ for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
+ snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
+ sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
+ if (sec == NULL || sec->size == 0)
+ continue;
start = slide + sec->addr;
end = start + sec->size;
- LOCK();
- /* The user callback is called holding the lock */
- if (callback == 0 || callback(name, (void*)start, (size_t)sec->size)) {
-# ifdef DARWIN_DEBUG
- GC_printf("Adding section at %p-%p (%lu bytes) from image %s\n",
- start,end,sec->size,name);
-# endif
- GC_add_roots_inner((ptr_t)start, (ptr_t)end, FALSE);
- }
- UNLOCK();
+# ifdef DARWIN_DEBUG
+ GC_log_printf("Adding on-demand section __DATA,%s at"
+ " %p-%p (%lu bytes) from image %s\n",
+ secnam, (void*)start, (void*)end,
+ (unsigned long)sec->size, name);
+# 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 */
+/* This should never be called by a thread holding the lock. */
STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
intptr_t slide)
{
- unsigned long start,end,i;
- const struct GC_MACH_SECTION *sec;
- for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
- sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
- GC_dyld_sections[i].sect);
- if(sec == NULL || sec->size == 0) continue;
- start = slide + sec->addr;
- end = start + sec->size;
+ unsigned long start, end;
+ int i, j;
+ const struct GC_MACH_SECTION *sec;
+ char secnam[16];
+ const char *fmt;
+
+ for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
+ sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
+ GC_dyld_sections[i].sect);
+ if (sec == NULL || sec->size == 0)
+ continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
# ifdef DARWIN_DEBUG
- GC_printf("Removing section at %p-%p (%lu bytes) from image %s\n",
- start,end,sec->size,GC_dyld_name_for_hdr(hdr));
+ GC_log_printf(
+ "Removing section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
+ GC_dyld_sections[i].sect, (void*)start, (void*)end,
+ (unsigned long)sec->size, GC_dyld_name_for_hdr(hdr));
# endif
- GC_remove_roots((char*)start,(char*)end);
+ GC_remove_roots((char*)start, (char*)end);
+ }
+
+ /* Remove our on-demand sections. */
+ for (j = 0; (fmt = GC_dyld_add_sect_fmts[j]) != NULL; j++) {
+ for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
+ snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
+ sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
+ if (sec == NULL || sec->size == 0)
+ continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+# ifdef DARWIN_DEBUG
+ GC_log_printf("Removing on-demand section __DATA,%s at"
+ " %p-%p (%lu bytes) from image %s\n", secnam,
+ (void*)start, (void*)end, (unsigned long)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
}
GC_INNER void GC_register_dynamic_libraries(void)
@@ -1306,7 +1362,7 @@ GC_INNER void GC_init_dyld(void)
if (initialized) return;
# ifdef DARWIN_DEBUG
- GC_printf("Registering dyld callbacks...\n");
+ GC_log_printf("Registering dyld callbacks...\n");
# endif
/* Apple's Documentation:
@@ -1341,7 +1397,7 @@ GC_INNER void GC_init_dyld(void)
if (GETENV("DYLD_BIND_AT_LAUNCH") == 0) {
/* The environment variable is unset, so we should bind manually. */
# ifdef DARWIN_DEBUG
- GC_printf("Forcing full bind of GC code...\n");
+ GC_log_printf("Forcing full bind of GC code...\n");
# endif
/* FIXME: '_dyld_bind_fully_image_containing_address' is deprecated. */
if (!_dyld_bind_fully_image_containing_address(
@@ -1385,10 +1441,8 @@ GC_INNER GC_bool GC_register_main_static_data(void)
for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
== PCR_IL_SegFlags_Traced_on) {
- GC_add_roots_inner
- ((char *)(q -> ls_addr),
- (char *)(q -> ls_addr) + q -> ls_bytes,
- TRUE);
+ GC_add_roots_inner((char *)(q -> ls_addr),
+ (char *)(q -> ls_addr) + q -> ls_bytes, TRUE);
}
}
}
diff --git a/extra/setjmp_t.c b/extra/setjmp_t.c
index 5a171df0..0952fb03 100644
--- a/extra/setjmp_t.c
+++ b/extra/setjmp_t.c
@@ -10,126 +10,127 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-
+
/* Check whether setjmp actually saves registers in jmp_buf. */
/* If it doesn't, the generic mark_regs code won't work. */
-/* Compilers vary as to whether they will put x in a */
-/* (callee-save) register without -O. The code is */
+/* Compilers vary as to whether they will put x in a */
+/* (callee-save) register without -O. The code is */
/* contrived such that any decent compiler should put x in */
-/* a callee-save register with -O. Thus it is is */
+/* a callee-save register with -O. Thus it is */
/* recommended that this be run optimized. (If the machine */
/* has no callee-save registers, then the generic code is */
/* safe, but this will not be noticed by this piece of */
-/* code.) This test appears to be far from perfect. */
+/* code.) This test appears to be far from perfect. */
#include <stdio.h>
#include <setjmp.h>
#include <string.h>
#include "private/gc_priv.h"
#ifdef OS2
-/* GETPAGESIZE() is set to getpagesize() by default, but that */
-/* doesn't really exist, and the collector doesn't need it. */
+/* GETPAGESIZE() is set to getpagesize() by default, but that */
+/* doesn't really exist, and the collector doesn't need it. */
#define INCL_DOSFILEMGR
#define INCL_DOSMISC
#define INCL_DOSERRORS
#include <os2.h>
-int
-getpagesize()
+int getpagesize(void)
{
ULONG result[1];
-
+
if (DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE,
- (void *)result, sizeof(ULONG)) != NO_ERROR) {
- fprintf(stderr, "DosQuerySysInfo failed\n");
- result[0] = 4096;
+ (void *)result, sizeof(ULONG)) != NO_ERROR) {
+ fprintf(stderr, "DosQuerySysInfo failed\n");
+ result[0] = 4096;
}
return((int)(result[0]));
}
#endif
-struct {char a_a; char * a_b;} a;
+struct {
+ char a_a;
+ char * a_b;
+} a;
-int * nested_sp()
+int * nested_sp(void)
{
- int dummy;
-
- return(&dummy);
+ volatile int sp;
+ sp = (int)&sp;
+ return (int *)sp;
}
-int main()
+int main(void)
{
- int dummy;
- long ps = GETPAGESIZE();
- jmp_buf b;
- register int x = (int)strlen("a"); /* 1, slightly disguised */
- static int y = 0;
+ int dummy;
+ long ps = GETPAGESIZE();
+ jmp_buf b;
+ register int x = (int)strlen("a"); /* 1, slightly disguised */
+ static int y = 0;
- printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
- if (nested_sp() < &dummy) {
- printf("Stack appears to grow down, which is the default.\n");
- printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
- ((unsigned long)(&dummy) + ps) & ~(ps-1));
- } else {
- printf("Stack appears to grow up.\n");
- printf("Define STACK_GROWS_UP in gc_private.h\n");
- printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
- ((unsigned long)(&dummy) + ps) & ~(ps-1));
- }
- printf("Note that this may vary between machines of ostensibly\n");
- printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
- printf("On many machines the value is not fixed.\n");
- printf("A good guess for ALIGNMENT on this machine is %ld.\n",
- (unsigned long)(&(a.a_b))-(unsigned long)(&a));
-
- printf("The following is a very dubious test of one root marking"
- " strategy.\n");
- printf("Results may not be accurate/useful:\n");
- /* Encourage the compiler to keep x in a callee-save register */
- x = 2*x-1;
- printf("");
- x = 2*x-1;
- setjmp(b);
- if (y == 1) {
- if (x == 2) {
- printf("Setjmp-based generic mark_regs code probably wont work.\n");
- printf("But we rarely try that anymore. If you have getcontect()\n");
- printf("this probably doesn't matter.\n");
- } else if (x == 1) {
- printf("Setjmp-based register marking code may work.\n");
- } else {
- printf("Very strange setjmp implementation.\n");
- }
- }
- y++;
- x = 2;
- if (y == 1) longjmp(b,1);
- printf("Some GC internal configuration stuff: \n");
- printf("\tWORDSZ = %d, ALIGNMENT = %d, GC_GRANULE_BYTES = %d\n",
- WORDSZ, ALIGNMENT, GC_GRANULE_BYTES);
- printf("\tUsing one mark ");
-# if defined(USE_MARK_BYTES)
- printf("byte");
-# elif defined(USE_MARK_BITS)
- printf("bit");
-# endif
- printf(" per ");
-# if defined(MARK_BIT_PER_OBJ)
- printf("object.\n");
-# elif defined(MARK_BIT_PER_GRANULE)
- printf("granule.\n");
-# endif
-# ifdef THREAD_LOCAL_ALLOC
- printf("Thread local allocation enabled.\n");
-# endif
-# ifdef PARALLEL_MARK
- printf("Parallel marking enabled.\n");
-# endif
- return(0);
+ printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
+ if (nested_sp() < &dummy) {
+ printf("Stack appears to grow down, which is the default.\n");
+ printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
+ ((unsigned long)(&dummy) + ps) & ~(ps-1));
+ } else {
+ printf("Stack appears to grow up.\n");
+ printf("Define STACK_GROWS_UP in gc_private.h\n");
+ printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
+ ((unsigned long)(&dummy) + ps) & ~(ps-1));
+ }
+ printf("Note that this may vary between machines of ostensibly\n");
+ printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
+ printf("On many machines the value is not fixed.\n");
+ printf("A good guess for ALIGNMENT on this machine is %ld.\n",
+ (unsigned long)(&(a.a_b))-(unsigned long)(&a));
+
+ printf("The following is a very dubious test of one root marking"
+ " strategy.\n");
+ printf("Results may not be accurate/useful:\n");
+ /* Encourage the compiler to keep x in a callee-save register */
+ x = 2*x-1;
+ printf("");
+ x = 2*x-1;
+ setjmp(b);
+ if (y == 1) {
+ if (x == 2) {
+ printf("Setjmp-based generic mark_regs code probably wont work.\n");
+ printf("But we rarely try that anymore. If you have getcontect()\n");
+ printf("this probably doesn't matter.\n");
+ } else if (x == 1) {
+ printf("Setjmp-based register marking code may work.\n");
+ } else {
+ printf("Very strange setjmp implementation.\n");
+ }
+ }
+ y++;
+ x = 2;
+ if (y == 1) longjmp(b,1);
+ printf("Some GC internal configuration stuff: \n");
+ printf("\tWORDSZ = %d, ALIGNMENT = %d, GC_GRANULE_BYTES = %d\n",
+ WORDSZ, ALIGNMENT, GC_GRANULE_BYTES);
+ printf("\tUsing one mark ");
+# if defined(USE_MARK_BYTES)
+ printf("byte");
+# else
+ printf("bit");
+# endif
+ printf(" per ");
+# if defined(MARK_BIT_PER_OBJ)
+ printf("object.\n");
+# elif defined(MARK_BIT_PER_GRANULE)
+ printf("granule.\n");
+# endif
+# ifdef THREAD_LOCAL_ALLOC
+ printf("Thread local allocation enabled.\n");
+# endif
+# ifdef PARALLEL_MARK
+ printf("Parallel marking enabled.\n");
+# endif
+ return(0);
}
-int g(x)
-int x;
+int g(int x)
{
- return(x);
+ return(x);
}
diff --git a/finalize.c b/finalize.c
index c10d8543..40c725a9 100644
--- a/finalize.c
+++ b/finalize.c
@@ -485,18 +485,13 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
}
}
}
-#endif
+#endif /* !NO_DEBUGGING */
#ifndef SMALL_CONFIG
STATIC word GC_old_dl_entries = 0; /* for stats printing */
#endif
-#ifdef THREADS
- /* Defined in pthread_support.c or win32_threads.c. Called with the */
- /* allocation lock held. */
- GC_INNER void GC_reset_finalizer_nested(void);
- GC_INNER unsigned char *GC_check_finalizer_nested(void);
-#else
+#ifndef THREADS
/* Global variables to minimize the level of recursion when a client */
/* finalizer allocates memory. */
STATIC unsigned char GC_finalizer_nested = 0;
diff --git a/gc_dlopen.c b/gc_dlopen.c
index e466d65c..f76230ec 100644
--- a/gc_dlopen.c
+++ b/gc_dlopen.c
@@ -43,16 +43,18 @@
/* dlopen calls in either a multi-threaded environment, or if the */
/* library initialization code allocates substantial amounts of GC'ed */
/* memory. */
-static void disable_gc_for_dlopen(void)
-{
- DCL_LOCK_STATE;
- LOCK();
- while (GC_incremental && GC_collection_in_progress()) {
- GC_collect_a_little_inner(1000);
+#ifndef USE_PROC_FOR_LIBRARIES
+ static void disable_gc_for_dlopen(void)
+ {
+ DCL_LOCK_STATE;
+ LOCK();
+ while (GC_incremental && GC_collection_in_progress()) {
+ GC_collect_a_little_inner(1000);
+ }
+ ++GC_dont_gc;
+ UNLOCK();
}
- ++GC_dont_gc;
- UNLOCK();
-}
+#endif
/* Redefine dlopen to guarantee mutual exclusion with */
/* GC_register_dynamic_libraries. Should probably happen for */
diff --git a/gcj_mlc.c b/gcj_mlc.c
index 6c160c49..3467a396 100644
--- a/gcj_mlc.c
+++ b/gcj_mlc.c
@@ -39,7 +39,12 @@
#include "gc_gcj.h"
#include "private/dbg_mlc.h"
-GC_INNER GC_bool GC_gcj_malloc_initialized = FALSE;
+#ifdef GC_ASSERTIONS
+ GC_INNER /* variable is also used in thread_local_alloc.c */
+#else
+ STATIC
+#endif
+GC_bool GC_gcj_malloc_initialized = FALSE;
int GC_gcj_kind = 0; /* Object kind for objects with descriptors */
/* in "vtable". */
@@ -199,8 +204,6 @@ static void maybe_finalize(void)
return((void *) op);
}
-GC_INNER void GC_start_debugging(void);
-
/* Similar to GC_gcj_malloc, but add debug info. This is allocated */
/* with GC_gcj_debug_kind. */
GC_API void * GC_CALL GC_debug_gcj_malloc(size_t lb,
@@ -209,7 +212,7 @@ GC_API void * GC_CALL GC_debug_gcj_malloc(size_t lb,
void * result;
DCL_LOCK_STATE;
- /* We're careful to avoid extra calls, which could */
+ /* We're careful to avoid extra calls, which could */
/* confuse the backtrace. */
LOCK();
maybe_finalize();
@@ -229,7 +232,7 @@ GC_API void * GC_CALL GC_debug_gcj_malloc(size_t lb,
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
/* There is no THREAD_LOCAL_ALLOC for GC_gcj_malloc_ignore_off_page(). */
diff --git a/headers.c b/headers.c
index c4f5023c..de82c204 100644
--- a/headers.c
+++ b/headers.c
@@ -145,7 +145,7 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
GC_add_to_our_memory(result, bytes_to_get);
if (result == 0) {
if (GC_print_stats)
- GC_printf("Out of memory - trying to allocate less\n");
+ GC_log_printf("Out of memory - trying to allocate less\n");
scratch_free_ptr -= bytes;
bytes_to_get = bytes;
# ifdef USE_MMAP
diff --git a/include/gc.h b/include/gc.h
index a00112eb..28cf86f7 100644
--- a/include/gc.h
+++ b/include/gc.h
@@ -382,12 +382,6 @@ GC_API void * GC_CALL GC_memalign(size_t /* align */, size_t /* lb */)
GC_API int GC_CALL GC_posix_memalign(void ** /* memptr */, size_t /* align */,
size_t /* lb */);
-/* The following is only defined if the library has been suitably */
-/* compiled: */
-GC_API void * GC_CALL GC_malloc_atomic_uncollectable(
- size_t /* size_in_bytes */)
- GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1);
-
/* Explicitly deallocate an object. Dangerous if used incorrectly. */
/* Requires a pointer to the base of an object. */
/* If the argument is stubborn, it should not be changeable when freed. */
@@ -615,6 +609,15 @@ GC_API void * GC_CALL GC_malloc_atomic_ignore_off_page(size_t /* lb */)
# define GC_EXTRA_PARAMS const char * s, int i
#endif
+/* The following is only defined if the library has been suitably */
+/* compiled: */
+GC_API void * GC_CALL GC_malloc_atomic_uncollectable(
+ size_t /* size_in_bytes */)
+ GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1);
+GC_API void * GC_CALL GC_debug_malloc_atomic_uncollectable(size_t,
+ GC_EXTRA_PARAMS)
+ GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1);
+
/* Debugging (annotated) allocation. GC_gcollect will check */
/* objects allocated in this way for overwrites, etc. */
GC_API void * GC_CALL GC_debug_malloc(size_t /* size_in_bytes */,
@@ -682,6 +685,8 @@ GC_API void * GC_CALL GC_debug_realloc_replacement(void * /* object_addr */,
# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
# define GC_STRDUP(s) GC_debug_strdup(s, GC_EXTRAS)
# define GC_STRNDUP(s, sz) GC_debug_strndup(s, sz, GC_EXTRAS)
+# define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) \
+ GC_debug_malloc_atomic_uncollectable(sz, GC_EXTRAS)
# define GC_MALLOC_UNCOLLECTABLE(sz) \
GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
@@ -708,6 +713,7 @@ GC_API void * GC_CALL GC_debug_realloc_replacement(void * /* object_addr */,
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
# define GC_STRDUP(s) GC_strdup(s)
# define GC_STRNDUP(s, sz) GC_strndup(s, sz)
+# define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) GC_malloc_atomic_uncollectable(sz)
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
GC_malloc_ignore_off_page(sz)
@@ -734,7 +740,8 @@ GC_API void * GC_CALL GC_debug_realloc_replacement(void * /* object_addr */,
/* The following are included because they are often convenient, and */
/* reduce the chance for a misspecified size argument. But calls may */
/* expand to something syntactically incorrect if t is a complicated */
-/* type expression. */
+/* type expression. Note that, unlike C++ new operator, these ones */
+/* may return NULL (if out of memory). */
#define GC_NEW(t) ((t*)GC_MALLOC(sizeof(t)))
#define GC_NEW_ATOMIC(t) ((t*)GC_MALLOC_ATOMIC(sizeof(t)))
#define GC_NEW_STUBBORN(t) ((t*)GC_MALLOC_STUBBORN(sizeof(t)))
@@ -975,22 +982,19 @@ GC_API void GC_CALLBACK GC_ignore_warn_proc(char *, GC_word);
/* Note that putting pointers in atomic objects or in */
/* non-pointer slots of "typed" objects is equivalent to */
/* disguising them in this way, and may have other advantages. */
-#if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
- typedef GC_word GC_hidden_pointer;
-# define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
-# define REVEAL_POINTER(p) ((void *)HIDE_POINTER(p))
- /* Converting a hidden pointer to a real pointer requires verifying */
- /* that the object still exists. This involves acquiring the */
- /* allocator lock to avoid a race with the collector. */
-#endif /* I_HIDE_POINTERS */
-
-/* The GC-prefixed symbols are preferred for new code (I_HIDE_POINTERS, */
-/* HIDE_POINTER and REVEAL_POINTER remain for compatibility). */
-//#ifdef GC_I_HIDE_POINTERS
- typedef GC_word GC_hidden_pointer;
-# define GC_HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
-# define GC_REVEAL_POINTER(p) ((void*) (~(GC_hidden_pointer)(p)))
-//#endif
+typedef GC_word GC_hidden_pointer;
+#define GC_HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
+/* Converting a hidden pointer to a real pointer requires verifying */
+/* that the object still exists. This involves acquiring the */
+/* allocator lock to avoid a race with the collector. */
+#define GC_REVEAL_POINTER(p) ((void *)GC_HIDE_POINTER(p))
+
+#ifdef I_HIDE_POINTERS
+ /* This exists only for compatibility (the GC-prefixed symbols are */
+ /* preferred for new code). */
+# define HIDE_POINTER(p) GC_HIDE_POINTER(p)
+# define REVEAL_POINTER(p) GC_REVEAL_POINTER(p)
+#endif
typedef void * (GC_CALLBACK * GC_fn_type)(void * /* client_data */);
GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type /* fn */,
@@ -1064,11 +1068,15 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
/* always done implicitly. This is normally done implicitly if GC_ */
/* functions are called to create the thread, e.g. by including gc.h */
/* (which redefines some system functions) before calling the system */
- /* thread creation function. */
+ /* thread creation function. Nonetheless, thread cleanup routines */
+ /* (eg., pthread key destructor) typically require manual thread */
+ /* registering (and unregistering) if pointers to GC-allocated */
+ /* objects are manipulated inside. */
/* It is also always done implicitly on some platforms if */
/* GC_use_threads_discovery() is called at start-up. Except for the */
/* latter case, the explicit call is normally required for threads */
/* created by third-party libraries. */
+ /* A manually registered thread requires manual unregistering. */
GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *);
/* Unregister the current thread. Only an explicitly registered */
@@ -1507,11 +1515,6 @@ GC_API void GC_CALL GC_win32_free_heap(void);
# include "gc_amiga_redirects.h"
#endif
- /*
- * GC_REDIRECT_TO_LOCAL is now redundant;
- * that's the default with THREAD_LOCAL_ALLOC.
- */
-
#ifdef __cplusplus
} /* end of extern "C" */
#endif
diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h
index 030218e4..a27f8dd7 100644
--- a/include/gc_config_macros.h
+++ b/include/gc_config_macros.h
@@ -273,8 +273,8 @@
/* This may also be desirable if it is possible but expensive to */
/* retrieve the call chain. */
#if (defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) \
- || defined(__FreeBSD__) || defined(__DragonFly__)) \
- && !defined(GC_CAN_SAVE_CALL_STACKS)
+ || defined(__FreeBSD__) || defined(__DragonFly__) \
+ || defined(PLATFORM_ANDROID)) && !defined(GC_CAN_SAVE_CALL_STACKS)
# define GC_ADD_CALLER
# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
/* gcc knows how to retrieve return address, but we don't know */
diff --git a/include/gc_cpp.h b/include/gc_cpp.h
index 60eafcf9..4bee8dec 100644
--- a/include/gc_cpp.h
+++ b/include/gc_cpp.h
@@ -252,9 +252,9 @@ inline void* operator new(
classes derived from "gc_cleanup" or containing members derived
from "gc_cleanup". */
-# ifdef GC_PLACEMENT_DELETE
- inline void operator delete( void*, GCPlacement, GCCleanUpFunc, void * );
-# endif
+#ifdef GC_PLACEMENT_DELETE
+ inline void operator delete( void*, GCPlacement, GCCleanUpFunc, void * );
+#endif
#ifdef _MSC_VER
/** This ensures that the system default operator new[] doesn't get
@@ -307,10 +307,9 @@ _Ret_bytecap_(_Size) inline void* operator new[](size_t size, int nBlockUse, con
#endif /* _MSC_VER */
-
#ifdef GC_OPERATOR_NEW_ARRAY
-inline void* operator new[](
+ inline void* operator new[](
size_t size,
GCPlacement gcp,
GCCleanUpFunc cleanup = 0,
@@ -360,30 +359,26 @@ inline void gc::operator delete( void* obj ) {
#endif
#ifdef GC_OPERATOR_NEW_ARRAY
-
-inline void* gc::operator new[]( size_t size ) {
+ inline void* gc::operator new[]( size_t size ) {
return gc::operator new( size );}
-inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
+ inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
return gc::operator new( size, gcp );}
-inline void* gc::operator new[]( size_t size, void *p ) {
+ inline void* gc::operator new[]( size_t size, void *p ) {
return p;}
-inline void gc::operator delete[]( void* obj ) {
+ inline void gc::operator delete[]( void* obj ) {
gc::operator delete( obj );}
-#ifdef GC_PLACEMENT_DELETE
- inline void gc::operator delete[]( void*, void* ) {}
-
- inline void gc::operator delete[]( void* p, GCPlacement gcp ) {
- gc::operator delete(p); }
-
-#endif
+# ifdef GC_PLACEMENT_DELETE
+ inline void gc::operator delete[]( void*, void* ) {}
+ inline void gc::operator delete[]( void* p, GCPlacement gcp ) {
+ gc::operator delete(p); }
+# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
-
inline gc_cleanup::~gc_cleanup() {
GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );}
@@ -397,7 +392,7 @@ inline gc_cleanup::gc_cleanup() {
if (0 != base) {
// Don't call the debug version, since this is a real base address.
GC_register_finalizer_ignore_self(
- base, (GC_finalization_proc)cleanup, (void*) ((char*) this - (char*) base),
+ base, (GC_finalization_proc)cleanup, (void*)((char*)this - (char*)base),
&oldProc, &oldData );
if (0 != oldProc) {
GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );}}}
@@ -435,27 +430,26 @@ inline void* operator new(
return obj;
}
-# ifdef GC_PLACEMENT_DELETE
-inline void operator delete (
+#ifdef GC_PLACEMENT_DELETE
+ inline void operator delete (
void *p,
GCPlacement gcp,
GCCleanUpFunc cleanup,
void* clientData )
-{
+ {
GC_FREE(p);
-}
-# endif
+ }
+#endif /* GC_PLACEMENT_DELETE */
#ifdef GC_OPERATOR_NEW_ARRAY
-
-inline void* operator new[](
+ inline void* operator new[](
size_t size,
GCPlacement gcp,
GCCleanUpFunc cleanup,
void* clientData )
-{
- return ::operator new( size, gcp, cleanup, clientData );}
-
+ {
+ return ::operator new( size, gcp, cleanup, clientData );
+ }
#endif /* GC_OPERATOR_NEW_ARRAY */
// oooohh... big hack (mainly for vnl which explicitly references mem-stuff via std namespace)
@@ -466,6 +460,13 @@ namespace std
using ::GC_realloc;
using ::GC_malloc_uncollectable;
}
+#if defined(__CYGWIN__)
+# include <new> // for delete throw()
+ inline void operator delete(void *p)
+ {
+ GC_FREE(p);
+ }
+#endif
#endif // __cplusplus
diff --git a/include/gc_inline.h b/include/gc_inline.h
index 312ed61b..cc49da22 100644
--- a/include/gc_inline.h
+++ b/include/gc_inline.h
@@ -118,15 +118,15 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
/* free list array. For single-threaded applications, this may be */
/* a global array. */
# define GC_MALLOC_WORDS(result,n,tiny_fl) \
-{ \
+{ \
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
- *(void **)result = 0); \
+ *(void **)(result) = 0); \
}
# define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
-{ \
+{ \
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
PTRFREE, GC_malloc_atomic(grans*GC_GRANULE_BYTES), \
@@ -135,12 +135,12 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
/* And once more for two word initialized objects: */
# define GC_CONS(result, first, second, tiny_fl) \
-{ \
+{ \
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(2); \
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
- *(void **)result = (void *)(first)); \
- ((void **)(result))[1] = (void *)(second); \
+ *(void **)(result) = (void *)(first)); \
+ ((void **)(result))[1] = (void *)(second); \
}
#endif /* !GC_INLINE_H */
diff --git a/include/gc_typed.h b/include/gc_typed.h
index 10111cdb..a794fbbe 100644
--- a/include/gc_typed.h
+++ b/include/gc_typed.h
@@ -39,9 +39,9 @@ typedef GC_word * GC_bitmap;
#define GC_WORDSZ (8 * sizeof(GC_word))
#define GC_get_bit(bm, index) \
- (((bm)[index / GC_WORDSZ] >> (index % GC_WORDSZ)) & 1)
+ (((bm)[(index) / GC_WORDSZ] >> ((index) % GC_WORDSZ)) & 1)
#define GC_set_bit(bm, index) \
- (bm)[index / GC_WORDSZ] |= ((GC_word)1 << (index % GC_WORDSZ))
+ ((bm)[(index) / GC_WORDSZ] |= (GC_word)1 << ((index) % GC_WORDSZ))
#define GC_WORD_OFFSET(t, f) (offsetof(t,f) / sizeof(GC_word))
#define GC_WORD_LEN(t) (sizeof(t) / sizeof(GC_word))
#define GC_BITMAP_SIZE(t) ((GC_WORD_LEN(t) + GC_WORDSZ - 1) / GC_WORDSZ)
@@ -99,7 +99,7 @@ GC_API void * GC_CALL GC_calloc_explicitly_typed(size_t /* nelements */,
#ifdef GC_DEBUG
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes)
-# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC(n * bytes)
+# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC((n) * (bytes))
#else
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
GC_malloc_explicitly_typed(bytes, d)
diff --git a/include/gc_version.h b/include/gc_version.h
index ee3bb22c..4ea1a897 100644
--- a/include/gc_version.h
+++ b/include/gc_version.h
@@ -23,7 +23,7 @@
/* it to keep the old-style build process working. */
#define GC_TMP_VERSION_MAJOR 7
#define GC_TMP_VERSION_MINOR 2
-#define GC_TMP_ALPHA_VERSION 5
+#define GC_TMP_ALPHA_VERSION 7
#ifndef GC_NOT_ALPHA
# define GC_NOT_ALPHA 0xff
diff --git a/include/private/config.h.in b/include/private/config.h.in
index 6af87d14..a14c0f34 100755..100644
--- a/include/private/config.h.in
+++ b/include/private/config.h.in
@@ -69,7 +69,7 @@
/* Define to support Solaris pthreads. */
#undef GC_SOLARIS_THREADS
-/* Define to support threads. */
+/* Define to support platform-specific threads. */
#undef GC_THREADS
/* See doc/README.macros. */
@@ -81,7 +81,10 @@
/* The minor version number of this GC release. */
#undef GC_VERSION_MINOR
-/* Define to support win32 threads. */
+/* Define to support win32-pthreads. */
+#undef GC_WIN32_PTHREADS
+
+/* Define to support Win32 threads. */
#undef GC_WIN32_THREADS
/* Define to 1 if you have the <dlfcn.h> header file. */
diff --git a/include/private/darwin_stop_world.h b/include/private/darwin_stop_world.h
index ee601144..399304ea 100644
--- a/include/private/darwin_stop_world.h
+++ b/include/private/darwin_stop_world.h
@@ -30,4 +30,17 @@ struct thread_stop_info {
ptr_t stack_ptr; /* Valid only when thread is in a "blocked" state. */
};
+#ifndef DARWIN_DONT_PARSE_STACK
+ GC_INNER ptr_t GC_FindTopOfStack(unsigned long);
+#endif
+
+#ifdef MPROTECT_VDB
+ GC_INNER void GC_mprotect_stop(void);
+ GC_INNER void GC_mprotect_resume(void);
+#endif
+
+#if defined(PARALLEL_MARK) && !defined(GC_NO_THREADS_DISCOVERY)
+ GC_INNER GC_bool GC_is_mach_marker(thread_act_t);
+#endif
+
#endif
diff --git a/include/private/dbg_mlc.h b/include/private/dbg_mlc.h
index 45dc1812..7b2969d2 100644
--- a/include/private/dbg_mlc.h
+++ b/include/private/dbg_mlc.h
@@ -25,92 +25,96 @@
#ifndef _DBG_MLC_H
#define _DBG_MLC_H
-# include "gc_priv.h"
-# ifdef KEEP_BACK_PTRS
-# include "gc_backptr.h"
-# endif
+#include "gc_priv.h"
+#ifdef KEEP_BACK_PTRS
+# include "gc_backptr.h"
+#endif
-# define START_FLAG ((word)0xfedcedcb)
-# define END_FLAG ((word)0xbcdecdef)
+#if CPP_WORDSZ == 32
+# define START_FLAG (word)0xfedcedcb
+# define END_FLAG (word)0xbcdecdef
+#else
+# define START_FLAG GC_WORD_C(0xFEDCEDCBfedcedcb)
+# define END_FLAG GC_WORD_C(0xBCDECDEFbcdecdef)
+#endif
/* Stored both one past the end of user object, and one before */
/* the end of the object as seen by the allocator. */
-# if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) \
- || defined(MAKE_BACK_GRAPH)
- /* Pointer "source"s that aren't real locations. */
- /* Used in oh_back_ptr fields and as "source" */
- /* argument to some marking functions. */
-# define NOT_MARKED (ptr_t)(0)
-# define MARKED_FOR_FINALIZATION ((ptr_t)(word)2)
- /* Object was marked because it is finalizable. */
-# define MARKED_FROM_REGISTER ((ptr_t)(word)4)
- /* Object was marked from a register. Hence the */
- /* source of the reference doesn't have an address. */
-# endif /* KEEP_BACK_PTRS || PRINT_BLACK_LIST */
+#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) \
+ || defined(MAKE_BACK_GRAPH)
+ /* Pointer "source"s that aren't real locations. */
+ /* Used in oh_back_ptr fields and as "source" */
+ /* argument to some marking functions. */
+# define NOT_MARKED (ptr_t)0
+# define MARKED_FOR_FINALIZATION ((ptr_t)(word)2)
+ /* Object was marked because it is finalizable. */
+# define MARKED_FROM_REGISTER ((ptr_t)(word)4)
+ /* Object was marked from a register. Hence the */
+ /* source of the reference doesn't have an address. */
+#endif /* KEEP_BACK_PTRS || PRINT_BLACK_LIST */
/* Object header */
typedef struct {
-# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
- /* We potentially keep two different kinds of back */
- /* pointers. KEEP_BACK_PTRS stores a single back */
- /* pointer in each reachable object to allow reporting */
- /* of why an object was retained. MAKE_BACK_GRAPH */
- /* builds a graph containing the inverse of all */
- /* "points-to" edges including those involving */
- /* objects that have just become unreachable. This */
- /* allows detection of growing chains of unreachable */
- /* objects. It may be possible to eventually combine */
- /* both, but for now we keep them separate. Both */
- /* kinds of back pointers are hidden using the */
- /* following macros. In both cases, the plain version */
- /* is constrained to have an least significant bit of 1,*/
- /* to allow it to be distinguished from a free list */
- /* link. This means the plain version must have an */
- /* lsb of 0. */
- /* Note that blocks dropped by black-listing will */
- /* also have the lsb clear once debugging has */
- /* started. */
- /* We're careful never to overwrite a value with lsb 0. */
-# if ALIGNMENT == 1
- /* Fudge back pointer to be even. */
-# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (GC_word)(p))
-# else
-# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p)
-# endif
-
-# ifdef KEEP_BACK_PTRS
- GC_hidden_pointer oh_back_ptr;
-# endif
-# ifdef MAKE_BACK_GRAPH
- GC_hidden_pointer oh_bg_ptr;
-# endif
-# if defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH)
- /* Keep double-pointer-sized alignment. */
- word oh_dummy;
-# endif
+# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
+ /* We potentially keep two different kinds of back */
+ /* pointers. KEEP_BACK_PTRS stores a single back */
+ /* pointer in each reachable object to allow reporting */
+ /* of why an object was retained. MAKE_BACK_GRAPH */
+ /* builds a graph containing the inverse of all */
+ /* "points-to" edges including those involving */
+ /* objects that have just become unreachable. This */
+ /* allows detection of growing chains of unreachable */
+ /* objects. It may be possible to eventually combine */
+ /* both, but for now we keep them separate. Both */
+ /* kinds of back pointers are hidden using the */
+ /* following macros. In both cases, the plain version */
+ /* is constrained to have an least significant bit of 1, */
+ /* to allow it to be distinguished from a free list */
+ /* link. This means the plain version must have an */
+ /* lsb of 0. */
+ /* Note that blocks dropped by black-listing will */
+ /* also have the lsb clear once debugging has */
+ /* started. */
+ /* We're careful never to overwrite a value with lsb 0. */
+# if ALIGNMENT == 1
+ /* Fudge back pointer to be even. */
+# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (GC_word)(p))
+# else
+# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p)
+# endif
+# ifdef KEEP_BACK_PTRS
+ GC_hidden_pointer oh_back_ptr;
+# endif
+# ifdef MAKE_BACK_GRAPH
+ GC_hidden_pointer oh_bg_ptr;
# endif
- const char * oh_string; /* object descriptor string */
- word oh_int; /* object descriptor integers */
-# ifdef NEED_CALLINFO
- struct callinfo oh_ci[NFRAMES];
+# if defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH)
+ /* Keep double-pointer-sized alignment. */
+ word oh_dummy;
# endif
-# ifndef SHORT_DBG_HDRS
- word oh_sz; /* Original malloc arg. */
- word oh_sf; /* start flag */
-# endif /* SHORT_DBG_HDRS */
+# endif
+ const char * oh_string; /* object descriptor string */
+ word oh_int; /* object descriptor integers */
+# ifdef NEED_CALLINFO
+ struct callinfo oh_ci[NFRAMES];
+# endif
+# ifndef SHORT_DBG_HDRS
+ word oh_sz; /* Original malloc arg. */
+ word oh_sf; /* start flag */
+# endif /* SHORT_DBG_HDRS */
} oh;
/* The size of the above structure is assumed not to de-align things, */
/* and to be a multiple of the word length. */
#ifdef SHORT_DBG_HDRS
-# define DEBUG_BYTES (sizeof (oh))
-# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
+# define DEBUG_BYTES (sizeof (oh))
+# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
#else
- /* Add space for END_FLAG, but use any extra space that was already */
- /* added to catch off-the-end pointers. */
- /* For uncollectable objects, the extra byte is not added. */
-# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
-# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
+ /* Add space for END_FLAG, but use any extra space that was already */
+ /* added to catch off-the-end pointers. */
+ /* For uncollectable objects, the extra byte is not added. */
+# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
+# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
#endif
/* Round bytes to words without adding extra byte at end. */
@@ -122,47 +126,41 @@ typedef struct {
/* PRINT_CALL_CHAIN prints the call chain stored in an object */
/* to stderr. It requires that we do not hold the lock. */
#if defined(SAVE_CALL_CHAIN)
- struct callinfo;
- GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
- GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
-# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
-# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
+ struct callinfo;
+ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
+ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
+# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
#elif defined(GC_ADD_CALLER)
- struct callinfo;
- GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
-# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
-# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
+ struct callinfo;
+ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
+# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
#else
-# define ADD_CALL_CHAIN(base, ra)
-# define PRINT_CALL_CHAIN(base)
+# define ADD_CALL_CHAIN(base, ra)
+# define PRINT_CALL_CHAIN(base)
#endif
-# ifdef GC_ADD_CALLER
-# define OPT_RA ra,
-# else
-# define OPT_RA
-# endif
-
+#ifdef GC_ADD_CALLER
+# define OPT_RA ra,
+#else
+# define OPT_RA
+#endif
/* Check whether object with base pointer p has debugging info */
/* p is assumed to point to a legitimate object in our part */
/* of the heap. */
#ifdef SHORT_DBG_HDRS
-# define GC_has_other_debug_info(p) TRUE
+# define GC_has_other_debug_info(p) 1
#else
- GC_INNER GC_bool GC_has_other_debug_info(ptr_t p);
+ GC_INNER int GC_has_other_debug_info(ptr_t p);
#endif
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
# define GC_HAS_DEBUG_INFO(p) \
- ((*((word *)p) & 1) && GC_has_other_debug_info(p))
+ ((*((word *)p) & 1) && GC_has_other_debug_info(p) > 0)
#else
-# define GC_HAS_DEBUG_INFO(p) GC_has_other_debug_info(p)
+# define GC_HAS_DEBUG_INFO(p) (GC_has_other_debug_info(p) > 0)
#endif
-/* Store debugging info into p. Return displaced pointer. */
-/* Assumes we don't hold allocation lock. */
-GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
- word integer);
-
#endif /* _DBG_MLC_H */
diff --git a/include/private/gc_hdrs.h b/include/private/gc_hdrs.h
index 777b016a..0360adbc 100644
--- a/include/private/gc_hdrs.h
+++ b/include/private/gc_hdrs.h
@@ -176,7 +176,6 @@ typedef struct bi {
register word hi = \
(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
- \
while (_bi -> key != hi && _bi != GC_all_nils) \
_bi = _bi -> hash_link; \
(bottom_indx) = _bi; \
@@ -184,8 +183,7 @@ typedef struct bi {
# define GET_HDR_ADDR(p, ha) \
{ \
register bottom_index * bi; \
- \
- GET_BI(p, bi); \
+ GET_BI(p, bi); \
(ha) = &(HDR_FROM_BI(bi, p)); \
}
# define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
diff --git a/include/private/gc_locks.h b/include/private/gc_locks.h
index 3b0d1c3a..113b4aea 100644
--- a/include/private/gc_locks.h
+++ b/include/private/gc_locks.h
@@ -52,6 +52,10 @@
# endif
# if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# define NOSERVICE
# include <windows.h>
# define NO_THREAD (DWORD)(-1)
GC_EXTERN DWORD GC_lock_holder;
@@ -64,8 +68,8 @@
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
LeaveCriticalSection(&GC_allocate_ml); }
# else
-# define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml);
-# define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
+# define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml)
+# define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
# define SET_LOCK_HOLDER() GC_lock_holder = GetCurrentThreadId()
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
@@ -95,20 +99,15 @@
# define THREAD_EQUAL(id1, id2) ((id1) == (id2))
# define NUMERIC_THREAD_ID_UNIQUE
# else
-# if defined(GC_WIN32_PTHREADS)
-# define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
- /* Using documented internal details of win32_pthread library. */
- /* Faster than pthread_equal(). Should not change with */
- /* future versions of win32_pthread library. */
-# define THREAD_EQUAL(id1, id2) ((id1.p == id2.p) && (id1.x == id2.x))
-# undef NUMERIC_THREAD_ID_UNIQUE
-# else
- /* Generic definitions that always work, but will result in */
- /* poor performance and weak assertion checking. */
-# define NUMERIC_THREAD_ID(id) 1l
-# define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
-# undef NUMERIC_THREAD_ID_UNIQUE
-# endif
+# define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
+ /* Using documented internal details of win32-pthread library. */
+ /* Faster than pthread_equal(). Should not change with */
+ /* future versions of win32-pthread library. */
+# define THREAD_EQUAL(id1, id2) ((id1.p == id2.p) && (id1.x == id2.x))
+# undef NUMERIC_THREAD_ID_UNIQUE
+ /* Generic definitions based on pthread_equal() always work but */
+ /* will result in poor performance (as NUMERIC_THREAD_ID is */
+ /* defined to just a constant) and weak assertion checking. */
# endif
# define NO_THREAD ((unsigned long)(-1l))
/* != NUMERIC_THREAD_ID(pthread_self()) for any thread */
@@ -125,18 +124,17 @@
/* GC_call_with_alloc_lock. */
# ifdef GC_ASSERTIONS
# define UNCOND_LOCK() \
- { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
- GC_lock(); \
- SET_LOCK_HOLDER(); }
+ { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
+ GC_lock(); \
+ SET_LOCK_HOLDER(); }
# define UNCOND_UNLOCK() \
- { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
- AO_CLEAR(&GC_allocate_lock); }
+ { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
+ AO_CLEAR(&GC_allocate_lock); }
# else
# define UNCOND_LOCK() \
- { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
- GC_lock(); }
-# define UNCOND_UNLOCK() \
- AO_CLEAR(&GC_allocate_lock)
+ { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
+ GC_lock(); }
+# define UNCOND_UNLOCK() AO_CLEAR(&GC_allocate_lock)
# endif /* !GC_ASSERTIONS */
# else /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
# ifndef USE_PTHREAD_LOCKS
@@ -147,18 +145,17 @@
# include <pthread.h>
GC_EXTERN pthread_mutex_t GC_allocate_ml;
# ifdef GC_ASSERTIONS
-# define UNCOND_LOCK() \
- { GC_lock(); \
- SET_LOCK_HOLDER(); }
+# define UNCOND_LOCK() { GC_lock(); SET_LOCK_HOLDER(); }
# define UNCOND_UNLOCK() \
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
pthread_mutex_unlock(&GC_allocate_ml); }
# else /* !GC_ASSERTIONS */
# if defined(NO_PTHREAD_TRYLOCK)
-# define UNCOND_LOCK() GC_lock();
+# define UNCOND_LOCK() GC_lock()
# else /* !defined(NO_PTHREAD_TRYLOCK) */
# define UNCOND_LOCK() \
- { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
+ { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \
+ GC_lock(); }
# endif
# define UNCOND_UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
@@ -201,8 +198,8 @@
#if defined(UNCOND_LOCK) && !defined(LOCK)
/* At least two thread running; need to lock. */
-# define LOCK() if (GC_need_to_lock) { UNCOND_LOCK(); }
-# define UNLOCK() if (GC_need_to_lock) { UNCOND_UNLOCK(); }
+# define LOCK() { if (GC_need_to_lock) UNCOND_LOCK(); }
+# define UNLOCK() { if (GC_need_to_lock) UNCOND_UNLOCK(); }
#endif
# ifndef ENTER_GC
diff --git a/include/private/gc_pmark.h b/include/private/gc_pmark.h
index c0232cc4..42fbb204 100644
--- a/include/private/gc_pmark.h
+++ b/include/private/gc_pmark.h
@@ -35,9 +35,6 @@
#endif
#ifndef GC_MARK_H
-# ifndef GC_H
-# define GC_I_HIDE_POINTERS /* to get GC_HIDE_POINTER() and friends */
-# endif
# include "../gc_mark.h"
#endif
@@ -136,7 +133,6 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
#define PUSH_OBJ(obj, hhdr, mark_stack_top, mark_stack_limit) \
{ \
register word _descr = (hhdr) -> hb_descr; \
- \
GC_ASSERT(!HBLK_IS_FREE(hhdr)); \
if (_descr != 0) { \
mark_stack_top++; \
@@ -156,17 +152,26 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
source, exit_label) \
{ \
hdr * my_hhdr; \
- \
HC_GET_HDR(current, my_hhdr, source, exit_label); \
PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
- source, exit_label, my_hhdr, TRUE); \
+ source, exit_label, my_hhdr, TRUE); \
exit_label: ; \
}
/* Set mark bit, exit if it was already set. */
-
-#ifdef USE_MARK_BITS
+#ifdef USE_MARK_BYTES
+ /* There is a race here, and we may set */
+ /* the bit twice in the concurrent case. This can result in the */
+ /* object being pushed twice. But that's only a performance issue. */
+# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
+ { \
+ char * mark_byte_addr = (char *)hhdr -> hb_marks + (bit_no); \
+ if (*mark_byte_addr) goto exit_label; \
+ *mark_byte_addr = 1; \
+ }
+#else
# ifdef PARALLEL_MARK
+ /* This is used only if we explicitly set USE_MARK_BITS. */
/* The following may fail to exit even if the bit was already set. */
/* For our uses, that's benign: */
# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
@@ -189,44 +194,16 @@ exit_label: ; \
# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
{ \
word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(bit_no); \
- \
OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(bit_no), \
exit_label); \
}
-#endif
-
-#if defined(I386) && defined(__GNUC__)
-# define LONG_MULT(hprod, lprod, x, y) { \
- asm("mull %2" : "=a"(lprod), "=d"(hprod) : "g"(y), "0"(x)); \
- }
-#else /* No in-line X86 assembly code */
-# define LONG_MULT(hprod, lprod, x, y) { \
- unsigned long long prod = (unsigned long long)x \
- * (unsigned long long)y; \
- hprod = prod >> 32; \
- lprod = (unsigned32)prod; \
- }
-#endif
-
-#ifdef USE_MARK_BYTES
- /* There is a race here, and we may set */
- /* the bit twice in the concurrent case. This can result in the */
- /* object being pushed twice. But that's only a performance issue. */
-# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
- { \
- char * mark_byte_addr = (char *)hhdr -> hb_marks + (bit_no); \
- char mark_byte = *mark_byte_addr; \
- \
- if (mark_byte) goto exit_label; \
- *mark_byte_addr = 1; \
- }
-#endif /* USE_MARK_BYTES */
+#endif /* !USE_MARK_BYTES */
#ifdef PARALLEL_MARK
# define INCR_MARKS(hhdr) \
- AO_store(&(hhdr -> hb_n_marks), AO_load(&(hhdr -> hb_n_marks))+1);
+ AO_store(&hhdr->hb_n_marks, AO_load(&hhdr->hb_n_marks) + 1)
#else
-# define INCR_MARKS(hhdr) ++(hhdr -> hb_n_marks)
+# define INCR_MARKS(hhdr) (void)(++hhdr->hb_n_marks)
#endif
#ifdef ENABLE_TRACE
@@ -239,6 +216,20 @@ exit_label: ; \
# define TRACE_TARGET(source, cmd)
#endif
+#if defined(I386) && defined(__GNUC__)
+# define LONG_MULT(hprod, lprod, x, y) { \
+ __asm__ __volatile__("mull %2" : "=a"(lprod), "=d"(hprod) \
+ : "g"(y), "0"(x)); \
+ }
+#else
+# define LONG_MULT(hprod, lprod, x, y) { \
+ unsigned long long prod = (unsigned long long)(x) \
+ * (unsigned long long)(y); \
+ hprod = prod >> 32; \
+ lprod = (unsigned32)prod; \
+ }
+#endif /* !I386 */
+
/* If the mark bit corresponding to current is not set, set it, and */
/* push the contents of the object on the mark stack. Current points */
/* to the beginning of the object. We rely on the fact that the */
@@ -257,16 +248,16 @@ exit_label: ; \
/* first block, then we are in the all_interior_pointers case, and */ \
/* it is safe to use any displacement value. */ \
size_t gran_displ = BYTES_TO_GRANULES(displ); \
- size_t gran_offset = hhdr -> hb_map[gran_displ]; \
+ size_t gran_offset = hhdr -> hb_map[gran_displ]; \
size_t byte_offset = displ & (GRANULE_BYTES - 1); \
- ptr_t base = current; \
+ ptr_t base = current; \
/* The following always fails for large block references. */ \
if (EXPECT((gran_offset | byte_offset) != 0, FALSE)) { \
if (hhdr -> hb_large_block) { \
/* gran_offset is bogus. */ \
size_t obj_displ; \
base = (ptr_t)(hhdr -> hb_block); \
- obj_displ = (ptr_t)(current) - base; \
+ obj_displ = (ptr_t)(current) - base; \
if (obj_displ != displ) { \
GC_ASSERT(obj_displ < hhdr -> hb_sz); \
/* Must be in all_interior_pointer case, not first block */ \
@@ -315,7 +306,7 @@ exit_label: ; \
size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
unsigned32 low_prod, high_prod; \
unsigned32 inv_sz = hhdr -> hb_inv_sz; \
- ptr_t base = current; \
+ ptr_t base = current; \
LONG_MULT(high_prod, low_prod, displ, inv_sz); \
/* product is > and within sz_in_bytes of displ * sz_in_bytes * 2**32 */ \
if (EXPECT(low_prod >> 16 != 0, FALSE)) { \
@@ -323,7 +314,7 @@ exit_label: ; \
if (inv_sz == LARGE_INV_SZ) { \
size_t obj_displ; \
base = (ptr_t)(hhdr -> hb_block); \
- obj_displ = (ptr_t)(current) - base; \
+ obj_displ = (ptr_t)(current) - base; \
if (obj_displ != displ) { \
GC_ASSERT(obj_displ < hhdr -> hb_sz); \
/* Must be in all_interior_pointer case, not first block */ \
@@ -358,8 +349,7 @@ exit_label: ; \
(unsigned)GC_gc_no)); \
TRACE_TARGET(base, \
GC_log_printf("GC:%u: marking %p from %p instead\n", \
- (unsigned)GC_gc_no, \
- base, source)); \
+ (unsigned)GC_gc_no, base, source)); \
INCR_MARKS(hhdr); \
GC_STORE_BACK_PTR((ptr_t)source, base); \
PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
@@ -385,20 +375,20 @@ exit_label: ; \
#if NEED_FIXUP_POINTER
/* Try both the raw version and the fixed up one. */
# define GC_PUSH_ONE_STACK(p, source) \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- PUSH_ONE_CHECKED_STACK(p, source); \
+ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
+ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
} \
FIXUP_POINTER(p); \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- PUSH_ONE_CHECKED_STACK(p, source); \
+ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
+ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
}
#else /* !NEED_FIXUP_POINTER */
# define GC_PUSH_ONE_STACK(p, source) \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- PUSH_ONE_CHECKED_STACK(p, source); \
+ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
+ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
}
#endif
@@ -409,9 +399,9 @@ exit_label: ; \
*/
#define GC_PUSH_ONE_HEAP(p,source) \
FIXUP_POINTER(p); \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- GC_mark_stack_top = GC_mark_and_push( \
+ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
+ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
+ GC_mark_stack_top = GC_mark_and_push( \
(void *)(p), GC_mark_stack_top, \
GC_mark_stack_limit, (void * *)(source)); \
}
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index 816bb0f0..d3d14ca3 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -29,7 +29,7 @@
#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
&& !defined(_GNU_SOURCE)
/* Can't test LINUX, since this must be defined before other includes. */
-# define _GNU_SOURCE
+# define _GNU_SOURCE 1
#endif
#if (defined(DGUX) && defined(GC_THREADS) || defined(DGUX386_THREADS) \
@@ -43,7 +43,6 @@
# endif
#ifndef GC_H
-# define GC_I_HIDE_POINTERS /* to get GC_HIDE_POINTER() and friends */
# include "../gc.h"
#endif
@@ -172,6 +171,8 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# include "gc_locks.h"
#endif
+#define ONES ((word)(signed_word)(-1))
+
# ifdef STACK_GROWS_DOWN
# define COOLER_THAN >
# define HOTTER_THAN <
@@ -310,51 +311,54 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/*********************************/
#ifdef BSD_TIME
-# undef CLOCK_TYPE
-# undef GET_TIME
-# undef MS_TIME_DIFF
-# define CLOCK_TYPE struct timeval
-# define GET_TIME(x) { struct rusage rusage; \
- getrusage (RUSAGE_SELF, &rusage); \
- x = rusage.ru_utime; }
-# define MS_TIME_DIFF(a,b) \
- ((unsigned long)((double) (a.tv_sec - b.tv_sec) * 1000.0 \
- + (double) (a.tv_usec - b.tv_usec) / 1000.0))
-#else /* !BSD_TIME */
-# if defined(MSWIN32) || defined(MSWINCE)
-# include <windows.h>
-# include <winbase.h>
-# define CLOCK_TYPE DWORD
-# define GET_TIME(x) x = GetTickCount()
-# define MS_TIME_DIFF(a,b) ((long)((a)-(b)))
-# else /* !MSWIN32, !MSWINCE, !BSD_TIME */
-# include <time.h>
-# if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
- clock_t clock(void); /* Not in time.h, where it belongs */
-# endif
-# if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
-# include <machine/limits.h>
-# define CLOCKS_PER_SEC CLK_TCK
-# endif
-# if !defined(CLOCKS_PER_SEC)
-# define CLOCKS_PER_SEC 1000000
-/*
- * This is technically a bug in the implementation. ANSI requires that
- * CLOCKS_PER_SEC be defined. But at least under SunOS4.1.1, it isn't.
- * Also note that the combination of ANSI C and POSIX is incredibly gross
- * here. The type clock_t is used by both clock() and times(). But on
- * some machines these use different notions of a clock tick, CLOCKS_PER_SEC
- * seems to apply only to clock. Hence we use it here. On many machines,
- * including SunOS, clock actually uses units of microseconds (which are
- * not really clock ticks).
- */
-# endif
-# define CLOCK_TYPE clock_t
-# define GET_TIME(x) x = clock()
-# define MS_TIME_DIFF(a,b) ((unsigned long) \
- (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC))
-# endif /* !MSWIN32 */
-#endif /* !BSD_TIME */
+# undef CLOCK_TYPE
+# undef GET_TIME
+# undef MS_TIME_DIFF
+# define CLOCK_TYPE struct timeval
+# define GET_TIME(x) { struct rusage rusage; \
+ getrusage (RUSAGE_SELF, &rusage); \
+ x = rusage.ru_utime; }
+# define MS_TIME_DIFF(a,b) ((unsigned long)(a.tv_sec - b.tv_sec) * 1000 \
+ + (unsigned long)(a.tv_usec - b.tv_usec) / 1000)
+#elif defined(MSWIN32) || defined(MSWINCE)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# define NOSERVICE
+# include <windows.h>
+# include <winbase.h>
+# define CLOCK_TYPE DWORD
+# define GET_TIME(x) x = GetTickCount()
+# define MS_TIME_DIFF(a,b) ((long)((a)-(b)))
+#else /* !MSWIN32, !MSWINCE, !BSD_TIME */
+# include <time.h>
+# if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
+ clock_t clock(void); /* Not in time.h, where it belongs */
+# endif
+# if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
+# include <machine/limits.h>
+# define CLOCKS_PER_SEC CLK_TCK
+# endif
+# if !defined(CLOCKS_PER_SEC)
+# define CLOCKS_PER_SEC 1000000
+ /* This is technically a bug in the implementation. */
+ /* ANSI requires that CLOCKS_PER_SEC be defined. But at least */
+ /* under SunOS 4.1.1, it isn't. Also note that the combination of */
+ /* ANSI C and POSIX is incredibly gross here. The type clock_t */
+ /* is used by both clock() and times(). But on some machines */
+ /* these use different notions of a clock tick, CLOCKS_PER_SEC */
+ /* seems to apply only to clock. Hence we use it here. On many */
+ /* machines, including SunOS, clock actually uses units of */
+ /* microseconds (which are not really clock ticks). */
+# endif
+# define CLOCK_TYPE clock_t
+# define GET_TIME(x) x = clock()
+# define MS_TIME_DIFF(a,b) (CLOCKS_PER_SEC % 1000 == 0 ? \
+ (unsigned long)((a) - (b)) / (unsigned long)(CLOCKS_PER_SEC / 1000) \
+ : ((unsigned long)((a) - (b)) * 1000) / (unsigned long)CLOCKS_PER_SEC)
+ /* Avoid using double type since some targets (like ARM) might */
+ /* require -lm option for double-to-long conversion. */
+#endif /* !BSD_TIME && !MSWIN32 */
/* We use bzero and bcopy internally. They may not be available. */
# if defined(SPARC) && defined(SUNOS4)
@@ -399,7 +403,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# define START_WORLD() \
PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null, \
PCR_allSigsBlocked, \
- PCR_waitForever);
+ PCR_waitForever)
# else
# if defined(GC_WIN32_THREADS) || defined(GC_PTHREADS)
GC_INNER void GC_stop_world(void);
@@ -427,7 +431,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# define DebugBreak() _exit(-1) /* there is no abort() in WinCE */
# endif
# ifdef SMALL_CONFIG
-# if defined(MSWIN32) || defined(MSWINCE)
+# if (defined(MSWIN32) && !defined(LINT2)) || defined(MSWINCE)
# define ABORT(msg) DebugBreak()
# else
# define ABORT(msg) abort()
@@ -579,7 +583,6 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
#define WORDSZ ((word)CPP_WORDSZ)
#define SIGNB ((word)1 << (WORDSZ-1))
#define BYTES_PER_WORD ((word)(sizeof (word)))
-#define ONES ((word)(signed_word)(-1))
#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */
#if GRANULE_BYTES == 8
@@ -768,17 +771,6 @@ typedef word page_hash_table[PHT_SIZE];
/* initial group of mark bits, and it is safe */
/* to allocate smaller header for large objects. */
-# ifdef USE_MARK_BYTES
-# define MARK_BITS_SZ (MARK_BITS_PER_HBLK + 1)
- /* Unlike the other case, this is in units of bytes. */
- /* Since we force doubleword alignment, we need at most one */
- /* mark bit per 2 words. But we do allocate and set one */
- /* extra mark bit to avoid an explicit check for the */
- /* partial object at the end of each block. */
-# else
-# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ + 1)
-# endif
-
#ifdef PARALLEL_MARK
# include "atomic_ops.h"
typedef AO_t counter_t;
@@ -787,7 +779,7 @@ typedef word page_hash_table[PHT_SIZE];
# if defined(THREADS) && defined(MPROTECT_VDB)
# include "atomic_ops.h"
# endif
-#endif
+#endif /* !PARALLEL_MARK */
/* We maintain layout maps for heap blocks containing objects of a given */
/* size. Each entry in this map describes a byte offset and has the */
@@ -860,6 +852,12 @@ struct hblkhdr {
/* Without parallel marking, the count */
/* is accurate. */
# ifdef USE_MARK_BYTES
+# define MARK_BITS_SZ (MARK_BITS_PER_HBLK + 1)
+ /* Unlike the other case, this is in units of bytes. */
+ /* Since we force double-word alignment, we need at most one */
+ /* mark bit per 2 words. But we do allocate and set one */
+ /* extra mark bit to avoid an explicit check for the */
+ /* partial object at the end of each block. */
union {
char _hb_marks[MARK_BITS_SZ];
/* The i'th byte is 1 if the object */
@@ -872,6 +870,7 @@ struct hblkhdr {
} _mark_byte_union;
# define hb_marks _mark_byte_union._hb_marks
# else
+# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ + 1)
word hb_marks[MARK_BITS_SZ];
# endif /* !USE_MARK_BYTES */
};
@@ -953,7 +952,7 @@ struct roots {
# else
# define MAX_HEAP_SECTS 768 /* Separately added heap sections. */
# endif
-# elif defined(SMALL_CONFIG)
+# elif defined(SMALL_CONFIG) && !defined(USE_PROC_FOR_LIBRARIES)
# define MAX_HEAP_SECTS 128 /* Roughly 256MB (128*2048*1K) */
# elif CPP_WORDSZ > 32
# define MAX_HEAP_SECTS 1024 /* Roughly 8GB */
@@ -1268,8 +1267,10 @@ GC_EXTERN word GC_page_size;
#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
struct _SYSTEM_INFO;
GC_EXTERN struct _SYSTEM_INFO GC_sysinfo;
+ GC_INNER GC_bool GC_is_heap_base(ptr_t p);
#endif
+
GC_EXTERN word GC_black_list_spacing;
/* Average number of bytes between blacklisted */
/* blocks. Approximate. */
@@ -1335,15 +1336,6 @@ struct GC_traced_stack_sect_s {
/* with it. Only those corresponding to the beginning of an */
/* object are used. */
-/* Set mark bit correctly, even if mark bits may be concurrently */
-/* accessed. */
-#ifdef PARALLEL_MARK
-# define OR_WORD(addr, bits) \
- { AO_or((volatile AO_t *)(addr), (AO_t)bits); }
-#else
-# define OR_WORD(addr, bits) *(addr) |= (bits)
-#endif
-
/* Mark bit operations */
/*
@@ -1355,16 +1347,23 @@ struct GC_traced_stack_sect_s {
#ifdef USE_MARK_BYTES
# define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n])
-# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n]) = 1
-# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n]) = 0
-#else /* !USE_MARK_BYTES */
-# define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \
- >> (modWORDSZ(n))) & (word)1)
+# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n] = 1)
+# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n] = 0)
+#else
+/* Set mark bit correctly, even if mark bits may be concurrently */
+/* accessed. */
+# ifdef PARALLEL_MARK
+ /* This is used only if we explicitly set USE_MARK_BITS. */
+# define OR_WORD(addr, bits) AO_or((volatile AO_t *)(addr), (AO_t)(bits))
+# else
+# define OR_WORD(addr, bits) (void)(*(addr) |= (bits))
+# endif
+# define mark_bit_from_hdr(hhdr,n) \
+ (((hhdr)->hb_marks[divWORDSZ(n)] >> modWORDSZ(n)) & (word)1)
# define set_mark_bit_from_hdr(hhdr,n) \
- OR_WORD((hhdr)->hb_marks+divWORDSZ(n), \
- (word)1 << modWORDSZ(n))
-# define clear_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \
- &= ~((word)1 << modWORDSZ(n))
+ OR_WORD((hhdr)->hb_marks+divWORDSZ(n), (word)1 << modWORDSZ(n))
+# define clear_mark_bit_from_hdr(hhdr,n) \
+ ((hhdr)->hb_marks[divWORDSZ(n)] &= ~((word)1 << modWORDSZ(n)))
#endif /* !USE_MARK_BYTES */
#ifdef MARK_BIT_PER_OBJ
@@ -1381,8 +1380,8 @@ struct GC_traced_stack_sect_s {
# define MARK_BIT_OFFSET(sz) BYTES_TO_GRANULES(sz)
# define IF_PER_OBJ(x)
# define FINAL_MARK_BIT(sz) \
- ((sz) > MAXOBJBYTES? MARK_BITS_PER_HBLK \
- : BYTES_TO_GRANULES((sz) * HBLK_OBJS(sz)))
+ ((sz) > MAXOBJBYTES ? MARK_BITS_PER_HBLK \
+ : BYTES_TO_GRANULES((sz) * HBLK_OBJS(sz)))
#endif
/* Important internal collector routines */
@@ -1628,7 +1627,7 @@ GC_INNER void GC_freehblk(struct hblk * p);
/* Misc GC: */
GC_INNER GC_bool GC_expand_hp_inner(word n);
-GC_INNER void GC_start_reclaim(int abort_if_found);
+GC_INNER void GC_start_reclaim(GC_bool abort_if_found);
/* Restore unmarked objects to free */
/* lists, or (if abort_if_found is */
/* TRUE) report them. */
@@ -1709,6 +1708,12 @@ GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
GC_INNER void * GC_clear_stack(void *);
/* in misc.c, behaves like identity. */
+#ifdef GC_ADD_CALLER
+# define GC_DBG_RA GC_RETURN_ADDR,
+#else
+# define GC_DBG_RA /* empty */
+#endif
+
/* We make the GC_clear_stack() call a tail one, hoping to get more of */
/* the stack. */
#define GENERAL_MALLOC(lb,k) \
@@ -1786,9 +1791,18 @@ GC_EXTERN void (*GC_print_heap_obj)(ptr_t p);
/* Print an address map of the process. */
#endif
+#ifndef SHORT_DBG_HDRS
+ GC_EXTERN GC_bool GC_findleak_delay_free;
+ /* Do not immediately deallocate object on */
+ /* free() in the leak-finding mode, just mark */
+ /* it as freed (and deallocate it after GC). */
+ GC_INNER GC_bool GC_check_leaked(ptr_t base); /* from dbg_mlc.c */
+#endif
+
GC_EXTERN GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
/* Call error printing routine */
- /* occasionally. */
+ /* occasionally. It is ok to read it */
+ /* without acquiring the lock. */
#ifndef SMALL_CONFIG
/* GC_print_stats should be visible outside the GC in some cases. */
@@ -1804,9 +1818,9 @@ GC_EXTERN GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
#ifndef NO_DEBUGGING
GC_EXTERN GC_bool GC_dump_regularly;
/* Generate regular debugging dumps. */
-# define COND_DUMP if (GC_dump_regularly) GC_dump();
+# define COND_DUMP if (GC_dump_regularly) GC_dump()
#else
-# define COND_DUMP
+# define COND_DUMP /* empty */
#endif
#ifdef KEEP_BACK_PTRS
@@ -1915,7 +1929,7 @@ void GC_print_static_roots(void);
#endif
/* Make arguments appear live to compiler */
-#if defined(__BORLANDC__) || defined(__WATCOMC__)
+#if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__CC_ARM)
void GC_noop(void*, ...);
#else
# ifdef __DMC__
@@ -1951,12 +1965,6 @@ void GC_err_puts(const char *s);
/* Write s to stderr, don't buffer, don't add */
/* newlines, don't ... */
-#if defined(LINUX) && !defined(SMALL_CONFIG)
- GC_INNER void GC_err_write(const char *buf, size_t len);
- /* Write buf to stderr, don't buffer, don't add */
- /* newlines, don't ... */
-#endif
-
GC_EXTERN unsigned GC_fail_count;
/* How many consecutive GC/expansion failures? */
/* Reset by GC_allochblk(); defined in alloc.c. */
@@ -2003,18 +2011,121 @@ GC_EXTERN signed_word GC_bytes_found;
#ifdef THREAD_LOCAL_ALLOC
GC_EXTERN GC_bool GC_world_stopped; /* defined in alloc.c */
+ GC_INNER void GC_mark_thread_local_free_lists(void);
#endif
#ifdef GC_GCJ_SUPPORT
- GC_EXTERN GC_bool GC_gcj_malloc_initialized; /* defined in gcj_mlc.c */
+# ifdef GC_ASSERTIONS
+ GC_EXTERN GC_bool GC_gcj_malloc_initialized; /* defined in gcj_mlc.c */
+# endif
GC_EXTERN ptr_t * GC_gcjobjfreelist;
#endif
+#if defined(GWW_VDB) && defined(MPROTECT_VDB)
+ GC_INNER GC_bool GC_gww_dirty_init(void);
+ /* Defined in os_dep.c. Returns TRUE if GetWriteWatch is available. */
+ /* May be called repeatedly. */
+#endif
+
+#if defined(CHECKSUMS) || defined(PROC_VDB)
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h);
+ /* Could the page contain valid heap pointers? */
+#endif
+
+GC_INNER void GC_default_print_heap_obj_proc(ptr_t p);
+
+GC_INNER void GC_extend_size_map(size_t); /* in misc.c */
+
+GC_INNER void GC_setpagesize(void);
+
+GC_INNER void GC_initialize_offsets(void); /* defined in obj_map.c */
+
+GC_INNER void GC_bl_init(void);
+GC_INNER void GC_bl_init_no_interiors(void); /* defined in blacklst.c */
+
+GC_INNER void GC_start_debugging(void); /* defined in dbg_mlc.c */
+
+/* Store debugging info into p. Return displaced pointer. */
+/* Assumes we don't hold allocation lock. */
+GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
+ int linenum);
+
+#ifdef REDIRECT_MALLOC
+# ifdef GC_LINUX_THREADS
+ GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp);
+ /* from os_dep.c */
+# endif
+#elif defined(MSWIN32) || defined(MSWINCE)
+ GC_INNER void GC_add_current_malloc_heap(void);
+#endif /* !REDIRECT_MALLOC */
+
+#ifdef MAKE_BACK_GRAPH
+ GC_INNER void GC_build_back_graph(void);
+ GC_INNER void GC_traverse_back_graph(void);
+#endif
+
+#ifdef MSWIN32
+ GC_INNER void GC_init_win32(void);
+#endif
+
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ GC_INNER void * GC_roots_present(ptr_t);
+ /* The type is a lie, since the real type doesn't make sense here, */
+ /* and we only test for NULL. */
+#endif
+
+#ifdef GC_WIN32_THREADS
+ GC_INNER void GC_get_next_stack(char *start, char * limit, char **lo,
+ char **hi);
+# ifdef MPROTECT_VDB
+ GC_INNER void GC_set_write_fault_handler(void);
+# endif
+#endif /* GC_WIN32_THREADS */
+
+#ifdef THREADS
+ GC_INNER void GC_reset_finalizer_nested(void);
+ GC_INNER unsigned char *GC_check_finalizer_nested(void);
+ GC_INNER void GC_do_blocking_inner(ptr_t data, void * context);
+ GC_INNER void GC_push_all_stacks(void);
+# ifdef USE_PROC_FOR_LIBRARIES
+ GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi);
+# endif
+# ifdef IA64
+ GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound);
+# endif
+#endif /* THREADS */
+
+#ifdef DYNAMIC_LOADING
+ GC_INNER GC_bool GC_register_main_static_data(void);
+# ifdef DARWIN
+ GC_INNER void GC_init_dyld(void);
+# endif
+#endif /* DYNAMIC_LOADING */
+
+#ifdef SEARCH_FOR_DATA_START
+ GC_INNER void GC_init_linux_data_start(void);
+#endif
+
+#if defined(NETBSD) && defined(__ELF__)
+ GC_INNER void GC_init_netbsd_elf(void);
+#endif
+
+#ifdef UNIX_LIKE
+ GC_INNER void GC_set_and_save_fault_handler(void (*handler)(int));
+#endif
+
+#ifdef NEED_PROC_MAPS
+ GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
+ char **prot, unsigned int *maj_dev,
+ char **mapping_name);
+ GC_INNER char *GC_get_maps(void); /* from os_dep.c */
+#endif
+
#ifdef GC_ASSERTIONS
# define GC_ASSERT(expr) \
if (!(expr)) { \
- GC_err_printf("Assertion failure: %s:%ld\n", \
- __FILE__, (unsigned long)__LINE__); \
+ GC_err_printf("Assertion failure: %s:%d\n", \
+ __FILE__, __LINE__); \
ABORT("assertion failure"); \
}
#else
@@ -2096,13 +2207,17 @@ GC_EXTERN signed_word GC_bytes_found;
# endif
#endif /* GC_PTHREADS && !SIG_SUSPEND */
+#if defined(GC_PTHREADS) && !defined(GC_SEM_INIT_PSHARED)
+# define GC_SEM_INIT_PSHARED 0
+#endif
+
/* Some macros for setjmp that works across signal handlers */
/* were possible, and a couple of routines to facilitate */
/* catching accesses to bad addresses when that's */
/* possible/needed. */
#if defined(UNIX_LIKE) || (defined(NEED_FIND_LIMIT) && defined(CYGWIN32))
# include <setjmp.h>
-# if defined(SUNOS5SIGS) && !defined(FREEBSD)
+# if defined(SUNOS5SIGS) && !defined(FREEBSD) && !defined(LINUX)
# include <sys/siginfo.h>
# endif
/* Define SETJMP and friends to be the version that restores */
diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h
index e914391b..81aa4b52 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -54,8 +54,8 @@
# endif
/* And one for FreeBSD: */
-# if (defined(__FreeBSD__) || defined(__DragonFly__) || \
- defined(__FreeBSD_kernel__)) && !defined(FREEBSD)
+# if (defined(__FreeBSD__) || defined(__DragonFly__) \
+ || defined(__FreeBSD_kernel__)) && !defined(FREEBSD)
# define FREEBSD
# endif
@@ -70,7 +70,7 @@
# define I386
# define mach_type_known
# endif
-# if defined(__arm__) || defined(__thumb__)
+# if defined(__arm) || defined(__arm__) || defined(__thumb__)
# define ARM32
# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) \
&& !defined(DARWIN) && !defined(_WIN32) && !defined(__CEGCC__)
@@ -186,8 +186,8 @@
# define mach_type_known
# endif
# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
- && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__) \
- && !defined(__DragonFly__)
+ && !defined(__OpenBSD__) && !defined(__NetBSD__) \
+ && !defined(__FreeBSD__) && !defined(__DragonFly__)
# define SPARC
# define DRSNX
# define mach_type_known
@@ -250,7 +250,7 @@
# define IA64
# define mach_type_known
# endif
-# if defined(LINUX) && defined(__arm__)
+# if defined(LINUX) && (defined(__arm) || defined(__arm__))
# define ARM32
# define mach_type_known
# endif
@@ -260,12 +260,8 @@
# 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__))
+# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) \
+ || defined(powerpc64) || defined(__powerpc64__))
# define POWERPC
# define mach_type_known
# endif
@@ -277,10 +273,6 @@
# define SPARC
# define mach_type_known
# endif
-# if defined(LINUX) && defined(__arm__)
-# define ARM32
-# define mach_type_known
-# endif
# if defined(LINUX) && defined(__sh__)
# define SH
# define mach_type_known
@@ -293,9 +285,14 @@
# define M32R
# define mach_type_known
# endif
+# if defined(FREEBSD) && (defined(powerpc) || defined(__powerpc__))
+# define POWERPC
+# define mach_type_known
+# endif
# if defined(__alpha) || defined(__alpha__)
# define ALPHA
-# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) && !defined(FREEBSD)
+# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) \
+ && !defined(FREEBSD)
# define OSF1 /* a.k.a Digital Unix */
# endif
# define mach_type_known
@@ -338,6 +335,11 @@
# define DARWIN_DONT_PARSE_STACK
# endif
# endif
+# if defined(__rtems__) && (defined(i386) || defined(__i386__))
+# define I386
+# define RTEMS
+# define mach_type_known
+# endif
# if defined(NeXT) && defined(mc68000)
# define M68K
# define NEXT
@@ -669,11 +671,10 @@
* allocation.
*/
-/* If we are using a recent version of gcc, we can use __builtin_unwind_init()
- * to push the relevant registers onto the stack.
- */
-# if defined(__GNUC__) && ((__GNUC__ >= 3) || \
- (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
+/* If we are using a recent version of gcc, we can use */
+/* __builtin_unwind_init() to push the relevant registers onto the stack. */
+# if defined(__GNUC__) && ((__GNUC__ >= 3) \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
&& !defined(__INTEL_COMPILER) && !defined(__PATHCC__)
# define HAVE_BUILTIN_UNWIND_INIT
# endif
@@ -750,7 +751,7 @@
# include <LowMem.h>
# endif
# define OS_TYPE "MACOS"
- /* see os_dep.c for details of global data segments. */
+ /* see os_dep.c for details of global data segments. */
# define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
# define DATAEND /* not needed */
# define GETPAGESIZE() 4096
@@ -810,8 +811,8 @@
# define ALIGNMENT 4
# define STACKBOTTOM ((ptr_t) 0xc0000000)
# endif
- /* XXX: see get_end(3), get_etext() and get_end() should not be used.
- These aren't used when dyld support is enabled (it is by default) */
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used. */
+ /* These aren't used when dyld support is enabled (it is by default). */
# define DATASTART ((ptr_t) get_etext())
# define DATAEND ((ptr_t) get_end())
# ifndef USE_MMAP
@@ -828,8 +829,8 @@
# define PREFETCH_FOR_WRITE(x) \
__asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
# endif
- /* There seems to be some issues with trylock hanging on darwin. This
- should be looked into some more */
+ /* There seems to be some issues with trylock hanging on darwin. */
+ /* This should be looked into some more. */
# define NO_PTHREAD_TRYLOCK
# endif
# ifdef OPENBSD
@@ -877,7 +878,6 @@
# define ALIGNMENT 4
# define OS_TYPE "NETBSD"
# define HEURISTIC2
- extern char etext[];
extern ptr_t GC_data_start;
# define DATASTART GC_data_start
# define DYNAMIC_LOADING
@@ -1128,6 +1128,9 @@
# ifdef SOLARIS25_PROC_VDB_BUG_FIXED
# define PROC_VDB
# endif
+# ifndef GC_THREADS
+# define MPROTECT_VDB
+# endif
# define DYNAMIC_LOADING
# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
# define USE_MMAP
@@ -1247,26 +1250,26 @@
# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
# endif
# ifdef USE_I686_PREFETCH
- /* FIXME: Thus should use __builtin_prefetch, but we'll leave that */
- /* for the next rtelease. */
+ /* FIXME: Thus should use __builtin_prefetch, but we'll leave that */
+ /* for the next rtelease. */
# define PREFETCH(x) \
- __asm__ __volatile__ (" prefetchnta %0": : "m"(*(char *)(x)))
- /* Empirically prefetcht0 is much more effective at reducing */
- /* cache miss stalls for the targeted load instructions. But it */
- /* seems to interfere enough with other cache traffic that the net */
- /* result is worse than prefetchnta. */
-# if 0
- /* Using prefetches for write seems to have a slight negative */
- /* impact on performance, at least for a PIII/500. */
+ __asm__ __volatile__ ("prefetchnta %0" : : "m"(*(char *)(x)))
+ /* Empirically prefetcht0 is much more effective at reducing */
+ /* cache miss stalls for the targeted load instructions. But it */
+ /* seems to interfere enough with other cache traffic that the */
+ /* net result is worse than prefetchnta. */
+# ifdef FORCE_WRITE_PREFETCH
+ /* Using prefetches for write seems to have a slight negative */
+ /* impact on performance, at least for a PIII/500. */
# define PREFETCH_FOR_WRITE(x) \
- __asm__ __volatile__ (" prefetcht0 %0": : "m"(*(char *)(x)))
+ __asm__ __volatile__ ("prefetcht0 %0" : : "m"(*(char *)(x)))
# endif
# endif
# ifdef USE_3DNOW_PREFETCH
# define PREFETCH(x) \
- __asm__ __volatile__ (" prefetch %0": : "m"(*(char *)(x)))
+ __asm__ __volatile__ ("prefetch %0" : : "m"(*(char *)(x)))
# define PREFETCH_FOR_WRITE(x) \
- __asm__ __volatile__ (" prefetchw %0": : "m"(*(char *)(x)))
+ __asm__ __volatile__ ("prefetchw %0" : : "m"(*(char *)(x)))
# endif
# endif
# ifdef CYGWIN32
@@ -1306,8 +1309,7 @@
extern int _stklen;
extern int __djgpp_stack_limit;
# define DATASTART ((ptr_t)((((word) (etext)) + 0x1ff) & ~0x1ff))
-/* # define STACKBOTTOM ((ptr_t)((word) _stubinfo + _stubinfo->size \
- + _stklen)) */
+/* #define STACKBOTTOM ((ptr_t)((word)_stubinfo+_stubinfo->size+_stklen)) */
# define STACKBOTTOM ((ptr_t)((word) __djgpp_stack_limit + _stklen))
/* This may not be right. */
# endif
@@ -1373,14 +1375,24 @@
# define STACKBOTTOM ((ptr_t)0xc0000000)
# define DATAEND /* not needed */
# endif
+# ifdef RTEMS
+# define OS_TYPE "RTEMS"
+# include <sys/unistd.h>
+ extern int etext[];
+ extern int end[];
+ extern void *InitStackBottom;
+# define DATASTART ((ptr_t)etext)
+# define DATAEND ((ptr_t)end)
+# define STACKBOTTOM ((ptr_t)InitStackBottom)
+# endif
# ifdef DOS4GW
# define OS_TYPE "DOS4GW"
extern long __nullarea;
extern char _end;
extern char *_STACKTOP;
- /* Depending on calling conventions Watcom C either precedes
- or does not precedes with underscore names of C-variables.
- Make sure startup code variables always have the same names. */
+ /* Depending on calling conventions Watcom C either precedes */
+ /* or does not precedes with underscore names of C-variables. */
+ /* Make sure startup code variables always have the same names. */
#pragma aux __nullarea "*";
#pragma aux _end "*";
# define STACKBOTTOM ((ptr_t) _STACKTOP)
@@ -1404,8 +1416,8 @@
# define OS_TYPE "DARWIN"
# define DARWIN_DONT_PARSE_STACK
# define DYNAMIC_LOADING
- /* XXX: see get_end(3), get_etext() and get_end() should not be used.
- These aren't used when dyld support is enabled (it is by default) */
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used. */
+ /* These aren't used when dyld support is enabled (it is by default). */
# define DATASTART ((ptr_t) get_etext())
# define DATAEND ((ptr_t) get_end())
# define STACKBOTTOM ((ptr_t) 0xc0000000)
@@ -1416,8 +1428,8 @@
# define MPROTECT_VDB
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
- /* There seems to be some issues with trylock hanging on darwin. This
- should be looked into some more */
+ /* There seems to be some issues with trylock hanging on darwin. */
+ /* This should be looked into some more. */
# define NO_PTHREAD_TRYLOCK
# endif /* DARWIN */
# endif
@@ -1516,7 +1528,6 @@
# define ALIGNMENT 4
# define HEURISTIC2
# ifdef __ELF__
- extern int etext[];
extern ptr_t GC_data_start;
# define DATASTART GC_data_start
# define NEED_FIND_LIMIT
@@ -1563,22 +1574,15 @@
# define ALIGNMENT 4
# endif
# if !defined(GC_HPUX_THREADS) && !defined(GC_LINUX_THREADS) \
- && !defined(OPENBSD)
-# ifndef LINUX /* For now. */
-# define MPROTECT_VDB
-# endif
-# else
-# ifdef PARALLEL_MARK
-# define USE_MARK_BYTES
- /* Minimize compare-and-swap usage. */
-# endif
+ && !defined(OPENBSD) && !defined(LINUX) /* For now. */
+# define MPROTECT_VDB
# endif
# define STACK_GROWS_UP
# ifdef HPUX
# define OS_TYPE "HPUX"
extern int __data_start[];
# define DATASTART ((ptr_t)(__data_start))
-# if 0
+# ifdef USE_HPUX_FIXED_STACKBOTTOM
/* The following appears to work for 7xx systems running HP/UX */
/* 9.xx Furthermore, it might result in much faster */
/* collections than HEURISTIC2, which may involve scanning */
@@ -1729,7 +1733,7 @@
# define ALIGNMENT 4
# else
# ifndef _LP64
- ---> unknown ABI
+# error --> unknown ABI
# endif
# define CPP_WORDSZ 64
/* Requires 16 byte alignment for malloc */
@@ -2124,8 +2128,8 @@
# define OS_TYPE "DARWIN"
# define DARWIN_DONT_PARSE_STACK
# define DYNAMIC_LOADING
- /* XXX: see get_end(3), get_etext() and get_end() should not be used.
- These aren't used when dyld support is enabled (it is by default) */
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used. */
+ /* These aren't used when dyld support is enabled (it is by default) */
# define DATASTART ((ptr_t) get_etext())
# define DATAEND ((ptr_t) get_end())
# define STACKBOTTOM ((ptr_t) 0x7fff5fc00000)
@@ -2136,8 +2140,8 @@
# define MPROTECT_VDB
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
- /* There seems to be some issues with trylock hanging on darwin. This
- should be looked into some more */
+ /* There seems to be some issues with trylock hanging on darwin. */
+ /* This should be looked into some more. */
# define NO_PTHREAD_TRYLOCK
# endif
# ifdef FREEBSD
@@ -2165,12 +2169,14 @@
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
+# define HEURISTIC2
# ifdef __ELF__
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
# define DYNAMIC_LOADING
+# else
+# define SEARCH_FOR_DATA_START
# endif
-# define HEURISTIC2
- extern char etext[];
-# define SEARCH_FOR_DATA_START
# endif
# ifdef SOLARIS
# define OS_TYPE "SOLARIS"
@@ -2200,6 +2206,9 @@
# ifdef SOLARIS25_PROC_VDB_BUG_FIXED
# define PROC_VDB
# endif
+# ifndef GC_THREADS
+# define MPROTECT_VDB
+# endif
# define DYNAMIC_LOADING
# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
# define USE_MMAP
@@ -2244,7 +2253,8 @@
# define USE_MMAP_ANON
#endif
-#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
+#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
+ && !defined(USE_PROC_FOR_LIBRARIES)
/* Nptl allocates thread stacks with mmap, which is fine. But it */
/* keeps a cache of thread stacks. Thread stacks contain the */
/* thread control blocks. These in turn contain a pointer to */
@@ -2270,354 +2280,387 @@
# define USE_PROC_FOR_LIBRARIES
#endif
-# ifndef STACK_GROWS_UP
-# define STACK_GROWS_DOWN
-# endif
+#ifndef STACK_GROWS_UP
+# define STACK_GROWS_DOWN
+#endif
-# ifndef CPP_WORDSZ
-# define CPP_WORDSZ 32
-# endif
+#ifndef CPP_WORDSZ
+# define CPP_WORDSZ 32
+#endif
-# ifndef OS_TYPE
-# define OS_TYPE ""
-# endif
+#ifndef OS_TYPE
+# define OS_TYPE ""
+#endif
-# ifndef DATAEND
- extern int end[];
-# define DATAEND (ptr_t)(end)
-# endif
+#ifndef DATAEND
+ extern int end[];
+# define DATAEND (ptr_t)(end)
+#endif
-# if defined(SVR4) && !defined(GETPAGESIZE)
-# include <unistd.h>
-# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
-# endif
+#if (defined(SVR4) || defined(PLATFORM_ANDROID)) && !defined(GETPAGESIZE)
+# include <unistd.h>
+# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
+#endif
-# ifndef GETPAGESIZE
-# if defined(SOLARIS) || defined(IRIX5) || defined(LINUX) \
- || defined(NETBSD) || defined(FREEBSD) || defined(HPUX)
-# include <unistd.h>
-# endif
-# define GETPAGESIZE() getpagesize()
+#ifndef GETPAGESIZE
+# if defined(SOLARIS) || defined(IRIX5) || defined(LINUX) \
+ || defined(NETBSD) || defined(FREEBSD) || defined(HPUX)
+# include <unistd.h>
# endif
+# define GETPAGESIZE() getpagesize()
+#endif
-# if defined(SOLARIS) || defined(DRSNX) || defined(UTS4)
- /* OS has SVR4 generic features. */
- /* Probably others also qualify. */
-# define SVR4
-# endif
+#if defined(SOLARIS) || defined(DRSNX) || defined(UTS4)
+ /* OS has SVR4 generic features. */
+ /* Probably others also qualify. */
+# define SVR4
+#endif
-# if defined(SOLARIS) || defined(DRSNX)
- /* OS has SOLARIS style semi-undocumented interface */
- /* to dynamic loader. */
-# define SOLARISDL
- /* OS has SOLARIS style signal handlers. */
-# define SUNOS5SIGS
-# endif
+#if defined(SOLARIS) || defined(DRSNX)
+ /* OS has SOLARIS style semi-undocumented interface */
+ /* to dynamic loader. */
+# define SOLARISDL
+ /* OS has SOLARIS style signal handlers. */
+# define SUNOS5SIGS
+#endif
-# if defined(HPUX)
-# define SUNOS5SIGS
-# endif
+#if defined(HPUX)
+# define SUNOS5SIGS
+#endif
-# if defined(FREEBSD) && \
- (defined(__DragonFly__) || __FreeBSD__ >= 4 || (__FreeBSD_kernel__ >= 4))
-# define SUNOS5SIGS
-# endif
+#if defined(FREEBSD) && (defined(__DragonFly__) || __FreeBSD__ >= 4 \
+ || (__FreeBSD_kernel__ >= 4))
+# define SUNOS5SIGS
+#endif
-# ifdef GC_NETBSD_THREADS
-# define SIGRTMIN 33
-# define SIGRTMAX 63
-# endif
+#if !defined(GC_EXPLICIT_SIGNALS_UNBLOCK) && defined(SUNOS5SIGS) \
+ && !defined(GC_NO_PTHREAD_SIGMASK)
+# define GC_EXPLICIT_SIGNALS_UNBLOCK
+#endif
-# if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
- || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
- || defined(DGUX) || defined(BSD) || defined(HURD) \
- || defined(AIX) || defined(DARWIN) || defined(OSF1)
-# define UNIX_LIKE /* Basic Unix-like system calls work. */
-# endif
+#ifdef GC_NETBSD_THREADS
+# define SIGRTMIN 33
+# define SIGRTMAX 63
+#endif
-# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
- -> bad word size
-# endif
+#if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
+ || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
+ || defined(DGUX) || defined(BSD) || defined(HURD) \
+ || defined(AIX) || defined(DARWIN) || defined(OSF1)
+# define UNIX_LIKE /* Basic Unix-like system calls work. */
+#endif
-# ifndef ALIGNMENT
- --> undefined ALIGNMENT
-# endif
+#if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
+# error --> bad word size
+#endif
-# ifdef PCR
-# undef DYNAMIC_LOADING
-# undef STACKBOTTOM
-# undef HEURISTIC1
-# undef HEURISTIC2
-# undef PROC_VDB
-# undef MPROTECT_VDB
-# define PCR_VDB
-# endif
+#ifndef ALIGNMENT
+# error --> undefined ALIGNMENT
+#endif
-# if !defined(STACKBOTTOM) && (defined(ECOS) || defined(NOSYS))
-# error --> undefined STACKBOTTOM
-# endif
+#ifdef PCR
+# undef DYNAMIC_LOADING
+# undef STACKBOTTOM
+# undef HEURISTIC1
+# undef HEURISTIC2
+# undef PROC_VDB
+# undef MPROTECT_VDB
+# define PCR_VDB
+#endif
-# ifdef IGNORE_DYNAMIC_LOADING
-# undef DYNAMIC_LOADING
-# endif
+#if !defined(STACKBOTTOM) && (defined(ECOS) || defined(NOSYS))
+# error --> undefined STACKBOTTOM
+#endif
-# if defined(SMALL_CONFIG) && !defined(GC_DISABLE_INCREMENTAL)
- /* Presumably not worth the space it takes. */
-# define GC_DISABLE_INCREMENTAL
-# endif
+#ifdef IGNORE_DYNAMIC_LOADING
+# undef DYNAMIC_LOADING
+#endif
-# ifdef GC_DISABLE_INCREMENTAL
-# undef GWW_VDB
-# undef MPROTECT_VDB
-# undef PCR_VDB
-# undef PROC_VDB
-# undef CHECKSUMS
-# endif
+#if defined(SMALL_CONFIG) && !defined(GC_DISABLE_INCREMENTAL)
+ /* Presumably not worth the space it takes. */
+# define GC_DISABLE_INCREMENTAL
+#endif
-# ifdef USE_GLOBAL_ALLOC
- /* Cannot pass MEM_WRITE_WATCH to GlobalAlloc(). */
-# undef GWW_VDB
-# endif
+#if defined(GC_DISABLE_INCREMENTAL) || defined(MANUAL_VDB)
+# undef GWW_VDB
+# undef MPROTECT_VDB
+# undef PCR_VDB
+# undef PROC_VDB
+#endif
-# ifdef USE_MUNMAP
- /* FIXME: Remove this undef if possible. */
-# undef MPROTECT_VDB /* Can't deal with address space holes. */
-# endif
+#ifdef GC_DISABLE_INCREMENTAL
+# undef CHECKSUMS
+#endif
+
+#ifdef USE_GLOBAL_ALLOC
+ /* Cannot pass MEM_WRITE_WATCH to GlobalAlloc(). */
+# undef GWW_VDB
+#endif
+
+#ifdef USE_MUNMAP
+ /* FIXME: Remove this undef if possible. */
+# undef MPROTECT_VDB /* Can't deal with address space holes. */
+#endif
/* PARALLEL_MARK does not cause undef MPROTECT_VDB any longer. */
-# if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB)
- /* Choose MPROTECT_VDB manually (if multiple strategies available). */
-# undef PCR_VDB
-# undef PROC_VDB
- /* #undef GWW_VDB - handled in os_dep.c */
-# endif
+#if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB)
+ /* Choose MPROTECT_VDB manually (if multiple strategies available). */
+# undef PCR_VDB
+# undef PROC_VDB
+ /* #undef GWW_VDB - handled in os_dep.c */
+#endif
-# if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) \
- && !defined(GWW_VDB) && !defined(GC_DISABLE_INCREMENTAL)
-# define DEFAULT_VDB
-# endif
+#ifdef PROC_VDB
+ /* Multi-VDB mode is not implemented. */
+# undef MPROTECT_VDB
+#endif
-# ifndef PREFETCH
-# define PREFETCH(x)
-# define NO_PREFETCH
-# endif
+#if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) \
+ && !defined(GWW_VDB) && !defined(MANUAL_VDB) \
+ && !defined(GC_DISABLE_INCREMENTAL)
+# define DEFAULT_VDB
+#endif
-# ifndef PREFETCH_FOR_WRITE
-# define PREFETCH_FOR_WRITE(x)
-# define NO_PREFETCH_FOR_WRITE
-# endif
+#if ((defined(UNIX_LIKE) && (defined(DARWIN) || defined(HURD) \
+ || defined(OPENBSD) || defined(ARM32) \
+ || defined(MIPS) || defined(AVR32))) \
+ || (defined(LINUX) && (defined(SPARC) || defined(M68K))) \
+ || (defined(RTEMS) && defined(I386))) && !defined(NO_GETCONTEXT)
+# define NO_GETCONTEXT
+#endif
-# ifndef CACHE_LINE_SIZE
-# define CACHE_LINE_SIZE 32 /* Wild guess */
-# endif
+#ifndef PREFETCH
+# define PREFETCH(x)
+# define NO_PREFETCH
+#endif
-# ifndef STATIC
-# ifndef NO_DEBUGGING
-# define STATIC /* ignore to aid profiling and possibly debugging */
-# else
-# define STATIC static
-# endif
-# endif
+#ifndef PREFETCH_FOR_WRITE
+# define PREFETCH_FOR_WRITE(x)
+# define NO_PREFETCH_FOR_WRITE
+#endif
-# if defined(LINUX) || defined(HURD) || defined(__GLIBC__)
-# define REGISTER_LIBRARIES_EARLY
- /* We sometimes use dl_iterate_phdr, which may acquire an internal */
- /* lock. This isn't safe after the world has stopped. So we must */
- /* call GC_register_dynamic_libraries before stopping the world. */
- /* For performance reasons, this may be beneficial on other */
- /* platforms as well, though it should be avoided in win32. */
-# endif /* LINUX */
+#ifndef CACHE_LINE_SIZE
+# define CACHE_LINE_SIZE 32 /* Wild guess */
+#endif
-# if defined(SEARCH_FOR_DATA_START)
- extern ptr_t GC_data_start;
-# define DATASTART GC_data_start
+#ifndef STATIC
+# ifndef NO_DEBUGGING
+# define STATIC /* ignore to aid profiling and possibly debugging */
+# else
+# define STATIC static
# endif
+#endif
-# ifndef CLEAR_DOUBLE
-# define CLEAR_DOUBLE(x) \
- ((word*)x)[0] = 0; \
- ((word*)x)[1] = 0;
-# endif /* CLEAR_DOUBLE */
+#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) \
+ || !defined(SMALL_CONFIG))
+# define NEED_PROC_MAPS
+#endif
-# if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
- && !defined(INCLUDE_LINUX_THREAD_DESCR)
- /* Will not work, since libc and the dynamic loader use thread */
- /* locals, sometimes as the only reference. */
-# define INCLUDE_LINUX_THREAD_DESCR
-# endif
+#if defined(LINUX) || defined(HURD) || defined(__GLIBC__)
+# define REGISTER_LIBRARIES_EARLY
+ /* We sometimes use dl_iterate_phdr, which may acquire an internal */
+ /* lock. This isn't safe after the world has stopped. So we must */
+ /* call GC_register_dynamic_libraries before stopping the world. */
+ /* For performance reasons, this may be beneficial on other */
+ /* platforms as well, though it should be avoided in win32. */
+#endif /* LINUX */
+
+#if defined(SEARCH_FOR_DATA_START)
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+#endif
-# if defined(GC_IRIX_THREADS) && !defined(IRIX5)
- --> inconsistent configuration
-# endif
-# if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL)
- --> inconsistent configuration
-# endif
-# if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
- --> inconsistent configuration
-# endif
-# if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD)
- --> inconsistent configuration
-# endif
-# if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS)
- --> inconsistent configuration
-# endif
-# if defined(GC_HPUX_THREADS) && !defined(HPUX)
- --> inconsistent configuration
-# endif
-# if defined(GC_AIX_THREADS) && !defined(_AIX)
- --> inconsistent configuration
-# endif
-# if defined(GC_GNU_THREADS) && !defined(HURD)
- --> inconsistent configuration
-# endif
-# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32) \
- && !defined(MSWINCE)
- --> inconsistent configuration
-# endif
+#ifndef CLEAR_DOUBLE
+# define CLEAR_DOUBLE(x) (((word*)(x))[0] = 0, ((word*)(x))[1] = 0)
+#endif
-# if defined(PCR) || defined(GC_WIN32_THREADS) || defined(GC_PTHREADS) \
- || defined(SN_TARGET_PS3)
-# define THREADS
-# endif
+#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
+ && !defined(INCLUDE_LINUX_THREAD_DESCR)
+ /* Will not work, since libc and the dynamic loader use thread */
+ /* locals, sometimes as the only reference. */
+# define INCLUDE_LINUX_THREAD_DESCR
+#endif
-# if defined(UNIX_LIKE) && defined(THREADS) && !defined(NO_CANCEL_SAFE) \
- && !defined(PLATFORM_ANDROID)
- /* Make the code cancellation-safe. This basically means that we */
- /* ensure that cancellation requests are ignored while we are in */
- /* the collector. This applies only to Posix deferred cancellation;*/
- /* we don't handle Posix asynchronous cancellation. */
- /* Note that this only works if pthread_setcancelstate is */
- /* async-signal-safe, at least in the absence of asynchronous */
- /* cancellation. This appears to be true for the glibc version, */
- /* though it is not documented. Without that assumption, there */
- /* seems to be no way to safely wait in a signal handler, which */
- /* we need to do for thread suspension. */
- /* Also note that little other code appears to be cancellation-safe.*/
- /* Hence it may make sense to turn this off for performance. */
-# define CANCEL_SAFE
-# endif
+#if defined(GC_IRIX_THREADS) && !defined(IRIX5)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_HPUX_THREADS) && !defined(HPUX)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_AIX_THREADS) && !defined(_AIX)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_GNU_THREADS) && !defined(HURD)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32) \
+ && !defined(MSWINCE)
+# error --> inconsistent configuration
+#endif
-# ifdef CANCEL_SAFE
-# define IF_CANCEL(x) x
-# else
-# define IF_CANCEL(x)
-# endif
+#if defined(PCR) || defined(GC_WIN32_THREADS) || defined(GC_PTHREADS) \
+ || defined(SN_TARGET_PS3)
+# define THREADS
+#endif
-# if !defined(USE_MARK_BITS) && !defined(USE_MARK_BYTES)
-# if defined(THREADS) && defined(PARALLEL_MARK)
-# define USE_MARK_BYTES
-# else
-# define USE_MARK_BITS
-# endif
-# endif
+#if defined(UNIX_LIKE) && defined(THREADS) && !defined(NO_CANCEL_SAFE) \
+ && !defined(PLATFORM_ANDROID)
+ /* Make the code cancellation-safe. This basically means that we */
+ /* ensure that cancellation requests are ignored while we are in */
+ /* the collector. This applies only to Posix deferred cancellation; */
+ /* we don't handle Posix asynchronous cancellation. */
+ /* Note that this only works if pthread_setcancelstate is */
+ /* async-signal-safe, at least in the absence of asynchronous */
+ /* cancellation. This appears to be true for the glibc version, */
+ /* though it is not documented. Without that assumption, there */
+ /* seems to be no way to safely wait in a signal handler, which */
+ /* we need to do for thread suspension. */
+ /* Also note that little other code appears to be cancellation-safe. */
+ /* Hence it may make sense to turn this off for performance. */
+# define CANCEL_SAFE
+#endif
-# if defined(MSWINCE) && !defined(__CEGCC__) && !defined(NO_GETENV)
-# define NO_GETENV
-# endif
+#ifdef CANCEL_SAFE
+# define IF_CANCEL(x) x
+#else
+# define IF_CANCEL(x) /* empty */
+#endif
-# if (defined(NO_GETENV) || defined(MSWINCE)) && !defined(NO_GETENV_WIN32)
-# define NO_GETENV_WIN32
-# endif
+#if !defined(USE_MARK_BITS) && !defined(USE_MARK_BYTES) \
+ && defined(PARALLEL_MARK)
+ /* Minimize compare-and-swap usage. */
+# define USE_MARK_BYTES
+#endif
-# ifndef STRTOULL
-# if defined(_WIN64) && !defined(__GNUC__)
-# define STRTOULL _strtoui64
-# elif defined(_LLP64) || defined(__LLP64__) || defined(_WIN64)
-# define STRTOULL strtoull
-# else
- /* strtoul() fits since sizeof(long) >= sizeof(word). */
-# define STRTOULL strtoul
-# endif
+#if defined(MSWINCE) && !defined(__CEGCC__) && !defined(NO_GETENV)
+# define NO_GETENV
+#endif
+
+#if (defined(NO_GETENV) || defined(MSWINCE)) && !defined(NO_GETENV_WIN32)
+# define NO_GETENV_WIN32
+#endif
+
+#ifndef STRTOULL
+# if defined(_WIN64) && !defined(__GNUC__)
+# define STRTOULL _strtoui64
+# elif defined(_LLP64) || defined(__LLP64__) || defined(_WIN64)
+# define STRTOULL strtoull
+# else
+ /* strtoul() fits since sizeof(long) >= sizeof(word). */
+# define STRTOULL strtoul
# endif
+#endif /* !STRTOULL */
-# if defined(SPARC)
-# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */
- /* include assembly code to do it well. */
+#ifndef GC_WORD_C
+# if defined(_WIN64) && !defined(__GNUC__)
+# define GC_WORD_C(val) val##ui64
+# elif defined(_LLP64) || defined(__LLP64__) || defined(_WIN64)
+# define GC_WORD_C(val) val##ULL
+# else
+# define GC_WORD_C(val) ((word)val##UL)
# endif
+#endif /* !GC_WORD_C */
- /* Can we save call chain in objects for debugging? */
- /* SET NFRAMES (# of saved frames) and NARGS (#of args for each */
- /* frame) to reasonable values for the platform. */
- /* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */
- /* at build time, though we feel free to adjust it slightly. */
- /* Define NEED_CALLINFO if we either save the call stack or */
- /* GC_ADD_CALLER is defined. */
- /* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */
+#if defined(SPARC)
+# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */
+ /* include assembly code to do it well. */
+#endif
+/* Can we save call chain in objects for debugging? */
+/* SET NFRAMES (# of saved frames) and NARGS (#of args for each */
+/* frame) to reasonable values for the platform. */
+/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */
+/* at build time, though we feel free to adjust it slightly. */
+/* Define NEED_CALLINFO if we either save the call stack or */
+/* GC_ADD_CALLER is defined. */
+/* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */
#if defined(SPARC)
# define CAN_SAVE_CALL_ARGS
#endif
-#if (defined(I386) || defined(X86_64)) && (defined(LINUX) || defined(__GLIBC__))
- /* SAVE_CALL_CHAIN is supported if the code is compiled to save */
- /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
+#if (defined(I386) || defined(X86_64)) \
+ && (defined(LINUX) || defined(__GLIBC__))
+ /* SAVE_CALL_CHAIN is supported if the code is compiled to save */
+ /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
# define CAN_SAVE_CALL_ARGS
#endif
-# if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
- && defined(GC_CAN_SAVE_CALL_STACKS)
-# define SAVE_CALL_CHAIN
-# endif
-# ifdef SAVE_CALL_CHAIN
-# if defined(SAVE_CALL_NARGS) && defined(CAN_SAVE_CALL_ARGS)
-# define NARGS SAVE_CALL_NARGS
-# else
-# define NARGS 0 /* Number of arguments to save for each call. */
-# endif
-# endif
-# ifdef SAVE_CALL_CHAIN
-# ifndef SAVE_CALL_COUNT
-# define NFRAMES 6 /* Number of frames to save. Even for */
- /* alignment reasons. */
-# else
-# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
-# endif
-# define NEED_CALLINFO
-# endif /* SAVE_CALL_CHAIN */
-# ifdef GC_ADD_CALLER
-# define NFRAMES 1
-# define NARGS 0
-# define NEED_CALLINFO
+#if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
+ && defined(GC_CAN_SAVE_CALL_STACKS)
+# define SAVE_CALL_CHAIN
+#endif
+#ifdef SAVE_CALL_CHAIN
+# if defined(SAVE_CALL_NARGS) && defined(CAN_SAVE_CALL_ARGS)
+# define NARGS SAVE_CALL_NARGS
+# else
+# define NARGS 0 /* Number of arguments to save for each call. */
# endif
+#endif
+#ifdef SAVE_CALL_CHAIN
+# ifndef SAVE_CALL_COUNT
+# define NFRAMES 6 /* Number of frames to save. Even for */
+ /* alignment reasons. */
+# else
+# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
+# endif
+# define NEED_CALLINFO
+#endif /* SAVE_CALL_CHAIN */
+#ifdef GC_ADD_CALLER
+# define NFRAMES 1
+# define NARGS 0
+# define NEED_CALLINFO
+#endif
-# if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL)
-# define DBG_HDRS_ALL
-# endif
+#if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL)
+# define DBG_HDRS_ALL
+#endif
-# if defined(POINTER_MASK) && !defined(POINTER_SHIFT)
-# define POINTER_SHIFT 0
-# endif
+#if defined(POINTER_MASK) && !defined(POINTER_SHIFT)
+# define POINTER_SHIFT 0
+#endif
-# if defined(POINTER_SHIFT) && !defined(POINTER_MASK)
-# define POINTER_MASK ((GC_word)(-1))
-# endif
+#if defined(POINTER_SHIFT) && !defined(POINTER_MASK)
+# define POINTER_MASK ((GC_word)(-1))
+#endif
-# if !defined(FIXUP_POINTER) && defined(POINTER_MASK)
-# define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT)
-# endif
+#if !defined(FIXUP_POINTER) && defined(POINTER_MASK)
+# define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT)
+#endif
-# if defined(FIXUP_POINTER)
-# define NEED_FIXUP_POINTER 1
-# else
-# define NEED_FIXUP_POINTER 0
-# define FIXUP_POINTER(p)
-# endif
+#if defined(FIXUP_POINTER)
+# define NEED_FIXUP_POINTER 1
+#else
+# define NEED_FIXUP_POINTER 0
+# define FIXUP_POINTER(p)
+#endif
-# if !defined(MARK_BIT_PER_GRANULE) && !defined(MARK_BIT_PER_OBJ)
-# define MARK_BIT_PER_GRANULE /* Usually faster */
-# endif
+#if !defined(MARK_BIT_PER_GRANULE) && !defined(MARK_BIT_PER_OBJ)
+# define MARK_BIT_PER_GRANULE /* Usually faster */
+#endif
/* Some static sanity tests. */
-# if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ)
-# error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ.
-# endif
+#if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ)
+# error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ.
+#endif
-# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
-# error "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
-# endif
-# if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
-# error "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
-# endif
+#if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
+# error "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
+#endif
+#if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
+# error "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
+#endif
# if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX)
// FIXME: no idea if this is really true!
@@ -2643,18 +2686,19 @@
struct hblk; /* See gc_priv.h. */
# if defined(PCR)
char * real_malloc(size_t bytes);
-# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
+# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)(bytes) + GC_page_size) \
+ GC_page_size-1)
# elif defined(OS2)
void * os2_alloc(size_t bytes);
-# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
- + GC_page_size) \
- + GC_page_size-1)
-# elif defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) || \
- (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
- (defined(SOLARIS) && !defined(USE_MMAP))
-# define GET_MEM(bytes) HBLKPTR((size_t) calloc(1, (size_t)bytes + GC_page_size) \
- + GC_page_size-1)
+# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)(bytes) \
+ + GC_page_size) + GC_page_size-1)
+# elif defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) \
+ || (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) \
+ || (defined(SOLARIS) && !defined(USE_MMAP)) || defined(RTEMS) \
+ || defined(__CC_ARM)
+# define GET_MEM(bytes) HBLKPTR((size_t)calloc(1, \
+ (size_t)(bytes) + GC_page_size) \
+ + GC_page_size - 1)
# elif defined(MSWIN32) || defined(CYGWIN32)
ptr_t GC_win32_get_mem(GC_word bytes);
# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
@@ -2662,10 +2706,10 @@
# if defined(USE_TEMPORARY_MEMORY)
Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory);
# define GET_MEM(bytes) HBLKPTR( \
- GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
- + GC_page_size-1)
+ GC_MacTemporaryNewPtr((bytes) + GC_page_size, true) \
+ + GC_page_size-1)
# else
-# define GET_MEM(bytes) HBLKPTR(NewPtrClear(bytes + GC_page_size) \
+# define GET_MEM(bytes) HBLKPTR(NewPtrClear((bytes) + GC_page_size) \
+ GC_page_size-1)
# endif
# elif defined(MSWINCE)
@@ -2674,7 +2718,7 @@
# elif defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
void *GC_amiga_get_mem(size_t size);
# define GET_MEM(bytes) HBLKPTR((size_t) \
- GC_amiga_get_mem((size_t)bytes + GC_page_size) \
+ GC_amiga_get_mem((size_t)(bytes) + GC_page_size) \
+ GC_page_size-1)
# elif defined(SN_TARGET_PS3)
void *ps3_get_mem(size_t size);
diff --git a/include/private/pthread_stop_world.h b/include/private/pthread_stop_world.h
index c883c3c8..cb67d230 100644
--- a/include/private/pthread_stop_world.h
+++ b/include/private/pthread_stop_world.h
@@ -39,4 +39,6 @@ struct thread_stop_info {
# endif
};
+GC_INNER void GC_stop_init(void);
+
#endif
diff --git a/include/private/pthread_support.h b/include/private/pthread_support.h
index 73fa8fee..ba0f6936 100644
--- a/include/private/pthread_support.h
+++ b/include/private/pthread_support.h
@@ -30,7 +30,7 @@
#ifdef THREAD_LOCAL_ALLOC
# include "thread_local_alloc.h"
-#endif /* THREAD_LOCAL_ALLOC */
+#endif
/* We use the allocation lock to protect thread-related data structures. */
@@ -53,7 +53,7 @@ typedef struct GC_Thread_Rep {
struct thread_stop_info stop_info;
unsigned char flags;
-# define FINISHED 1 /* Thread has exited. */
+# define FINISHED 1 /* Thread has exited. */
# define DETACHED 2 /* Thread is treated as detached. */
/* Thread may really be detached, or */
/* it may have have been explicitly */
@@ -62,7 +62,10 @@ typedef struct GC_Thread_Rep {
/* it unregisters itself, since it */
/* may not return a GC pointer. */
# define MAIN_THREAD 4 /* True for the original thread only. */
-# define DISABLED_GC 8 /* Collections are disabled while the */
+# define SUSPENDED_EXT 8 /* Thread was suspended externally */
+ /* (this is not used by the unmodified */
+ /* GC itself at present). */
+# define DISABLED_GC 0x10 /* Collections are disabled while the */
/* thread is exiting. */
unsigned char thread_blocked;
@@ -123,9 +126,20 @@ GC_EXTERN GC_bool GC_in_thread_creation;
/* Only set to TRUE while allocation lock is held. */
/* When set, it is OK to run GC from unknown thread. */
-# ifdef NACL
- GC_EXTERN __thread GC_thread GC_nacl_gc_thread_self;
-# endif
+#ifdef NACL
+ GC_EXTERN __thread GC_thread GC_nacl_gc_thread_self;
+ GC_INNER void GC_nacl_initialize_gc_thread(void);
+ GC_INNER void GC_nacl_shutdown_gc_thread(void);
+#endif
+
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ GC_INNER void GC_unblock_gc_signals(void);
+#endif
+
+GC_INNER GC_thread GC_start_rtn_prepare_thread(void *(**pstart)(void *),
+ void **pstart_arg,
+ struct GC_stack_base *sb, void *arg);
+GC_INNER void GC_thread_exit_proc(void *);
#endif /* GC_PTHREADS && !GC_WIN32_THREADS */
diff --git a/include/private/specific.h b/include/private/specific.h
index 372238dc..8b5cf847 100644
--- a/include/private/specific.h
+++ b/include/private/specific.h
@@ -51,8 +51,8 @@ typedef struct thread_specific_entry {
/* Return the "quick thread id". Default version. Assumes page size, */
/* or at least thread stack separation, is at least 4K. */
-/* Must be defined so that it never returns 0. (Page 0 can't really */
-/* be part of any stack, since that would make 0 a valid stack pointer.)*/
+/* Must be defined so that it never returns 0. (Page 0 can't really be */
+/* part of any stack, since that would make 0 a valid stack pointer.) */
#define quick_thread_id() (((unsigned long)GC_approx_sp()) >> 12)
#define INVALID_QTID ((unsigned long)0)
@@ -67,11 +67,9 @@ typedef struct thread_specific_data {
typedef tsd * PREFIXED(key_t);
-extern int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *));
-
-extern int PREFIXED(setspecific) (tsd * key, void * value);
-
-extern void PREFIXED(remove_specific) (tsd * key);
+int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *));
+int PREFIXED(setspecific) (tsd * key, void * value);
+void PREFIXED(remove_specific) (tsd * key);
/* An internal version of getspecific that assumes a cache miss. */
void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
@@ -80,7 +78,7 @@ void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
/* GC_INLINE is defined in gc_priv.h. */
GC_INLINE void * PREFIXED(getspecific) (tsd * key)
{
- long qtid = quick_thread_id();
+ unsigned long qtid = quick_thread_id();
unsigned hash_val = CACHE_HASH(qtid);
tse * volatile * entry_ptr = key -> cache + hash_val;
tse * entry = *entry_ptr; /* Must be loaded only once. */
diff --git a/include/private/thread_local_alloc.h b/include/private/thread_local_alloc.h
index ab14fdbf..55d8fd6e 100644
--- a/include/private/thread_local_alloc.h
+++ b/include/private/thread_local_alloc.h
@@ -24,107 +24,107 @@
#include "private/gc_priv.h"
-#if defined(THREAD_LOCAL_ALLOC)
+#ifdef THREAD_LOCAL_ALLOC
#include "gc_inline.h"
-# if defined(USE_HPUX_TLS)
-# error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
-# endif
+#if defined(USE_HPUX_TLS)
+# error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
+#endif
-# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) && \
- !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) && \
- !defined(USE_CUSTOM_SPECIFIC)
-# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
-# if defined(__GNUC__) /* Fixed for versions past 2.95? */ \
- || defined(MSWINCE)
-# define USE_WIN32_SPECIFIC
-# else
-# define USE_WIN32_COMPILER_TLS
-# endif /* !GNU */
-# elif defined(LINUX) && !defined(ARM32) && !defined(AVR32) && \
- (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >=3))
-# define USE_COMPILER_TLS
-# elif (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
- defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) || \
- defined(GC_NETBSD_THREADS)
-# define USE_PTHREAD_SPECIFIC
-# elif defined(GC_HPUX_THREADS)
-# ifdef __GNUC__
-# define USE_PTHREAD_SPECIFIC
- /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work. */
-# else
-# define USE_COMPILER_TLS
-# endif
+#if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) \
+ && !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) \
+ && !defined(USE_CUSTOM_SPECIFIC)
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+# if defined(__GNUC__) /* Fixed for versions past 2.95? */ \
+ || defined(MSWINCE)
+# define USE_WIN32_SPECIFIC
# else
-# define USE_CUSTOM_SPECIFIC /* Use our own. */
+# define USE_WIN32_COMPILER_TLS
+# endif /* !GNU */
+# elif defined(LINUX) && !defined(ARM32) && !defined(AVR32) \
+ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >=3))
+# define USE_COMPILER_TLS
+# elif defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) \
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) \
+ || defined(GC_NETBSD_THREADS)
+# define USE_PTHREAD_SPECIFIC
+# elif defined(GC_HPUX_THREADS)
+# ifdef __GNUC__
+# define USE_PTHREAD_SPECIFIC
+ /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work. */
+# else
+# define USE_COMPILER_TLS
# endif
+# else
+# define USE_CUSTOM_SPECIFIC /* Use our own. */
# endif
+#endif
-# include <stdlib.h>
+#include <stdlib.h>
/* One of these should be declared as the tlfs field in the */
/* structure pointed to by a GC_thread. */
typedef struct thread_local_freelists {
-# ifdef THREAD_LOCAL_ALLOC
- void * ptrfree_freelists[TINY_FREELISTS];
- void * normal_freelists[TINY_FREELISTS];
-# ifdef GC_GCJ_SUPPORT
- void * gcj_freelists[TINY_FREELISTS];
-# define ERROR_FL ((void *)(word)-1)
- /* Value used for gcj_freelist[-1]; allocation is */
- /* erroneous. */
-# endif
- /* Free lists contain either a pointer or a small count */
- /* reflecting the number of granules allocated at that */
- /* size. */
- /* 0 ==> thread-local allocation in use, free list */
- /* empty. */
- /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
- /* too few objects of this size have been */
- /* allocated by this thread. */
- /* >= HBLKSIZE => pointer to nonempty free list. */
- /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
- /* local alloc, equivalent to 0. */
-# define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
- /* Don't use local free lists for up to this much */
- /* allocation. */
-
-# endif
+ void * ptrfree_freelists[TINY_FREELISTS];
+ void * normal_freelists[TINY_FREELISTS];
+# ifdef GC_GCJ_SUPPORT
+ void * gcj_freelists[TINY_FREELISTS];
+# define ERROR_FL ((void *)(word)-1)
+ /* Value used for gcj_freelist[-1]; allocation is */
+ /* erroneous. */
+# endif
+ /* Free lists contain either a pointer or a small count */
+ /* reflecting the number of granules allocated at that */
+ /* size. */
+ /* 0 ==> thread-local allocation in use, free list */
+ /* empty. */
+ /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
+ /* too few objects of this size have been */
+ /* allocated by this thread. */
+ /* >= HBLKSIZE => pointer to nonempty free list. */
+ /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
+ /* local alloc, equivalent to 0. */
+# define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
+ /* Don't use local free lists for up to this much */
+ /* allocation. */
} *GC_tlfs;
-# if defined(USE_PTHREAD_SPECIFIC)
-# define GC_getspecific pthread_getspecific
-# define GC_setspecific pthread_setspecific
-# define GC_key_create pthread_key_create
-# define GC_remove_specific(key) /* No need for cleanup on exit. */
- typedef pthread_key_t GC_key_t;
-# elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
-# define GC_getspecific(x) (x)
-# define GC_setspecific(key, v) ((key) = (v), 0)
-# define GC_key_create(key, d) 0
-# define GC_remove_specific(key) /* No need for cleanup on exit. */
- typedef void * GC_key_t;
-# elif defined(USE_WIN32_SPECIFIC)
-# include <windows.h>
-# define GC_getspecific TlsGetValue
-# define GC_setspecific(key, v) !TlsSetValue(key, v)
+#if defined(USE_PTHREAD_SPECIFIC)
+# define GC_getspecific pthread_getspecific
+# define GC_setspecific pthread_setspecific
+# define GC_key_create pthread_key_create
+# define GC_remove_specific(key) /* No need for cleanup on exit. */
+ typedef pthread_key_t GC_key_t;
+#elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
+# define GC_getspecific(x) (x)
+# define GC_setspecific(key, v) ((key) = (v), 0)
+# define GC_key_create(key, d) 0
+# define GC_remove_specific(key) /* No need for cleanup on exit. */
+ typedef void * GC_key_t;
+#elif defined(USE_WIN32_SPECIFIC)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# define NOSERVICE
+# include <windows.h>
+# define GC_getspecific TlsGetValue
+# define GC_setspecific(key, v) !TlsSetValue(key, v)
/* We assume 0 == success, msft does the opposite. */
-# ifndef TLS_OUT_OF_INDEXES
- /* this is currently missing in WinCE */
-# define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
-# endif
-# define GC_key_create(key, d) \
- ((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
-# define GC_remove_specific(key) /* No need for cleanup on thread exit. */
- /* Need TlsFree on process exit/detach ? */
- typedef DWORD GC_key_t;
-# elif defined(USE_CUSTOM_SPECIFIC)
-# include "private/specific.h"
-# else
-# error implement me
+# ifndef TLS_OUT_OF_INDEXES
+ /* this is currently missing in WinCE */
+# define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
# endif
-
+# define GC_key_create(key, d) \
+ ((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
+# define GC_remove_specific(key) /* No need for cleanup on exit. */
+ /* Need TlsFree on process exit/detach? */
+ typedef DWORD GC_key_t;
+#elif defined(USE_CUSTOM_SPECIFIC)
+# include "private/specific.h"
+#else
+# error implement me
+#endif
/* Each thread structure must be initialized. */
/* This call must be made from the new thread. */
@@ -148,12 +148,9 @@ extern
__declspec(thread)
#endif
GC_key_t GC_thread_key;
-
-/* This is set up by the thread_local_alloc implementation. But the */
-/* thread support layer calls GC_remove_specific(GC_thread_key) */
-/* before a thread exits. */
-/* And the thread support layer makes sure that GC_thread_key is traced,*/
-/* if necessary. */
+/* This is set up by the thread_local_alloc implementation. No need */
+/* for cleanup on thread exit. But the thread support layer makes sure */
+/* that GC_thread_key is traced, if necessary. */
#endif /* THREAD_LOCAL_ALLOC */
diff --git a/mach_dep.c b/mach_dep.c
index 54697759..969947c2 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -17,7 +17,7 @@
#include <stdio.h>
#include <setjmp.h>
-#if defined(OS2) || defined(CX_UX)
+#if defined(OS2) || defined(CX_UX) || defined(__CC_ARM)
# define _setjmp(b) setjmp(b)
# define _longjmp(b,v) longjmp(b,v)
#endif
@@ -171,16 +171,6 @@ asm static void PushMacRegisters()
# undef HAVE_PUSH_REGS
#endif
-#if defined(UNIX_LIKE) && !defined(NO_GETCONTEXT) && \
- (defined(DARWIN) || defined(HURD) || defined(OPENBSD) \
- || defined(ARM32) || defined(MIPS) || defined(AVR32))
-# define NO_GETCONTEXT
-#endif
-
-#if defined(LINUX) && defined(SPARC) && !defined(NO_GETCONTEXT)
-# define NO_GETCONTEXT
-#endif
-
#if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
# include <signal.h>
# ifndef NO_GETCONTEXT
@@ -244,8 +234,9 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
/* subsumed by the getcontext() call. */
GC_save_regs_ret_val = GC_save_regs_in_stack();
# endif /* register windows. */
-# elif defined(HAVE_BUILTIN_UNWIND_INIT) && \
- !(defined(POWERPC) && defined(DARWIN))
+# elif defined(HAVE_BUILTIN_UNWIND_INIT) \
+ && !(defined(POWERPC) && defined(DARWIN)) \
+ && !(defined(I386) && defined(RTEMS))
/* This was suggested by Richard Henderson as the way to */
/* force callee-save registers and register windows onto */
/* the stack. */
@@ -267,8 +258,8 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
for (; (char *)i < lim; i++) {
*i = 0;
}
-# if defined(MSWIN32) || defined(MSWINCE) \
- || defined(UTS4) || defined(LINUX) || defined(EWS4800)
+# if defined(MSWIN32) || defined(MSWINCE) || defined(UTS4) \
+ || defined(LINUX) || defined(EWS4800) || defined(RTEMS)
(void) setjmp(regs);
# else
(void) _setjmp(regs);
diff --git a/malloc.c b/malloc.c
index f2cd7601..ec3881a9 100644
--- a/malloc.c
+++ b/malloc.c
@@ -17,11 +17,6 @@
#include <stdio.h>
#include <string.h>
-#ifndef MSWINCE
-# include <errno.h>
-#endif
-
-GC_INNER void GC_extend_size_map(size_t); /* in misc.c */
/* Allocate reclaim list for kind: */
/* Return TRUE on success */
@@ -232,65 +227,6 @@ GC_API void * GC_CALL GC_generic_malloc(size_t lb, int k)
}
}
-/* provide a version of strdup() that uses the collector to allocate the
- copy of the string */
-GC_API char * GC_CALL GC_strdup(const char *s)
-{
- char *copy;
- size_t lb;
- if (s == NULL) return NULL;
- lb = strlen(s) + 1;
- if ((copy = GC_malloc_atomic(lb)) == NULL) {
-# ifndef MSWINCE
- errno = ENOMEM;
-# endif
- return NULL;
- }
-# ifndef MSWINCE
- strcpy(copy, s);
-# else
- /* strcpy() is deprecated in WinCE */
- memcpy(copy, s, lb);
-# endif
- return copy;
-}
-
-GC_API char * GC_CALL GC_strndup(const char *str, size_t size)
-{
- char *copy;
- size_t len = strlen(str); /* str is expected to be non-NULL */
- if (len > size)
- len = size;
- copy = GC_malloc_atomic(len + 1);
- if (copy == NULL) {
-# ifndef MSWINCE
- errno = ENOMEM;
-# endif
- return NULL;
- }
- BCOPY(str, copy, len);
- copy[len] = '\0';
- return copy;
-}
-
-#ifdef GC_REQUIRE_WCSDUP
-# include <wchar.h> /* for wcslen() */
-
- GC_API wchar_t * GC_CALL GC_wcsdup(const wchar_t *str)
- {
- size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
- wchar_t *copy = GC_malloc_atomic(lb);
- if (copy == NULL) {
-# ifndef MSWINCE
- errno = ENOMEM;
-# endif
- return NULL;
- }
- BCOPY(str, copy, lb);
- return copy;
- }
-#endif /* GC_REQUIRE_WCSDUP */
-
/* Allocate lb bytes of composite (pointerful) data */
#ifdef THREAD_LOCAL_ALLOC
GC_INNER void * GC_core_malloc(size_t lb)
@@ -326,19 +262,70 @@ GC_API char * GC_CALL GC_strndup(const char *str, size_t size)
}
}
-# ifdef REDIRECT_MALLOC
+/* Allocate lb bytes of pointerful, traced, but not collectable data */
+GC_API void * GC_CALL GC_malloc_uncollectable(size_t lb)
+{
+ void *op;
+ void **opp;
+ size_t lg;
+ DCL_LOCK_STATE;
+
+ if( SMALL_OBJ(lb) ) {
+ if (EXTRA_BYTES != 0 && lb != 0) lb--;
+ /* We don't need the extra byte, since this won't be */
+ /* collected anyway. */
+ lg = GC_size_map[lb];
+ opp = &(GC_uobjfreelist[lg]);
+ LOCK();
+ if( (op = *opp) != 0 ) {
+ *opp = obj_link(op);
+ obj_link(op) = 0;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ /* Mark bit ws already set on free list. It will be */
+ /* cleared only temporarily during a collection, as a */
+ /* result of the normal free list mark bit clearing. */
+ GC_non_gc_bytes += GRANULES_TO_BYTES(lg);
+ UNLOCK();
+ } else {
+ UNLOCK();
+ op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
+ /* For small objects, the free lists are completely marked. */
+ }
+ GC_ASSERT(0 == op || GC_is_marked(op));
+ return((void *) op);
+ } else {
+ hdr * hhdr;
+
+ op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
+ if (0 == op) return(0);
+
+ GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0); /* large block */
+ hhdr = HDR(op);
+ /* We don't need the lock here, since we have an undisguised */
+ /* pointer. We do need to hold the lock while we adjust */
+ /* mark bits. */
+ LOCK();
+ set_mark_bit_from_hdr(hhdr, 0); /* Only object. */
+ GC_ASSERT(hhdr -> hb_n_marks == 0);
+ hhdr -> hb_n_marks = 1;
+ UNLOCK();
+ return((void *) op);
+ }
+}
+
+#ifdef REDIRECT_MALLOC
+
+# ifndef MSWINCE
+# include <errno.h>
+# endif
/* Avoid unnecessary nested procedure calls here, by #defining some */
/* malloc replacements. Otherwise we end up saving a */
/* meaningless return address in the object. It also speeds things up, */
/* but it is admittedly quite ugly. */
-# ifdef GC_ADD_CALLER
-# define RA GC_RETURN_ADDR,
-# else
-# define RA
-# endif
+
# define GC_debug_malloc_replacement(lb) \
- GC_debug_malloc(lb, RA "unknown", 0)
+ GC_debug_malloc(lb, GC_DBG_RA "unknown", 0)
#if 0
void * malloc(size_t lb)
@@ -365,12 +352,11 @@ void * malloc(size_t lb)
STATIC ptr_t GC_libpthread_end = 0;
STATIC ptr_t GC_libld_start = 0;
STATIC ptr_t GC_libld_end = 0;
- GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp);
- /* From os_dep.c */
STATIC void GC_init_lib_bounds(void)
{
if (GC_libpthread_start != 0) return;
+ GC_init(); /* if not called yet */
if (!GC_text_mapping("libpthread-",
&GC_libpthread_start, &GC_libpthread_end)) {
WARN("Failed to find libpthread.so text mapping: Expect crash\n", 0);
@@ -383,7 +369,7 @@ void * malloc(size_t lb)
WARN("Failed to find ld.so text mapping: Expect crash\n", 0);
}
}
-#endif
+#endif /* GC_LINUX_THREADS */
#if 0
void * calloc(size_t n, size_t lb)
@@ -400,7 +386,7 @@ void * calloc(size_t n, size_t lb)
GC_init_lib_bounds();
lib_bounds_set = TRUE;
}
- if (caller >= GC_libpthread_start && caller < GC_libpthread_end
+ if ((caller >= GC_libpthread_start && caller < GC_libpthread_end)
|| (caller >= GC_libld_start && caller < GC_libld_end))
return GC_malloc_uncollectable(n*lb);
/* The two ranges are actually usually adjacent, so there may */
@@ -413,7 +399,6 @@ void * calloc(size_t n, size_t lb)
#if 0
#ifndef strdup
-# include <string.h>
char *strdup(const char *s)
{
size_t lb = strlen(s) + 1;
@@ -433,7 +418,6 @@ void * calloc(size_t n, size_t lb)
#ifndef strndup
/* This is similar to strdup(). */
-# include <string.h>
char *strndup(const char *str, size_t size)
{
char *copy;
@@ -453,7 +437,7 @@ void * calloc(size_t n, size_t lb)
#undef GC_debug_malloc_replacement
-# endif /* REDIRECT_MALLOC */
+#endif /* REDIRECT_MALLOC */
/* Explicitly deallocate an object p. */
GC_API void GC_CALL GC_free(void * p)
diff --git a/mallocx.c b/mallocx.c
index e214bcfd..1c3fd4ab 100644
--- a/mallocx.c
+++ b/mallocx.c
@@ -24,6 +24,7 @@
*/
#include <stdio.h>
+#include <string.h>
#ifdef MSWINCE
# ifndef WIN32_LEAN_AND_MEAN
@@ -152,13 +153,9 @@ GC_API void * GC_CALL GC_realloc(void * p, size_t lb)
# ifdef REDIRECT_REALLOC
/* As with malloc, avoid two levels of extra calls here. */
-# ifdef GC_ADD_CALLER
-# define RA GC_RETURN_ADDR,
-# else
-# define RA
-# endif
+
# define GC_debug_realloc_replacement(p, lb) \
- GC_debug_realloc(p, lb, RA "unknown", 0)
+ GC_debug_realloc(p, lb, GC_DBG_RA "unknown", 0)
#if 0
void * realloc(void * p, size_t lb)
@@ -443,57 +440,6 @@ GC_API void * GC_CALL GC_malloc_many(size_t lb)
return result;
}
-/* Allocate lb bytes of pointerful, traced, but not collectable data */
-GC_API void * GC_CALL GC_malloc_uncollectable(size_t lb)
-{
- void *op;
- void **opp;
- size_t lg;
- DCL_LOCK_STATE;
-
- if( SMALL_OBJ(lb) ) {
- if (EXTRA_BYTES != 0 && lb != 0) lb--;
- /* We don't need the extra byte, since this won't be */
- /* collected anyway. */
- lg = GC_size_map[lb];
- opp = &(GC_uobjfreelist[lg]);
- LOCK();
- if( (op = *opp) != 0 ) {
- *opp = obj_link(op);
- obj_link(op) = 0;
- GC_bytes_allocd += GRANULES_TO_BYTES(lg);
- /* Mark bit ws already set on free list. It will be */
- /* cleared only temporarily during a collection, as a */
- /* result of the normal free list mark bit clearing. */
- GC_non_gc_bytes += GRANULES_TO_BYTES(lg);
- UNLOCK();
- } else {
- UNLOCK();
- op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
- /* For small objects, the free lists are completely marked. */
- }
- GC_ASSERT(0 == op || GC_is_marked(op));
- return((void *) op);
- } else {
- hdr * hhdr;
-
- op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
- if (0 == op) return(0);
-
- GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0); /* large block */
- hhdr = HDR(op);
- /* We don't need the lock here, since we have an undisguised */
- /* pointer. We do need to hold the lock while we adjust */
- /* mark bits. */
- LOCK();
- set_mark_bit_from_hdr(hhdr, 0); /* Only object. */
- GC_ASSERT(hhdr -> hb_n_marks == 0);
- hhdr -> hb_n_marks = 1;
- UNLOCK();
- return((void *) op);
- }
-}
-
/* Not well tested nor integrated. */
/* Debug version is tricky and currently missing. */
#include <limits.h>
@@ -600,3 +546,62 @@ GC_API int GC_CALL GC_posix_memalign(void **memptr, size_t align, size_t lb)
}
}
#endif /* ATOMIC_UNCOLLECTABLE */
+
+/* provide a version of strdup() that uses the collector to allocate the
+ copy of the string */
+GC_API char * GC_CALL GC_strdup(const char *s)
+{
+ char *copy;
+ size_t lb;
+ if (s == NULL) return NULL;
+ lb = strlen(s) + 1;
+ if ((copy = GC_malloc_atomic(lb)) == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+# ifndef MSWINCE
+ strcpy(copy, s);
+# else
+ /* strcpy() is deprecated in WinCE */
+ memcpy(copy, s, lb);
+# endif
+ return copy;
+}
+
+GC_API char * GC_CALL GC_strndup(const char *str, size_t size)
+{
+ char *copy;
+ size_t len = strlen(str); /* str is expected to be non-NULL */
+ if (len > size)
+ len = size;
+ copy = GC_malloc_atomic(len + 1);
+ if (copy == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(str, copy, len);
+ copy[len] = '\0';
+ return copy;
+}
+
+#ifdef GC_REQUIRE_WCSDUP
+# include <wchar.h> /* for wcslen() */
+
+ GC_API wchar_t * GC_CALL GC_wcsdup(const wchar_t *str)
+ {
+ size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
+ wchar_t *copy = GC_malloc_atomic(lb);
+ if (copy == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(str, copy, lb);
+ return copy;
+ }
+#endif /* GC_REQUIRE_WCSDUP */
diff --git a/mark.c b/mark.c
index e69d7dc2..9a34082d 100644
--- a/mark.c
+++ b/mark.c
@@ -24,7 +24,7 @@
/* We put this here to minimize the risk of inlining. */
/*VARARGS*/
-#if defined(__BORLANDC__) || defined(__WATCOMC__)
+#if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__CC_ARM)
/*ARGSUSED*/
void GC_noop(void *p, ...) {}
#else
@@ -36,11 +36,10 @@
#endif
/* Single argument version, robust against whole program analysis. */
+volatile word GC_noop_sink;
GC_API void GC_CALL GC_noop1(word x)
{
- static volatile word sink;
-
- sink = x;
+ GC_noop_sink = x;
}
/* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */
@@ -144,14 +143,8 @@ GC_INNER GC_bool GC_collection_in_progress(void)
GC_INNER void GC_clear_hdr_marks(hdr *hhdr)
{
size_t last_bit = FINAL_MARK_BIT(hhdr -> hb_sz);
-
-# ifdef USE_MARK_BYTES
- BZERO(hhdr -> hb_marks, MARK_BITS_SZ);
- hhdr -> hb_marks[last_bit] = 1;
-# else
- BZERO(hhdr -> hb_marks, MARK_BITS_SZ*sizeof(word));
- set_mark_bit_from_hdr(hhdr, last_bit);
-# endif
+ BZERO(hhdr -> hb_marks, sizeof(hhdr->hb_marks));
+ set_mark_bit_from_hdr(hhdr, last_bit);
hhdr -> hb_n_marks = 0;
}
@@ -272,7 +265,7 @@ GC_INNER void GC_initiate_gc(void)
if (GC_mark_state == MS_NONE) {
GC_mark_state = MS_PUSH_RESCUERS;
} else if (GC_mark_state != MS_INVALID) {
- ABORT("unexpected state");
+ ABORT("Unexpected state");
} /* else this is really a full collection, and mark */
/* bits are invalid. */
scan_ptr = 0;
@@ -576,8 +569,8 @@ static void alloc_mark_stack(size_t);
handle_ex:
/* Exception handler starts here for all cases. */
if (GC_print_stats) {
- GC_log_printf("Caught ACCESS_VIOLATION in marker. "
- "Memory mapping disappeared.\n");
+ GC_log_printf(
+ "Caught ACCESS_VIOLATION in marker; memory mapping disappeared\n");
}
/* We have bad roots on the stack. Discard mark stack. */
@@ -670,9 +663,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# ifdef ENABLE_TRACE
if (GC_trace_addr >= current_p
&& GC_trace_addr < current_p + descr) {
- GC_log_printf("GC:%u Large section; start %p len %lu\n",
- (unsigned)GC_gc_no, current_p,
- (unsigned long) descr);
+ GC_log_printf("GC:%u Large section; start %p len %lu\n",
+ (unsigned)GC_gc_no, current_p, (unsigned long)descr);
}
# endif /* ENABLE_TRACE */
# ifdef PARALLEL_MARK
@@ -688,9 +680,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# ifdef ENABLE_TRACE
if (GC_trace_addr >= current_p
&& GC_trace_addr < current_p + descr) {
- GC_log_printf("GC:%u splitting (parallel) %p at %p\n",
- (unsigned)GC_gc_no, current_p,
- current_p + new_size);
+ GC_log_printf("GC:%u Splitting (parallel) %p at %p\n",
+ (unsigned)GC_gc_no, current_p, current_p + new_size);
}
# endif /* ENABLE_TRACE */
current_p += new_size;
@@ -705,8 +696,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# ifdef ENABLE_TRACE
if (GC_trace_addr >= current_p
&& GC_trace_addr < current_p + descr) {
- GC_log_printf("GC:%u splitting %p at %p\n",
- (unsigned)GC_gc_no, current_p, limit);
+ GC_log_printf("GC:%u Splitting %p at %p\n",
+ (unsigned)GC_gc_no, current_p, limit);
}
# endif /* ENABLE_TRACE */
/* Make sure that pointers overlapping the two ranges are */
@@ -718,9 +709,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# ifdef ENABLE_TRACE
if (GC_trace_addr >= current_p
&& GC_trace_addr < current_p + WORDS_TO_BYTES(WORDSZ-2)) {
- GC_log_printf("GC:%u Tracing from %p bitmap descr %lu\n",
- (unsigned)GC_gc_no, current_p,
- (unsigned long) descr);
+ GC_log_printf("GC:%u Tracing from %p bitmap descr %lu\n",
+ (unsigned)GC_gc_no, current_p, (unsigned long)descr);
}
# endif /* ENABLE_TRACE */
descr &= ~GC_DS_TAGS;
@@ -734,8 +724,7 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# ifdef ENABLE_TRACE
if (GC_trace_addr == current_p) {
GC_log_printf("GC:%u Considering(3) %p -> %p\n",
- (unsigned)GC_gc_no, current_p,
- (ptr_t) current);
+ (unsigned)GC_gc_no, current_p, (ptr_t)current);
}
# endif /* ENABLE_TRACE */
PUSH_CONTENTS((ptr_t)current, mark_stack_top,
@@ -752,9 +741,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
if (GC_trace_addr >= current_p
&& GC_base(current_p) != 0
&& GC_base(current_p) == GC_base(GC_trace_addr)) {
- GC_log_printf("GC:%u Tracing from %p proc descr %lu\n",
- (unsigned)GC_gc_no, current_p,
- (unsigned long) descr);
+ GC_log_printf("GC:%u Tracing from %p proc descr %lu\n",
+ (unsigned)GC_gc_no, current_p, (unsigned long)descr);
}
# endif /* ENABLE_TRACE */
credit -= GC_PROC_BYTES;
@@ -805,8 +793,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
# ifdef ENABLE_TRACE
if (GC_trace_addr >= current_p
&& GC_trace_addr < limit) {
- GC_log_printf("GC:%u Tracing from %p len %lu\n",
- (int)GC_gc_no, current_p, (unsigned long) descr);
+ GC_log_printf("GC:%u Tracing from %p len %lu\n",
+ (int)GC_gc_no, current_p, (unsigned long)descr);
}
# endif /* ENABLE_TRACE */
/* The simple case in which we're scanning a range. */
@@ -862,8 +850,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
PREFETCH((ptr_t)current);
# ifdef ENABLE_TRACE
if (GC_trace_addr == current_p) {
- GC_log_printf("GC:%u Considering(1) %p -> %p\n",
- (unsigned)GC_gc_no, current_p, (ptr_t) current);
+ GC_log_printf("GC:%u Considering(1) %p -> %p\n",
+ (unsigned)GC_gc_no, current_p, (ptr_t)current);
}
# endif /* ENABLE_TRACE */
PUSH_CONTENTS((ptr_t)current, mark_stack_top,
@@ -878,8 +866,8 @@ GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
/* validity test. */
# ifdef ENABLE_TRACE
if (GC_trace_addr == current_p) {
- GC_log_printf("GC:%u Considering(2) %p -> %p\n",
- (unsigned)GC_gc_no, current_p, (ptr_t) deferred);
+ GC_log_printf("GC:%u Considering(2) %p -> %p\n",
+ (unsigned)GC_gc_no, current_p, (ptr_t)deferred);
}
# endif /* ENABLE_TRACE */
PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
@@ -1106,8 +1094,8 @@ STATIC void GC_mark_local(mse *local_mark_stack, int id)
GC_helper_count--;
if (0 == GC_helper_count) need_to_notify = TRUE;
if (GC_print_stats == VERBOSE)
- GC_log_printf(
- "Finished mark helper %lu\n", (unsigned long)id);
+ GC_log_printf("Finished mark helper %lu\n",
+ (unsigned long)id);
GC_release_mark_lock();
if (need_to_notify) GC_notify_all_marker();
return;
@@ -1150,7 +1138,7 @@ STATIC void GC_do_parallel_mark(void)
ABORT("Tried to start parallel mark in bad state");
if (GC_print_stats == VERBOSE)
GC_log_printf("Starting marking for mark phase number %lu\n",
- (unsigned long)GC_mark_no);
+ (unsigned long)GC_mark_no);
GC_first_nonempty = (AO_t)GC_mark_stack;
GC_active_count = 0;
GC_helper_count = 1;
@@ -1165,9 +1153,8 @@ STATIC void GC_do_parallel_mark(void)
while (GC_helper_count > 0) GC_wait_marker();
/* GC_helper_count cannot be incremented while GC_help_wanted == FALSE */
if (GC_print_stats == VERBOSE)
- GC_log_printf(
- "Finished marking for mark phase number %lu\n",
- (unsigned long)GC_mark_no);
+ GC_log_printf("Finished marking for mark phase number %lu\n",
+ (unsigned long)GC_mark_no);
GC_mark_no++;
GC_release_mark_lock();
GC_notify_all_marker();
@@ -1210,12 +1197,12 @@ static void alloc_mark_stack(size_t n)
# ifdef GWW_VDB
/* Don't recycle a stack segment obtained with the wrong flags. */
/* Win32 GetWriteWatch requires the right kind of memory. */
- static GC_bool GC_incremental_at_stack_alloc = 0;
+ static GC_bool GC_incremental_at_stack_alloc = FALSE;
GC_bool recycle_old = (!GC_incremental || GC_incremental_at_stack_alloc);
GC_incremental_at_stack_alloc = GC_incremental;
# else
-# define recycle_old 1
+# define recycle_old TRUE
# endif
GC_mark_stack_too_small = FALSE;
@@ -1280,7 +1267,7 @@ GC_INNER void GC_push_all(ptr_t bottom, ptr_t top)
if (top == 0 || bottom == top) return;
GC_mark_stack_top++;
if (GC_mark_stack_top >= GC_mark_stack_limit) {
- ABORT("unexpected mark stack overflow");
+ ABORT("Unexpected mark stack overflow");
}
length = top - bottom;
# if GC_DS_TAGS > ALIGNMENT - 1
@@ -1293,80 +1280,70 @@ GC_INNER void GC_push_all(ptr_t bottom, ptr_t top)
#ifndef GC_DISABLE_INCREMENTAL
- /*
- * Analogous to the above, but push only those pages h with
- * dirty_fn(h) != 0. We use push_fn to actually push the block.
- * Used both to selectively push dirty pages, or to push a block
- * in piecemeal fashion, to allow for more marking concurrency.
- * Will not overflow mark stack if push_fn pushes a small fixed number
- * of entries. (This is invoked only if push_fn pushes a single entry,
- * or if it marks each object before pushing it, thus ensuring progress
- * in the event of a stack overflow.)
- */
+ /* Analogous to the above, but push only those pages h with */
+ /* dirty_fn(h) != 0. We use GC_push_all to actually push the block. */
+ /* Used both to selectively push dirty pages, or to push a block in */
+ /* piecemeal fashion, to allow for more marking concurrency. */
+ /* Will not overflow mark stack if GC_push_all pushes a small fixed */
+ /* number of entries. (This is invoked only if GC_push_all pushes */
+ /* a single entry, or if it marks each object before pushing it, thus */
+ /* ensuring progress in the event of a stack overflow.) */
STATIC void GC_push_selected(ptr_t bottom, ptr_t top,
- int (*dirty_fn)(struct hblk *),
- void (*push_fn)(ptr_t, ptr_t))
+ GC_bool (*dirty_fn)(struct hblk *))
{
struct hblk * h;
bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
-
if (top == 0 || bottom == top) return;
+
h = HBLKPTR(bottom + HBLKSIZE);
if (top <= (ptr_t) h) {
if ((*dirty_fn)(h-1)) {
- (*push_fn)(bottom, top);
+ GC_push_all(bottom, top);
}
return;
}
if ((*dirty_fn)(h-1)) {
- (*push_fn)(bottom, (ptr_t)h);
+ GC_push_all(bottom, (ptr_t)h);
}
+
while ((ptr_t)(h+1) <= top) {
if ((*dirty_fn)(h)) {
if ((word)(GC_mark_stack_top - GC_mark_stack)
> 3 * GC_mark_stack_size / 4) {
/* Danger of mark stack overflow */
- (*push_fn)((ptr_t)h, top);
+ GC_push_all((ptr_t)h, top);
return;
} else {
- (*push_fn)((ptr_t)h, (ptr_t)(h+1));
+ GC_push_all((ptr_t)h, (ptr_t)(h+1));
}
}
h++;
}
- if ((ptr_t)h != top) {
- if ((*dirty_fn)(h)) {
- (*push_fn)((ptr_t)h, top);
- }
+
+ if ((ptr_t)h != top && (*dirty_fn)(h)) {
+ GC_push_all((ptr_t)h, top);
}
if (GC_mark_stack_top >= GC_mark_stack_limit) {
- ABORT("unexpected mark stack overflow");
+ ABORT("Unexpected mark stack overflow");
}
}
-# ifdef PROC_VDB
- GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h);
- /* Could the page contain valid heap pointers? */
-# endif
-
GC_INNER void GC_push_conditional(ptr_t bottom, ptr_t top, GC_bool all)
{
- if (all) {
- if (GC_dirty_maintained) {
-# ifdef PROC_VDB
- /* Pages that were never dirtied cannot contain pointers */
- GC_push_selected(bottom, top, GC_page_was_ever_dirty,
- GC_push_all);
-# else
- GC_push_all(bottom, top);
-# endif
- } else {
+ if (!all) {
+ GC_push_selected(bottom, top, GC_page_was_dirty);
+ } else {
+# ifdef PROC_VDB
+ if (GC_dirty_maintained) {
+ /* Pages that were never dirtied cannot contain pointers. */
+ GC_push_selected(bottom, top, GC_page_was_ever_dirty);
+ } else
+# endif
+ /* else */ {
GC_push_all(bottom, top);
}
- } else {
- GC_push_selected(bottom, top, GC_page_was_dirty, GC_push_all);
}
}
#endif /* !GC_DISABLE_INCREMENTAL */
@@ -1413,6 +1390,10 @@ GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void *obj,
return mark_stack_ptr;
}
+#if defined(MANUAL_VDB) && defined(THREADS)
+ void GC_dirty(ptr_t p);
+#endif
+
/* Mark and push (i.e. gray) a single object p onto the main */
/* mark stack. Consider p to be valid if it is an interior */
/* pointer. */
@@ -1448,8 +1429,8 @@ GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void *obj,
}
# if defined(MANUAL_VDB) && defined(THREADS)
/* Pointer is on the stack. We may have dirtied the object */
- /* it points to, but not yet have called GC_dirty(); */
- GC_dirty(p); /* Implicitly affects entire object. */
+ /* it points to, but not yet have called GC_dirty(); */
+ GC_dirty(p); /* Implicitly affects entire object. */
# endif
PUSH_CONTENTS_HDR(r, GC_mark_stack_top, GC_mark_stack_limit,
source, mark_and_push_exit, hhdr, FALSE);
@@ -1576,7 +1557,7 @@ GC_INNER void GC_push_all_stack(ptr_t bottom, ptr_t top)
qcontents = (q)[3]; \
GC_PUSH_ONE_HEAP(qcontents, (q)+3); }
# endif
-#endif
+#endif /* !USE_MARK_BYTES && MARK_BIT_PER_GRANULE */
#ifdef USE_PUSH_MARKED_ACCELERATORS
/* Push all objects reachable from marked objects in the given block */
@@ -1820,7 +1801,7 @@ STATIC struct hblk * GC_push_next_marked(struct hblk *h)
{
hdr * hhdr = HDR(h);
- if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); }
+ if (!GC_dirty_maintained) ABORT("Dirty bits not set up");
for (;;) {
if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)
|| HBLK_IS_FREE(hhdr), FALSE)) {
diff --git a/mark_rts.c b/mark_rts.c
index d808e8e5..4cd97bdc 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -111,7 +111,7 @@ static int n_root_sets = 0;
/* Is a range starting at b already in the table? If so return a */
/* pointer to it, else NULL. */
- GC_INNER struct roots * GC_roots_present(ptr_t b)
+ GC_INNER void * GC_roots_present(ptr_t b)
{
int h = rt_hash(b);
struct roots *p = GC_root_index[h];
@@ -120,7 +120,7 @@ static int n_root_sets = 0;
if (p -> r_start == (ptr_t)b) return(p);
p = p -> r_next;
}
- return(FALSE);
+ return NULL;
}
/* Add the given root structure to the index. */
@@ -216,7 +216,7 @@ void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp)
}
}
# else
- old = GC_roots_present(b);
+ old = (struct roots *)GC_roots_present(b);
if (old != 0) {
if (e <= old -> r_end) /* already there */ return;
/* else extend */
@@ -251,10 +251,7 @@ GC_API void GC_CALL GC_clear_roots(void)
n_root_sets = 0;
GC_root_size = 0;
# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
- {
- int i;
- for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
- }
+ BZERO(GC_root_index, RT_SIZE * sizeof(void *));
# endif
UNLOCK();
}
@@ -273,8 +270,7 @@ STATIC void GC_remove_root_at_pos(int i)
STATIC void GC_rebuild_root_index(void)
{
int i;
-
- for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
+ BZERO(GC_root_index, RT_SIZE * sizeof(void *));
for (i = 0; i < n_root_sets; i++)
add_roots_to_index(GC_static_roots + i);
}
@@ -426,7 +422,7 @@ GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish)
if (0 != next) {
if ((word)(next -> e_start) < (word) finish) {
/* incomplete error check. */
- ABORT("exclusion ranges overlap");
+ ABORT("Exclusion ranges overlap");
}
if ((word)(next -> e_start) == (word) finish) {
/* extend old range backwards */
@@ -694,10 +690,6 @@ STATIC void GC_push_gc_structures(void)
GC_push_typed_structures();
}
-#ifdef THREAD_LOCAL_ALLOC
- GC_INNER void GC_mark_thread_local_free_lists(void);
-#endif
-
GC_INNER void GC_cond_register_dynamic_libraries(void)
{
# if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
diff --git a/misc.c b/misc.c
index 044520fc..1be41d02 100644
--- a/misc.c
+++ b/misc.c
@@ -59,7 +59,6 @@
#ifdef DYNAMIC_LOADING
/* We need to register the main data segment. Returns TRUE unless */
/* this is done implicitly as part of dynamic library registration. */
- GC_INNER GC_bool GC_register_main_static_data(void);
# define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
#else
/* Don't unnecessarily call GC_register_main_static_data() in case */
@@ -76,9 +75,6 @@ GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
GC_INNER GC_bool GC_debugging_started = FALSE;
/* defined here so we don't have to load debug_malloc.o */
-GC_INNER void (*GC_check_heap)(void) = 0;
-GC_INNER void (*GC_print_all_smashed)(void) = 0;
-
ptr_t GC_stackbottom = 0;
#ifdef IA64
@@ -95,10 +91,14 @@ GC_bool GC_quiet = 0; /* used also in pcr_interface.c */
GC_bool GC_print_stats = 0;
#endif
-GC_INNER GC_bool GC_print_back_height = 0;
+#ifdef GC_PRINT_BACK_HEIGHT
+ GC_INNER GC_bool GC_print_back_height = TRUE;
+#else
+ GC_INNER GC_bool GC_print_back_height = FALSE;
+#endif
#ifndef NO_DEBUGGING
- GC_INNER GC_bool GC_dump_regularly = 0;
+ GC_INNER GC_bool GC_dump_regularly = FALSE;
/* Generate regular debugging dumps. */
#endif
@@ -113,6 +113,14 @@ GC_INNER GC_bool GC_print_back_height = 0;
int GC_find_leak = 0;
#endif
+#ifndef SHORT_DBG_HDRS
+# ifdef GC_FINDLEAK_DELAY_FREE
+ GC_INNER GC_bool GC_findleak_delay_free = TRUE;
+# else
+ GC_INNER GC_bool GC_findleak_delay_free = FALSE;
+# endif
+#endif /* !SHORT_DBG_HDRS */
+
#ifdef ALL_INTERIOR_POINTERS
int GC_all_interior_pointers = 1;
#else
@@ -577,25 +585,12 @@ GC_INNER GC_bool GC_is_initialized = FALSE;
GC_INNER CRITICAL_SECTION GC_write_cs;
#endif
-#ifdef MSWIN32
- GC_INNER void GC_init_win32(void);
-#endif
-
-GC_INNER void GC_setpagesize(void);
-
STATIC void GC_exit_check(void)
{
GC_gcollect();
}
-#ifdef SEARCH_FOR_DATA_START
- GC_INNER void GC_init_linux_data_start(void);
-#endif
-
#ifdef UNIX_LIKE
-
- GC_INNER void GC_set_and_save_fault_handler(void (*handler)(int));
-
static void looping_handler(int sig)
{
GC_err_printf("Caught signal %d: looping in handler\n", sig);
@@ -618,20 +613,45 @@ STATIC void GC_exit_check(void)
# define maybe_install_looping_handler()
#endif
-#if defined(DYNAMIC_LOADING) && defined(DARWIN)
- GC_INNER void GC_init_dyld(void);
-#endif
-
-#if defined(NETBSD) && defined(__ELF__)
- GC_INNER void GC_init_netbsd_elf(void);
-#endif
-
#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
- STATIC int GC_log = 2;
+ STATIC int GC_stdout = 1;
+ STATIC int GC_stderr = 2;
+ STATIC int GC_log = 2; /* stderr */
#endif
-GC_INNER void GC_initialize_offsets(void); /* defined in obj_map.c */
-GC_INNER void GC_bl_init(void); /* defined in blacklst.c */
+STATIC word GC_parse_mem_size_arg(const char *str)
+{
+ char *endptr;
+ word result = 0; /* bad value */
+ char ch;
+
+ if (*str != '\0') {
+ result = (word)STRTOULL(str, &endptr, 10);
+ ch = *endptr;
+ if (ch != '\0') {
+ if (*(endptr + 1) != '\0')
+ return 0;
+ /* Allow k, M or G suffix. */
+ switch (ch) {
+ case 'K':
+ case 'k':
+ result <<= 10;
+ break;
+ case 'M':
+ case 'm':
+ result <<= 20;
+ break;
+ case 'G':
+ case 'g':
+ result <<= 30;
+ break;
+ default:
+ result = 0;
+ }
+ }
+ }
+ return result;
+}
GC_API void GC_CALL GC_init(void)
{
@@ -643,6 +663,14 @@ GC_API void GC_CALL GC_init(void)
IF_CANCEL(int cancel_state;)
if (GC_is_initialized) return;
+# ifdef REDIRECT_MALLOC
+ {
+ static GC_bool init_started = FALSE;
+ if (init_started)
+ ABORT("Redirected malloc() called during GC init");
+ init_started = TRUE;
+ }
+# endif
# ifdef GC_INITIAL_HEAP_SIZE
initial_heap_sz = divHBLKSZ(GC_INITIAL_HEAP_SIZE);
@@ -741,7 +769,23 @@ GC_API void GC_CALL GC_init(void)
if (log_d < 0) {
GC_err_printf("Failed to open %s as log file\n", file_name);
} else {
+ char *str;
GC_log = log_d;
+ str = GETENV("GC_ONLY_LOG_TO_FILE");
+# ifdef GC_ONLY_LOG_TO_FILE
+ /* The similar environment variable set to "0" */
+ /* overrides the effect of the macro defined. */
+ if (str != NULL && *str == '0' && *(str + 1) == '\0')
+# else
+ /* Otherwise setting the environment variable */
+ /* to anything other than "0" will prevent from */
+ /* redirecting stdout/err to the log file. */
+ if (str == NULL || (*str == '0' && *(str + 1) == '\0'))
+# endif
+ {
+ GC_stdout = log_d;
+ GC_stderr = log_d;
+ }
}
}
}
@@ -749,7 +793,7 @@ GC_API void GC_CALL GC_init(void)
# endif /* !SMALL_CONFIG */
# ifndef NO_DEBUGGING
if (0 != GETENV("GC_DUMP_REGULARLY")) {
- GC_dump_regularly = 1;
+ GC_dump_regularly = TRUE;
}
# endif
# ifdef KEEP_BACK_PTRS
@@ -764,6 +808,11 @@ GC_API void GC_CALL GC_init(void)
if (0 != GETENV("GC_FIND_LEAK")) {
GC_find_leak = 1;
}
+# ifndef SHORT_DBG_HDRS
+ if (0 != GETENV("GC_FINDLEAK_DELAY_FREE")) {
+ GC_findleak_delay_free = TRUE;
+ }
+# endif
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
GC_all_interior_pointers = 1;
}
@@ -771,7 +820,7 @@ GC_API void GC_CALL GC_init(void)
GC_dont_gc = 1;
}
if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) {
- GC_print_back_height = 1;
+ GC_print_back_height = TRUE;
}
if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
GC_large_alloc_warn_interval = LONG_MAX;
@@ -893,8 +942,8 @@ GC_API void GC_CALL GC_init(void)
# if defined(NETBSD) && defined(__ELF__)
GC_init_netbsd_elf();
# endif
-# if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
- || defined(GC_SOLARIS_THREADS)
+# if !defined(THREADS) || defined(GC_PTHREADS) \
+ || defined(GC_WIN32_THREADS) || defined(GC_SOLARIS_THREADS)
if (GC_stackbottom == 0) {
GC_stackbottom = GC_get_main_stack_base();
# if (defined(LINUX) || defined(HPUX)) && defined(IA64)
@@ -916,19 +965,15 @@ GC_API void GC_CALL GC_init(void)
GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
# ifndef THREADS
-# ifdef STACK_GROWS_DOWN
- GC_ASSERT((word)(&dummy) <= (word)GC_stackbottom);
-# else
- GC_ASSERT((word)(&dummy) >= (word)GC_stackbottom);
-# endif
+ GC_ASSERT(!((word)GC_stackbottom HOTTER_THAN (word)(&dummy)));
# endif
# if !defined(_AUX_SOURCE) || defined(__GNUC__)
GC_STATIC_ASSERT((word)(-1) > (word)0);
/* word should be unsigned */
# endif
-# if !defined(__BORLANDC__) /* Workaround for Borland C */
- GC_STATIC_ASSERT((ptr_t)(word)(-1) > (ptr_t)0);
- /* Ptr_t comparisons should behave as unsigned comparisons. */
+# if !defined(__BORLANDC__) && !defined(__CC_ARM) /* Workaround */
+ GC_STATIC_ASSERT((ptr_t)(word)(-1) > (ptr_t)0);
+ /* Ptr_t comparisons should behave as unsigned comparisons. */
# endif
GC_STATIC_ASSERT((signed_word)(-1) < (signed_word)0);
# ifndef GC_DISABLE_INCREMENTAL
@@ -950,10 +995,9 @@ GC_API void GC_CALL GC_init(void)
{
char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
if (sz_str != NULL) {
- initial_heap_sz = (word)STRTOULL(sz_str, NULL, 10);
+ initial_heap_sz = GC_parse_mem_size_arg(sz_str);
if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
- WARN("Bad initial heap size %s - ignoring it.\n",
- sz_str);
+ WARN("Bad initial heap size %s - ignoring it.\n", sz_str);
}
initial_heap_sz = divHBLKSZ(initial_heap_sz);
}
@@ -961,10 +1005,9 @@ GC_API void GC_CALL GC_init(void)
{
char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
if (sz_str != NULL) {
- word max_heap_sz = (word)STRTOULL(sz_str, NULL, 10);
+ word max_heap_sz = GC_parse_mem_size_arg(sz_str);
if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
- WARN("Bad maximum heap size %s - ignoring it.\n",
- sz_str);
+ WARN("Bad maximum heap size %s - ignoring it.\n", sz_str);
}
if (0 == GC_max_retries) GC_max_retries = 2;
GC_set_max_heap_size(max_heap_sz);
@@ -1078,14 +1121,13 @@ GC_API void GC_CALL GC_enable_incremental(void)
GC_init();
}
-
#if defined(MSWIN32) || defined(MSWINCE)
# if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
# include <crtdbg.h>
# endif
- STATIC HANDLE GC_stdout = 0;
+ STATIC HANDLE GC_log = 0;
void GC_deinit(void)
{
@@ -1096,19 +1138,19 @@ GC_API void GC_CALL GC_enable_incremental(void)
# endif
}
-#ifdef THREADS
-# ifdef PARALLEL_MARK
-# define IF_NEED_TO_LOCK(x) if (GC_parallel || GC_need_to_lock) x
+# ifdef THREADS
+# ifdef PARALLEL_MARK
+# define IF_NEED_TO_LOCK(x) if (GC_parallel || GC_need_to_lock) x
+# else
+# define IF_NEED_TO_LOCK(x) if (GC_need_to_lock) x
+# endif
# else
-# define IF_NEED_TO_LOCK(x) if (GC_need_to_lock) x
-# endif
-#else
-# define IF_NEED_TO_LOCK(x)
-#endif
+# define IF_NEED_TO_LOCK(x)
+# endif /* !THREADS */
-#ifndef _MAX_PATH
-# define _MAX_PATH MAX_PATH
-#endif
+# ifndef _MAX_PATH
+# define _MAX_PATH MAX_PATH
+# endif
STATIC HANDLE GC_CreateLogFile(void)
{
@@ -1157,19 +1199,19 @@ GC_API void GC_CALL GC_enable_incremental(void)
# ifdef THREADS
GC_ASSERT(!GC_write_disabled);
# endif
- if (GC_stdout == INVALID_HANDLE_VALUE) {
+ if (GC_log == INVALID_HANDLE_VALUE) {
IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
return -1;
- } else if (GC_stdout == 0) {
- GC_stdout = GC_CreateLogFile();
+ } else if (GC_log == 0) {
+ GC_log = GC_CreateLogFile();
/* Ignore open log failure if the collector is built with */
/* print_stats always set on. */
# ifndef GC_PRINT_VERBOSE_STATS
- if (GC_stdout == INVALID_HANDLE_VALUE)
+ if (GC_log == INVALID_HANDLE_VALUE)
ABORT("Open of log file failed");
# endif
}
- tmp = WriteFile(GC_stdout, buf, (DWORD)len, &written, NULL);
+ tmp = WriteFile(GC_log, buf, (DWORD)len, &written, NULL);
if (!tmp)
DebugBreak();
# if defined(_MSC_VER) && defined(_DEBUG)
@@ -1191,89 +1233,85 @@ GC_API void GC_CALL GC_enable_incremental(void)
return tmp ? (int)written : -1;
}
-#endif /* MSWIN32 */
+ /* FIXME: This is pretty ugly ... */
+# define WRITE(f, buf, len) GC_write(buf, len)
-#if defined(OS2) || defined(MACOS)
+#elif defined(OS2) || defined(MACOS)
STATIC FILE * GC_stdout = NULL;
STATIC FILE * GC_stderr = NULL;
STATIC FILE * GC_log = NULL;
+ /* Initialize GC_log (and the friends) passed to GC_write(). */
STATIC void GC_set_files(void)
{
- if (GC_stdout == NULL) {
- GC_stdout = stdout;
+ if (GC_stdout == NULL) {
+ GC_stdout = stdout;
}
if (GC_stderr == NULL) {
- GC_stderr = stderr;
+ GC_stderr = stderr;
}
if (GC_log == NULL) {
- GC_log = stderr;
+ GC_log = stderr;
}
}
-#endif
-#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
- STATIC int GC_stdout = 1;
- STATIC int GC_stderr = 2;
-# if !defined(AMIGA)
+ GC_INLINE int GC_write(FILE *f, const char *buf, size_t len)
+ {
+ int res = fwrite(buf, 1, len, f);
+ fflush(f);
+ return res;
+ }
+
+# define WRITE(f, buf, len) (GC_set_files(), GC_write(f, buf, len))
+
+#else
+# if !defined(AMIGA) && !defined(__CC_ARM)
# include <unistd.h>
# endif
-#endif
-#if defined(ECOS) || defined(NOSYS)
STATIC int GC_write(int fd, const char *buf, size_t len)
{
-# ifdef ECOS
- /* FIXME: This seems to be defined nowhere at present. */
- /* _Jv_diag_write(buf, len); */
+# if defined(ECOS) || defined(NOSYS)
+# ifdef ECOS
+ /* FIXME: This seems to be defined nowhere at present. */
+ /* _Jv_diag_write(buf, len); */
+# else
+ /* No writing. */
+# endif
+ return len;
# else
- /* No writing. */
+ int bytes_written = 0;
+ int result;
+ IF_CANCEL(int cancel_state;)
+
+ DISABLE_CANCEL(cancel_state);
+ while (bytes_written < len) {
+# ifdef GC_SOLARIS_THREADS
+ result = syscall(SYS_write, fd, buf + bytes_written,
+ len - bytes_written);
+# else
+ result = write(fd, buf + bytes_written, len - bytes_written);
+# endif
+ if (-1 == result) {
+ RESTORE_CANCEL(cancel_state);
+ return(result);
+ }
+ bytes_written += result;
+ }
+ RESTORE_CANCEL(cancel_state);
+ return(bytes_written);
# endif
- return len;
- }
-#elif !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) \
- && !defined(MACOS)
- STATIC int GC_write(int fd, const char *buf, size_t len)
- {
- int bytes_written = 0;
- int result;
- IF_CANCEL(int cancel_state;)
-
- DISABLE_CANCEL(cancel_state);
- while (bytes_written < len) {
-# ifdef GC_SOLARIS_THREADS
- result = syscall(SYS_write, fd, buf + bytes_written,
- len - bytes_written);
-# else
- result = write(fd, buf + bytes_written, len - bytes_written);
-# endif
- if (-1 == result) {
- RESTORE_CANCEL(cancel_state);
- return(result);
- }
- bytes_written += result;
- }
- RESTORE_CANCEL(cancel_state);
- return(bytes_written);
}
-#endif /* UN*X */
-#if defined(MSWIN32) || defined(MSWINCE)
- /* FIXME: This is pretty ugly ... */
-# define WRITE(f, buf, len) GC_write(buf, len)
-#else
-# if defined(OS2) || defined(MACOS)
- static int fwrite_gc_res; /* Should really be local ... */
-# define WRITE(f, buf, len) (GC_set_files(), \
- fwrite_gc_res = fwrite((buf), 1, (len), (f)), \
- fflush(f), fwrite_gc_res)
-# else
-# define WRITE(f, buf, len) GC_write((f), (buf), (len))
-# endif
-#endif
+# define WRITE(f, buf, len) GC_write(f, buf, len)
+#endif /* !MSWIN32 && !OS2 && !MACOS */
#define BUFSZ 1024
-#ifdef _MSC_VER
+
+#ifdef NO_VSNPRINTF
+ /* In case this function is missing (eg., in DJGPP v2.0.3). */
+# define vsnprintf(buf, bufsz, format, args) vsprintf(buf, format, args)
+#elif defined(_MSC_VER)
# ifdef MSWINCE
/* _vsnprintf is deprecated in WinCE */
# define vsnprintf StringCchVPrintfA
@@ -1291,8 +1329,8 @@ void GC_printf(const char *format, ...)
va_list args;
char buf[BUFSZ+1];
- va_start(args, format);
if (GC_quiet) return;
+ va_start(args, format);
buf[BUFSZ] = 0x15;
(void) vsnprintf(buf, BUFSZ, format, args);
va_end(args);
@@ -1329,18 +1367,12 @@ void GC_log_printf(const char *format, ...)
ABORT("write to log failed");
}
+/* This is equivalent to GC_err_printf("%s",s). */
void GC_err_puts(const char *s)
{
if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
}
-#if defined(LINUX) && !defined(SMALL_CONFIG)
- GC_INNER void GC_err_write(const char *buf, size_t len)
- {
- if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed");
- }
-#endif
-
STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg)
{
GC_err_printf(msg, arg);
@@ -1531,12 +1563,7 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
return fn(&base, arg);
}
-#ifdef THREADS
-
- /* Defined in pthread_support.c or win32_threads.c. */
- GC_INNER void GC_do_blocking_inner(ptr_t data, void * context);
-
-#else
+#ifndef THREADS
GC_INNER ptr_t GC_blocked_sp = NULL;
/* NULL value means we are not inside GC_do_blocking() call. */
@@ -1729,8 +1756,6 @@ GC_API int GC_CALL GC_get_find_leak(void)
return GC_find_leak;
}
-GC_INNER void GC_bl_init_no_interiors(void); /* defined in blacklst.c */
-
GC_API void GC_CALL GC_set_all_interior_pointers(int value)
{
DCL_LOCK_STATE;
diff --git a/new_hblk.c b/new_hblk.c
index 6e2dca56..1366b131 100644
--- a/new_hblk.c
+++ b/new_hblk.c
@@ -158,12 +158,10 @@ GC_INNER ptr_t GC_build_fl(struct hblk *h, size_t sz, GC_bool clear,
}
p -= sz; /* p now points to last object */
- /*
- * put p (which is now head of list of objects in *h) as first
- * pointer in the appropriate free list for this size.
- */
- obj_link(h -> hb_body) = list;
- return ((ptr_t)p);
+ /* Put p (which is now head of list of objects in *h) as first */
+ /* pointer in the appropriate free list for this size. */
+ *(ptr_t *)h = list;
+ return ((ptr_t)p);
}
/*
diff --git a/os_dep.c b/os_dep.c
index bc53d7ce..2d73340a 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -19,10 +19,10 @@
#if defined(LINUX) && !defined(POWERPC)
# include <linux/version.h>
# if (LINUX_VERSION_CODE <= 0x10400)
- /* Ugly hack to get struct sigcontext_struct definition. Required */
- /* for some early 1.3.X releases. Will hopefully go away soon. */
- /* in some later Linux releases, asm/sigcontext.h may have to */
- /* be included instead. */
+ /* Ugly hack to get struct sigcontext_struct definition. Required */
+ /* for some early 1.3.X releases. Will hopefully go away soon. */
+ /* in some later Linux releases, asm/sigcontext.h may have to */
+ /* be included instead. */
# define __KERNEL__
# include <asm/signal.h>
# undef __KERNEL__
@@ -34,8 +34,8 @@
# include <features.h>
# if 2 <= __GLIBC__
# if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
- /* glibc 2.1 no longer has sigcontext.h. But signal.h */
- /* has the right declaration for glibc 2.1. */
+ /* glibc 2.1 no longer has sigcontext.h. But signal.h */
+ /* has the right declaration for glibc 2.1. */
# include <sigcontext.h>
# endif /* 0 == __GLIBC_MINOR__ */
# else /* not 2 <= __GLIBC__ */
@@ -47,7 +47,7 @@
#endif
#if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
- && !defined(MSWINCE)
+ && !defined(MSWINCE) && !defined(__CC_ARM)
# include <sys/types.h>
# if !defined(MSWIN32)
# include <unistd.h>
@@ -131,22 +131,17 @@
#endif
#if !defined(NO_EXECUTE_PERMISSION)
- static GC_bool pages_executable = TRUE;
+ STATIC GC_bool GC_pages_executable = TRUE;
#else
- static GC_bool pages_executable = FALSE;
+ STATIC GC_bool GC_pages_executable = FALSE;
#endif
#define IGNORE_PAGES_EXECUTABLE 1
- /* Undefined on pages_executable real use. */
-
-#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) \
- || !defined(SMALL_CONFIG))
-# define NEED_PROC_MAPS
-#endif
+ /* Undefined on GC_pages_executable real use. */
#ifdef NEED_PROC_MAPS
-/* We need to parse /proc/self/maps, either to find dynamic libraries, */
-/* and/or to find the register backing store base (IA64). Do it once */
-/* here. */
+/* We need to parse /proc/self/maps, either to find dynamic libraries, */
+/* and/or to find the register backing store base (IA64). Do it once */
+/* here. */
#define READ read
@@ -197,12 +192,10 @@ STATIC ssize_t GC_repeat_read(int fd, char *buf, size_t count)
}
#endif /* THREADS */
-/*
- * Copy the contents of /proc/self/maps to a buffer in our address space.
- * Return the address of the buffer, or zero on failure.
- * This code could be simplified if we could determine its size
- * ahead of time.
- */
+/* Copy the contents of /proc/self/maps to a buffer in our address */
+/* space. Return the address of the buffer, or zero on failure. */
+/* This code could be simplified if we could determine its size ahead */
+/* of time. */
GC_INNER char * GC_get_maps(void)
{
int f;
@@ -243,7 +236,7 @@ GC_INNER char * GC_get_maps(void)
/* thus can't use stdio. */
do {
while (maps_size >= maps_buf_sz) {
- /* Grow only by powers of 2, since we leak "too small" buffers. */
+ /* Grow only by powers of 2, since we leak "too small" buffers.*/
while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
maps_buf = GC_scratch_alloc(maps_buf_sz);
# ifdef THREADS
@@ -264,25 +257,29 @@ GC_INNER char * GC_get_maps(void)
maps_size = 0;
do {
result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
- if (result <= 0) return 0;
+ if (result <= 0)
+ break;
maps_size += result;
} while (result == maps_buf_sz-1);
close(f);
+ if (result <= 0)
+ return 0;
# ifdef THREADS
if (maps_size > old_maps_size) {
if (GC_print_stats)
- GC_printf("Unexpected maps size growth from %lu to %lu\n",
- (unsigned long)old_maps_size,
- (unsigned long)maps_size);
+ GC_log_printf(
+ "Unexpected maps size growth from %lu to %lu\n",
+ (unsigned long)old_maps_size,
+ (unsigned long)maps_size);
ABORT("Unexpected asynchronous /proc/self/maps growth: "
"unregistered thread?");
}
# endif
} while (maps_size >= maps_buf_sz || maps_size < old_maps_size);
- /* In the single-threaded case, the second clause is false. */
+ /* In the single-threaded case, the second clause is false. */
maps_buf[maps_size] = '\0';
- /* Apply fn to result. */
+ /* Apply fn to result. */
return maps_buf;
}
@@ -300,12 +297,10 @@ GC_INNER char * GC_get_maps(void)
* anywhere, which is safer anyway.
*/
-/*
- * Assign various fields of the first line in buf_ptr to *start, *end,
- * *prot, *maj_dev and *mapping_name. Mapping_name may be NULL.
- * *prot and *mapping_name are assigned pointers into the original
- * buffer.
- */
+/* Assign various fields of the first line in buf_ptr to (*start), */
+/* (*end), (*prot), (*maj_dev) and (*mapping_name). mapping_name may */
+/* be NULL. (*prot) and (*mapping_name) are assigned pointers into the */
+/* original buffer. */
GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
char **prot, unsigned int *maj_dev,
char **mapping_name)
@@ -354,34 +349,37 @@ GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
return p;
}
-/* Try to read the backing store base from /proc/self/maps. */
-/* Return the bounds of the writable mapping with a 0 major device, */
-/* which includes the address passed as data. */
-/* Return FALSE if there is no such mapping. */
-GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
-{
- char *prot;
- ptr_t my_start, my_end;
- unsigned int maj_dev;
- char *maps = GC_get_maps();
- char *buf_ptr = maps;
+#if defined(IA64) || defined(INCLUDE_LINUX_THREAD_DESCR)
+ /* Try to read the backing store base from /proc/self/maps. */
+ /* Return the bounds of the writable mapping with a 0 major device, */
+ /* which includes the address passed as data. */
+ /* Return FALSE if there is no such mapping. */
+ GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp,
+ ptr_t *endp)
+ {
+ char *prot;
+ ptr_t my_start, my_end;
+ unsigned int maj_dev;
+ char *maps = GC_get_maps();
+ char *buf_ptr = maps;
- if (0 == maps) return(FALSE);
- for (;;) {
- buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
- &prot, &maj_dev, 0);
-
- if (buf_ptr == NULL) return FALSE;
- if (prot[1] == 'w' && maj_dev == 0) {
- if (my_end > addr && my_start <= addr) {
- *startp = my_start;
- *endp = my_end;
- return TRUE;
- }
+ if (0 == maps) return(FALSE);
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
+ &prot, &maj_dev, 0);
+
+ if (buf_ptr == NULL) return FALSE;
+ if (prot[1] == 'w' && maj_dev == 0) {
+ if (my_end > addr && my_start <= addr) {
+ *startp = my_start;
+ *endp = my_end;
+ return TRUE;
+ }
+ }
}
+ return FALSE;
}
- return FALSE;
-}
+#endif /* IA64 || INCLUDE_LINUX_THREAD_DESCR */
#if defined(REDIRECT_MALLOC)
/* Find the text(code) mapping for the library whose name, after */
@@ -425,7 +423,7 @@ GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
ptr_t my_start, my_end;
if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {
if (GC_print_stats) {
- GC_log_printf("Failed to find backing store base from /proc\n");
+ GC_log_printf("Failed to find backing store base from /proc\n");
}
return 0;
}
@@ -474,7 +472,7 @@ GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
# endif /* LINUX */
GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
}
-#endif
+#endif /* SEARCH_FOR_DATA_START */
#ifdef ECOS
@@ -568,7 +566,7 @@ GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
}
# ifdef THREADS
- /* Due to the siglongjump we need to manually unmask SIGPROF. */
+ /* Due to the siglongjump we need to manually unmask SIGPROF. */
__syscall(SYS_sigprocmask, SIG_UNBLOCK, sigmask(SIGPROF));
# endif
@@ -770,7 +768,6 @@ GC_INNER word GC_page_size = 0;
sb -> mem_base = trunc_sp + size;
return GC_SUCCESS;
}
-
# else /* CYGWIN32 */
/* An alternate version for Cygwin (adapted from Dave Korn's */
/* gcc version of boehm-gc). */
@@ -783,20 +780,12 @@ GC_INNER word GC_page_size = 0;
# endif /* CYGWIN32 */
# define HAVE_GET_STACK_BASE
- /* This is always called from the main thread. */
- ptr_t GC_get_main_stack_base(void)
- {
- struct GC_stack_base sb;
- GC_get_stack_base(&sb);
- GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
- return (ptr_t)sb.mem_base;
- }
-
#else /* !MSWIN32 */
GC_INNER void GC_setpagesize(void)
{
# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
GC_page_size = GETPAGESIZE();
+ if (!GC_page_size) ABORT("getpagesize() failed");
# else
/* It's acceptable to fake it. */
GC_page_size = HBLKSIZE;
@@ -806,25 +795,29 @@ GC_INNER word GC_page_size = 0;
#ifdef BEOS
# include <kernel/OS.h>
- ptr_t GC_get_main_stack_base(void)
+
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
{
thread_info th;
get_thread_info(find_thread(NULL),&th);
- return th.stack_end;
+ sb->mem_base = th.stack_end;
+ return GC_SUCCESS;
}
+# define HAVE_GET_STACK_BASE
#endif /* BEOS */
#ifdef OS2
- ptr_t GC_get_main_stack_base(void)
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
{
- PTIB ptib;
+ PTIB ptib; /* thread information block */
PPIB ppib;
-
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
ABORT("DosGetInfoBlocks failed");
}
- return((ptr_t)(ptib -> tib_pstacklimit));
+ sb->mem_base = ptib->tib_pstacklimit;
+ return GC_SUCCESS;
}
+# define HAVE_GET_STACK_BASE
#endif /* OS2 */
# ifdef AMIGA
@@ -850,22 +843,23 @@ GC_INNER word GC_page_size = 0;
GC_INNER void GC_set_and_save_fault_handler(GC_fault_handler_t h)
{
-# if defined(SUNOS5SIGS) || defined(IRIX5) \
+# if defined(SUNOS5SIGS) || defined(IRIX5) \
|| defined(OSF1) || defined(HURD) || defined(NETBSD)
- struct sigaction act;
+ struct sigaction act;
- act.sa_handler = h;
-# if 0 /* Was necessary for Solaris 2.3 and very temporary */
- /* NetBSD bugs. */
- act.sa_flags = SA_RESTART | SA_NODEFER;
+ act.sa_handler = h;
+# ifdef SIGACTION_FLAGS_NODEFER_HACK
+ /* Was necessary for Solaris 2.3 and very temporary */
+ /* NetBSD bugs. */
+ act.sa_flags = SA_RESTART | SA_NODEFER;
# else
- act.sa_flags = SA_RESTART;
+ act.sa_flags = SA_RESTART;
# endif
(void) sigemptyset(&act.sa_mask);
# ifdef GC_IRIX_THREADS
- /* Older versions have a bug related to retrieving and */
- /* and setting a handler at the same time. */
+ /* Older versions have a bug related to retrieving and */
+ /* and setting a handler at the same time. */
(void) sigaction(SIGSEGV, 0, &old_segv_act);
(void) sigaction(SIGSEGV, &act, 0);
# else
@@ -873,9 +867,9 @@ GC_INNER word GC_page_size = 0;
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
|| defined(HPUX) || defined(HURD) || defined(NETBSD) \
|| defined(FREEBSD)
- /* 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. */
+ /* 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. */
(void) sigaction(SIGBUS, &act, &old_bus_act);
# endif
# endif /* GC_IRIX_THREADS */
@@ -888,8 +882,8 @@ GC_INNER word GC_page_size = 0;
}
# endif /* NEED_FIND_LIMIT || UNIX_LIKE */
-# if defined(NEED_FIND_LIMIT) || \
- defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
+# if defined(NEED_FIND_LIMIT) \
+ || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
/* Some tools to implement HEURISTIC2 */
# define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
@@ -901,8 +895,8 @@ GC_INNER word GC_page_size = 0;
GC_INNER void GC_setup_temporary_fault_handler(void)
{
- /* Handler is process-wide, so this should only happen in */
- /* one thread at a time. */
+ /* Handler is process-wide, so this should only happen in */
+ /* one thread at a time. */
GC_ASSERT(I_HOLD_LOCK());
GC_set_and_save_fault_handler(GC_fault_handler);
}
@@ -1033,7 +1027,7 @@ GC_INNER word GC_page_size = 0;
}
# endif /* IA64 */
- STATIC ptr_t GC_linux_stack_base(void)
+ STATIC ptr_t GC_linux_main_stack_base(void)
{
/* We read the stack base value from /proc/self/stat. We do this */
/* using direct I/O system calls in order to avoid calling malloc */
@@ -1107,11 +1101,9 @@ GC_INNER word GC_page_size = 0;
ABORT("Absurd stack bottom value");
return (ptr_t)result;
}
-
#endif /* LINUX_STACKBOTTOM */
#ifdef FREEBSD_STACKBOTTOM
-
/* This uses an undocumented sysctl call, but at least one expert */
/* believes it will stay. */
@@ -1119,15 +1111,13 @@ GC_INNER word GC_page_size = 0;
# include <sys/types.h>
# include <sys/sysctl.h>
- STATIC ptr_t GC_freebsd_stack_base(void)
+ STATIC ptr_t GC_freebsd_main_stack_base(void)
{
int nm[2] = {CTL_KERN, KERN_USRSTACK};
ptr_t base;
size_t len = sizeof(ptr_t);
int r = sysctl(nm, 2, &base, &len, NULL, 0);
-
- if (r) ABORT("Error getting stack base");
-
+ if (r) ABORT("Error getting main stack base");
return base;
}
#endif /* FREEBSD_STACKBOTTOM */
@@ -1137,6 +1127,7 @@ GC_INNER word GC_page_size = 0;
{
return STACKBOTTOM;
}
+# define GET_MAIN_STACKBASE_SPECIAL
#elif !defined(BEOS) && !defined(AMIGA) && !defined(OS2) \
&& !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) \
&& !defined(GC_OPENBSD_THREADS) \
@@ -1155,7 +1146,9 @@ GC_INNER word GC_page_size = 0;
ptr_t GC_get_main_stack_base(void)
{
ptr_t result; /* also used as "dummy" to get the approx. sp value */
-# if defined(LINUX) && defined(USE_GET_STACKBASE_FOR_MAIN) && !defined(NACL)
+# if defined(LINUX) && !defined(NACL) \
+ && (defined(USE_GET_STACKBASE_FOR_MAIN) \
+ || (defined(THREADS) && !defined(REDIRECT_MALLOC)))
pthread_attr_t attr;
void *stackaddr;
size_t size;
@@ -1186,10 +1179,10 @@ GC_INNER word GC_page_size = 0;
# endif
# endif /* HEURISTIC1 */
# ifdef LINUX_STACKBOTTOM
- result = GC_linux_stack_base();
+ result = GC_linux_main_stack_base();
# endif
# ifdef FREEBSD_STACKBOTTOM
- result = GC_freebsd_stack_base();
+ result = GC_freebsd_main_stack_base();
# endif
# ifdef HEURISTIC2
# ifdef STACK_GROWS_DOWN
@@ -1218,19 +1211,14 @@ GC_INNER word GC_page_size = 0;
GC_ASSERT((ptr_t)(&result) HOTTER_THAN result);
return(result);
}
+# define GET_MAIN_STACKBASE_SPECIAL
#endif /* !AMIGA, !BEOS, !OPENBSD, !OS2, !Windows */
-#if defined(GC_LINUX_THREADS) && !defined(HAVE_GET_STACK_BASE) \
- && !defined(NACL)
+#if (defined(GC_LINUX_THREADS) || defined(PLATFORM_ANDROID)) && !defined(NACL)
# include <pthread.h>
/* extern int pthread_getattr_np(pthread_t, pthread_attr_t *); */
-# ifdef IA64
- GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound);
- /* From pthread_support.c */
-# endif
-
GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
{
pthread_attr_t attr;
@@ -1277,7 +1265,6 @@ GC_INNER word GC_page_size = 0;
# endif
return GC_SUCCESS;
}
-
# define HAVE_GET_STACK_BASE
#endif /* GC_LINUX_THREADS */
@@ -1311,17 +1298,7 @@ GC_INNER word GC_page_size = 0;
sb->mem_base = stack.ss_sp;
return GC_SUCCESS;
}
-
# define HAVE_GET_STACK_BASE
-
- /* This is always called from the main thread. */
- ptr_t GC_get_main_stack_base(void)
- {
- struct GC_stack_base sb;
- GC_get_stack_base(&sb);
- GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
- return (ptr_t)sb.mem_base;
- }
#endif /* GC_OPENBSD_THREADS */
#if defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC)
@@ -1360,7 +1337,7 @@ GC_INNER word GC_page_size = 0;
/* s.ss_sp holds the pointer to the stack bottom. */
GC_ASSERT((void *)&s HOTTER_THAN s.ss_sp);
- if (!stackbase_main_self)
+ if (!stackbase_main_self && thr_main() != 0)
{
/* Cache the stack base value for the primordial thread (this */
/* is done during GC_init, so there is no race). */
@@ -1371,19 +1348,7 @@ GC_INNER word GC_page_size = 0;
b -> mem_base = s.ss_sp;
return GC_SUCCESS;
}
-
# define HAVE_GET_STACK_BASE
-
- /* This is always called from the main thread. The above */
- /* implementation of GC_get_stack_base() requires the latter to be */
- /* first called from GC_get_main_stack_base() (to cache the proper */
- /* ss_sp value). */
- ptr_t GC_get_main_stack_base(void)
- {
- struct GC_stack_base sb;
- GC_get_stack_base(&sb);
- return (ptr_t)sb.mem_base;
- }
#endif /* GC_SOLARIS_THREADS */
#ifndef HAVE_GET_STACK_BASE
@@ -1420,14 +1385,22 @@ GC_INNER word GC_page_size = 0;
}
#endif /* !HAVE_GET_STACK_BASE */
-/*
- * Register static data segment(s) as roots.
- * If more data segments are added later then they need to be registered
- * add that point (as we do with SunOS dynamic loading),
- * or GC_mark_roots needs to check for them (as we do with PCR).
- * Called with allocator lock held.
- */
+#ifndef GET_MAIN_STACKBASE_SPECIAL
+ /* This is always called from the main thread. Default implementation. */
+ ptr_t GC_get_main_stack_base(void)
+ {
+ struct GC_stack_base sb;
+ if (GC_get_stack_base(&sb) != GC_SUCCESS)
+ ABORT("GC_get_stack_base failed");
+ GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
+ return (ptr_t)sb.mem_base;
+ }
+#endif /* !GET_MAIN_STACKBASE_SPECIAL */
+/* Register static data segment(s) as roots. If more data segments are */
+/* added later then they need to be registered at that point (as we do */
+/* with SunOS dynamic loading), or GC_mark_roots needs to check for */
+/* them (as we do with PCR). Called with allocator lock held. */
# ifdef OS2
void GC_register_data_segments(void)
@@ -1553,11 +1526,9 @@ void GC_register_data_segments(void)
# else /* !OS2 */
# if defined(GWW_VDB)
-
# ifndef MEM_WRITE_WATCH
# define MEM_WRITE_WATCH 0x200000
# endif
-
# ifndef WRITE_WATCH_FLAG_RESET
# define WRITE_WATCH_FLAG_RESET 1
# endif
@@ -1644,9 +1615,9 @@ void GC_register_data_segments(void)
done = TRUE;
}
-# else /* !GWW_VDB */
+# else
# define GetWriteWatch_alloc_flag 0
-# endif /* GWW_VDB */
+# endif /* !GWW_VDB */
# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
@@ -1716,7 +1687,7 @@ void GC_register_data_segments(void)
/* the malloc heap with HeapWalk on the default heap. But that */
/* apparently works only for NT-based Windows. */
- STATIC size_t GC_max_root_size = 100000; /* Appr. largest root size. */
+ STATIC size_t GC_max_root_size = 100000; /* Appr. largest root size. */
# ifndef CYGWIN32
/* In the long run, a better data structure would also be nice ... */
@@ -1775,8 +1746,8 @@ void GC_register_data_segments(void)
}
}
if (GC_print_stats)
- GC_log_printf("Found new system malloc AllocationBase at %p\n",
- candidate);
+ GC_log_printf("Found new system malloc AllocationBase at %p\n",
+ candidate);
new_l -> allocation_base = candidate;
new_l -> next = GC_malloc_heap_l;
GC_malloc_heap_l = new_l;
@@ -2009,7 +1980,8 @@ void GC_register_data_segments(void)
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
&& !defined(MSWINCE) && !defined(MACOS) && !defined(DOS4GW) \
- && !defined(NONSTOP) && !defined(SN_TARGET_PS3)
+ && !defined(NONSTOP) && !defined(SN_TARGET_PS3) && !defined(RTEMS) \
+ && !defined(__CC_ARM)
# define SBRK_ARG_T ptrdiff_t
@@ -2056,7 +2028,7 @@ STATIC ptr_t GC_unix_mmap_get_mem(word bytes)
if (bytes & (GC_page_size - 1)) ABORT("Bad GET_MEM arg");
result = mmap(last_addr, bytes, (PROT_READ | PROT_WRITE)
- | (pages_executable ? PROT_EXEC : 0),
+ | (GC_pages_executable ? PROT_EXEC : 0),
GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */);
# undef IGNORE_PAGES_EXECUTABLE
@@ -2069,7 +2041,7 @@ STATIC ptr_t GC_unix_mmap_get_mem(word bytes)
/* usable by arbitrary C code, since one-past-end pointers */
/* don't work, so we discard it and try again. */
munmap(result, (size_t)(-GC_page_size) - (size_t)result);
- /* Leave last page mapped, so we can't repeat. */
+ /* Leave last page mapped, so we can't repeat. */
return GC_unix_mmap_get_mem(bytes);
}
# else
@@ -2161,7 +2133,7 @@ void * os2_alloc(size_t bytes)
void * result;
if (DosAllocMem(&result, bytes, (PAG_READ | PAG_WRITE | PAG_COMMIT)
- | (pages_executable ? PAG_EXECUTE : 0))
+ | (GC_pages_executable ? PAG_EXECUTE : 0))
!= NO_ERROR) {
return(0);
}
@@ -2240,8 +2212,8 @@ void * os2_alloc(size_t bytes)
GetWriteWatch_alloc_flag
| (MEM_COMMIT | MEM_RESERVE)
| GC_mem_top_down,
- pages_executable ? PAGE_EXECUTE_READWRITE :
- PAGE_READWRITE);
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
# undef IGNORE_PAGES_EXECUTABLE
}
# endif /* !CYGWIN32 */
@@ -2256,13 +2228,18 @@ void * os2_alloc(size_t bytes)
GC_API void GC_CALL GC_win32_free_heap(void)
{
# ifndef CYGWIN32
- if (GC_no_win32_dlls) {
- while (GC_n_heap_bases > 0) {
- GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
- GC_heap_bases[GC_n_heap_bases] = 0;
- }
- }
+ if (GC_no_win32_dlls)
# endif
+ {
+ while (GC_n_heap_bases-- > 0) {
+# ifdef CYGWIN32
+ /* FIXME: Is it ok to use non-GC free() here? */
+# else
+ GlobalFree(GC_heap_bases[GC_n_heap_bases]);
+# endif
+ GC_heap_bases[GC_n_heap_bases] = 0;
+ }
+ }
}
#endif /* MSWIN32 || CYGWIN32 */
@@ -2302,8 +2279,8 @@ void * os2_alloc(size_t bytes)
/* argument to span regions, so we should be OK for now. */
result = (ptr_t) VirtualAlloc(NULL, res_bytes,
MEM_RESERVE | MEM_TOP_DOWN,
- pages_executable ? PAGE_EXECUTE_READWRITE :
- PAGE_READWRITE);
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
/* If I read the documentation correctly, this can */
/* only happen if HBLKSIZE > 64k or not a power of 2. */
@@ -2316,8 +2293,8 @@ void * os2_alloc(size_t bytes)
/* Commit pages */
result = (ptr_t) VirtualAlloc(result, bytes, MEM_COMMIT,
- pages_executable ? PAGE_EXECUTE_READWRITE :
- PAGE_READWRITE);
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
# undef IGNORE_PAGES_EXECUTABLE
if (result != NULL) {
@@ -2428,8 +2405,8 @@ GC_INNER void GC_remap(ptr_t start, size_t bytes)
ABORT("Weird VirtualQuery result");
alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
result = VirtualAlloc(start_addr, alloc_len, MEM_COMMIT,
- pages_executable ? PAGE_EXECUTE_READWRITE :
- PAGE_READWRITE);
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
if (result != start_addr) {
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
GetLastError() == ERROR_OUTOFMEMORY) {
@@ -2449,12 +2426,12 @@ GC_INNER void GC_remap(ptr_t start, size_t bytes)
# ifndef NACL
result = mprotect(start_addr, len, (PROT_READ | PROT_WRITE)
- | (pages_executable ? PROT_EXEC : 0));
+ | (GC_pages_executable ? PROT_EXEC : 0));
# else
{
/* NaCl does not expose mprotect, but mmap should work fine. */
void *mmap_result = mmap(start_addr, len, (PROT_READ | PROT_WRITE)
- | (pages_executable ? PROT_EXEC : 0),
+ | (GC_pages_executable ? PROT_EXEC : 0),
MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
zero_fd, 0 /* offset */);
if (mmap_result != (void *)start_addr)
@@ -2467,9 +2444,9 @@ GC_INNER void GC_remap(ptr_t start, size_t bytes)
if (result != 0) {
if (GC_print_stats)
- GC_printf("Mprotect failed at %p (length %lu) with errno %d\n",
- start_addr, (unsigned long)len, errno);
- ABORT("Mprotect remapping failed");
+ GC_log_printf("Mprotect failed at %p (length %lu) with errno %d\n",
+ start_addr, (unsigned long)len, errno);
+ ABORT("mprotect remapping failed");
}
GC_unmapped_bytes -= len;
# endif
@@ -2565,39 +2542,33 @@ STATIC void GC_default_push_other_roots(void)
/* Traverse all thread stacks. */
if (PCR_ERes_IsErr(
PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
- || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
- ABORT("Thread stack marking failed\n");
+ || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
+ ABORT("Thread stack marking failed");
}
}
# endif /* PCR */
-
# if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
-
-GC_INNER void GC_push_all_stacks(void);
-
-STATIC void GC_default_push_other_roots(void)
-{
- GC_push_all_stacks();
-}
-
+ STATIC void GC_default_push_other_roots(void)
+ {
+ GC_push_all_stacks();
+ }
# endif /* GC_WIN32_THREADS || GC_PTHREADS */
# ifdef SN_TARGET_PS3
STATIC void GC_default_push_other_roots(void)
{
- ABORT("GC_default_push_other_roots is not implemented\n");
+ ABORT("GC_default_push_other_roots is not implemented");
}
void GC_push_thread_structures(void)
{
- ABORT("GC_push_thread_structures is not implemented\n");
+ ABORT("GC_push_thread_structures is not implemented");
}
# endif /* SN_TARGET_PS3 */
GC_INNER void (*GC_push_other_roots)(void) = GC_default_push_other_roots;
-
#endif /* THREADS */
/*
@@ -2648,9 +2619,45 @@ STATIC void GC_default_push_other_roots(void)
STATIC void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
{
register int i;
-
for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
}
+
+# ifdef MPROTECT_VDB
+ STATIC GC_bool GC_gww_page_was_dirty(struct hblk * h)
+# else
+ GC_INNER GC_bool GC_page_was_dirty(struct hblk * h)
+# endif
+ {
+ register word index;
+ if (HDR(h) == 0)
+ return TRUE;
+ index = PHT_HASH(h);
+ return get_pht_entry_from_index(GC_grungy_pages, index);
+ }
+
+# if defined(CHECKSUMS) || defined(PROC_VDB)
+ /* Used only if GWW_VDB. */
+# ifdef MPROTECT_VDB
+ STATIC GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
+# else
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h)
+# endif
+ {
+ register word index;
+ if (HDR(h) == 0)
+ return TRUE;
+ index = PHT_HASH(h);
+ return get_pht_entry_from_index(GC_written_pages, index);
+ }
+# endif /* CHECKSUMS || PROC_VDB */
+
+# ifndef MPROTECT_VDB
+ /* Ignore write hints. They don't help us here. */
+ /*ARGSUSED*/
+ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
+ GC_bool is_ptrfree) {}
+# endif
+
#endif /* PROC_VDB || GWW_VDB */
#ifdef GWW_VDB
@@ -2672,7 +2679,7 @@ STATIC void GC_default_push_other_roots(void)
detect_GetWriteWatch();
GC_dirty_maintained = GC_GWW_AVAILABLE();
}
-# endif
+# endif /* !MPROTECT_VDB */
# ifdef MPROTECT_VDB
STATIC void GC_gww_read_dirty(void)
@@ -2693,23 +2700,20 @@ STATIC void GC_default_push_other_roots(void)
pages = gww_buf;
count = GC_GWW_BUF_LEN;
- /*
- * GetWriteWatch is documented as returning non-zero when it fails,
- * but the documentation doesn't explicitly say why it would fail or
- * what its behaviour will be if it fails.
- * It does appear to fail, at least on recent W2K instances, if
- * the underlying memory was not allocated with the appropriate
- * flag. This is common if GC_enable_incremental is called
- * shortly after GC initialization. To avoid modifying the
- * interface, we silently work around such a failure, it it only
- * affects the initial (small) heap allocation.
- * If there are more dirty
- * pages than will fit in the buffer, this is not treated as a
- * failure; we must check the page count in the loop condition.
- * Since each partial call will reset the status of some
- * pages, this should eventually terminate even in the overflow
- * case.
- */
+ /* GetWriteWatch is documented as returning non-zero when it */
+ /* fails, but the documentation doesn't explicitly say why it */
+ /* would fail or what its behaviour will be if it fails. */
+ /* It does appear to fail, at least on recent W2K instances, if */
+ /* the underlying memory was not allocated with the appropriate */
+ /* flag. This is common if GC_enable_incremental is called */
+ /* shortly after GC initialization. To avoid modifying the */
+ /* interface, we silently work around such a failure, it only */
+ /* affects the initial (small) heap allocation. If there are */
+ /* more dirty pages than will fit in the buffer, this is not */
+ /* treated as a failure; we must check the page count in the */
+ /* loop condition. Since each partial call will reset the */
+ /* status of some pages, this should eventually terminate even */
+ /* in the overflow case. */
if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
GC_heap_sects[i].hs_start,
GC_heap_sects[i].hs_bytes,
@@ -2733,7 +2737,7 @@ STATIC void GC_default_push_other_roots(void)
set_pht_entry_from_index(GC_grungy_pages, hash);
}
count = 1; /* Done with this section. */
- } else /* succeeded */{
+ } else /* succeeded */ {
pages_end = pages + count;
while (pages != pages_end) {
struct hblk * h = (struct hblk *) *pages++;
@@ -2744,47 +2748,16 @@ STATIC void GC_default_push_other_roots(void)
}
}
} while (count == GC_GWW_BUF_LEN);
- /* FIXME: It's unclear from Microsoft's documentation if this loop */
- /* is useful. We suspect the call just fails if the buffer fills */
- /* up. But that should still be handled correctly. */
+ /* FIXME: It's unclear from Microsoft's documentation if this loop */
+ /* is useful. We suspect the call just fails if the buffer fills */
+ /* up. But that should still be handled correctly. */
}
GC_or_pages(GC_written_pages, GC_grungy_pages);
}
-
-# ifdef MPROTECT_VDB
- STATIC GC_bool GC_gww_page_was_dirty(struct hblk * h)
-# else
- GC_INNER GC_bool GC_page_was_dirty(struct hblk * h)
-# endif
- {
- return HDR(h) == 0 ||
- get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
- }
-
-# ifdef CHECKSUMS
- /* Used only if PROC_VDB. */
-# ifdef MPROTECT_VDB
- STATIC GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
-# else
- GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h)
-# endif
- {
- return HDR(h) == 0 ||
- get_pht_entry_from_index(GC_written_pages, PHT_HASH(h));
- }
-# endif /* CHECKSUMS */
-
-# ifndef MPROTECT_VDB
- /*ARGSUSED*/
- GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
- GC_bool is_ptrfree) {}
-# endif
-
#endif /* GWW_VDB */
#ifdef DEFAULT_VDB
-
/* All of the following assume the allocation lock is held. */
/* The client asserts that unallocated pages in the heap are never */
@@ -2812,12 +2785,10 @@ STATIC void GC_default_push_other_roots(void)
return(TRUE);
}
- /*
- * The following two routines are typically less crucial. They matter
- * most with large dynamic libraries, or if we can't accurately identify
- * stacks, e.g. under Solaris 2.X. Otherwise the following default
- * versions are adequate.
- */
+ /* The following two routines are typically less crucial. */
+ /* They matter most with large dynamic libraries, or if we can't */
+ /* accurately identify stacks, e.g. under Solaris 2.X. Otherwise the */
+ /* following default versions are adequate. */
# ifdef CHECKSUMS
/* Could any valid GC heap pointer ever have been written to this page? */
/*ARGSUSED*/
@@ -2837,17 +2808,15 @@ STATIC void GC_default_push_other_roots(void)
/*ARGSUSED*/
GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
GC_bool is_ptrfree) {}
-
#endif /* DEFAULT_VDB */
#ifdef MANUAL_VDB
-
/* Initialize virtual dirty bit implementation. */
GC_INNER void GC_dirty_init(void)
{
if (GC_print_stats == VERBOSE)
GC_log_printf("Initializing MANUAL_VDB...\n");
- /* GC_dirty_pages and GC_grungy_pages are already cleared. */
+ /* GC_dirty_pages and GC_grungy_pages are already cleared. */
GC_dirty_maintained = TRUE;
}
@@ -2870,6 +2839,9 @@ STATIC void GC_default_push_other_roots(void)
return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
}
+# define async_set_pht_entry_from_index(db, index) \
+ set_pht_entry_from_index(db, index) /* for now */
+
/* Mark the page containing p as dirty. Logically, this dirties the */
/* entire object. */
void GC_dirty(ptr_t p)
@@ -2885,7 +2857,7 @@ STATIC void GC_default_push_other_roots(void)
# ifdef CHECKSUMS
/* Could any valid GC heap pointer ever have been written to this page? */
/*ARGSUSED*/
- GC_bool GC_page_was_ever_dirty(struct hblk *h)
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
{
/* FIXME - implement me. */
return(TRUE);
@@ -2894,9 +2866,7 @@ STATIC void GC_default_push_other_roots(void)
#endif /* MANUAL_VDB */
-
#ifdef MPROTECT_VDB
-
/* See DEFAULT_VDB for interface descriptions. */
/*
@@ -2922,16 +2892,16 @@ STATIC void GC_default_push_other_roots(void)
# define PROTECT(addr,len) \
if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
FALSE, VM_PROT_READ \
- | (pages_executable ? VM_PROT_EXECUTE : 0)) \
+ | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \
!= KERN_SUCCESS) { \
- ABORT("vm_protect (PROTECT) failed"); \
+ ABORT("vm_protect(PROTECT) failed"); \
}
# define UNPROTECT(addr,len) \
if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
FALSE, (VM_PROT_READ | VM_PROT_WRITE) \
- | (pages_executable ? VM_PROT_EXECUTE : 0)) \
+ | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \
!= KERN_SUCCESS) { \
- ABORT("vm_protect (UNPROTECT) failed"); \
+ ABORT("vm_protect(UNPROTECT) failed"); \
}
# elif !defined(MSWIN32) && !defined(MSWINCE)
@@ -2940,19 +2910,19 @@ STATIC void GC_default_push_other_roots(void)
# include <sys/syscall.h>
# define PROTECT(addr, len) \
- if (mprotect((caddr_t)(addr), (size_t)(len), \
- PROT_READ \
- | (pages_executable ? PROT_EXEC : 0)) < 0) { \
- ABORT("mprotect failed"); \
- }
+ if (mprotect((caddr_t)(addr), (size_t)(len), \
+ PROT_READ \
+ | (GC_pages_executable ? PROT_EXEC : 0)) < 0) { \
+ ABORT("mprotect failed"); \
+ }
# define UNPROTECT(addr, len) \
- if (mprotect((caddr_t)(addr), (size_t)(len), \
- (PROT_READ | PROT_WRITE) \
- | (pages_executable ? PROT_EXEC : 0)) < 0) { \
- ABORT(pages_executable ? "un-mprotect executable page" \
- " failed (probably disabled by OS)" : \
- "un-mprotect failed"); \
- }
+ if (mprotect((caddr_t)(addr), (size_t)(len), \
+ (PROT_READ | PROT_WRITE) \
+ | (GC_pages_executable ? PROT_EXEC : 0)) < 0) { \
+ ABORT(GC_pages_executable ? "un-mprotect executable page" \
+ " failed (probably disabled by OS)" : \
+ "un-mprotect failed"); \
+ }
# undef IGNORE_PAGES_EXECUTABLE
# else /* MSWIN32 */
@@ -2962,21 +2932,21 @@ STATIC void GC_default_push_other_roots(void)
static DWORD protect_junk;
# define PROTECT(addr, len) \
- if (!VirtualProtect((addr), (len), \
- pages_executable ? PAGE_EXECUTE_READ : \
- PAGE_READONLY, \
- &protect_junk)) { \
- if (GC_print_stats) \
- GC_printf("Last error code: 0x%lx\n", (long)GetLastError()); \
- ABORT("VirtualProtect failed"); \
- }
+ if (!VirtualProtect((addr), (len), \
+ GC_pages_executable ? PAGE_EXECUTE_READ : \
+ PAGE_READONLY, \
+ &protect_junk)) { \
+ if (GC_print_stats) \
+ GC_log_printf("Last error code: 0x%lx\n", (long)GetLastError()); \
+ ABORT("VirtualProtect failed"); \
+ }
# define UNPROTECT(addr, len) \
- if (!VirtualProtect((addr), (len), \
- pages_executable ? PAGE_EXECUTE_READWRITE : \
- PAGE_READWRITE, \
- &protect_junk)) { \
- ABORT("un-VirtualProtect failed"); \
- }
+ if (!VirtualProtect((addr), (len), \
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE : \
+ PAGE_READWRITE, \
+ &protect_junk)) { \
+ ABORT("un-VirtualProtect failed"); \
+ }
# endif /* MSWIN32 || MSWINCE || DARWIN */
# if defined(MSWIN32)
@@ -3105,7 +3075,9 @@ STATIC void GC_default_push_other_roots(void)
# elif defined(SUNOS5SIGS)
# define CODE_OK (si -> si_code == SEGV_ACCERR)
# endif
-# include <ucontext.h>
+# ifndef NO_GETCONTEXT
+# include <ucontext.h>
+# endif
/*ARGSUSED*/
STATIC void GC_write_fault_handler(int sig, siginfo_t *si, void *raw_sc)
# else
@@ -3113,7 +3085,7 @@ STATIC void GC_default_push_other_roots(void)
== STATUS_ACCESS_VIOLATION)
# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] \
== 1) /* Write fault */
- GC_INNER LONG WINAPI GC_write_fault_handler(
+ STATIC LONG WINAPI GC_write_fault_handler(
struct _EXCEPTION_POINTERS *exc_info)
# endif /* MSWIN32 || MSWINCE */
{
@@ -3139,6 +3111,7 @@ STATIC void GC_default_push_other_roots(void)
for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
if (HDR(h+i) != 0) {
in_allocd_block = TRUE;
+ break;
}
}
# else
@@ -3169,7 +3142,7 @@ STATIC void GC_default_push_other_roots(void)
if (old_handler == (SIG_HNDLR_PTR)SIG_DFL) {
# if !defined(MSWIN32) && !defined(MSWINCE)
if (GC_print_stats)
- GC_printf("Unexpected segfault at %p\n", addr);
+ GC_log_printf("Unexpected segfault at %p\n", addr);
ABORT("Unexpected bus error or segmentation fault");
# else
return(EXCEPTION_CONTINUE_SEARCH);
@@ -3221,20 +3194,25 @@ STATIC void GC_default_push_other_roots(void)
return EXCEPTION_CONTINUE_SEARCH;
# else
if (GC_print_stats)
- GC_printf("Unexpected segfault at %p\n", addr);
+ GC_log_printf("Unexpected segfault at %p\n", addr);
ABORT("Unexpected bus error or segmentation fault");
# endif
}
+
+# ifdef GC_WIN32_THREADS
+ GC_INNER void GC_set_write_fault_handler(void)
+ {
+ SetUnhandledExceptionFilter(GC_write_fault_handler);
+ }
+# endif
#endif /* !DARWIN */
-/*
- * We hold the allocation lock. We expect block h to be written
- * shortly. Ensure that all pages containing any part of the n hblks
- * starting at h are no longer protected. If is_ptrfree is false,
- * also ensure that they will subsequently appear to be dirty.
- * Not allowed to call GC_printf (and the friends) here, see Win32
- * GC_stop_world() for the information.
- */
+/* We hold the allocation lock. We expect block h to be written */
+/* shortly. Ensure that all pages containing any part of the n hblks */
+/* starting at h are no longer protected. If is_ptrfree is false, also */
+/* ensure that they will subsequently appear to be dirty. Not allowed */
+/* to call GC_printf (and the friends) here, see Win32 GC_stop_world() */
+/* for the information. */
GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
GC_bool is_ptrfree)
{
@@ -3279,7 +3257,7 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
# endif /* SIG_SUSPEND */
# endif
if (GC_print_stats == VERBOSE)
- GC_log_printf(
+ GC_log_printf(
"Initializing mprotect virtual dirty bit implementation\n");
GC_dirty_maintained = TRUE;
if (GC_page_size % HBLKSIZE != 0) {
@@ -3578,66 +3556,57 @@ ssize_t read(int fd, void *buf, size_t nbyte)
/* We should probably also do this for __read, or whatever stdio */
/* actually calls. */
#endif
-
#endif /* 0 */
-#ifdef CHECKSUMS
- /*ARGSUSED*/
- GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
- {
-# if defined(GWW_VDB)
- if (GC_GWW_AVAILABLE())
- return GC_gww_page_was_ever_dirty(h);
-# endif
- return(TRUE);
- }
-#endif /* CHECKSUMS */
+# ifdef CHECKSUMS
+ /*ARGSUSED*/
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
+ {
+# if defined(GWW_VDB)
+ if (GC_GWW_AVAILABLE())
+ return GC_gww_page_was_ever_dirty(h);
+# endif
+ return(TRUE);
+ }
+# endif /* CHECKSUMS */
-# endif /* MPROTECT_VDB */
+#endif /* MPROTECT_VDB */
-# ifdef PROC_VDB
+#ifdef PROC_VDB
+/* See DEFAULT_VDB for interface descriptions. */
-/*
- * See DEFAULT_VDB for interface descriptions.
- */
+/* This implementation assumes a Solaris 2.X like /proc */
+/* pseudo-file-system from which we can read page modified bits. This */
+/* facility is far from optimal (e.g. we would like to get the info for */
+/* only some of the address space), but it avoids intercepting system */
+/* calls. */
-/*
- * This implementation assumes a Solaris 2.X like /proc pseudo-file-system
- * from which we can read page modified bits. This facility is far from
- * optimal (e.g. we would like to get the info for only some of the
- * address space), but it avoids intercepting system calls.
- */
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/signal.h>
-#include <sys/fault.h>
-#include <sys/syscall.h>
-#include <sys/procfs.h>
-#include <sys/stat.h>
-
-#define INITIAL_BUF_SZ 16384
-STATIC word GC_proc_buf_size = INITIAL_BUF_SZ;
-STATIC char *GC_proc_buf = NULL;
+# include <errno.h>
+# include <sys/types.h>
+# include <sys/signal.h>
+# include <sys/fault.h>
+# include <sys/syscall.h>
+# include <sys/procfs.h>
+# include <sys/stat.h>
-STATIC int GC_proc_fd = 0;
+# define INITIAL_BUF_SZ 16384
+ STATIC word GC_proc_buf_size = INITIAL_BUF_SZ;
+ STATIC char *GC_proc_buf = NULL;
+ STATIC int GC_proc_fd = 0;
GC_INNER void GC_dirty_init(void)
{
int fd;
char buf[30];
- GC_dirty_maintained = TRUE;
if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) {
- register int i;
-
- for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
- if (GC_print_stats == VERBOSE)
- GC_log_printf(
- "Allocated bytes:%lu:all pages may have been written\n",
- (unsigned long)
- (GC_bytes_allocd + GC_bytes_allocd_before_gc));
+ memset(GC_written_pages, 0xff, sizeof(page_hash_table));
+ if (GC_print_stats == VERBOSE)
+ GC_log_printf("Allocated bytes:%lu:all pages may have been written\n",
+ (unsigned long)(GC_bytes_allocd
+ + GC_bytes_allocd_before_gc));
}
+
sprintf(buf, "/proc/%ld", (long)getpid());
fd = open(buf, O_RDONLY);
if (fd < 0) {
@@ -3647,104 +3616,98 @@ GC_INNER void GC_dirty_init(void)
close(fd);
syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC);
if (GC_proc_fd < 0) {
- ABORT("/proc ioctl failed");
+ WARN("/proc ioctl(PIOCOPENPD) failed", 0);
+ return;
}
+
+ GC_dirty_maintained = TRUE;
GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
}
-/* Ignore write hints. They don't help us here. */
-/*ARGSUSED*/
-GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
- GC_bool is_ptrfree) {}
-
-# define READ(fd,buf,nbytes) read(fd, buf, nbytes)
+# define READ read
GC_INNER void GC_read_dirty(void)
{
- unsigned long ps, np;
int nmaps;
- ptr_t vaddr;
+ unsigned long npages;
+ unsigned pagesize;
+ ptr_t vaddr, limit;
struct prasmap * map;
char * bufp;
- ptr_t current_addr, limit;
int i;
- BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
-
+ BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
bufp = GC_proc_buf;
if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
+ /* Retry with larger buffer. */
+ word new_size = 2 * GC_proc_buf_size;
+ char *new_buf;
if (GC_print_stats)
- GC_log_printf("/proc read failed: GC_proc_buf_size = %lu\n",
- (unsigned long)GC_proc_buf_size);
- {
- /* Retry with larger buffer. */
- word new_size = 2 * GC_proc_buf_size;
- char * new_buf = GC_scratch_alloc(new_size);
+ GC_err_printf("/proc read failed: GC_proc_buf_size = %lu\n",
+ (unsigned long)GC_proc_buf_size);
- if (new_buf != 0) {
- GC_proc_buf = bufp = new_buf;
- GC_proc_buf_size = new_size;
- }
- if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
- WARN("Insufficient space for /proc read\n", 0);
- /* Punt: */
- memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
- memset(GC_written_pages, 0xff, sizeof(page_hash_table));
- return;
- }
+ new_buf = GC_scratch_alloc(new_size);
+ if (new_buf != 0) {
+ GC_proc_buf = bufp = new_buf;
+ GC_proc_buf_size = new_size;
+ }
+ if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
+ WARN("Insufficient space for /proc read\n", 0);
+ /* Punt: */
+ memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
+ memset(GC_written_pages, 0xff, sizeof(page_hash_table));
+ return;
}
}
- /* Copy dirty bits into GC_grungy_pages */
- nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
- /* printf( "nmaps = %d, PG_REFERENCED = %d, PG_MODIFIED = %d\n",
- nmaps, PG_REFERENCED, PG_MODIFIED); */
- bufp = bufp + sizeof(struct prpageheader);
- for (i = 0; i < nmaps; i++) {
- map = (struct prasmap *)bufp;
- vaddr = (ptr_t)(map -> pr_vaddr);
- ps = map -> pr_pagesize;
- np = map -> pr_npage;
- /* printf("vaddr = 0x%X, ps = 0x%X, np = 0x%X\n", vaddr, ps, np); */
- limit = vaddr + ps * np;
- bufp += sizeof (struct prasmap);
- for (current_addr = vaddr;
- current_addr < limit; current_addr += ps) {
- if ((*bufp++) & PG_MODIFIED) {
- register struct hblk * h = (struct hblk *) current_addr;
-
- while ((ptr_t)h < current_addr + ps) {
- register word index = PHT_HASH(h);
-
- set_pht_entry_from_index(GC_grungy_pages, index);
- h++;
- }
+
+ /* Copy dirty bits into GC_grungy_pages */
+ nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf("Proc VDB read: pr_nmap= %u, pr_npage= %lu\n",
+ nmaps, ((struct prpageheader *)bufp)->pr_npage);
+
+# endif
+ bufp += sizeof(struct prpageheader);
+ for (i = 0; i < nmaps; i++) {
+ map = (struct prasmap *)bufp;
+ vaddr = (ptr_t)(map -> pr_vaddr);
+ npages = map -> pr_npage;
+ pagesize = map -> pr_pagesize;
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf(
+ "pr_vaddr= %p, npage= %lu, mflags= 0x%x, pagesize= 0x%x\n",
+ vaddr, npages, map->pr_mflags, pagesize);
+# endif
+
+ bufp += sizeof(struct prasmap);
+ limit = vaddr + pagesize * npages;
+ for (; vaddr < limit; vaddr += pagesize) {
+ if ((*bufp++) & PG_MODIFIED) {
+ register struct hblk * h;
+ ptr_t next_vaddr = vaddr + pagesize;
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf("dirty page at: %p\n", vaddr);
+# endif
+ for (h = (struct hblk *)vaddr; (ptr_t)h < next_vaddr; h++) {
+ register word index = PHT_HASH(h);
+ set_pht_entry_from_index(GC_grungy_pages, index);
}
}
- bufp += sizeof(long) - 1;
- bufp = (char *)((unsigned long)bufp & ~(sizeof(long)-1));
}
- /* Update GC_written_pages. */
- GC_or_pages(GC_written_pages, GC_grungy_pages);
-}
-
-#undef READ
-
-GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
-{
- register word index = PHT_HASH(h);
- return get_pht_entry_from_index(GC_grungy_pages, index);
-}
+ bufp = (char *)(((word)bufp + (sizeof(long)-1)) & ~(sizeof(long)-1));
+ }
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf("Proc VDB read done.\n");
+# endif
-GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
-{
- register word index = PHT_HASH(h);
- return get_pht_entry_from_index(GC_written_pages, index);
+ /* Update GC_written_pages. */
+ GC_or_pages(GC_written_pages, GC_grungy_pages);
}
-# endif /* PROC_VDB */
-
+# undef READ
+#endif /* PROC_VDB */
-# ifdef PCR_VDB
+#ifdef PCR_VDB
# include "vd/PCR_VD.h"
@@ -3766,7 +3729,7 @@ GC_INNER void GC_dirty_init(void)
}
if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
!= PCR_ERes_okay) {
- ABORT("dirty bit initialization failed");
+ ABORT("Dirty bit initialization failed");
}
}
@@ -3785,7 +3748,7 @@ GC_INNER void GC_read_dirty(void)
if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
!= PCR_ERes_okay) {
- ABORT("dirty bit read failed");
+ ABORT("Dirty bit read failed");
}
}
@@ -3805,7 +3768,7 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
}
-# endif /* PCR_VDB */
+#endif /* PCR_VDB */
#if defined(MPROTECT_VDB) && defined(DARWIN)
/* The following sources were used as a "reference" for this exception
@@ -3864,7 +3827,7 @@ catch_exception_raise_state(mach_port_name_t exception_port, int exception,
thread_state_t old_state, int old_stateCnt,
thread_state_t new_state, int new_stateCnt)
{
- ABORT("catch_exception_raise_state");
+ ABORT("Unexpected catch_exception_raise_state invocation");
return(KERN_INVALID_ARGUMENT);
}
@@ -3876,7 +3839,7 @@ catch_exception_raise_state_identity(mach_port_name_t exception_port,
thread_state_t old_state, int old_stateCnt,
thread_state_t new_state, int new_stateCnt)
{
- ABORT("catch_exception_raise_state_identity");
+ ABORT("Unexpected catch_exception_raise_state_identity invocation");
return(KERN_INVALID_ARGUMENT);
}
@@ -3950,7 +3913,7 @@ typedef enum {
if (r != MACH_MSG_SUCCESS)
ABORT("mach_msg failed in GC_mprotect_thread_notify");
if (buf.msg.head.msgh_id != ID_ACK)
- ABORT("invalid ack in GC_mprotect_thread_notify");
+ ABORT("Invalid ack in GC_mprotect_thread_notify");
}
/* Should only be called by the mprotect thread */
@@ -3986,17 +3949,17 @@ typedef enum {
GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
# endif
-#else /* !THREADS */
+#else
/* The compiler should optimize away any GC_mprotect_state computations */
# define GC_mprotect_state GC_MP_NORMAL
-#endif
+#endif /* !THREADS */
STATIC void *GC_mprotect_thread(void *arg)
{
mach_msg_return_t r;
- /* These two structures contain some private kernel data. We don't need to
- access any of it so we don't bother defining a proper struct. The
- correct definitions are in the xnu source code. */
+ /* These two structures contain some private kernel data. We don't */
+ /* need to access any of it so we don't bother defining a proper */
+ /* struct. The correct definitions are in the xnu source code. */
struct {
mach_msg_header_t head;
char data[256];
@@ -4028,14 +3991,14 @@ STATIC void *GC_mprotect_thread(void *arg)
continue;
}
if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
- ABORT("out of order mprotect thread request");
+ ABORT("Out of order mprotect thread request");
}
# endif /* THREADS */
if (r != MACH_MSG_SUCCESS) {
if (GC_print_stats)
- GC_printf("mach_msg failed with code %d: %s\n", (int)r,
- mach_error_string(r));
+ GC_log_printf("mach_msg failed with code %d: %s\n", (int)r,
+ mach_error_string(r));
ABORT("mach_msg failed");
}
@@ -4113,8 +4076,8 @@ GC_INNER void GC_dirty_init(void)
exception_mask_t mask;
if (GC_print_stats == VERBOSE)
- GC_log_printf("Initializing mach/darwin mprotect virtual dirty bit "
- "implementation\n");
+ GC_log_printf(
+ "Initializing mach/darwin mprotect virtual dirty bit implementation\n");
# ifdef BROKEN_EXCEPTION_HANDLING
WARN("Enabling workarounds for various darwin "
"exception handling bugs.\n", 0);
@@ -4174,7 +4137,7 @@ GC_INNER void GC_dirty_init(void)
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART|SA_SIGINFO;
if (sigaction(SIGBUS, &sa, &oldsa) < 0)
- ABORT("sigaction");
+ ABORT("sigaction failed");
if ((SIG_HNDLR_PTR)oldsa.sa_handler != SIG_DFL) {
if (GC_print_stats == VERBOSE)
GC_err_printf("Replaced other SIGBUS handler\n");
@@ -4183,9 +4146,9 @@ GC_INNER void GC_dirty_init(void)
# endif /* BROKEN_EXCEPTION_HANDLING */
}
-/* The source code for Apple's GDB was used as a reference for the exception
- forwarding code. This code is similar to be GDB code only because there is
- only one way to do it. */
+/* The source code for Apple's GDB was used as a reference for the */
+/* exception forwarding code. This code is similar to be GDB code only */
+/* because there is only one way to do it. */
STATIC kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
exception_type_t exception,
exception_data_t data,
@@ -4294,8 +4257,9 @@ catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
if (exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
# ifdef DEBUG_EXCEPTION_HANDLING
/* We aren't interested, pass it on to the old handler */
- GC_printf("Exception: 0x%x Code: 0x%x 0x%x in catch...\n", exception,
- code_count > 0 ? code[0] : -1, code_count > 1 ? code[1] : -1);
+ GC_log_printf("Exception: 0x%x Code: 0x%x 0x%x in catch...\n",
+ exception, code_count > 0 ? code[0] : -1,
+ code_count > 1 ? code[1] : -1);
# endif
return FWD();
}
@@ -4303,8 +4267,8 @@ catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
r = thread_get_state(thread, flavor, (natural_t*)&exc_state,
&exc_state_count);
if(r != KERN_SUCCESS) {
- /* The thread is supposed to be suspended while the exception handler
- is called. This shouldn't fail. */
+ /* The thread is supposed to be suspended while the exception */
+ /* handler is called. This shouldn't fail. */
# ifdef BROKEN_EXCEPTION_HANDLING
GC_err_printf("thread_get_state failed in catch_exception_raise\n");
return KERN_SUCCESS;
@@ -4316,11 +4280,11 @@ catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
/* This is the address that caused the fault */
addr = (char*) exc_state.DARWIN_EXC_STATE_DAR;
if (HDR(addr) == 0) {
- /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
- KERN_PROTECTION_FAILURE every once and a while. We wait till we get
- a bunch in a row before doing anything about it. If a "real" fault
- ever occurs it'll just keep faulting over and over and we'll hit
- the limit pretty quickly. */
+ /* Ugh... just like the SIGBUS problem above, it seems we get */
+ /* a bogus KERN_PROTECTION_FAILURE every once and a while. We wait */
+ /* till we get a bunch in a row before doing anything about it. */
+ /* If a "real" fault ever occurs it'll just keep faulting over and */
+ /* over and we'll hit the limit pretty quickly. */
# ifdef BROKEN_EXCEPTION_HANDLING
static char *last_fault;
static int last_fault_count;
@@ -4335,11 +4299,11 @@ catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
return KERN_SUCCESS;
}
- GC_err_printf("Unexpected KERN_PROTECTION_FAILURE at %p\n"
- "Aborting...\n", addr);
- /* Can't pass it along to the signal handler because that is
- ignoring SIGBUS signals. We also shouldn't call ABORT here as
- signals don't always work too well from the exception handler. */
+ GC_err_printf(
+ "Unexpected KERN_PROTECTION_FAILURE at %p; aborting...\n", addr);
+ /* Can't pass it along to the signal handler because that is */
+ /* ignoring SIGBUS signals. We also shouldn't call ABORT here as */
+ /* signals don't always work too well from the exception handler. */
exit(EXIT_FAILURE);
# else /* BROKEN_EXCEPTION_HANDLING */
/* Pass it along to the next exception handler
@@ -4399,9 +4363,9 @@ catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
GC_API void GC_CALL GC_set_pages_executable(int value)
{
GC_ASSERT(!GC_is_initialized);
- /* Even if IGNORE_PAGES_EXECUTABLE is defined, pages_executable is */
+ /* Even if IGNORE_PAGES_EXECUTABLE is defined, GC_pages_executable is */
/* touched here to prevent a compiler warning. */
- pages_executable = (GC_bool)(value != 0);
+ GC_pages_executable = (GC_bool)(value != 0);
}
/* Returns non-zero if the GC-allocated memory is executable. */
@@ -4412,14 +4376,12 @@ GC_API int GC_CALL GC_get_pages_executable(void)
# ifdef IGNORE_PAGES_EXECUTABLE
return 1; /* Always allocate executable memory. */
# else
- return (int)pages_executable;
+ return (int)GC_pages_executable;
# endif
}
-/*
- * Call stack save code for debugging.
- * Should probably be in mach_dep.c, but that requires reorganization.
- */
+/* Call stack save code for debugging. Should probably be in */
+/* mach_dep.c, but that requires reorganization. */
/* I suspect the following works for most X86 *nix variants, so */
/* long as the frame pointer is explicitly stored. In the case of gcc, */
@@ -4459,7 +4421,7 @@ GC_API int GC_CALL GC_get_pages_executable(void)
# include <sys/frame.h>
# endif
# if NARGS > 6
-# error We only know how to to get the first 6 arguments
+# error We only know how to get the first 6 arguments
# endif
#endif /* SPARC */
@@ -4724,21 +4686,12 @@ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
#endif /* NEED_CALLINFO */
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
-
-/* Dump /proc/self/maps to GC_stderr, to enable looking up names for
- addresses in FIND_LEAK output. */
-
-static word dump_maps(char *maps)
-{
- GC_err_write(maps, strlen(maps));
- return 1;
-}
-
-void GC_print_address_map(void)
-{
+ /* Dump /proc/self/maps to GC_stderr, to enable looking up names for */
+ /* addresses in FIND_LEAK output. */
+ void GC_print_address_map(void)
+ {
GC_err_printf("---------- Begin address map ----------\n");
- dump_maps(GC_get_maps());
+ GC_err_puts(GC_get_maps());
GC_err_printf("---------- End address map ----------\n");
-}
-
+ }
#endif /* LINUX && ELF */
diff --git a/pthread_start.c b/pthread_start.c
index cbe5a857..9d3556b4 100644
--- a/pthread_start.c
+++ b/pthread_start.c
@@ -41,12 +41,6 @@
#include <pthread.h>
#include <sched.h>
-GC_INNER void * GC_start_rtn_prepare_thread(void *(**pstart)(void *),
- void **pstart_arg,
- struct GC_stack_base *sb, void *arg);
-GC_INNER void GC_thread_exit_proc(void *arg);
- /* defined in pthread_support.c */
-
/* Invoked from GC_start_routine(). */
void * GC_CALLBACK GC_inner_start_routine(struct GC_stack_base *sb, void *arg)
{
@@ -56,11 +50,11 @@ void * GC_CALLBACK GC_inner_start_routine(struct GC_stack_base *sb, void *arg)
GC_thread me = GC_start_rtn_prepare_thread(&start, &start_arg, sb, arg);
# ifndef NACL
- pthread_cleanup_push(GC_thread_exit_proc, 0);
+ pthread_cleanup_push(GC_thread_exit_proc, me);
# endif
result = (*start)(start_arg);
# ifdef DEBUG_THREADS
- GC_printf("Finishing thread 0x%x\n", (unsigned)pthread_self());
+ GC_log_printf("Finishing thread 0x%x\n", (unsigned)pthread_self());
# endif
me -> status = result;
# ifndef NACL
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
index 0ef0d221..9302f93f 100644
--- a/pthread_stop_world.c
+++ b/pthread_stop_world.c
@@ -43,6 +43,9 @@ int GC_nacl_thread_used[MAX_NACL_GC_THREADS];
#include <unistd.h>
#include "atomic_ops.h"
+/* It's safe to call original pthread_sigmask() here. */
+#undef pthread_sigmask
+
#ifdef DEBUG_THREADS
# ifndef NSIG
# if defined(MAXSIG)
@@ -56,19 +59,17 @@ int GC_nacl_thread_used[MAX_NACL_GC_THREADS];
# endif
# endif /* NSIG */
- /* It's safe to call original pthread_sigmask() here. */
-# undef pthread_sigmask
-
void GC_print_sig_mask(void)
{
sigset_t blocked;
int i;
if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
- ABORT("pthread_sigmask");
+ ABORT("pthread_sigmask failed");
GC_printf("Blocked: ");
for (i = 1; i < NSIG; i++) {
- if (sigismember(&blocked, i)) { GC_printf("%d ", i); }
+ if (sigismember(&blocked, i))
+ GC_printf("%d ", i);
}
GC_printf("\n");
}
@@ -128,7 +129,8 @@ STATIC volatile AO_t GC_world_is_stopped = FALSE;
*/
#ifndef SIG_THR_RESTART
-# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || defined(GC_NETBSD_THREADS)
+# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) \
+ || defined(GC_NETBSD_THREADS)
# ifdef _SIGRTMIN
# define SIG_THR_RESTART _SIGRTMIN + 5
# else
@@ -139,6 +141,20 @@ STATIC volatile AO_t GC_world_is_stopped = FALSE;
# endif
#endif
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ /* Some targets (eg., Solaris) might require this to be called when */
+ /* doing thread registering from the thread destructor. */
+ GC_INNER void GC_unblock_gc_signals(void)
+ {
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIG_SUSPEND);
+ sigaddset(&set, SIG_THR_RESTART);
+ if (pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0)
+ ABORT("pthread_sigmask failed");
+ }
+#endif /* GC_EXPLICIT_SIGNALS_UNBLOCK */
+
STATIC sem_t GC_suspend_ack_sem;
#ifdef GC_NETBSD_THREADS
@@ -176,15 +192,13 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
/*ARGSUSED*/
STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
{
- int sig = (int)(word)sig_arg;
- int dummy;
- pthread_t my_thread = pthread_self();
+ pthread_t self = pthread_self();
GC_thread me;
IF_CANCEL(int cancel_state;)
-
AO_t my_stop_count = AO_load(&GC_stop_count);
- if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
+ if ((signed_word)sig_arg != SIG_SUSPEND)
+ ABORT("Bad signal in suspend_handler");
DISABLE_CANCEL(cancel_state);
/* pthread_setcancelstate is not defined to be async-signal-safe. */
@@ -196,10 +210,10 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
/* cancellation point is inherently a problem, unless there is */
/* some way to disable cancellation in the handler. */
# ifdef DEBUG_THREADS
- GC_printf("Suspending 0x%x\n", (unsigned)my_thread);
+ GC_log_printf("Suspending 0x%x\n", (unsigned)self);
# endif
- me = GC_lookup_thread(my_thread);
+ me = GC_lookup_thread(self);
/* The lookup here is safe, since I'm doing this on behalf */
/* of a thread which holds the allocation lock in order */
/* to stop the world. Thus concurrent modification of the */
@@ -207,7 +221,7 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
if (me -> stop_info.last_stop_count == my_stop_count) {
/* Duplicate signal. OK if we are retrying. */
if (!GC_retry_signals) {
- WARN("Duplicate suspend signal in thread %p\n", pthread_self());
+ WARN("Duplicate suspend signal in thread %p\n", self);
}
RESTORE_CANCEL(cancel_state);
return;
@@ -215,7 +229,7 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
# ifdef SPARC
me -> stop_info.stack_ptr = GC_save_regs_in_stack();
# else
- me -> stop_info.stack_ptr = (ptr_t)(&dummy);
+ me -> stop_info.stack_ptr = (ptr_t)(&me);
# endif
# ifdef IA64
me -> backing_store_ptr = GC_save_regs_in_stack();
@@ -250,7 +264,7 @@ STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
/* unlikely to be efficient. */
# ifdef DEBUG_THREADS
- GC_printf("Continuing 0x%x\n", (unsigned)my_thread);
+ GC_log_printf("Continuing 0x%x\n", (unsigned)self);
# endif
RESTORE_CANCEL(cancel_state);
}
@@ -272,7 +286,8 @@ STATIC void GC_restart_handler(int sig)
*/
# ifdef DEBUG_THREADS
- GC_printf("In GC_restart_handler for 0x%x\n", (unsigned)pthread_self());
+ GC_log_printf("In GC_restart_handler for 0x%x\n",
+ (unsigned)pthread_self());
# endif
}
@@ -294,18 +309,18 @@ GC_INNER void GC_push_all_stacks(void)
ptr_t lo, hi;
/* On IA64, we also need to scan the register backing store. */
IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
- pthread_t me = pthread_self();
+ pthread_t self = pthread_self();
word total_size = 0;
if (!GC_thr_initialized) GC_thr_init();
# ifdef DEBUG_THREADS
- GC_printf("Pushing stacks from thread 0x%x\n", (unsigned) me);
+ GC_log_printf("Pushing stacks from thread 0x%x\n", (unsigned)self);
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> flags & FINISHED) continue;
++nthreads;
- if (THREAD_EQUAL(p -> id, me)) {
+ if (THREAD_EQUAL(p -> id, self)) {
GC_ASSERT(!p->thread_blocked);
# ifdef SPARC
lo = (ptr_t)GC_save_regs_in_stack();
@@ -327,8 +342,8 @@ GC_INNER void GC_push_all_stacks(void)
IF_IA64(bs_lo = BACKING_STORE_BASE;)
}
# ifdef DEBUG_THREADS
- GC_printf("Stack for thread 0x%x = [%p,%p)\n",
- (unsigned)(p -> id), lo, hi);
+ GC_log_printf("Stack for thread 0x%x = [%p,%p)\n",
+ (unsigned)(p -> id), lo, hi);
# endif
if (0 == lo) ABORT("GC_push_all_stacks: sp not set!");
GC_push_all_stack_sections(lo, hi, p -> traced_stack_sect);
@@ -345,23 +360,23 @@ GC_INNER void GC_push_all_stacks(void)
# endif
# ifdef IA64
# ifdef DEBUG_THREADS
- GC_printf("Reg stack for thread 0x%x = [%p,%p)\n",
- (unsigned)p -> id, bs_lo, bs_hi);
+ GC_log_printf("Reg stack for thread 0x%x = [%p,%p)\n",
+ (unsigned)p -> id, bs_lo, bs_hi);
# endif
- /* FIXME: This (if p->id==me) may add an unbounded number of */
- /* entries, and hence overflow the mark stack, which is bad. */
+ /* FIXME: This (if p->id==self) may add an unbounded number of */
+ /* entries, and hence overflow the mark stack, which is bad. */
GC_push_all_register_sections(bs_lo, bs_hi,
- THREAD_EQUAL(p -> id, me),
+ THREAD_EQUAL(p -> id, self),
p -> traced_stack_sect);
total_size += bs_hi - bs_lo; /* bs_lo <= bs_hi */
# endif
}
}
if (GC_print_stats == VERBOSE) {
- GC_log_printf("Pushed %d thread stacks\n", (int)nthreads);
+ GC_log_printf("Pushed %d thread stacks\n", (int)nthreads);
}
if (!found_me && !GC_in_thread_creation)
- ABORT("Collecting from unknown thread.");
+ ABORT("Collecting from unknown thread");
GC_total_stacksize = total_size;
}
@@ -373,6 +388,8 @@ GC_INNER void GC_push_all_stacks(void)
#endif
#ifdef PLATFORM_ANDROID
+ extern int tkill(pid_t tid, int sig); /* from sys/linux-unistd.h */
+
static int android_thread_kill(pid_t tid, int sig)
{
int ret;
@@ -401,15 +418,15 @@ STATIC int GC_suspend_all(void)
# ifndef GC_OPENBSD_THREADS
int result;
# endif
- pthread_t my_thread = pthread_self();
+ pthread_t self = pthread_self();
# ifdef DEBUG_THREADS
- GC_stopping_thread = my_thread;
+ GC_stopping_thread = self;
GC_stopping_pid = getpid();
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (!THREAD_EQUAL(p -> id, my_thread)) {
+ if (!THREAD_EQUAL(p -> id, self)) {
if (p -> flags & FINISHED) continue;
if (p -> thread_blocked) /* Will wait */ continue;
# ifndef GC_OPENBSD_THREADS
@@ -417,8 +434,8 @@ STATIC int GC_suspend_all(void)
n_live_threads++;
# endif
# ifdef DEBUG_THREADS
- GC_printf("Sending suspend signal to 0x%x\n",
- (unsigned)(p -> id));
+ GC_log_printf("Sending suspend signal to 0x%x\n",
+ (unsigned)(p -> id));
# endif
# ifdef GC_OPENBSD_THREADS
@@ -457,8 +474,8 @@ STATIC int GC_suspend_all(void)
# define NACL_PARK_WAIT_NANOSECONDS (100 * 1000)
# endif
# ifdef DEBUG_THREADS
- GC_printf("pthread_stop_world: num_threads %d\n",
- GC_nacl_num_gc_threads - 1);
+ GC_log_printf("pthread_stop_world: num_threads %d\n",
+ GC_nacl_num_gc_threads - 1);
# endif
GC_nacl_thread_parker = pthread_self();
GC_nacl_park_threads_now = 1;
@@ -488,8 +505,8 @@ STATIC int GC_suspend_all(void)
ts.tv_sec = 0;
ts.tv_nsec = NACL_PARK_WAIT_NANOSECONDS;
# ifdef DEBUG_THREADS
- GC_printf("Sleep waiting for %d threads to park...\n",
- GC_nacl_num_gc_threads - num_threads_parked - 1);
+ GC_log_printf("Sleep waiting for %d threads to park...\n",
+ GC_nacl_num_gc_threads - num_threads_parked - 1);
# endif
/* This requires _POSIX_TIMERS feature. */
nanosleep(&ts, 0);
@@ -507,7 +524,7 @@ GC_INNER void GC_stop_world(void)
# endif
GC_ASSERT(I_HOLD_LOCK());
# ifdef DEBUG_THREADS
- GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
+ GC_log_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
# endif
/* Make sure all free list construction has stopped before we start. */
@@ -543,8 +560,7 @@ GC_INNER void GC_stop_world(void)
int newly_sent = GC_suspend_all();
if (GC_print_stats) {
- GC_log_printf("Resent %d signals after timeout\n",
- newly_sent);
+ GC_log_printf("Resent %d signals after timeout\n", newly_sent);
}
sem_getvalue(&GC_suspend_ack_sem, &ack_count);
if (newly_sent < n_live_threads - ack_count) {
@@ -577,7 +593,7 @@ GC_INNER void GC_stop_world(void)
GC_release_mark_lock();
# endif
# ifdef DEBUG_THREADS
- GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
+ GC_log_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
GC_stopping_thread = 0;
# endif
}
@@ -712,7 +728,7 @@ GC_INNER void GC_stop_world(void)
GC_INNER void GC_start_world(void)
{
# ifndef NACL
- pthread_t my_thread = pthread_self();
+ pthread_t self = pthread_self();
register int i;
register GC_thread p;
# ifndef GC_OPENBSD_THREADS
@@ -724,7 +740,7 @@ GC_INNER void GC_start_world(void)
# endif
# ifdef DEBUG_THREADS
- GC_printf("World starting\n");
+ GC_log_printf("World starting\n");
# endif
# ifndef GC_OPENBSD_THREADS
@@ -732,15 +748,15 @@ GC_INNER void GC_start_world(void)
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (!THREAD_EQUAL(p -> id, my_thread)) {
+ if (!THREAD_EQUAL(p -> id, self)) {
if (p -> flags & FINISHED) continue;
if (p -> thread_blocked) continue;
# ifndef GC_OPENBSD_THREADS
n_live_threads++;
# endif
# ifdef DEBUG_THREADS
- GC_printf("Sending restart signal to 0x%x\n",
- (unsigned)(p -> id));
+ GC_log_printf("Sending restart signal to 0x%x\n",
+ (unsigned)(p -> id));
# endif
# ifdef GC_OPENBSD_THREADS
@@ -767,20 +783,22 @@ GC_INNER void GC_start_world(void)
}
}
# ifdef GC_NETBSD_THREADS_WORKAROUND
- for (i = 0; i < n_live_threads; i++)
- while (0 != (code = sem_wait(&GC_restart_ack_sem)))
- if (errno != EINTR) {
- if (GC_print_stats)
- GC_printf("sem_wait() returned %d\n", code);
- ABORT("sem_wait() for restart handler failed");
- }
+ for (i = 0; i < n_live_threads; i++) {
+ while (0 != (code = sem_wait(&GC_restart_ack_sem))) {
+ if (errno != EINTR) {
+ if (GC_print_stats)
+ GC_log_printf("sem_wait() returned %d\n", code);
+ ABORT("sem_wait() for restart handler failed");
+ }
+ }
+ }
# endif
# ifdef DEBUG_THREADS
- GC_printf("World started\n");
+ GC_log_printf("World started\n");
# endif
# else /* NACL */
# ifdef DEBUG_THREADS
- GC_printf("World starting...\n");
+ GC_log_printf("World starting...\n");
# endif
GC_nacl_park_threads_now = 0;
# endif
@@ -791,10 +809,10 @@ GC_INNER void GC_stop_init(void)
# if !defined(GC_OPENBSD_THREADS) && !defined(NACL)
struct sigaction act;
- if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
+ if (sem_init(&GC_suspend_ack_sem, GC_SEM_INIT_PSHARED, 0) != 0)
ABORT("sem_init failed");
# ifdef GC_NETBSD_THREADS_WORKAROUND
- if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
+ if (sem_init(&GC_restart_ack_sem, GC_SEM_INIT_PSHARED, 0) != 0)
ABORT("sem_init failed");
# endif
@@ -840,7 +858,7 @@ GC_INNER void GC_stop_init(void)
GC_retry_signals = FALSE;
}
if (GC_print_stats && GC_retry_signals) {
- GC_log_printf("Will retry suspend signal if necessary.\n");
+ GC_log_printf("Will retry suspend signal if necessary\n");
}
# endif /* !GC_OPENBSD_THREADS && !NACL */
}
diff --git a/pthread_support.c b/pthread_support.c
index 68384bc6..bcdfebd1 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -288,12 +288,12 @@ STATIC long GC_nprocs = 1;
/* a guess as any ... */
#ifdef THREAD_LOCAL_ALLOC
-/* We must explicitly mark ptrfree and gcj free lists, since the free */
-/* list links wouldn't otherwise be found. We also set them in the */
-/* normal free lists, since that involves touching less memory than if */
-/* we scanned them normally. */
-GC_INNER void GC_mark_thread_local_free_lists(void)
-{
+ /* We must explicitly mark ptrfree and gcj free lists, since the free */
+ /* list links wouldn't otherwise be found. We also set them in the */
+ /* normal free lists, since that involves touching less memory than */
+ /* if we scanned them normally. */
+ GC_INNER void GC_mark_thread_local_free_lists(void)
+ {
int i;
GC_thread p;
@@ -303,9 +303,9 @@ GC_INNER void GC_mark_thread_local_free_lists(void)
GC_mark_thread_local_fls_for(&(p->tlfs));
}
}
-}
+ }
-#if defined(GC_ASSERTIONS)
+# if defined(GC_ASSERTIONS)
void GC_check_tls_for(GC_tlfs p);
# if defined(USE_CUSTOM_SPECIFIC)
void GC_check_tsd_marks(tsd *key);
@@ -328,9 +328,8 @@ GC_INNER void GC_mark_thread_local_free_lists(void)
GC_check_tsd_marks(GC_thread_key);
# endif
}
-#endif /* GC_ASSERTIONS */
-
-#endif /* Thread_local_alloc */
+# endif /* GC_ASSERTIONS */
+#endif /* THREAD_LOCAL_ALLOC */
#ifdef PARALLEL_MARK
@@ -388,8 +387,8 @@ STATIC void * GC_mark_thread(void * id)
my_mark_no = GC_mark_no;
}
# ifdef DEBUG_THREADS
- GC_printf("Starting mark helper for mark number %lu\n",
- (unsigned long)my_mark_no);
+ GC_log_printf("Starting mark helper for mark number %lu\n",
+ (unsigned long)my_mark_no);
# endif
GC_help_marker(my_mark_no);
}
@@ -423,7 +422,7 @@ static void start_mark_threads(void)
ABORT("pthread_attr_getstacksize failed");
if (old_size < MIN_STACK_SIZE) {
if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
- ABORT("pthread_attr_setstacksize failed");
+ ABORT("pthread_attr_setstacksize failed");
}
}
# endif /* HPUX || GC_DGUX386_THREADS */
@@ -439,7 +438,7 @@ static void start_mark_threads(void)
}
}
if (GC_print_stats) {
- GC_log_printf("Started %ld mark helper threads\n", GC_markers - 1);
+ GC_log_printf("Started %ld mark helper threads\n", GC_markers - 1);
}
pthread_attr_destroy(&attr);
}
@@ -456,18 +455,13 @@ void GC_push_thread_structures(void)
GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
# if defined(THREAD_LOCAL_ALLOC)
GC_push_all((ptr_t)(&GC_thread_key),
- (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
+ (ptr_t)(&GC_thread_key) + sizeof(&GC_thread_key));
# endif
}
/* It may not be safe to allocate when we register the first thread. */
static struct GC_Thread_Rep first_thread;
-#ifdef NACL
- GC_INNER void GC_nacl_initialize_gc_thread(void);
- GC_INNER void GC_nacl_shutdown_gc_thread(void);
-#endif
-
/* Add a thread to GC_threads. We assume it wasn't already there. */
/* Caller holds allocation lock. */
STATIC GC_thread GC_new_thread(pthread_t id)
@@ -535,15 +529,15 @@ STATIC void GC_delete_thread(pthread_t id)
/* been notified, then there may be more than one thread */
/* in the table with the same pthread id. */
/* This is OK, but we need a way to delete a specific one. */
-STATIC void GC_delete_gc_thread(GC_thread gc_id)
+STATIC void GC_delete_gc_thread(GC_thread t)
{
- pthread_t id = gc_id -> id;
+ pthread_t id = t -> id;
int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
register GC_thread p = GC_threads[hv];
register GC_thread prev = 0;
GC_ASSERT(I_HOLD_LOCK());
- while (p != gc_id) {
+ while (p != t) {
prev = p;
p = p -> next;
}
@@ -615,7 +609,7 @@ GC_INNER unsigned char *GC_check_finalizer_nested(void)
/* thread_local_alloc.c) checks only that it's close. */
return((char *)tsd > me && (char *)tsd < me + 1000);
}
-#endif
+#endif /* GC_ASSERTIONS && THREAD_LOCAL_ALLOC */
#ifdef HANDLE_FORK
/* Remove all entries from the GC_threads table, except the */
@@ -640,7 +634,7 @@ STATIC void GC_remove_all_threads_but_me(void)
if (!(p -> flags & FINISHED)) {
GC_destroy_thread_local(&(p->tlfs));
}
-# endif /* THREAD_LOCAL_ALLOC */
+# endif
if (p != &first_thread) GC_INTERNAL_FREE(p);
}
}
@@ -658,9 +652,9 @@ STATIC void GC_remove_all_threads_but_me(void)
GC_ASSERT(I_HOLD_LOCK());
# ifdef PARALLEL_MARK
for (i = 0; i < GC_markers - 1; ++i) {
- if (marker_sp[i] > lo & marker_sp[i] < hi) return TRUE;
+ if (marker_sp[i] > lo && marker_sp[i] < hi) return TRUE;
# ifdef IA64
- if (marker_bsp[i] > lo & marker_bsp[i] < hi) return TRUE;
+ if (marker_bsp[i] > lo && marker_bsp[i] < hi) return TRUE;
# endif
}
# endif
@@ -707,8 +701,8 @@ STATIC void GC_remove_all_threads_but_me(void)
}
#endif /* IA64 */
-#if defined(GC_LINUX_THREADS) && !defined(NACL)
- /* Return the number of processors, or i<= 0 if it can't be determined. */
+#if defined(GC_LINUX_THREADS) && !defined(PLATFORM_ANDROID) && !defined(NACL)
+ /* Return the number of processors. */
STATIC int GC_get_nprocs(void)
{
/* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
@@ -727,21 +721,24 @@ STATIC void GC_remove_all_threads_but_me(void)
/* Some old kernels only have a single "cpu nnnn ..." */
/* entry in /proc/stat. We identify those as */
/* uniprocessors. */
- size_t i, len = 0;
+ int i, len;
f = open("/proc/stat", O_RDONLY);
- if (f < 0 || (len = STAT_READ(f, stat_buf, STAT_BUF_SIZE)) < 100) {
+ if (f < 0) {
WARN("Couldn't read /proc/stat\n", 0);
- return -1;
+ return 1; /* assume an uniprocessor */
}
+ len = STAT_READ(f, stat_buf, STAT_BUF_SIZE);
+ close(f);
+
for (i = 0; i < len - 100; ++i) {
if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
&& stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
- int cpu_no = atoi(stat_buf + i + 4);
- if (cpu_no >= result) result = cpu_no + 1;
+ int cpu_no = atoi(&stat_buf[i + 4]);
+ if (cpu_no >= result)
+ result = cpu_no + 1;
}
}
- close(f);
return result;
}
#endif /* GC_LINUX_THREADS && !NACL */
@@ -849,7 +846,7 @@ STATIC void GC_fork_child_proc(void)
/* <takis@XFree86.Org> */
int numCpus;
struct dg_sys_info_pm_info pm_sysinfo;
- int status =0;
+ int status = 0;
status = dg_sys_info((long int *) &pm_sysinfo,
DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION);
@@ -861,7 +858,7 @@ STATIC void GC_fork_child_proc(void)
numCpus = pm_sysinfo.idle_vp_count;
# ifdef DEBUG_THREADS
- GC_printf("Number of active CPUs in this system: %d\n", numCpus);
+ GC_log_printf("Number of active CPUs in this system: %d\n", numCpus);
# endif
return(numCpus);
}
@@ -880,12 +877,10 @@ STATIC void GC_fork_child_proc(void)
}
#endif /* GC_DARWIN_THREADS || ... */
-#if defined(GC_LINUX_THREADS) && defined(INCLUDE_LINUX_THREAD_DESCR)
+#ifdef INCLUDE_LINUX_THREAD_DESCR
__thread int GC_dummy_thread_local;
-#endif
-
-#ifndef GC_DARWIN_THREADS
- GC_INNER void GC_stop_init(void); /* defined in pthread_stop_world.c */
+ GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr,
+ ptr_t *startp, ptr_t *endp);
#endif
/* We hold the allocation lock. */
@@ -913,15 +908,17 @@ GC_INNER void GC_thr_init(void)
if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start,
&main_thread_end)) {
ABORT("Failed to find mapping for main thread thread locals");
+ } else {
+ /* main_thread_start and main_thread_end are initialized. */
+ GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
}
- GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
}
# endif
/* Add the initial thread, so we can stop it. */
{
GC_thread t = GC_new_thread(pthread_self());
if (t == NULL)
- ABORT("Failed to allocate memory for the initial thread.");
+ ABORT("Failed to allocate memory for the initial thread");
# ifdef GC_DARWIN_THREADS
t -> stop_info.mach_thread = mach_thread_self();
# else
@@ -945,7 +942,7 @@ GC_INNER void GC_thr_init(void)
GC_nprocs = pthread_num_processors_np();
# elif defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
|| defined(GC_SOLARIS_THREADS) || defined(GC_GNU_THREADS) \
- || defined(NACL)
+ || defined(PLATFORM_ANDROID) || defined(NACL)
GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
if (GC_nprocs <= 0) GC_nprocs = 1;
# elif defined(GC_IRIX_THREADS)
@@ -960,7 +957,7 @@ GC_INNER void GC_thr_init(void)
}
if (GC_nprocs <= 0) {
WARN("GC_get_nprocs() returned %" GC_PRIdPTR "\n", GC_nprocs);
- GC_nprocs = 2;
+ GC_nprocs = 2; /* assume dual-core */
# ifdef PARALLEL_MARK
GC_markers = 1;
# endif
@@ -984,8 +981,9 @@ GC_INNER void GC_thr_init(void)
}
# ifdef PARALLEL_MARK
if (GC_print_stats) {
- GC_log_printf("Number of processors = %ld, "
- "number of marker threads = %ld\n", GC_nprocs, GC_markers);
+ GC_log_printf(
+ "Number of processors = %ld, number of marker threads = %ld\n",
+ GC_nprocs, GC_markers);
}
if (GC_markers <= 1) {
GC_parallel = FALSE;
@@ -1043,10 +1041,6 @@ GC_INNER void GC_init_parallel(void)
}
#endif /* !GC_NO_PTHREAD_SIGMASK */
-#if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
- GC_INNER ptr_t GC_FindTopOfStack(unsigned long);
-#endif
-
/* Wrapper for functions that are likely to block for an appreciable */
/* length of time. */
@@ -1158,18 +1152,11 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
return client_data; /* result */
}
-GC_API int GC_CALL GC_unregister_my_thread(void)
+STATIC void GC_unregister_my_thread_inner(GC_thread me)
{
- GC_thread me;
- IF_CANCEL(int cancel_state;)
- DCL_LOCK_STATE;
-
- LOCK();
- DISABLE_CANCEL(cancel_state);
- /* Wait for any GC that may be marking from our stack to */
- /* complete before we remove this thread. */
- GC_wait_for_gc_completion(FALSE);
- me = GC_lookup_thread(pthread_self());
+# ifdef DEBUG_THREADS
+ GC_log_printf("Unregistering thread 0x%x\n", (unsigned)pthread_self());
+# endif
GC_ASSERT(!(me -> flags & FINISHED));
# if defined(THREAD_LOCAL_ALLOC)
GC_destroy_thread_local(&(me->tlfs));
@@ -1187,8 +1174,23 @@ GC_API int GC_CALL GC_unregister_my_thread(void)
me -> flags |= FINISHED;
}
# if defined(THREAD_LOCAL_ALLOC)
+ /* It is required to call remove_specific defined in specific.c. */
GC_remove_specific(GC_thread_key);
# endif
+}
+
+GC_API int GC_CALL GC_unregister_my_thread(void)
+{
+ pthread_t self = pthread_self();
+ IF_CANCEL(int cancel_state;)
+ DCL_LOCK_STATE;
+
+ LOCK();
+ DISABLE_CANCEL(cancel_state);
+ /* Wait for any GC that may be marking from our stack to */
+ /* complete before we remove this thread. */
+ GC_wait_for_gc_completion(FALSE);
+ GC_unregister_my_thread_inner(GC_lookup_thread(self));
RESTORE_CANCEL(cancel_state);
UNLOCK();
return GC_SUCCESS;
@@ -1201,18 +1203,26 @@ GC_API int GC_CALL GC_unregister_my_thread(void)
/* resources or id anyway. */
GC_INNER void GC_thread_exit_proc(void *arg)
{
- GC_unregister_my_thread();
+ IF_CANCEL(int cancel_state;)
+ DCL_LOCK_STATE;
+
+ LOCK();
+ DISABLE_CANCEL(cancel_state);
+ GC_wait_for_gc_completion(FALSE);
+ GC_unregister_my_thread_inner((GC_thread)arg);
+ RESTORE_CANCEL(cancel_state);
+ UNLOCK();
}
GC_API int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
{
int result;
- GC_thread thread_gc_id;
+ GC_thread t;
DCL_LOCK_STATE;
INIT_REAL_SYMS();
LOCK();
- thread_gc_id = GC_lookup_thread(thread);
+ t = GC_lookup_thread(thread);
/* This is guaranteed to be the intended one, since the thread id */
/* can't have been recycled by pthreads. */
UNLOCK();
@@ -1231,7 +1241,8 @@ GC_API int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
if (result == 0) {
LOCK();
/* Here the pthread thread id may have been recycled. */
- GC_delete_gc_thread(thread_gc_id);
+ GC_ASSERT((t -> flags & FINISHED) != 0);
+ GC_delete_gc_thread(t);
UNLOCK();
}
return result;
@@ -1240,20 +1251,20 @@ GC_API int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
GC_API int WRAP_FUNC(pthread_detach)(pthread_t thread)
{
int result;
- GC_thread thread_gc_id;
+ GC_thread t;
DCL_LOCK_STATE;
INIT_REAL_SYMS();
LOCK();
- thread_gc_id = GC_lookup_thread(thread);
+ t = GC_lookup_thread(thread);
UNLOCK();
result = REAL_FUNC(pthread_detach)(thread);
if (result == 0) {
LOCK();
- thread_gc_id -> flags |= DETACHED;
+ t -> flags |= DETACHED;
/* Here the pthread thread id may have been recycled. */
- if (thread_gc_id -> flags & FINISHED) {
- GC_delete_gc_thread(thread_gc_id);
+ if ((t -> flags & FINISHED) != 0) {
+ GC_delete_gc_thread(t);
}
UNLOCK();
}
@@ -1273,20 +1284,19 @@ GC_API int WRAP_FUNC(pthread_detach)(pthread_t thread)
GC_API int WRAP_FUNC(pthread_cancel)(pthread_t thread)
{
# ifdef CANCEL_SAFE
- GC_thread thread_gc_id;
+ GC_thread t;
DCL_LOCK_STATE;
# endif
INIT_REAL_SYMS();
# ifdef CANCEL_SAFE
LOCK();
- thread_gc_id = GC_lookup_thread(thread);
+ t = GC_lookup_thread(thread);
/* We test DISABLED_GC because pthread_exit could be called at */
- /* the same time. (If thread_gc_id is NULL then pthread_cancel */
- /* should return ESRCH.) */
- if (thread_gc_id != 0
- && (thread_gc_id -> flags & DISABLED_GC) == 0) {
- thread_gc_id -> flags |= DISABLED_GC;
+ /* the same time. (If t is NULL then pthread_cancel should */
+ /* return ESRCH.) */
+ if (t != NULL && (t -> flags & DISABLED_GC) == 0) {
+ t -> flags |= DISABLED_GC;
GC_dont_gc++;
}
UNLOCK();
@@ -1325,6 +1335,20 @@ GC_API int WRAP_FUNC(pthread_detach)(pthread_t thread)
GC_INNER GC_bool GC_in_thread_creation = FALSE;
/* Protected by allocation lock. */
+GC_INLINE void GC_record_stack_base(GC_thread me,
+ const struct GC_stack_base *sb)
+{
+# ifndef GC_DARWIN_THREADS
+ me -> stop_info.stack_ptr = sb -> mem_base;
+# endif
+ me -> stack_end = sb -> mem_base;
+ if (me -> stack_end == NULL)
+ ABORT("Bad stack base in GC_register_my_thread");
+# ifdef IA64
+ me -> backing_store_end = sb -> reg_base;
+# endif
+}
+
STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
pthread_t my_pthread)
{
@@ -1334,18 +1358,16 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
me = GC_new_thread(my_pthread);
GC_in_thread_creation = FALSE;
if (me == 0)
- ABORT("Failed to allocate memory for thread registering.");
+ ABORT("Failed to allocate memory for thread registering");
# ifdef GC_DARWIN_THREADS
me -> stop_info.mach_thread = mach_thread_self();
-# else
- me -> stop_info.stack_ptr = sb -> mem_base;
# endif
- me -> stack_end = sb -> mem_base;
- if (me -> stack_end == NULL)
- ABORT("Bad stack base in GC_register_my_thread");
-# ifdef IA64
- me -> backing_store_end = sb -> reg_base;
-# endif /* IA64 */
+ GC_record_stack_base(me, sb);
+# ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ /* Since this could be executed from a detached thread */
+ /* destructor, our signals might already be blocked. */
+ GC_unblock_gc_signals();
+# endif
return me;
}
@@ -1359,7 +1381,7 @@ GC_API void GC_CALL GC_allow_register_threads(void)
GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
{
- pthread_t my_pthread = pthread_self();
+ pthread_t self = pthread_self();
GC_thread me;
DCL_LOCK_STATE;
@@ -1367,9 +1389,9 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
ABORT("Threads explicit registering is not previously enabled");
LOCK();
- me = GC_lookup_thread(my_pthread);
+ me = GC_lookup_thread(self);
if (0 == me) {
- me = GC_register_my_thread_inner(sb, my_pthread);
+ me = GC_register_my_thread_inner(sb, self);
me -> flags |= DETACHED;
/* Treat as detached, since we do not need to worry about */
/* pointer results. */
@@ -1378,6 +1400,21 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
# endif
UNLOCK();
return GC_SUCCESS;
+ } else if ((me -> flags & FINISHED) != 0) {
+ /* This code is executed when a thread is registered from the */
+ /* client thread key destructor. */
+ GC_record_stack_base(me, sb);
+ me -> flags &= ~FINISHED; /* but not DETACHED */
+# ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ /* Since this could be executed from a thread destructor, */
+ /* our signals might be blocked. */
+ GC_unblock_gc_signals();
+# endif
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_init_thread_local(&(me->tlfs));
+# endif
+ UNLOCK();
+ return GC_SUCCESS;
} else {
UNLOCK();
return GC_DUPLICATE;
@@ -1395,30 +1432,29 @@ struct start_info {
/* Called from GC_inner_start_routine(). Defined in this file to */
/* minimize the number of include files in pthread_start.c (because */
/* sem_t and sem_post() are not used that file directly). */
-GC_INNER void * GC_start_rtn_prepare_thread(void *(**pstart)(void *),
+GC_INNER GC_thread GC_start_rtn_prepare_thread(void *(**pstart)(void *),
void **pstart_arg,
struct GC_stack_base *sb, void *arg)
{
struct start_info * si = arg;
+ pthread_t self = pthread_self();
GC_thread me;
- pthread_t my_pthread;
DCL_LOCK_STATE;
- my_pthread = pthread_self();
# ifdef DEBUG_THREADS
- GC_printf("Starting thread 0x%x, pid = %ld, sp = %p\n",
- (unsigned)my_pthread, (long) getpid(), &arg);
+ GC_log_printf("Starting thread 0x%x, pid = %ld, sp = %p\n",
+ (unsigned)self, (long)getpid(), &arg);
# endif
LOCK();
- me = GC_register_my_thread_inner(sb, my_pthread);
+ me = GC_register_my_thread_inner(sb, self);
me -> flags = si -> flags;
# if defined(THREAD_LOCAL_ALLOC)
- GC_init_thread_local(&(me->tlfs));
+ GC_init_thread_local(&(me->tlfs));
# endif
UNLOCK();
*pstart = si -> start_routine;
# ifdef DEBUG_THREADS
- GC_printf("start_routine = %p\n", (void *)(signed_word)(*pstart));
+ GC_log_printf("start_routine = %p\n", (void *)(signed_word)(*pstart));
# endif
*pstart_arg = si -> arg;
sem_post(&(si -> registered)); /* Last action on si. */
@@ -1442,7 +1478,7 @@ STATIC void * GC_start_routine(void * arg)
GC_disable();
# endif
if (GC_get_stack_base(&sb) != GC_SUCCESS)
- ABORT("Failed to get thread stack base.");
+ ABORT("Failed to get thread stack base");
# ifdef REDIRECT_MALLOC
GC_enable();
# endif
@@ -1478,7 +1514,9 @@ GC_API int WRAP_FUNC(pthread_create)(pthread_t *new_thread,
(si = (struct start_info *)
(*GC_get_oom_fn())(sizeof(struct start_info))) == 0)
return(ENOMEM);
- sem_init(&(si -> registered), 0, 0);
+ if (sem_init(&(si -> registered), GC_SEM_INIT_PSHARED, 0) != 0)
+ ABORT("sem_init failed");
+
si -> start_routine = start_routine;
si -> arg = arg;
LOCK();
@@ -1523,15 +1561,15 @@ GC_API int WRAP_FUNC(pthread_create)(pthread_t *new_thread,
si -> flags = my_flags;
UNLOCK();
# ifdef DEBUG_THREADS
- GC_printf("About to start new thread from thread 0x%x\n",
- (unsigned)pthread_self());
+ GC_log_printf("About to start new thread from thread 0x%x\n",
+ (unsigned)pthread_self());
# endif
GC_need_to_lock = TRUE;
result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
# ifdef DEBUG_THREADS
- GC_printf("Started thread 0x%x\n", (unsigned)(*new_thread));
+ GC_log_printf("Started thread 0x%x\n", (unsigned)(*new_thread));
# endif
/* Wait until child has been added to the thread table. */
/* This also ensures that we hold onto si until the child is done */
@@ -1738,7 +1776,7 @@ GC_INNER void GC_lock(void)
GC_INNER unsigned long GC_mark_lock_holder = NO_THREAD;
#endif
-#if 0
+#ifdef GLIBC_2_1_MUTEX_HACK
/* Ugly workaround for a linux threads bug in the final versions */
/* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
/* field even when it fails to acquire the mutex. This causes */
@@ -1756,11 +1794,6 @@ static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
GC_INNER void GC_acquire_mark_lock(void)
{
-/*
- if (pthread_mutex_lock(&mark_mutex) != 0) {
- ABORT("pthread_mutex_lock failed");
- }
-*/
GC_generic_lock(&mark_mutex);
# ifdef GC_ASSERTIONS
GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
@@ -1843,4 +1876,4 @@ GC_INNER void GC_notify_all_marker(void)
#endif /* PARALLEL_MARK */
-#endif /* GC_LINUX_THREADS and friends */
+#endif /* GC_PTHREADS */
diff --git a/ptr_chck.c b/ptr_chck.c
index 9b0da0c1..d8076e84 100644
--- a/ptr_chck.c
+++ b/ptr_chck.c
@@ -242,7 +242,7 @@ GC_API void * GC_CALL GC_is_visible(void *p)
} else {
ptr_t type_descr = *(ptr_t *)base;
descr = *(word *)(type_descr
- - (descr - (GC_DS_PER_OBJECT
+ - (descr - (word)(GC_DS_PER_OBJECT
- GC_INDIR_PER_OBJ_BIAS)));
}
goto retry;
diff --git a/reclaim.c b/reclaim.c
index 0199d8c7..405087b8 100644
--- a/reclaim.c
+++ b/reclaim.c
@@ -33,27 +33,36 @@ GC_INNER signed_word GC_bytes_found = 0;
/* We defer printing of leaked objects until we're done with the GC */
/* cycle, since the routine for printing objects needs to run outside */
/* the collector, e.g. without the allocation lock. */
-#define MAX_LEAKED 40
+#ifndef MAX_LEAKED
+# define MAX_LEAKED 40
+#endif
STATIC ptr_t GC_leaked[MAX_LEAKED] = { NULL };
STATIC unsigned GC_n_leaked = 0;
GC_INNER GC_bool GC_have_errors = FALSE;
-STATIC void GC_add_leaked(ptr_t leaked)
+GC_INLINE void GC_add_leaked(ptr_t leaked)
{
+# ifndef SHORT_DBG_HDRS
+ if (GC_findleak_delay_free && !GC_check_leaked(leaked))
+ return;
+# endif
+
+ GC_have_errors = TRUE;
+ /* FIXME: Prevent adding an object while printing leaked ones. */
if (GC_n_leaked < MAX_LEAKED) {
- GC_have_errors = TRUE;
GC_leaked[GC_n_leaked++] = leaked;
/* Make sure it's not reclaimed this cycle */
- GC_set_mark_bit(leaked);
+ GC_set_mark_bit(leaked);
}
}
/* Print all objects on the list after printing any smashed objects. */
-/* Clear both lists. */
+/* Clear both lists. Called without the allocation lock held. */
GC_INNER void GC_print_all_errors(void)
{
static GC_bool printing_errors = FALSE;
+ GC_bool have_errors;
unsigned i;
DCL_LOCK_STATE;
@@ -62,9 +71,16 @@ GC_INNER void GC_print_all_errors(void)
UNLOCK();
return;
}
+ have_errors = GC_have_errors;
printing_errors = TRUE;
UNLOCK();
- if (GC_debugging_started) GC_print_all_smashed();
+
+ if (GC_debugging_started) {
+ GC_print_all_smashed();
+ } else {
+ have_errors = FALSE;
+ }
+
for (i = 0; i < GC_n_leaked; ++i) {
ptr_t p = GC_leaked[i];
if (HDR(p) -> hb_obj_kind == PTRFREE) {
@@ -76,8 +92,18 @@ GC_INNER void GC_print_all_errors(void)
GC_err_printf("\n");
GC_free(p);
GC_leaked[i] = 0;
+ have_errors = TRUE;
}
GC_n_leaked = 0;
+
+ if (have_errors
+# ifndef GC_ABORT_ON_LEAK
+ && GETENV("GC_ABORT_ON_LEAK") != NULL
+# endif
+ ) {
+ ABORT("Leaked or smashed objects encountered");
+ }
+
printing_errors = FALSE;
}
@@ -183,24 +209,20 @@ STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, size_t sz,
/* Don't really reclaim objects, just check for unmarked ones: */
STATIC void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz)
{
- word bit_no = 0;
+ word bit_no;
ptr_t p, plim;
-
GC_ASSERT(sz == hhdr -> hb_sz);
- p = hbp->hb_body;
- plim = p + HBLKSIZE - sz;
/* go through all words in block */
- while (p <= plim) {
- if( !mark_bit_from_hdr(hhdr, bit_no) ) {
- GC_add_leaked(p);
- }
- p += sz;
- bit_no += MARK_BIT_OFFSET(sz);
- }
+ p = hbp->hb_body;
+ plim = p + HBLKSIZE - sz;
+ for (bit_no = 0; p <= plim; p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
+ if (!mark_bit_from_hdr(hhdr, bit_no)) {
+ GC_add_leaked(p);
+ }
+ }
}
-
/*
* Generic procedure to rebuild a free list in hbp.
* Also called directly from GC_malloc_many.
@@ -233,12 +255,11 @@ GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
* caller should perform that check.
*/
STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp,
- int report_if_found)
+ GC_bool report_if_found)
{
hdr *hhdr = HDR(hbp);
size_t sz = hhdr -> hb_sz;
- int kind = hhdr -> hb_obj_kind;
- struct obj_kind * ok = &GC_obj_kinds[kind];
+ struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
@@ -246,8 +267,7 @@ STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp,
if (report_if_found) {
GC_reclaim_check(hbp, hhdr, sz);
} else {
- *flh = GC_reclaim_generic(hbp, hhdr, sz,
- ok -> ok_init,
+ *flh = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init,
*flh, &GC_bytes_found);
}
}
@@ -305,7 +325,7 @@ STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found)
GC_atomic_in_use += sz * hhdr -> hb_n_marks;
}
if (report_if_found) {
- GC_reclaim_small_nonempty_block(hbp, (int)report_if_found);
+ GC_reclaim_small_nonempty_block(hbp, TRUE /* report_if_found */);
} else if (empty) {
GC_bytes_found += HBLKSIZE;
GC_freehblk(hbp);
@@ -404,10 +424,10 @@ STATIC void GC_print_block_descr(struct hblk *h,
if (hhdr -> hb_n_marks != n_marks) {
GC_printf("(%u:%u,%u!=%u)", hhdr -> hb_obj_kind, (unsigned)bytes,
- (unsigned)hhdr -> hb_n_marks, n_marks);
+ (unsigned)hhdr -> hb_n_marks, n_marks);
} else {
GC_printf("(%u:%u,%u)", hhdr -> hb_obj_kind,
- (unsigned)bytes, n_marks);
+ (unsigned)bytes, n_marks);
}
bytes += HBLKSIZE-1;
bytes &= ~(HBLKSIZE-1);
@@ -436,15 +456,15 @@ void GC_print_free_list(int kind, size_t sz_in_granules)
struct obj_kind * ok = &GC_obj_kinds[kind];
ptr_t flh = ok -> ok_freelist[sz_in_granules];
struct hblk *lastBlock = 0;
- int n = 0;
+ int n;
- while (flh) {
+ for (n = 1; flh; n++) {
struct hblk *block = HBLKPTR(flh);
if (block != lastBlock) {
- GC_printf("\nIn heap block at %p:\n\t", block);
- lastBlock = block;
+ GC_printf("\nIn heap block at %p:\n\t", block);
+ lastBlock = block;
}
- GC_printf("%d: %p;", ++n, flh);
+ GC_printf("%d: %p;", n, flh);
flh = obj_link(flh);
}
}
@@ -487,8 +507,6 @@ GC_INNER void GC_start_reclaim(GC_bool report_if_found)
for (kind = 0; kind < GC_n_kinds; kind++) {
void **fop;
void **lim;
- struct hblk ** rlp;
- struct hblk ** rlim;
struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
@@ -506,10 +524,7 @@ GC_INNER void GC_start_reclaim(GC_bool report_if_found)
}
} /* otherwise free list objects are marked, */
/* and its safe to leave them */
- rlim = rlist + MAXOBJGRANULES+1;
- for( rlp = rlist; rlp < rlim; rlp++ ) {
- *rlp = 0;
- }
+ BZERO(rlist, (MAXOBJGRANULES + 1) * sizeof(void *));
}
@@ -602,7 +617,7 @@ GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
if (GC_print_stats == VERBOSE) {
GET_TIME(done_time);
GC_log_printf("Disposing of reclaim lists took %lu msecs\n",
- MS_TIME_DIFF(done_time,start_time));
+ MS_TIME_DIFF(done_time,start_time));
}
# endif
return(TRUE);
diff --git a/specific.c b/specific.c
index b8ea49dd..98d86c31 100644
--- a/specific.c
+++ b/specific.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -11,35 +11,35 @@
* modified is included with the above copyright notice.
*/
-#include "private/gc_priv.h" /* For configuration, pthreads.h. */
+#include "private/gc_priv.h" /* For configuration, pthreads.h. */
#include "private/thread_local_alloc.h"
- /* To determine type of tsd impl. */
- /* Includes private/specific.h */
- /* if needed. */
+ /* To determine type of tsd impl. */
+ /* Includes private/specific.h */
+ /* if needed. */
#if defined(USE_CUSTOM_SPECIFIC)
#include "atomic_ops.h"
static tse invalid_tse = {INVALID_QTID, 0, 0, INVALID_THREADID};
- /* A thread-specific data entry which will never */
- /* appear valid to a reader. Used to fill in empty */
- /* cache entries to avoid a check for 0. */
+ /* A thread-specific data entry which will never */
+ /* appear valid to a reader. Used to fill in empty */
+ /* cache entries to avoid a check for 0. */
int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *)) {
int i;
- tsd * result = (tsd *)MALLOC_CLEAR(sizeof (tsd));
+ tsd * result = (tsd *)MALLOC_CLEAR(sizeof(tsd));
/* A quick alignment check, since we need atomic stores */
- GC_ASSERT((unsigned long)(&invalid_tse.next) % sizeof(tse *) == 0);
+ GC_ASSERT((unsigned long)(&invalid_tse.next) % sizeof(tse *) == 0);
if (0 == result) return ENOMEM;
pthread_mutex_init(&(result -> lock), NULL);
for (i = 0; i < TS_CACHE_SIZE; ++i) {
- result -> cache[i] = &invalid_tse;
+ result -> cache[i] = &invalid_tse;
}
# ifdef GC_ASSERTIONS
for (i = 0; i < TS_HASH_SIZE; ++i) {
- GC_ASSERT(result -> hash[i] == 0);
+ GC_ASSERT(result -> hash[i] == 0);
}
# endif
*key_ptr = result;
@@ -50,24 +50,24 @@ int PREFIXED(setspecific) (tsd * key, void * value) {
pthread_t self = pthread_self();
int hash_val = HASH(self);
volatile tse * entry = (volatile tse *)MALLOC_CLEAR(sizeof (tse));
-
+
GC_ASSERT(self != INVALID_THREADID);
if (0 == entry) return ENOMEM;
pthread_mutex_lock(&(key -> lock));
- /* Could easily check for an existing entry here. */
+ /* Could easily check for an existing entry here. */
entry -> next = key -> hash[hash_val];
entry -> thread = self;
entry -> value = value;
GC_ASSERT(entry -> qtid == INVALID_QTID);
- /* There can only be one writer at a time, but this needs to be */
- /* atomic with respect to concurrent readers. */
+ /* There can only be one writer at a time, but this needs to be */
+ /* atomic with respect to concurrent readers. */
AO_store_release((volatile AO_t *)(key -> hash + hash_val), (AO_t)entry);
pthread_mutex_unlock(&(key -> lock));
return 0;
}
-/* Remove thread-specific data for this thread. Should be called on */
-/* thread exit. */
+/* Remove thread-specific data for this thread. Should be called on */
+/* thread exit. */
void PREFIXED(remove_specific) (tsd * key) {
pthread_t self = pthread_self();
unsigned hash_val = HASH(self);
@@ -77,89 +77,86 @@ void PREFIXED(remove_specific) (tsd * key) {
pthread_mutex_lock(&(key -> lock));
entry = *link;
while (entry != NULL && entry -> thread != self) {
- link = &(entry -> next);
- entry = *link;
+ link = &(entry -> next);
+ entry = *link;
}
- /* Invalidate qtid field, since qtids may be reused, and a later */
- /* cache lookup could otherwise find this entry. */
- entry -> qtid = INVALID_QTID;
+ /* Invalidate qtid field, since qtids may be reused, and a later */
+ /* cache lookup could otherwise find this entry. */
if (entry != NULL) {
- *link = entry -> next;
- /* Atomic! concurrent accesses still work. */
- /* They must, since readers don't lock. */
- /* We shouldn't need a volatile access here, */
- /* since both this and the preceding write */
- /* should become visible no later than */
- /* the pthread_mutex_unlock() call. */
+ entry -> qtid = INVALID_QTID;
+ *link = entry -> next;
+ /* Atomic! concurrent accesses still work. */
+ /* They must, since readers don't lock. */
+ /* We shouldn't need a volatile access here, */
+ /* since both this and the preceding write */
+ /* should become visible no later than */
+ /* the pthread_mutex_unlock() call. */
}
- /* If we wanted to deallocate the entry, we'd first have to clear */
- /* any cache entries pointing to it. That probably requires */
- /* additional synchronization, since we can't prevent a concurrent */
+ /* If we wanted to deallocate the entry, we'd first have to clear */
+ /* any cache entries pointing to it. That probably requires */
+ /* additional synchronization, since we can't prevent a concurrent */
/* cache lookup, which should still be examining deallocated memory.*/
- /* This can only happen if the concurrent access is from another */
- /* thread, and hence has missed the cache, but still... */
+ /* This can only happen if the concurrent access is from another */
+ /* thread, and hence has missed the cache, but still... */
- /* With GC, we're done, since the pointers from the cache will */
- /* be overwritten, all local pointers to the entries will be */
- /* dropped, and the entry will then be reclaimed. */
+ /* With GC, we're done, since the pointers from the cache will */
+ /* be overwritten, all local pointers to the entries will be */
+ /* dropped, and the entry will then be reclaimed. */
pthread_mutex_unlock(&(key -> lock));
}
-/* Note that even the slow path doesn't lock. */
-void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
- tse * volatile * cache_ptr) {
+/* Note that even the slow path doesn't lock. */
+void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
+ tse * volatile * cache_ptr) {
pthread_t self = pthread_self();
unsigned hash_val = HASH(self);
tse *entry = key -> hash[hash_val];
GC_ASSERT(qtid != INVALID_QTID);
while (entry != NULL && entry -> thread != self) {
- entry = entry -> next;
- }
+ entry = entry -> next;
+ }
if (entry == NULL) return NULL;
- /* Set cache_entry. */
- entry -> qtid = qtid;
- /* It's safe to do this asynchronously. Either value */
- /* is safe, though may produce spurious misses. */
- /* We're replacing one qtid with another one for the */
- /* same thread. */
- *cache_ptr = entry;
- /* Again this is safe since pointer assignments are */
- /* presumed atomic, and either pointer is valid. */
+ /* Set cache_entry. */
+ entry -> qtid = (AO_t)qtid;
+ /* It's safe to do this asynchronously. Either value */
+ /* is safe, though may produce spurious misses. */
+ /* We're replacing one qtid with another one for the */
+ /* same thread. */
+ *cache_ptr = entry;
+ /* Again this is safe since pointer assignments are */
+ /* presumed atomic, and either pointer is valid. */
return entry -> value;
}
#ifdef GC_ASSERTIONS
-
-/* Check that that all elements of the data structure associated */
-/* with key are marked. */
-void PREFIXED(check_tsd_marks) (tsd *key)
-{
+ /* Check that that all elements of the data structure associated */
+ /* with key are marked. */
+ void PREFIXED(check_tsd_marks) (tsd *key)
+ {
int i;
tse *p;
if (!GC_is_marked(GC_base(key))) {
- ABORT("Unmarked thread-specific-data table");
+ ABORT("Unmarked thread-specific-data table");
}
for (i = 0; i < TS_HASH_SIZE; ++i) {
- for (p = key -> hash[i]; p != 0; p = p -> next) {
- if (!GC_is_marked(GC_base(p))) {
- GC_err_printf(
- "Thread-specific-data entry at %p not marked\n",p);
- ABORT("Unmarked tse");
- }
- }
+ for (p = key -> hash[i]; p != 0; p = p -> next) {
+ if (!GC_is_marked(GC_base(p))) {
+ GC_err_printf("Thread-specific-data entry at %p not marked\n", p);
+ ABORT("Unmarked tse");
+ }
+ }
}
for (i = 0; i < TS_CACHE_SIZE; ++i) {
- p = key -> cache[i];
- if (p != &invalid_tse && !GC_is_marked(GC_base(p))) {
- GC_err_printf(
- "Cached thread-specific-data entry at %p not marked\n",p);
- ABORT("Unmarked cached tse");
- }
+ p = key -> cache[i];
+ if (p != &invalid_tse && !GC_is_marked(GC_base(p))) {
+ GC_err_printf("Cached thread-specific-data entry at %p not marked\n",
+ p);
+ ABORT("Unmarked cached tse");
+ }
}
-}
-
-#endif
+ }
+#endif /* GC_ASSERTIONS */
#endif /* USE_CUSTOM_SPECIFIC */
diff --git a/stubborn.c b/stubborn.c
index a297dd51..b1991f13 100644
--- a/stubborn.c
+++ b/stubborn.c
@@ -22,6 +22,8 @@
/* written, but not yet GC_dirty()ed objects must be referenced */
/* by a stack. */
+ void GC_dirty(ptr_t p);
+
GC_API void * GC_CALL GC_malloc_stubborn(size_t lb)
{
return(GC_malloc(lb));
diff --git a/tests/huge_test.c b/tests/huge_test.c
index b09802fd..dd58a8e7 100644
--- a/tests/huge_test.c
+++ b/tests/huge_test.c
@@ -14,7 +14,7 @@
/*
* Check that very large allocation requests fail. "Success" would usually
- * indicate that the the size was somehow converted to a negative
+ * indicate that the size was somehow converted to a negative
* number. Clients shouldn't do this, but we should fail in the
* expected manner.
*/
diff --git a/tests/initsecondarythread.c b/tests/initsecondarythread.c
new file mode 100755
index 00000000..f89252e2
--- /dev/null
+++ b/tests/initsecondarythread.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 Ludovic Courtes <ludo@gnu.org>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* Make sure 'GC_INIT' can be called from threads other than the initial
+ * thread.
+ */
+
+#ifndef GC_THREADS
+# define GC_THREADS
+#endif
+
+#define GC_NO_THREAD_REDIRECTS 1
+
+#include "gc.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+
+static void *thread(void *arg)
+{
+ GC_INIT();
+ GC_MALLOC(123);
+ GC_MALLOC(12345);
+ return NULL;
+}
+
+#include "private/gcconfig.h"
+
+int main(void)
+{
+ pthread_t t;
+# if !(defined(BEOS) || defined(MSWIN32) || defined(MSWINCE) \
+ || defined(CYGWIN32) || defined(GC_OPENBSD_THREADS) \
+ || (defined(DARWIN) && !defined(NO_PTHREAD_GET_STACKADDR_NP)) \
+ || (defined(LINUX) && !defined(NACL)) \
+ || (defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC)) \
+ || (!defined(STACKBOTTOM) && (defined(HEURISTIC1) \
+ || (!defined(LINUX_STACKBOTTOM) && !defined(FREEBSD_STACKBOTTOM)))))
+ /* GC_INIT() must be called from main thread only. */
+ GC_INIT();
+# endif
+ pthread_create (&t, NULL, thread, NULL);
+ pthread_join (t, NULL);
+ return 0;
+}
diff --git a/tests/realloc_test.c b/tests/realloc_test.c
new file mode 100644
index 00000000..370ba466
--- /dev/null
+++ b/tests/realloc_test.c
@@ -0,0 +1,34 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gc.h"
+
+#define COUNT 10000000
+
+int main(void) {
+ int i;
+ unsigned long last_heap_size = 0;
+
+ GC_INIT();
+
+ for (i = 0; i < COUNT; i++) {
+ int **p = GC_MALLOC(sizeof(int *));
+ int *q = GC_MALLOC_ATOMIC(sizeof(int));
+
+ if (*p != 0) {
+ fprintf(stderr, "GC_malloc returned garbage\n");
+ exit(1);
+ }
+
+ *p = GC_REALLOC(q, 2 * sizeof(int));
+
+ if (i % 10 == 0) {
+ unsigned long heap_size = (unsigned long)GC_get_heap_size();
+ if (heap_size != last_heap_size) {
+ printf("Heap size: %lu\n", heap_size);
+ last_heap_size = heap_size;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/tests/smash_test.c b/tests/smash_test.c
index 86e081bd..0e8b1f08 100644
--- a/tests/smash_test.c
+++ b/tests/smash_test.c
@@ -22,7 +22,7 @@ int main(void)
A[i] = p = GC_MALLOC(SIZE);
if (i%3000 == 0) GC_gcollect();
- if (i%5678 == 0) p[SIZE + i/2000] = 42;
+ if (i%5678 == 0 && p != 0) p[SIZE + i/2000] = 42;
}
return 0;
}
diff --git a/tests/staticrootslib.c b/tests/staticrootslib.c
index 16f3352b..2a8fcd49 100755..100644
--- a/tests/staticrootslib.c
+++ b/tests/staticrootslib.c
@@ -19,8 +19,10 @@ struct treenode * libsrl_mktree(int i)
struct treenode * r = GC_MALLOC(sizeof(struct treenode));
if (0 == i) return 0;
if (1 == i) r = GC_MALLOC_ATOMIC(sizeof(struct treenode));
- r -> x = libsrl_mktree(i-1);
- r -> y = libsrl_mktree(i-1);
+ if (r) {
+ r -> x = libsrl_mktree(i-1);
+ r -> y = libsrl_mktree(i-1);
+ }
return r;
}
diff --git a/tests/test.c b/tests/test.c
index d8cf4f68..fa2eda17 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -81,16 +81,30 @@
# include <stdarg.h>
+#define CHECH_GCLIB_VERSION \
+ if (GC_get_version() != ((GC_VERSION_MAJOR<<16) \
+ | (GC_VERSION_MINOR<<8) \
+ | GC_ALPHA_VERSION)) { \
+ GC_printf("libgc version mismatch\n"); \
+ exit(1); \
+ }
+
/* Call GC_INIT only on platforms on which we think we really need it, */
/* so that we can test automatic initialization on the rest. */
#if defined(CYGWIN32) || defined (AIX) || defined(DARWIN) \
|| defined(THREAD_LOCAL_ALLOC) \
|| (defined(MSWINCE) && !defined(GC_WINMAIN_REDIRECT))
-# define GC_COND_INIT() GC_INIT()
+# define GC_COND_INIT() GC_INIT(); CHECH_GCLIB_VERSION
#else
-# define GC_COND_INIT()
+# define GC_COND_INIT() CHECH_GCLIB_VERSION
#endif
+#define CHECK_OUT_OF_MEMORY(p) \
+ if ((p) == NULL) { \
+ GC_printf("Out of memory\n"); \
+ exit(1); \
+ }
+
/* Allocation Statistics. Incremented without synchronization. */
/* FIXME: We should be using synchronization. */
int stubborn_count = 0;
@@ -113,7 +127,7 @@ int realloc_count = 0;
}
if(ret==NULL){
GC_printf("Out of memory, (typed allocations are not directly "
- "supported with the GC_AMIGA_FASTALLOC option.)\n");
+ "supported with the GC_AMIGA_FASTALLOC option.)\n");
FAIL;
}
}
@@ -128,7 +142,7 @@ int realloc_count = 0;
}
if(ret==NULL){
GC_printf("Out of memory, (typed allocations are not directly "
- "supported with the GC_AMIGA_FASTALLOC option.)\n");
+ "supported with the GC_AMIGA_FASTALLOC option.)\n");
FAIL;
}
}
@@ -139,7 +153,7 @@ int realloc_count = 0;
#else /* !AMIGA_FASTALLOC */
-# ifdef PCR
+# if defined(PCR) || defined(LINT2)
# define FAIL (void)abort()
# else
# define FAIL ABORT("Test failed")
@@ -186,14 +200,11 @@ sexpr cons (sexpr x, sexpr y)
stubborn_count++;
r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
- if (r == 0) {
- (void)GC_printf("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(r);
for (p = (int *)r;
((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
if (*p) {
- (void)GC_printf("Found nonzero at %p - allocator is broken\n", p);
+ GC_printf("Found nonzero at %p - allocator is broken\n", p);
FAIL;
}
*p = (int)((13 << 12) + ((p - (int *)r) & 0xfff));
@@ -262,10 +273,7 @@ sexpr small_cons (sexpr x, sexpr y)
collectable_count++;
r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(r);
r -> sexpr_car = x;
r -> sexpr_cdr = y;
return(r);
@@ -277,10 +285,7 @@ sexpr small_cons_uncollectable (sexpr x, sexpr y)
uncollectable_count++;
r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(r);
r -> sexpr_car = x;
r -> sexpr_cdr = (sexpr)(~(GC_word)y);
return(r);
@@ -297,10 +302,7 @@ sexpr gcj_cons(sexpr x, sexpr y)
r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR)
+ sizeof(struct fake_vtable*),
&gcj_class_struct2);
- if (r == 0) {
- (void)GC_printf("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(r);
result = (sexpr)(r + 1);
result -> sexpr_car = x;
result -> sexpr_cdr = y;
@@ -376,13 +378,13 @@ sexpr uncollectable_ints(int low, int up)
void check_ints(sexpr list, int low, int up)
{
if (SEXPR_TO_INT(car(car(list))) != low) {
- (void)GC_printf(
+ GC_printf(
"List reversal produced incorrect list - collector is broken\n");
FAIL;
}
if (low == up) {
if (cdr(list) != nil) {
- (void)GC_printf("List too long - collector is broken\n");
+ GC_printf("List too long - collector is broken\n");
FAIL;
}
} else {
@@ -395,15 +397,14 @@ void check_ints(sexpr list, int low, int up)
void check_uncollectable_ints(sexpr list, int low, int up)
{
if (SEXPR_TO_INT(car(car(list))) != low) {
- (void)GC_printf(
- "Uncollectable list corrupted - collector is broken\n");
+ GC_printf("Uncollectable list corrupted - collector is broken\n");
FAIL;
}
if (low == up) {
- if (UNCOLLECTABLE_CDR(list) != nil) {
- (void)GC_printf("Uncollectable list too long - collector is broken\n");
- FAIL;
- }
+ if (UNCOLLECTABLE_CDR(list) != nil) {
+ GC_printf("Uncollectable list too long - collector is broken\n");
+ FAIL;
+ }
} else {
check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
}
@@ -413,14 +414,14 @@ void check_uncollectable_ints(sexpr list, int low, int up)
void print_int_list(sexpr x)
{
if (is_nil(x)) {
- (void)GC_printf("NIL\n");
+ GC_printf("NIL\n");
} else {
- (void)GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
+ GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
if (!is_nil(cdr(x))) {
- (void)GC_printf(", ");
- (void)print_int_list(cdr(x));
+ GC_printf(", ");
+ print_int_list(cdr(x));
} else {
- (void)GC_printf("\n");
+ GC_printf("\n");
}
}
}
@@ -433,15 +434,16 @@ void check_marks_int_list(sexpr x)
else
GC_printf("[mkd:%p]", x);
if (is_nil(x)) {
- (void)GC_printf("NIL\n");
+ GC_printf("NIL\n");
} else {
- if (!GC_is_marked((ptr_t)car(x))) GC_printf("[unm car:%p]", car(x));
- (void)GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
+ if (!GC_is_marked((ptr_t)car(x)))
+ GC_printf("[unm car:%p]", car(x));
+ GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
if (!is_nil(cdr(x))) {
- (void)GC_printf(", ");
- (void)check_marks_int_list(cdr(x));
+ GC_printf(", ");
+ check_marks_int_list(cdr(x));
} else {
- (void)GC_printf("\n");
+ GC_printf("\n");
}
}
}
@@ -477,11 +479,11 @@ void check_marks_int_list(sexpr x)
pthread_t t;
int code;
if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) {
- (void)GC_printf("Small thread creation failed %d\n", code);
+ GC_printf("Small thread creation failed %d\n", code);
FAIL;
}
if ((code = pthread_join(t, 0)) != 0) {
- (void)GC_printf("Small thread join failed %d\n", code);
+ GC_printf("Small thread join failed %d\n", code);
FAIL;
}
}
@@ -493,13 +495,13 @@ void check_marks_int_list(sexpr x)
HANDLE h;
h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
if (h == (HANDLE)NULL) {
- (void)GC_printf("Small thread creation failed %d\n",
- (int)GetLastError());
+ GC_printf("Small thread creation failed %d\n",
+ (int)GetLastError());
FAIL;
}
if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
- (void)GC_printf("Small thread wait failed %d\n",
- (int)GetLastError());
+ GC_printf("Small thread wait failed %d\n",
+ (int)GetLastError());
FAIL;
}
}
@@ -536,23 +538,19 @@ void *GC_CALLBACK reverse_test_inner(void *data)
# if /*defined(MSWIN32) ||*/ defined(MACOS)
/* Win32S only allows 128K stacks */
# define BIG 1000
+# elif defined(PCR)
+ /* PCR default stack is 100K. Stack frames are up to 120 bytes. */
+# define BIG 700
+# elif defined(MSWINCE) || defined(RTEMS)
+ /* WinCE only allows 64K stacks */
+# define BIG 500
+# elif defined(OSF1)
+ /* OSF has limited stack space by default, and large frames. */
+# define BIG 200
+# elif defined(__MACH__) && defined(__ppc64__)
+# define BIG 2500
# else
-# if defined(PCR)
- /* PCR default stack is 100K. Stack frames are up to 120 bytes. */
-# define BIG 700
-# else
-# if defined(MSWINCE)
- /* WinCE only allows 64K stacks */
-# define BIG 500
-# else
-# if defined(OSF1)
- /* OSF has limited stack space by default, and large frames. */
-# define BIG 200
-# else
-# define BIG 4500
-# endif
-# endif
-# endif
+# define BIG 4500
# endif
A.dummy = 17;
@@ -566,16 +564,19 @@ void *GC_CALLBACK reverse_test_inner(void *data)
f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr));
realloc_count++;
f = (sexpr *)GC_REALLOC((void *)f, 6 * sizeof(sexpr));
+ CHECK_OUT_OF_MEMORY(f);
f[5] = ints(1,17);
collectable_count++;
g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr));
realloc_count++;
g = (sexpr *)GC_REALLOC((void *)g, 800 * sizeof(sexpr));
+ CHECK_OUT_OF_MEMORY(g);
g[799] = ints(1,18);
collectable_count++;
h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr));
realloc_count++;
h = (sexpr *)GC_REALLOC((void *)h, 2000 * sizeof(sexpr));
+ CHECK_OUT_OF_MEMORY(h);
# ifdef GC_GCJ_SUPPORT
h[1999] = gcj_ints(1,200);
for (i = 0; i < 51; ++i)
@@ -585,12 +586,12 @@ void *GC_CALLBACK reverse_test_inner(void *data)
h[1999] = ints(1,200);
# endif
/* Try to force some collections and reuse of small list elements */
- for (i = 0; i < 10; i++) {
- (void)ints(1, BIG);
- }
+ for (i = 0; i < 10; i++) {
+ (void)ints(1, BIG);
+ }
/* Superficially test interior pointer recognition on stack */
- c = (sexpr)((char *)c + sizeof(char *));
- d = (sexpr)((char *)d + sizeof(char *));
+ c = (sexpr)((char *)c + sizeof(char *));
+ d = (sexpr)((char *)d + sizeof(char *));
GC_FREE((void *)e);
@@ -621,8 +622,11 @@ void *GC_CALLBACK reverse_test_inner(void *data)
}
check_ints(a,1,49);
check_ints(b,1,50);
+
+ /* Restore c and d values. */
c = (sexpr)((char *)c - sizeof(char *));
d = (sexpr)((char *)d - sizeof(char *));
+
check_ints(c,1,BIG);
check_uncollectable_ints(d, 1, 100);
check_ints(f[5], 1,17);
@@ -634,8 +638,8 @@ void *GC_CALLBACK reverse_test_inner(void *data)
# ifndef THREADS
a = 0;
# endif
- *(volatile void **)&b = 0;
- *(volatile void **)&c = 0;
+ *(sexpr volatile *)&b = 0;
+ *(sexpr volatile *)&c = 0;
return 0;
}
@@ -675,7 +679,7 @@ void GC_CALLBACK finalizer(void * obj, void * client_data)
EnterCriticalSection(&incr_cs);
# endif
if ((int)(GC_word)client_data != t -> level) {
- (void)GC_printf("Wrong finalization data - collector is broken\n");
+ GC_printf("Wrong finalization data - collector is broken\n");
FAIL;
}
finalized_count++;
@@ -710,19 +714,14 @@ tn * mktree(int n)
collectable_count++;
# if defined(MACOS)
/* get around static data limitations. */
- if (!live_indicators)
- live_indicators =
- (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
if (!live_indicators) {
- (void)GC_printf("Out of memory\n");
- exit(1);
+ live_indicators =
+ (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
+ CHECK_OUT_OF_MEMORY(live_indicators);
}
# endif
if (n == 0) return(0);
- if (result == 0) {
- (void)GC_printf("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(result);
result -> level = n;
result -> lchild = mktree(n-1);
result -> rchild = mktree(n-1);
@@ -791,12 +790,12 @@ tn * mktree(int n)
void chktree(tn *t, int n)
{
if (n == 0 && t != 0) {
- (void)GC_printf("Clobbered a leaf - collector is broken\n");
+ GC_printf("Clobbered a leaf - collector is broken\n");
FAIL;
}
if (n == 0) return;
if (t -> level != n) {
- (void)GC_printf("Lost a node at level %d - collector is broken\n", n);
+ GC_printf("Lost a node at level %d - collector is broken\n", n);
FAIL;
}
if (counter++ % 373 == 0) {
@@ -828,18 +827,16 @@ void * alloc8bytes(void)
if (my_free_list_ptr == 0) {
uncollectable_count++;
my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
+ CHECK_OUT_OF_MEMORY(my_free_list_ptr);
if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) {
- (void)GC_printf("pthread_setspecific failed\n");
+ GC_printf("pthread_setspecific failed\n");
FAIL;
}
}
my_free_list = *my_free_list_ptr;
if (my_free_list == 0) {
my_free_list = GC_malloc_many(8);
- if (my_free_list == 0) {
- (void)GC_printf("alloc8bytes out of memory\n");
- FAIL;
- }
+ CHECK_OUT_OF_MEMORY(my_free_list);
}
*my_free_list_ptr = GC_NEXT(my_free_list);
GC_NEXT(my_free_list) = 0;
@@ -859,7 +856,7 @@ void alloc_small(int n)
for (i = 0; i < n; i += 8) {
atomic_count++;
if (alloc8bytes() == 0) {
- (void)GC_printf("Out of memory\n");
+ GC_printf("Out of memory\n");
FAIL;
}
}
@@ -889,7 +886,7 @@ void tree_test(void)
# endif
chktree(root, TREE_HEIGHT);
if (finalized_count && ! dropped_something) {
- (void)GC_printf("Premature finalization - collector is broken\n");
+ GC_printf("Premature finalization - collector is broken\n");
FAIL;
}
dropped_something = 1;
@@ -943,6 +940,7 @@ void typed_test(void)
for (i = 0; i < 4000; i++) {
collectable_count++;
new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
+ CHECK_OUT_OF_MEMORY(new);
if (0 != new[0] || 0 != new[1]) {
GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
FAIL;
@@ -952,17 +950,20 @@ void typed_test(void)
old = new;
collectable_count++;
new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d2);
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
collectable_count++;
new = (GC_word *) GC_malloc_explicitly_typed(33 * sizeof(GC_word), d3);
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
collectable_count++;
new = (GC_word *) GC_calloc_explicitly_typed(4, 2 * sizeof(GC_word),
d1);
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
@@ -974,19 +975,19 @@ void typed_test(void)
new = (GC_word *) GC_calloc_explicitly_typed(1001,
3 * sizeof(GC_word),
d2);
- if (0 != new[0] || 0 != new[1]) {
+ if (new && (0 != new[0] || 0 != new[1])) {
GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
FAIL;
}
}
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
}
for (i = 0; i < 20000; i++) {
if (new[0] != 17) {
- (void)GC_printf("typed alloc failed at %lu\n",
- (unsigned long)i);
+ GC_printf("typed alloc failed at %lu\n", (unsigned long)i);
FAIL;
}
new[0] = 0;
@@ -1055,22 +1056,22 @@ void run_one_test(void)
# ifdef FIND_LEAK
GC_printf(
- "This test program is not designed for leak detection mode\n");
- GC_printf("Expect lots of problems.\n");
+ "This test program is not designed for leak detection mode\n");
+ GC_printf("Expect lots of problems\n");
# endif
GC_FREE(0);
# ifndef DBG_HDRS_ALL
collectable_count += 3;
if ((GC_size(GC_malloc(7)) != 8 &&
GC_size(GC_malloc(7)) != MIN_WORDS * sizeof(GC_word))
- || GC_size(GC_malloc(15)) != 16) {
- GC_printf("GC_size produced unexpected results\n");
- FAIL;
+ || GC_size(GC_malloc(15)) != 16) {
+ GC_printf("GC_size produced unexpected results\n");
+ FAIL;
}
collectable_count += 1;
if (GC_size(GC_malloc(0)) != MIN_WORDS * sizeof(GC_word)) {
GC_printf("GC_malloc(0) failed: GC_size returns %ld\n",
- (unsigned long)GC_size(GC_malloc(0)));
+ (unsigned long)GC_size(GC_malloc(0)));
FAIL;
}
collectable_count += 1;
@@ -1126,8 +1127,7 @@ void run_one_test(void)
if (GC_is_valid_displacement(y) != y
|| GC_is_valid_displacement(x) != x
|| GC_is_valid_displacement(x + 3) != x + 3) {
- GC_printf(
- "GC_is_valid_displacement produced incorrect result\n");
+ GC_printf("GC_is_valid_displacement produced incorrect result\n");
FAIL;
}
{
@@ -1143,19 +1143,25 @@ void run_one_test(void)
# if defined(RS6000) || defined(POWERPC)
if (!TEST_FAIL_COUNT(1))
# else
- if ((GC_all_interior_pointers && !TEST_FAIL_COUNT(1))
- || (!GC_all_interior_pointers && !TEST_FAIL_COUNT(2)))
+ if (!TEST_FAIL_COUNT(GC_get_all_interior_pointers() ? 1 : 2))
# endif
{
- GC_printf("GC_is_valid_displacement produced wrong failure indication\n");
+ GC_printf(
+ "GC_is_valid_displacement produced wrong failure indication\n");
FAIL;
}
# endif
# endif /* DBG_HDRS_ALL */
/* Test floating point alignment */
collectable_count += 2;
- *(double *)GC_MALLOC(sizeof(double)) = 1.0;
- *(double *)GC_MALLOC(sizeof(double)) = 1.0;
+ {
+ double *dp = GC_MALLOC(sizeof(double));
+ CHECK_OUT_OF_MEMORY(dp);
+ *dp = 1.0;
+ dp = GC_MALLOC(sizeof(double));
+ CHECK_OUT_OF_MEMORY(dp);
+ *dp = 1.0;
+ }
/* Test size 0 allocation a bit more */
{
size_t i;
@@ -1211,15 +1217,16 @@ void run_one_test(void)
GET_TIME(tree_time);
time_diff = MS_TIME_DIFF(tree_time, start_time);
GC_log_printf("-------------Finished tree_test at time %u (%p)\n",
- (unsigned) time_diff, &start_time);
+ (unsigned) time_diff, &start_time);
}
/* Run reverse_test a second time, so we hopefully notice corruption. */
reverse_test();
if (GC_print_stats) {
- GET_TIME(reverse_time);
- time_diff = MS_TIME_DIFF(reverse_time, start_time);
- GC_log_printf("-------------Finished second reverse_test at time %u (%p)\n",
- (unsigned) time_diff, &start_time);
+ GET_TIME(reverse_time);
+ time_diff = MS_TIME_DIFF(reverse_time, start_time);
+ GC_log_printf(
+ "-------------Finished second reverse_test at time %u (%p)\n",
+ (unsigned)time_diff, &start_time);
}
/* GC_allocate_ml and GC_need_to_lock are no longer exported, and */
/* AO_fetch_and_add1() may be unavailable to update a counter. */
@@ -1238,6 +1245,8 @@ void run_one_test(void)
GC_log_printf("Finished %p\n", &start_time);
}
+#define NUMBER_ROUND_UP(v, bound) ((((v) + (bound) - 1) / (bound)) * (bound))
+
void check_heap_stats(void)
{
size_t max_heap_sz;
@@ -1274,6 +1283,10 @@ void check_heap_stats(void)
# endif
# endif
# endif
+ max_heap_sz *= n_tests;
+# if defined(USE_MMAP) || defined(MSWIN32)
+ max_heap_sz = NUMBER_ROUND_UP(max_heap_sz, 4 * 1024 * 1024);
+# endif
/* Garbage collect repeatedly so that all inaccessible objects */
/* can be finalized. */
while (GC_collect_a_little()) { }
@@ -1288,26 +1301,26 @@ void check_heap_stats(void)
GC_log_printf("Primordial thread stack bottom: %p\n",
GC_stackbottom);
}
- (void)GC_printf("Completed %u tests\n", n_tests);
- (void)GC_printf("Allocated %d collectable objects\n", collectable_count);
- (void)GC_printf("Allocated %d uncollectable objects\n",
- uncollectable_count);
- (void)GC_printf("Allocated %d atomic objects\n", atomic_count);
- (void)GC_printf("Allocated %d stubborn objects\n", stubborn_count);
- (void)GC_printf("Finalized %d/%d objects - ",
- finalized_count, finalizable_count);
+ GC_printf("Completed %u tests\n", n_tests);
+ GC_printf("Allocated %d collectable objects\n", collectable_count);
+ GC_printf("Allocated %d uncollectable objects\n",
+ uncollectable_count);
+ GC_printf("Allocated %d atomic objects\n", atomic_count);
+ GC_printf("Allocated %d stubborn objects\n", stubborn_count);
+ GC_printf("Finalized %d/%d objects - ",
+ finalized_count, finalizable_count);
# ifdef FINALIZE_ON_DEMAND
if (finalized_count != late_finalize_count) {
- (void)GC_printf("Demand finalization error\n");
+ GC_printf("Demand finalization error\n");
FAIL;
}
# endif
if (finalized_count > finalizable_count
|| finalized_count < finalizable_count/2) {
- (void)GC_printf("finalization is probably broken\n");
+ GC_printf("finalization is probably broken\n");
FAIL;
} else {
- (void)GC_printf("finalization is probably ok\n");
+ GC_printf("finalization is probably ok\n");
}
still_live = 0;
for (i = 0; i < MAX_FINALIZED; i++) {
@@ -1318,36 +1331,38 @@ void check_heap_stats(void)
i = finalizable_count - finalized_count - still_live;
if (0 != i) {
GC_printf("%d disappearing links remain and %d more objects "
- "were not finalized\n", still_live, i);
+ "were not finalized\n", still_live, i);
if (i > 10) {
GC_printf("\tVery suspicious!\n");
} else {
- GC_printf("\tSlightly suspicious, but probably OK.\n");
+ GC_printf("\tSlightly suspicious, but probably OK\n");
}
}
- (void)GC_printf("Total number of bytes allocated is %lu\n",
- (unsigned long)
- (GC_bytes_allocd + GC_bytes_allocd_before_gc));
- (void)GC_printf("Final heap size is %lu bytes\n",
- (unsigned long)GC_get_heap_size());
- if (GC_bytes_allocd + GC_bytes_allocd_before_gc < n_tests *
+ GC_printf("Total number of bytes allocated is %lu\n",
+ (unsigned long)GC_get_total_bytes());
+ GC_printf("Final heap size is %lu bytes\n",
+ (unsigned long)GC_get_heap_size());
+ if (GC_get_total_bytes() < n_tests *
# ifdef VERY_SMALL_CONFIG
2700000
# else
33500000
# endif
) {
- (void)GC_printf("Incorrect execution - missed some allocations\n");
- FAIL;
+ GC_printf("Incorrect execution - missed some allocations\n");
+ FAIL;
}
- if (GC_get_heap_size() + GC_get_unmapped_bytes() > max_heap_sz*n_tests) {
- (void)GC_printf("Unexpected heap growth - collector may be broken\n");
+ if (GC_get_heap_size() + GC_get_unmapped_bytes() > max_heap_sz) {
+ GC_printf("Unexpected heap growth - collector may be broken"
+ " (heapsize: %lu, expected: %lu)\n",
+ (unsigned long)(GC_get_heap_size() + GC_get_unmapped_bytes()),
+ (unsigned long)max_heap_sz);
FAIL;
}
# ifdef THREADS
GC_unregister_my_thread(); /* just to check it works (for main) */
# endif
- (void)GC_printf("Collector appears to work\n");
+ GC_printf("Collector appears to work\n");
}
#if defined(MACOS)
@@ -1380,12 +1395,21 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p)
# define WINMAIN_LPTSTR LPSTR
#endif
-#if !defined(PCR) \
- && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
+#if !defined(PCR) && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
|| defined(LINT)
#if defined(MSWIN32) && !defined(__MINGW32__) || defined(MSWINCE)
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev,
WINMAIN_LPTSTR cmd, int n)
+#elif defined(RTEMS)
+# include <bsp.h>
+# define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+# define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+# define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+# define CONFIGURE_MAXIMUM_TASKS 1
+# define CONFIGURE_INIT
+# define CONFIGURE_INIT_TASK_STACK_SIZE (64*1024)
+# include <rtems/confdefs.h>
+ rtems_task Init(rtems_task_argument ignord)
#else
int main(void)
#endif
@@ -1395,7 +1419,7 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p)
/* Make sure we have lots and lots of stack space. */
SetMinimumStack(cMinStackSpace);
/* Cheat and let stdio initialize toolbox for us. */
- printf("Testing GC Macintosh port.\n");
+ printf("Testing GC Macintosh port\n");
# endif
GC_COND_INIT();
GC_set_warn_proc(warn_proc);
@@ -1551,12 +1575,12 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev,
# ifdef MSWINCE
win_created_h = CreateEvent(NULL, FALSE, FALSE, NULL);
if (win_created_h == (HANDLE)NULL) {
- (void)GC_printf("Event creation failed %d\n", (int)GetLastError());
+ GC_printf("Event creation failed %d\n", (int)GetLastError());
FAIL;
}
win_thr_h = GC_CreateThread(NULL, 0, thr_window, 0, 0, &thread_id);
if (win_thr_h == (HANDLE)NULL) {
- (void)GC_printf("Thread creation failed %d\n", (int)GetLastError());
+ GC_printf("Thread creation failed %d\n", (int)GetLastError());
FAIL;
}
if (WaitForSingleObject(win_created_h, INFINITE) != WAIT_OBJECT_0)
@@ -1567,7 +1591,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev,
for (i = 0; i < NTHREADS; i++) {
h[i] = GC_CreateThread(NULL, 0, thr_run_one_test, 0, 0, &thread_id);
if (h[i] == (HANDLE)NULL) {
- (void)GC_printf("Thread creation failed %d\n", (int)GetLastError());
+ GC_printf("Thread creation failed %d\n", (int)GetLastError());
FAIL;
}
}
@@ -1576,7 +1600,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev,
# if NTHREADS > 0
for (i = 0; i < NTHREADS; i++) {
if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) {
- (void)GC_printf("Thread wait failed %d\n", (int)GetLastError());
+ GC_printf("Thread wait failed %d\n", (int)GetLastError());
FAIL;
}
}
@@ -1608,11 +1632,11 @@ int test(void)
run_one_test();
if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
!= PCR_ERes_okay || code != 0) {
- (void)GC_printf("Thread 1 failed\n");
+ GC_printf("Thread 1 failed\n");
}
if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
!= PCR_ERes_okay || code != 0) {
- (void)GC_printf("Thread 2 failed\n");
+ GC_printf("Thread 2 failed\n");
}
check_heap_stats();
return(0);
@@ -1645,7 +1669,7 @@ int main(void)
/* Default stack size is too small, especially with the 64 bit ABI */
/* Increase it. */
if (pthread_default_stacksize_np(1024*1024, 0) != 0) {
- (void)GC_printf("pthread_default_stacksize_np failed.\n");
+ GC_printf("pthread_default_stacksize_np failed\n");
}
# endif /* GC_HPUX_THREADS */
# ifdef PTW32_STATIC_LIB
@@ -1671,39 +1695,39 @@ int main(void)
&& !defined(MAKE_BACK_GRAPH) && !defined(USE_PROC_FOR_LIBRARIES) \
&& !defined(NO_INCREMENTAL)
GC_enable_incremental();
- (void) GC_printf("Switched to incremental mode\n");
+ GC_printf("Switched to incremental mode\n");
# if defined(MPROTECT_VDB)
- (void)GC_printf("Emulating dirty bits with mprotect/signals\n");
+ GC_printf("Emulating dirty bits with mprotect/signals\n");
# else
# ifdef PROC_VDB
- (void)GC_printf("Reading dirty bits from /proc\n");
+ GC_printf("Reading dirty bits from /proc\n");
# else
- (void)GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
+ GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
# endif
# endif
# endif
GC_set_warn_proc(warn_proc);
if ((code = pthread_key_create(&fl_key, 0)) != 0) {
- (void)GC_printf("Key creation failed %d\n", code);
+ GC_printf("Key creation failed %d\n", code);
FAIL;
}
for (i = 0; i < NTHREADS; ++i) {
if ((code = pthread_create(th+i, &attr, thr_run_one_test, 0)) != 0) {
- (void)GC_printf("Thread %d creation failed %d\n", i, code);
+ GC_printf("Thread %d creation failed %d\n", i, code);
FAIL;
}
}
run_one_test();
for (i = 0; i < NTHREADS; ++i) {
if ((code = pthread_join(th[i], 0)) != 0) {
- (void)GC_printf("Thread %d failed %d\n", i, code);
+ GC_printf("Thread %d failed %d\n", i, code);
FAIL;
}
}
check_heap_stats();
(void)fflush(stdout);
pthread_attr_destroy(&attr);
- GC_printf("Completed %u collections\n", (unsigned)GC_gc_no);
+ GC_printf("Completed %u collections\n", (unsigned)GC_get_gc_no());
# ifdef PTW32_STATIC_LIB
pthread_win32_thread_detach_np ();
pthread_win32_process_detach_np ();
diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc
index 94a8ca37..de01bf71 100644
--- a/tests/test_cpp.cc
+++ b/tests/test_cpp.cc
@@ -27,12 +27,17 @@ few minutes to complete.
#ifdef HAVE_CONFIG_H
# include "private/config.h"
#endif
+
#undef GC_BUILD
+
#include "gc_cpp.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
#define USE_STD_ALLOCATOR
+
#ifdef USE_STD_ALLOCATOR
# include "gc_allocator.h"
#elif __GNUC__
@@ -40,6 +45,7 @@ few minutes to complete.
#else
# include "gc_alloc.h"
#endif
+
extern "C" {
# include "private/gcconfig.h"
GC_API void GC_printf(const char *format, ...);
@@ -47,17 +53,18 @@ extern "C" {
/* Don't include gc_priv.h, since that may include Windows system */
/* header files that don't take kindly to this context. */
}
+
#ifdef MSWIN32
-# include <windows.h>
+# include <windows.h>
#endif
+
#ifdef GC_NAME_CONFLICT
-# define USE_GC UseGC
- struct foo * GC;
+# define USE_GC UseGC
+ struct foo * GC;
#else
-# define USE_GC GC
+# define USE_GC GC
#endif
-
#define my_assert( e ) \
if (! (e)) { \
GC_printf( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
@@ -180,37 +187,32 @@ GC_word Disguise( void* p ) {
void* Undisguise( GC_word i ) {
return (void*) ~ i;}
-
-#ifdef MSWIN32
+#if 0//def MSWIN32
int APIENTRY WinMain(
HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int cmdShow )
{
int argc;
char* argv[ 3 ];
- for (argc = 1; argc < sizeof( argv ) / sizeof( argv[ 0 ] ); argc++) {
+ for (argc = 1; argc < (int)(sizeof(argv) / sizeof(argv[0])); argc++) {
argv[ argc ] = strtok( argc == 1 ? cmd : 0, " \t" );
if (0 == argv[ argc ]) break;}
-
+#elif defined(MACOS)
+ int main() {
+ char* argv_[] = {"test_cpp", "10"}; // MacOS doesn't have a commandline
+ argv = argv_;
+ argc = sizeof(argv_)/sizeof(argv_[0]);
#else
-# ifdef MACOS
- int main() {
-# else
- int main( int argc, char* argv[] ) {
-# endif
+ int main( int argc, char* argv[] ) {
#endif
- GC_INIT();
+ GC_INIT();
-# if defined(MACOS) // MacOS
- char* argv_[] = {"test_cpp", "10"}; // doesn't
- argv = argv_; // have a
- argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
-# endif
int i, iters, n;
# ifdef USE_STD_ALLOCATOR
int *x = gc_allocator<int>().allocate(1);
- int *xio = gc_allocator_ignore_off_page<int>().allocate(1);
+ int *xio;
+ xio = gc_allocator_ignore_off_page<int>().allocate(1);
int **xptr = traceable_allocator<int *>().allocate(1);
# else
# ifdef __GNUC__
@@ -237,7 +239,7 @@ int APIENTRY WinMain(
GC_word as[ 1000 ];
GC_word bs[ 1000 ];
for (i = 0; i < 1000; i++) {
- as[ i ] = Disguise( new (NoGC) A( i ) );
+ as[ i ] = Disguise( new (NoGC ) A( i ) );
bs[ i ] = Disguise( new (NoGC) B( i ) );}
/* Allocate a fair number of finalizable Cs, Ds, and Fs.
@@ -245,15 +247,18 @@ int APIENTRY WinMain(
for (i = 0; i < 1000; i++) {
C* c = new C( 2 );
C c1( 2 ); /* stack allocation should work too */
- D* d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i );
- F* f = new F;
+ D* d;
+ F* f;
+ d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i );
+ f = new F;
if (0 == i % 10) delete c;}
/* Allocate a very large number of collectable As and Bs and
drop the references to them immediately, forcing many
collections. */
for (i = 0; i < 1000000; i++) {
- A* a = new (USE_GC) A( i );
+ A* a;
+ a = new (USE_GC) A( i );
B* b = new B( i );
b = new (USE_GC) B( i );
if (0 == i % 10) {
@@ -278,7 +283,6 @@ int APIENTRY WinMain(
# ifdef FINALIZE_ON_DEMAND
GC_invoke_finalizers();
# endif
-
}
/* Make sure most of the finalizable Cs, Ds, and Fs have
@@ -292,4 +296,6 @@ int APIENTRY WinMain(
# endif
my_assert (29 == x[0]);
GC_printf( "The test appears to have succeeded.\n" );
- return( 0 );}
+ return( 0 );
+}
+
diff --git a/tests/tests.am b/tests/tests.am
index b655c2ba..f3505749 100644
--- a/tests/tests.am
+++ b/tests/tests.am
@@ -45,6 +45,11 @@ check_PROGRAMS += hugetest
hugetest_SOURCES = tests/huge_test.c
hugetest_LDADD = $(test_ldadd)
+TESTS += realloc_test$(EXEEXT)
+check_PROGRAMS += realloc_test
+realloc_test_SOURCES = tests/realloc_test.c
+realloc_test_LDADD = $(test_ldadd)
+
TESTS += staticrootstest$(EXEEXT)
check_PROGRAMS += staticrootstest
staticrootstest_SOURCES = tests/staticrootstest.c
@@ -67,6 +72,16 @@ TESTS += threadleaktest$(EXEEXT)
check_PROGRAMS += threadleaktest
threadleaktest_SOURCES = tests/thread_leak_test.c
threadleaktest_LDADD = $(test_ldadd)
+
+TESTS += threadkey_test$(EXEEXT)
+check_PROGRAMS += threadkey_test
+threadkey_test_SOURCES = tests/threadkey_test.c
+threadkey_test_LDADD = $(test_ldadd)
+
+TESTS += initsecondarythread$(EXEEXT)
+check_PROGRAMS += initsecondarythread
+initsecondarythread_SOURCES = tests/initsecondarythread.c
+initsecondarythread_LDADD = $(test_ldadd)
endif
if CPLUSPLUS
diff --git a/tests/threadkey_test.c b/tests/threadkey_test.c
new file mode 100644
index 00000000..d080a7ba
--- /dev/null
+++ b/tests/threadkey_test.c
@@ -0,0 +1,92 @@
+
+#ifndef GC_THREADS
+# define GC_THREADS
+#endif
+
+#define GC_NO_THREAD_REDIRECTS 1
+
+#include "gc.h"
+
+#if (!defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
+ || defined(__native_client__)) && !defined(SKIP_THREADKEY_TEST)
+ /* FIXME: Skip this test on Solaris for now. The test may fail on */
+ /* other targets as well. Currently, tested only on Linux, Cygwin */
+ /* and Darwin. */
+# define SKIP_THREADKEY_TEST
+#endif
+
+#ifdef SKIP_THREADKEY_TEST
+
+int main (void)
+{
+ return 0;
+}
+
+#else
+
+#include <pthread.h>
+
+pthread_key_t key;
+
+#ifdef GC_SOLARIS_THREADS
+ /* pthread_once_t key_once = { PTHREAD_ONCE_INIT }; */
+#else
+ pthread_once_t key_once = PTHREAD_ONCE_INIT;
+#endif
+
+void * entry (void *arg)
+{
+ pthread_setspecific(key,
+ (void *)GC_HIDE_POINTER(GC_STRDUP("hello, world")));
+ return arg;
+}
+
+void * GC_CALLBACK on_thread_exit_inner (struct GC_stack_base * sb, void * arg)
+{
+ int res = GC_register_my_thread (sb);
+ pthread_t t;
+ int creation_res; /* Used to suppress a warning about */
+ /* unchecked pthread_create() result. */
+
+ creation_res = GC_pthread_create (&t, NULL, entry, NULL);
+ if (res == GC_SUCCESS)
+ GC_unregister_my_thread ();
+
+ return (void*)(GC_word)creation_res;
+}
+
+void on_thread_exit (void *v)
+{
+ GC_call_with_stack_base (on_thread_exit_inner, NULL);
+}
+
+void make_key (void)
+{
+ pthread_key_create (&key, on_thread_exit);
+}
+
+#ifndef LIMIT
+# define LIMIT 30
+#endif
+
+int main (void)
+{
+ int i;
+ GC_INIT ();
+
+# ifdef GC_SOLARIS_THREADS
+ pthread_key_create (&key, on_thread_exit);
+# else
+ pthread_once (&key_once, make_key);
+# endif
+ for (i = 0; i < LIMIT; i++) {
+ pthread_t t;
+ void *res;
+ if (GC_pthread_create (&t, NULL, entry, NULL) == 0
+ && (i & 1) != 0)
+ GC_pthread_join (t, &res);
+ }
+ return 0;
+}
+
+#endif
diff --git a/thread_local_alloc.c b/thread_local_alloc.c
index 2e27331d..610db6fd 100644
--- a/thread_local_alloc.c
+++ b/thread_local_alloc.c
@@ -147,8 +147,6 @@ GC_API void * GC_CALL GC_malloc(size_t bytes)
tsd = GC_getspecific(k);
# else
tsd = GC_getspecific(GC_thread_key);
-# endif
-# if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
if (EXPECT(0 == tsd, FALSE)) {
return GC_core_malloc(bytes);
}
@@ -179,15 +177,13 @@ GC_API void * GC_CALL GC_malloc_atomic(size_t bytes)
if (EXPECT(0 == k, FALSE)) {
/* We haven't yet run GC_init_parallel. That means */
/* we also aren't locking, so this is fairly cheap. */
- return GC_core_malloc(bytes);
+ return GC_core_malloc_atomic(bytes);
}
tsd = GC_getspecific(k);
# else
tsd = GC_getspecific(GC_thread_key);
-# endif
-# if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
if (EXPECT(0 == tsd, FALSE)) {
- return GC_core_malloc(bytes);
+ return GC_core_malloc_atomic(bytes);
}
# endif
GC_ASSERT(GC_is_initialized);
@@ -288,7 +284,7 @@ GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p)
}
#if defined(GC_ASSERTIONS)
- /* Check that all thread-local free-lists in p are completely marked. */
+ /* Check that all thread-local free-lists in p are completely marked. */
void GC_check_tls_for(GC_tlfs p)
{
ptr_t q;
diff --git a/vc9/test_cpp_libgc.vcproj b/vc9/test_cpp_libgc.vcproj
index 0fcc8eed..b15c9e9f 100644
--- a/vc9/test_cpp_libgc.vcproj
+++ b/vc9/test_cpp_libgc.vcproj
@@ -56,7 +56,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
@@ -81,11 +81,10 @@
/>
</Configuration>
<Configuration
- Name="Release|Win32"
+ Name="Debug|x64"
ConfigurationType="1"
InheritedPropertySheets="$(solutiondir)/$(solutionname)_$(platformname).$(configurationname).vsprops"
CharacterSet="0"
- WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
@@ -101,6 +100,7 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
@@ -118,7 +118,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
@@ -143,10 +143,11 @@
/>
</Configuration>
<Configuration
- Name="Debug|x64"
+ Name="Release|Win32"
ConfigurationType="1"
InheritedPropertySheets="$(solutiondir)/$(solutionname)_$(platformname).$(configurationname).vsprops"
CharacterSet="0"
+ WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
@@ -162,7 +163,6 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
@@ -180,7 +180,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
@@ -243,7 +243,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
diff --git a/vc9/test_libgc.vcproj b/vc9/test_libgc.vcproj
index 7cb89da9..0f40c859 100644
--- a/vc9/test_libgc.vcproj
+++ b/vc9/test_libgc.vcproj
@@ -55,7 +55,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
@@ -80,11 +80,10 @@
/>
</Configuration>
<Configuration
- Name="Release|Win32"
+ Name="Debug|x64"
ConfigurationType="1"
InheritedPropertySheets="$(solutiondir)/$(solutionname)_$(platformname).$(configurationname).vsprops"
CharacterSet="0"
- WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
@@ -100,6 +99,7 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
@@ -116,7 +116,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
@@ -141,10 +141,11 @@
/>
</Configuration>
<Configuration
- Name="Debug|x64"
+ Name="Release|Win32"
ConfigurationType="1"
InheritedPropertySheets="$(solutiondir)/$(solutionname)_$(platformname).$(configurationname).vsprops"
CharacterSet="0"
+ WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
@@ -160,7 +161,6 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
@@ -177,7 +177,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
@@ -239,7 +239,7 @@
/>
<Tool
Name="VCLinkerTool"
- SubSystem="2"
+ SubSystem="1"
/>
<Tool
Name="VCALinkTool"
diff --git a/win32_threads.c b/win32_threads.c
index 8322eb6b..123668cf 100755..100644
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -51,19 +51,6 @@
# undef pthread_sigmask
# endif
-# ifdef DEBUG_THREADS
-# ifdef CYGWIN32
-# define DEBUG_CYGWIN_THREADS 1
-# define DEBUG_WIN32_PTHREADS 0
-# else
-# define DEBUG_WIN32_PTHREADS 1
-# define DEBUG_CYGWIN_THREADS 0
-# endif
-# else
-# define DEBUG_CYGWIN_THREADS 0
-# define DEBUG_WIN32_PTHREADS 0
-# endif
-
STATIC void * GC_pthread_start(void * arg);
STATIC void GC_thread_exit_proc(void *arg);
@@ -76,12 +63,6 @@
# undef _beginthreadex
# undef _endthreadex
-# ifdef DEBUG_THREADS
-# define DEBUG_WIN32_THREADS 1
-# else
-# define DEBUG_WIN32_THREADS 0
-# endif
-
# ifdef MSWINCE
/* Force DONT_USE_SIGNALANDWAIT implementation of PARALLEL_MARK */
/* for WinCE (since Win32 SignalObjectAndWait() is missing). */
@@ -374,20 +355,20 @@ STATIC GC_thread GC_new_thread(DWORD id)
return(result);
}
-#ifdef MPROTECT_VDB
- GC_INNER LONG WINAPI GC_write_fault_handler(
- struct _EXCEPTION_POINTERS *exc_info);
-#endif
-
-#if defined(GWW_VDB) && defined(MPROTECT_VDB)
- GC_INNER GC_bool GC_gww_dirty_init(void);
- /* Defined in os_dep.c. Returns TRUE if GetWriteWatch is available. */
- /* may be called repeatedly. */
-#endif
-
STATIC GC_bool GC_in_thread_creation = FALSE;
/* Protected by allocation lock. */
+GC_INLINE void GC_record_stack_base(GC_vthread me,
+ const struct GC_stack_base *sb)
+{
+ me -> stack_base = sb -> mem_base;
+# ifdef IA64
+ me -> backing_store_end = sb -> reg_base;
+# endif
+ if (me -> stack_base == NULL)
+ ABORT("Bad stack base in GC_register_my_thread");
+}
+
/* This may be called from DllMain, and hence operates under unusual */
/* constraints. In particular, it must be lock-free if */
/* GC_win32_dll_threads is set. Always called from the thread being */
@@ -402,12 +383,12 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
/* documentation. There is empirical evidence that it */
/* isn't. - HB */
# if defined(MPROTECT_VDB)
-# if defined(GWW_VDB)
- if (GC_incremental && !GC_gww_dirty_init())
- SetUnhandledExceptionFilter(GC_write_fault_handler);
-# else
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
-# endif
+ if (GC_incremental
+# ifdef GWW_VDB
+ && !GC_gww_dirty_init()
+# endif
+ )
+ GC_set_write_fault_handler();
# endif
# ifndef GC_NO_THREADS_DISCOVERY
@@ -436,7 +417,7 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
/* FIXME: We should eventually declare Win95 dead and use AO_ */
/* primitives here. */
if (i == MAX_THREADS - 1)
- ABORT("too many threads");
+ ABORT("Too many threads");
}
/* Update GC_max_thread_index if necessary. The following is */
/* safe, and unlike CompareExchange-based solutions seems to work */
@@ -460,7 +441,7 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
me = GC_new_thread(thread_id);
GC_in_thread_creation = FALSE;
if (me == 0)
- ABORT("Failed to allocate memory for thread registering.");
+ ABORT("Failed to allocate memory for thread registering");
}
# ifdef GC_PTHREADS
/* me can be NULL -> segfault */
@@ -474,16 +455,13 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
DUPLICATE_SAME_ACCESS)) {
if (GC_print_stats)
- GC_printf("DuplicateHandle failed with error code: %d\n",
- (int)GetLastError());
+ GC_log_printf("DuplicateHandle failed with error code: %d\n",
+ (int)GetLastError());
ABORT("DuplicateHandle failed");
}
# endif
me -> last_stack_min = ADDR_LIMIT;
- me -> stack_base = sb -> mem_base;
-# ifdef IA64
- me -> backing_store_end = sb -> reg_base;
-# endif
+ GC_record_stack_base(me, sb);
/* Up until this point, GC_push_all_stacks considers this thread */
/* invalid. */
/* Up until this point, this entry is viewed as reserved but invalid */
@@ -492,8 +470,6 @@ STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
# if defined(THREAD_LOCAL_ALLOC)
GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
# endif
- if (me -> stack_base == NULL)
- ABORT("Bad stack base in GC_register_my_thread_inner");
# ifndef GC_NO_THREADS_DISCOVERY
if (GC_win32_dll_threads) {
if (GC_please_stop) {
@@ -558,11 +534,19 @@ STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
}
}
+#ifdef LINT2
+# define CHECK_LOOKUP_MY_THREAD(me) \
+ if (!(me)) ABORT("GC_lookup_thread_inner(GetCurrentThreadId) failed")
+#else
+# define CHECK_LOOKUP_MY_THREAD(me) /* empty */
+#endif
+
/* Called by GC_finalize() (in case of an allocation failure observed). */
/* GC_reset_finalizer_nested() is the same as in pthread_support.c. */
GC_INNER void GC_reset_finalizer_nested(void)
{
GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
+ CHECK_LOOKUP_MY_THREAD(me);
me->finalizer_nested = 0;
}
@@ -575,7 +559,9 @@ GC_INNER void GC_reset_finalizer_nested(void)
GC_INNER unsigned char *GC_check_finalizer_nested(void)
{
GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
- unsigned nesting_level = me->finalizer_nested;
+ unsigned nesting_level;
+ CHECK_LOOKUP_MY_THREAD(me);
+ nesting_level = me->finalizer_nested;
if (nesting_level) {
/* We are inside another GC_invoke_finalizers(). */
/* Skip some implicitly-called GC_invoke_finalizers() */
@@ -620,6 +606,12 @@ GC_INNER unsigned char *GC_check_finalizer_nested(void)
# define UNPROTECT_THREAD(t)
#endif
+#ifdef CYGWIN32
+# define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
+#elif defined(GC_WIN32_PTHREADS)
+# define GC_PTHREAD_PTRVAL(pthread_id) pthread_id.p
+#endif
+
/* If a thread has been joined, but we have not yet */
/* been notified, then there may be more than one thread */
/* in the table with the same win32 id. */
@@ -628,40 +620,36 @@ GC_INNER unsigned char *GC_check_finalizer_nested(void)
/* GC_win32_dll_threads is set. */
/* If GC_win32_dll_threads is set it should be called from the */
/* thread being deleted. */
-STATIC void GC_delete_gc_thread(GC_vthread gc_id)
+STATIC void GC_delete_gc_thread(GC_vthread t)
{
# ifndef MSWINCE
- CloseHandle(gc_id->handle);
+ CloseHandle(t->handle);
# endif
# ifndef GC_NO_THREADS_DISCOVERY
if (GC_win32_dll_threads) {
/* This is intended to be lock-free. */
/* It is either called synchronously from the thread being */
/* deleted, or by the joining thread. */
- /* In this branch asynchronous changes to *gc_id are possible. */
+ /* In this branch asynchronous changes to (*t) are possible. */
/* It's not allowed to call GC_printf (and the friends) here, */
/* see GC_stop_world() for the information. */
- gc_id -> stack_base = 0;
- gc_id -> id = 0;
-# ifdef CYGWIN32
- gc_id -> pthread_id = 0;
-# endif /* CYGWIN32 */
-# ifdef GC_WIN32_PTHREADS
- gc_id -> pthread_id.p = NULL;
-# endif /* GC_WIN32_PTHREADS */
- AO_store_release(&gc_id->tm.in_use, FALSE);
+ t -> stack_base = 0;
+ t -> id = 0;
+# ifdef GC_PTHREADS
+ GC_PTHREAD_PTRVAL(t->pthread_id) = 0;
+# endif
+ AO_store_release(&t->tm.in_use, FALSE);
} else
# endif
/* else */ {
- /* Cast away volatile qualifier, since we have lock. */
- GC_thread gc_nvid = (GC_thread)gc_id;
- DWORD id = gc_nvid -> id;
+ DWORD id = ((GC_thread)t) -> id;
+ /* Cast away volatile qualifier, since we have lock. */
word hv = THREAD_TABLE_INDEX(id);
register GC_thread p = GC_threads[hv];
register GC_thread prev = 0;
GC_ASSERT(I_HOLD_LOCK());
- while (p != gc_nvid) {
+ while (p != (GC_thread)t) {
prev = p;
p = p -> tm.next;
}
@@ -728,7 +716,8 @@ GC_API void GC_CALL GC_allow_register_threads(void)
GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
{
- DWORD t = GetCurrentThreadId();
+ GC_thread me;
+ DWORD thread_id = GetCurrentThreadId();
DCL_LOCK_STATE;
if (GC_need_to_lock == FALSE)
@@ -736,11 +725,27 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
/* We lock here, since we want to wait for an ongoing GC. */
LOCK();
- if (0 == GC_lookup_thread_inner(t)) {
- GC_register_my_thread_inner(sb, t);
+ me = GC_lookup_thread_inner(thread_id);
+ if (me == 0) {
+ GC_register_my_thread_inner(sb, thread_id);
+# ifdef GC_PTHREADS
+ me -> flags |= DETACHED;
+# endif
UNLOCK();
return GC_SUCCESS;
- } else {
+ } else
+# ifdef GC_PTHREADS
+ /* else */ if ((me -> flags & FINISHED) != 0) {
+ GC_record_stack_base(me, sb);
+ me -> flags &= ~FINISHED; /* but not DETACHED */
+# ifdef THREAD_LOCAL_ALLOC
+ GC_init_thread_local((GC_tlfs)(&me->tlfs));
+# endif
+ UNLOCK();
+ return GC_SUCCESS;
+ } else
+# endif
+ /* else */ {
UNLOCK();
return GC_DUPLICATE;
}
@@ -750,25 +755,45 @@ GC_API int GC_CALL GC_unregister_my_thread(void)
{
DCL_LOCK_STATE;
+# ifdef DEBUG_THREADS
+ GC_log_printf("Unregistering thread 0x%lx\n", (long)GetCurrentThreadId());
+# endif
+
/* FIXME: is GC_wait_for_gc_completion(FALSE) needed here? */
if (GC_win32_dll_threads) {
# if defined(THREAD_LOCAL_ALLOC)
/* Can't happen: see GC_use_threads_discovery(). */
GC_ASSERT(FALSE);
# else
+# ifdef GC_PTHREADS
+ /* FIXME: If not DETACHED then just set FINISHED. */
+# endif
/* FIXME: Should we just ignore this? */
GC_delete_thread(GetCurrentThreadId());
# endif
} else {
- DWORD t = GetCurrentThreadId();
+# if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
+ GC_thread me;
+# endif
+ DWORD thread_id = GetCurrentThreadId();
+
LOCK();
+# if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
+ me = GC_lookup_thread_inner(thread_id);
+ CHECK_LOOKUP_MY_THREAD(me);
+ GC_ASSERT(!KNOWN_FINISHED(me));
+# endif
# if defined(THREAD_LOCAL_ALLOC)
- {
- GC_thread me = GC_lookup_thread_inner(t);
- GC_destroy_thread_local(&(me->tlfs));
- }
+ GC_destroy_thread_local(&(me->tlfs));
+# endif
+# ifdef GC_PTHREADS
+ if ((me -> flags & DETACHED) == 0) {
+ me -> flags |= FINISHED;
+ } else
# endif
- GC_delete_thread(t);
+ /* else */ {
+ GC_delete_thread(thread_id);
+ }
UNLOCK();
}
return GC_SUCCESS;
@@ -782,7 +807,7 @@ GC_API int GC_CALL GC_unregister_my_thread(void)
GC_INNER void GC_do_blocking_inner(ptr_t data, void * context)
{
struct blocking_data * d = (struct blocking_data *) data;
- DWORD t = GetCurrentThreadId();
+ DWORD thread_id = GetCurrentThreadId();
GC_thread me;
# ifdef IA64
ptr_t stack_ptr = GC_save_regs_in_stack();
@@ -790,7 +815,8 @@ GC_INNER void GC_do_blocking_inner(ptr_t data, void * context)
DCL_LOCK_STATE;
LOCK();
- me = GC_lookup_thread_inner(t);
+ me = GC_lookup_thread_inner(thread_id);
+ CHECK_LOOKUP_MY_THREAD(me);
GC_ASSERT(me -> thread_blocked_sp == NULL);
# ifdef IA64
me -> backing_store_ptr = stack_ptr;
@@ -817,7 +843,7 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
LOCK(); /* This will block if the world is stopped. */
me = GC_lookup_thread_inner(GetCurrentThreadId());
-
+ CHECK_LOOKUP_MY_THREAD(me);
/* Adjust our stack base value (this could happen unless */
/* GC_get_stack_base() was used which returned GC_SUCCESS). */
GC_ASSERT(me -> stack_base != NULL);
@@ -1293,8 +1319,8 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
if (sp >= stack_min && sp < thread->stack_base) {
# ifdef DEBUG_THREADS
- GC_printf("Pushing stack for 0x%x from sp %p to %p from 0x%x\n",
- (int)thread -> id, sp, thread -> stack_base, (int)me);
+ GC_log_printf("Pushing stack for 0x%x from sp %p to %p from 0x%x\n",
+ (int)thread -> id, sp, thread -> stack_base, (int)me);
# endif
GC_push_all_stack_sections(sp, thread->stack_base, traced_stack_sect);
} else {
@@ -1306,9 +1332,8 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
WARN("Thread stack pointer %p out of range, pushing everything\n",
sp);
# ifdef DEBUG_THREADS
- GC_printf("Pushing stack for 0x%x from (min) %p to %p from 0x%x\n",
- (int)thread -> id, stack_min,
- thread -> stack_base, (int)me);
+ GC_log_printf("Pushing stack for 0x%x from (min) %p to %p from 0x%x\n",
+ (int)thread->id, stack_min, thread->stack_base, (int)me);
# endif
/* Push everything - ignore "traced stack section" data. */
GC_push_all_stack(stack_min, thread->stack_base);
@@ -1318,7 +1343,7 @@ STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
GC_INNER void GC_push_all_stacks(void)
{
- DWORD me = GetCurrentThreadId();
+ DWORD thread_id = GetCurrentThreadId();
GC_bool found_me = FALSE;
# ifndef SMALL_CONFIG
unsigned nthreads = 0;
@@ -1335,8 +1360,8 @@ GC_INNER void GC_push_all_stacks(void)
# ifndef SMALL_CONFIG
++nthreads;
# endif
- total_size += GC_push_stack_for(t, me);
- if (t -> id == me) found_me = TRUE;
+ total_size += GC_push_stack_for(t, thread_id);
+ if (t -> id == thread_id) found_me = TRUE;
}
}
} else
@@ -1350,8 +1375,8 @@ GC_INNER void GC_push_all_stacks(void)
# ifndef SMALL_CONFIG
++nthreads;
# endif
- total_size += GC_push_stack_for(t, me);
- if (t -> id == me) found_me = TRUE;
+ total_size += GC_push_stack_for(t, thread_id);
+ if (t -> id == thread_id) found_me = TRUE;
}
}
}
@@ -1363,7 +1388,7 @@ GC_INNER void GC_push_all_stacks(void)
}
# endif
if (!found_me && !GC_in_thread_creation)
- ABORT("Collecting from unknown thread.");
+ ABORT("Collecting from unknown thread");
GC_total_stacksize = total_size;
}
@@ -1384,7 +1409,7 @@ GC_INNER void GC_push_all_stacks(void)
/* in stack (or ADDR_LIMIT if unset) */
/* for markers. */
-#endif
+#endif /* PARALLEL_MARK */
/* Find stack with the lowest address which overlaps the */
/* interval [start, limit). */
@@ -1454,7 +1479,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
return;
}
- GC_ASSERT(current_min > start);
+ GC_ASSERT(current_min > start && plast_stack_min != NULL);
# ifdef MSWINCE
if (GC_dont_query_stack_min) {
*lo = GC_wince_evaluate_stack_min(current_min);
@@ -1522,8 +1547,8 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
my_mark_no = GC_mark_no;
}
# ifdef DEBUG_THREADS
- GC_printf("Starting mark helper for mark number %lu\n",
- (unsigned long)my_mark_no);
+ GC_log_printf("Starting mark helper for mark number %lu\n",
+ (unsigned long)my_mark_no);
# endif
GC_help_marker(my_mark_no);
}
@@ -1539,7 +1564,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
# include <pthread.h>
# ifndef NUMERIC_THREAD_ID
-# define NUMERIC_THREAD_ID(id) (unsigned long)(id.p)
+# define NUMERIC_THREAD_ID(id) (unsigned long)GC_PTHREAD_PTRVAL(id)
# endif
/* start_mark_threads() is the same as in pthread_support.c except for: */
@@ -1872,10 +1897,10 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_INNER void GC_wait_marker(void)
{
HANDLE event = mark_cv;
- DWORD id = GetCurrentThreadId();
+ DWORD thread_id = GetCurrentThreadId();
int i = (int)GC_markers - 1;
while (i-- > 0) {
- if (GC_marker_Id[i] == id) {
+ if (GC_marker_Id[i] == thread_id) {
event = GC_marker_cv[i];
break;
}
@@ -1891,11 +1916,11 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_INNER void GC_notify_all_marker(void)
{
- DWORD id = GetCurrentThreadId();
+ DWORD thread_id = GetCurrentThreadId();
int i = (int)GC_markers - 1;
while (i-- > 0) {
/* Notify every marker ignoring self (for efficiency). */
- if (SetEvent(GC_marker_Id[i] != id ? GC_marker_cv[i] :
+ if (SetEvent(GC_marker_Id[i] != thread_id ? GC_marker_cv[i] :
mark_cv) == FALSE)
ABORT("SetEvent() failed");
}
@@ -2002,8 +2027,8 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_register_my_thread(sb); /* This waits for an in-progress GC. */
-# if DEBUG_WIN32_THREADS
- GC_printf("thread 0x%x starting...\n", (unsigned)GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread 0x%lx starting...\n", (long)GetCurrentThreadId());
# endif
GC_free(arg);
@@ -2024,9 +2049,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
GC_unregister_my_thread();
}
-# if DEBUG_WIN32_THREADS
- GC_printf("thread 0x%x returned from start routine.\n",
- (unsigned)GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread 0x%lx returned from start routine\n",
+ (long)GetCurrentThreadId());
# endif
return ret;
}
@@ -2050,9 +2075,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
/* make sure GC is initialized (i.e. main thread is */
/* attached, tls initialized). */
-# if DEBUG_WIN32_THREADS
- GC_printf("About to create a thread from 0x%x\n",
- (unsigned)GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("About to create a thread from 0x%lx\n",
+ (long)GetCurrentThreadId());
# endif
if (GC_win32_dll_threads) {
return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
@@ -2097,9 +2122,9 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
if (!parallel_initialized) GC_init_parallel();
/* make sure GC is initialized (i.e. main thread is */
/* attached, tls initialized). */
-# if DEBUG_WIN32_THREADS
- GC_printf("About to create a thread from 0x%x\n",
- (unsigned)GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("About to create a thread from 0x%lx\n",
+ (long)GetCurrentThreadId());
# endif
if (GC_win32_dll_threads) {
@@ -2344,17 +2369,12 @@ GC_INNER void GC_thr_init(void)
GC_API int GC_pthread_join(pthread_t pthread_id, void **retval)
{
int result;
- GC_thread joinee;
+ GC_thread t;
-# if DEBUG_CYGWIN_THREADS
- GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
- (int)pthread_self(), (int)GetCurrentThreadId(),
- (int)pthread_id);
-# endif
-# if DEBUG_WIN32_PTHREADS
- GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
- (int)(pthread_self()).p, (int)GetCurrentThreadId(),
- pthread_id.p);
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%lx) is joining thread %p\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId(), GC_PTHREAD_PTRVAL(pthread_id));
# endif
if (!parallel_initialized) GC_init_parallel();
@@ -2364,33 +2384,29 @@ GC_INNER void GC_thr_init(void)
/* FIXME: It would be better if this worked more like */
/* pthread_support.c. */
# ifndef GC_WIN32_PTHREADS
- while ((joinee = GC_lookup_pthread(pthread_id)) == 0) Sleep(10);
+ while ((t = GC_lookup_pthread(pthread_id)) == 0)
+ Sleep(10);
# endif
result = pthread_join(pthread_id, retval);
# ifdef GC_WIN32_PTHREADS
/* win32_pthreads id are unique */
- joinee = GC_lookup_pthread(pthread_id);
+ t = GC_lookup_pthread(pthread_id);
# endif
if (!GC_win32_dll_threads) {
DCL_LOCK_STATE;
LOCK();
- GC_delete_gc_thread(joinee);
+ GC_delete_gc_thread(t);
UNLOCK();
} /* otherwise DllMain handles it. */
-# if DEBUG_CYGWIN_THREADS
- GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
- (int)pthread_self(), (int)GetCurrentThreadId(),
- (int)pthread_id);
-# endif
-# if DEBUG_WIN32_PTHREADS
- GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
- (int)(pthread_self()).p, (int)GetCurrentThreadId(),
- pthread_id.p);
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%lx) completed join with thread %p\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId(), GC_PTHREAD_PTRVAL(pthread_id));
# endif
return result;
}
@@ -2422,13 +2438,10 @@ GC_INNER void GC_thr_init(void)
si->detached = TRUE;
}
-# if DEBUG_CYGWIN_THREADS
- GC_printf("About to create a thread from 0x%x(0x%x)\n",
- (int)pthread_self(), (int)GetCurrentThreadId);
-# endif
-# if DEBUG_WIN32_PTHREADS
- GC_printf("About to create a thread from 0x%x(0x%x)\n",
- (int)(pthread_self()).p, (int)GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("About to create a thread from %p(0x%lx)\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId());
# endif
GC_need_to_lock = TRUE;
result = pthread_create(new_thread, attr, GC_pthread_start, si);
@@ -2452,13 +2465,9 @@ GC_INNER void GC_thr_init(void)
GC_thread me;
DCL_LOCK_STATE;
-# if DEBUG_CYGWIN_THREADS
- GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id,
- (int)thread_id);
-# endif
-# if DEBUG_WIN32_PTHREADS
- GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p,
- (int)thread_id);
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%x) starting...\n",
+ GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
# endif
GC_ASSERT(!GC_win32_dll_threads);
@@ -2485,13 +2494,9 @@ GC_INNER void GC_thr_init(void)
me -> status = result;
pthread_cleanup_pop(1);
-# if DEBUG_CYGWIN_THREADS
- GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
- (int)pthread_self(),(int)GetCurrentThreadId());
-# endif
-# if DEBUG_WIN32_PTHREADS
- GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
- (int)(pthread_self()).p, (int)GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%x) returned from start routine\n",
+ GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
# endif
return(result);
}
@@ -2507,13 +2512,10 @@ GC_INNER void GC_thr_init(void)
DCL_LOCK_STATE;
GC_ASSERT(!GC_win32_dll_threads);
-# if DEBUG_CYGWIN_THREADS
- GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
- (int)pthread_self(),(int)GetCurrentThreadId());
-# endif
-# if DEBUG_WIN32_PTHREADS
- GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
- (int)(pthread_self()).p,(int)GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%lx) called pthread_exit()\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId());
# endif
LOCK();
@@ -2543,20 +2545,20 @@ GC_INNER void GC_thr_init(void)
GC_API int GC_pthread_detach(pthread_t thread)
{
int result;
- GC_thread thread_gc_id;
+ GC_thread t;
DCL_LOCK_STATE;
if (!parallel_initialized) GC_init_parallel();
LOCK();
- thread_gc_id = GC_lookup_pthread(thread);
+ t = GC_lookup_pthread(thread);
UNLOCK();
result = pthread_detach(thread);
if (result == 0) {
LOCK();
- thread_gc_id -> flags |= DETACHED;
+ t -> flags |= DETACHED;
/* Here the pthread thread id may have been recycled. */
- if (thread_gc_id -> flags & FINISHED) {
- GC_delete_gc_thread(thread_gc_id);
+ if ((t -> flags & FINISHED) != 0) {
+ GC_delete_gc_thread(t);
}
UNLOCK();
}
@@ -2652,6 +2654,7 @@ GC_INNER void GC_thr_init(void)
GC_INNER void GC_init_parallel(void)
{
# if defined(THREAD_LOCAL_ALLOC)
+ GC_thread me;
DCL_LOCK_STATE;
# endif
@@ -2670,8 +2673,9 @@ GC_INNER void GC_init_parallel(void)
/* Initialize thread local free lists if used. */
# if defined(THREAD_LOCAL_ALLOC)
LOCK();
- GC_init_thread_local(
- &GC_lookup_thread_inner(GetCurrentThreadId())->tlfs);
+ me = GC_lookup_thread_inner(GetCurrentThreadId());
+ CHECK_LOOKUP_MY_THREAD(me);
+ GC_init_thread_local(&me->tlfs);
UNLOCK();
# endif
}
@@ -2709,7 +2713,7 @@ GC_INNER void GC_init_parallel(void)
for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
if (!KNOWN_FINISHED(p)) {
# ifdef DEBUG_THREADS
- GC_printf("Marking thread locals for 0x%x\n", (int)p -> id);
+ GC_log_printf("Marking thread locals for 0x%x\n", (int)p -> id);
# endif
GC_mark_thread_local_fls_for(&(p->tlfs));
}