version 1.4, 2001/04/20 07:39:19 |
version 1.7, 2003/06/24 05:11:33 |
|
|
/* |
/* |
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. |
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. |
|
* Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved. |
* |
* |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
|
|
|
|
|
|
#include <stdio.h> |
#include <stdio.h> |
|
#include <limits.h> |
#ifndef _WIN32_WCE |
#ifndef _WIN32_WCE |
#include <signal.h> |
#include <signal.h> |
#endif |
#endif |
|
|
#define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */ |
#define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */ |
#include "private/gc_pmark.h" |
#include "private/gc_pmark.h" |
|
|
#ifdef SOLARIS_THREADS |
#ifdef GC_SOLARIS_THREADS |
# include <sys/syscall.h> |
# include <sys/syscall.h> |
#endif |
#endif |
#if defined(MSWIN32) || defined(MSWINCE) |
#if defined(MSWIN32) || defined(MSWINCE) |
|
|
/* Critical section counter is defined in the M3 runtime */ |
/* Critical section counter is defined in the M3 runtime */ |
/* That's all we use. */ |
/* That's all we use. */ |
# else |
# else |
# ifdef SOLARIS_THREADS |
# ifdef GC_SOLARIS_THREADS |
mutex_t GC_allocate_ml; /* Implicitly initialized. */ |
mutex_t GC_allocate_ml; /* Implicitly initialized. */ |
# else |
# else |
# ifdef WIN32_THREADS |
# if defined(GC_WIN32_THREADS) |
# if defined(_DLL) || defined(GC_DLL) |
# if defined(GC_PTHREADS) |
|
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER; |
|
# elif defined(GC_DLL) |
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml; |
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml; |
# else |
# else |
CRITICAL_SECTION GC_allocate_ml; |
CRITICAL_SECTION GC_allocate_ml; |
# endif |
# endif |
# else |
# else |
# if defined(IRIX_THREADS) \ |
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) |
|| (defined(LINUX_THREADS) && defined(USE_SPIN_LOCK)) |
# if defined(USE_SPIN_LOCK) |
pthread_t GC_lock_holder = NO_THREAD; |
pthread_t GC_lock_holder = NO_THREAD; |
# else |
# else |
# if defined(HPUX_THREADS) \ |
|
|| defined(LINUX_THREADS) && !defined(USE_SPIN_LOCK) |
|
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER; |
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER; |
pthread_t GC_lock_holder = NO_THREAD; |
pthread_t GC_lock_holder = NO_THREAD; |
/* Used only for assertions, and to prevent */ |
/* Used only for assertions, and to prevent */ |
/* recursive reentry in the system call wrapper. */ |
/* recursive reentry in the system call wrapper. */ |
# else |
# endif |
|
# else |
--> declare allocator lock here |
--> declare allocator lock here |
# endif |
|
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
|
|
# endif |
# endif |
# endif |
# endif |
|
|
|
#if defined(NOSYS) || defined(ECOS) |
|
#undef STACKBASE |
|
#endif |
|
|
|
/* Dont unnecessarily call GC_register_main_static_data() in case */ |
|
/* dyn_load.c isn't linked in. */ |
|
#ifdef DYNAMIC_LOADING |
|
# define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data() |
|
#else |
|
# define GC_REGISTER_MAIN_STATIC_DATA() TRUE |
|
#endif |
|
|
GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */; |
GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */; |
|
|
|
|
Line 78 GC_bool GC_debugging_started = FALSE; |
|
Line 92 GC_bool GC_debugging_started = FALSE; |
|
/* defined here so we don't have to load debug_malloc.o */ |
/* defined here so we don't have to load debug_malloc.o */ |
|
|
void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0; |
void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0; |
|
void (*GC_print_all_smashed) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0; |
|
|
void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0; |
void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0; |
|
|
Line 95 GC_bool GC_quiet = 0; |
|
Line 110 GC_bool GC_quiet = 0; |
|
|
|
GC_bool GC_print_stats = 0; |
GC_bool GC_print_stats = 0; |
|
|
|
GC_bool GC_print_back_height = 0; |
|
|
|
#ifndef NO_DEBUGGING |
|
GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */ |
|
#endif |
|
|
#ifdef FIND_LEAK |
#ifdef FIND_LEAK |
int GC_find_leak = 1; |
int GC_find_leak = 1; |
#else |
#else |
Line 107 GC_bool GC_print_stats = 0; |
|
Line 128 GC_bool GC_print_stats = 0; |
|
int GC_all_interior_pointers = 0; |
int GC_all_interior_pointers = 0; |
#endif |
#endif |
|
|
|
long GC_large_alloc_warn_interval = 5; |
|
/* Interval between unsuppressed warnings. */ |
|
|
|
long GC_large_alloc_warn_suppressed = 0; |
|
/* Number of warnings suppressed so far. */ |
|
|
/*ARGSUSED*/ |
/*ARGSUSED*/ |
GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested)) |
GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested)) |
{ |
{ |
Line 117 GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) |
|
Line 144 GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) |
|
|
|
extern signed_word GC_mem_found; |
extern signed_word GC_mem_found; |
|
|
|
void * GC_project2(arg1, arg2) |
|
void *arg1; |
|
void *arg2; |
|
{ |
|
return arg2; |
|
} |
|
|
# ifdef MERGE_SIZES |
# ifdef MERGE_SIZES |
/* Set things up so that GC_size_map[i] >= words(i), */ |
/* Set things up so that GC_size_map[i] >= words(i), */ |
/* but not too much bigger */ |
/* but not too much bigger */ |
|
|
if (++random_no % 13 == 0) { |
if (++random_no % 13 == 0) { |
limit = sp; |
limit = sp; |
MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word)); |
MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word)); |
|
limit &= ~0xf; /* Make it sufficiently aligned for assembly */ |
|
/* implementations of GC_clear_stack_inner. */ |
return GC_clear_stack_inner(arg, limit); |
return GC_clear_stack_inner(arg, limit); |
} else { |
} else { |
BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word)); |
BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word)); |
|
|
DCL_LOCK_STATE; |
DCL_LOCK_STATE; |
|
|
DISABLE_SIGNALS(); |
DISABLE_SIGNALS(); |
|
|
|
#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) |
|
if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml); |
|
#endif /* MSWIN32 */ |
|
|
LOCK(); |
LOCK(); |
GC_init_inner(); |
GC_init_inner(); |
UNLOCK(); |
UNLOCK(); |
ENABLE_SIGNALS(); |
ENABLE_SIGNALS(); |
|
|
|
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) |
|
/* Make sure marker threads and started and thread local */ |
|
/* allocation is initialized, in case we didn't get */ |
|
/* called from GC_init_parallel(); */ |
|
{ |
|
extern void GC_init_parallel(void); |
|
GC_init_parallel(); |
|
} |
|
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */ |
|
|
|
# if defined(DYNAMIC_LOADING) && defined(DARWIN) |
|
{ |
|
/* This must be called WITHOUT the allocation lock held |
|
and before any threads are created */ |
|
extern void GC_init_dyld(); |
|
GC_init_dyld(); |
|
} |
|
# endif |
} |
} |
|
|
#if defined(MSWIN32) || defined(MSWINCE) |
#if defined(MSWIN32) || defined(MSWINCE) |
|
|
|
|
extern void GC_setpagesize(); |
extern void GC_setpagesize(); |
|
|
|
|
|
#ifdef MSWIN32 |
|
extern GC_bool GC_no_win32_dlls; |
|
#else |
|
# define GC_no_win32_dlls FALSE |
|
#endif |
|
|
|
void GC_exit_check GC_PROTO((void)) |
|
{ |
|
GC_gcollect(); |
|
} |
|
|
|
#ifdef SEARCH_FOR_DATA_START |
|
extern void GC_init_linux_data_start GC_PROTO((void)); |
|
#endif |
|
|
#ifdef UNIX_LIKE |
#ifdef UNIX_LIKE |
|
|
extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int))); |
extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int))); |
|
|
GC_err_printf1("Caught signal %d: looping in handler\n", sig); |
GC_err_printf1("Caught signal %d: looping in handler\n", sig); |
for(;;); |
for(;;); |
} |
} |
|
|
|
static GC_bool installed_looping_handler = FALSE; |
|
|
|
void maybe_install_looping_handler() |
|
{ |
|
/* Install looping handler before the write fault handler, so we */ |
|
/* handle write faults correctly. */ |
|
if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) { |
|
GC_set_and_save_fault_handler(looping_handler); |
|
installed_looping_handler = TRUE; |
|
} |
|
} |
|
|
|
#else /* !UNIX_LIKE */ |
|
|
|
# define maybe_install_looping_handler() |
|
|
#endif |
#endif |
|
|
void GC_init_inner() |
void GC_init_inner() |
Line 472 void GC_init_inner() |
|
Line 564 void GC_init_inner() |
|
# ifdef PRINTSTATS |
# ifdef PRINTSTATS |
GC_print_stats = 1; |
GC_print_stats = 1; |
# endif |
# endif |
|
# if defined(MSWIN32) || defined(MSWINCE) |
|
InitializeCriticalSection(&GC_write_cs); |
|
# endif |
if (0 != GETENV("GC_PRINT_STATS")) { |
if (0 != GETENV("GC_PRINT_STATS")) { |
GC_print_stats = 1; |
GC_print_stats = 1; |
} |
} |
|
# ifndef NO_DEBUGGING |
|
if (0 != GETENV("GC_DUMP_REGULARLY")) { |
|
GC_dump_regularly = 1; |
|
} |
|
# endif |
if (0 != GETENV("GC_FIND_LEAK")) { |
if (0 != GETENV("GC_FIND_LEAK")) { |
GC_find_leak = 1; |
GC_find_leak = 1; |
|
# ifdef __STDC__ |
|
atexit(GC_exit_check); |
|
# endif |
} |
} |
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) { |
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) { |
GC_all_interior_pointers = 1; |
GC_all_interior_pointers = 1; |
Line 484 void GC_init_inner() |
|
Line 587 void GC_init_inner() |
|
if (0 != GETENV("GC_DONT_GC")) { |
if (0 != GETENV("GC_DONT_GC")) { |
GC_dont_gc = 1; |
GC_dont_gc = 1; |
} |
} |
# ifdef UNIX_LIKE |
if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) { |
if (0 != GETENV("GC_LOOP_ON_ABORT")) { |
GC_print_back_height = 1; |
GC_set_and_save_fault_handler(looping_handler); |
} |
|
if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) { |
|
GC_large_alloc_warn_interval = LONG_MAX; |
|
} |
|
{ |
|
char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET"); |
|
if (0 != time_limit_string) { |
|
long time_limit = atol(time_limit_string); |
|
if (time_limit < 5) { |
|
WARN("GC_PAUSE_TIME_TARGET environment variable value too small " |
|
"or bad syntax: Ignoring\n", 0); |
|
} else { |
|
GC_time_limit = time_limit; |
|
} |
} |
} |
# endif |
} |
|
{ |
|
char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL"); |
|
if (0 != interval_string) { |
|
long interval = atol(interval_string); |
|
if (interval <= 0) { |
|
WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has " |
|
"bad value: Ignoring\n", 0); |
|
} else { |
|
GC_large_alloc_warn_interval = interval; |
|
} |
|
} |
|
} |
|
maybe_install_looping_handler(); |
/* Adjust normal object descriptor for extra allocation. */ |
/* Adjust normal object descriptor for extra allocation. */ |
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) { |
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) { |
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH); |
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH); |
} |
} |
# if defined(MSWIN32) || defined(MSWINCE) |
|
InitializeCriticalSection(&GC_write_cs); |
|
# endif |
|
GC_setpagesize(); |
GC_setpagesize(); |
GC_exclude_static_roots(beginGC_arrays, endGC_arrays); |
GC_exclude_static_roots(beginGC_arrays, endGC_arrays); |
GC_exclude_static_roots(beginGC_obj_kinds, endGC_obj_kinds); |
GC_exclude_static_roots(beginGC_obj_kinds, endGC_obj_kinds); |
Line 509 void GC_init_inner() |
|
Line 635 void GC_init_inner() |
|
# if defined(SEARCH_FOR_DATA_START) |
# if defined(SEARCH_FOR_DATA_START) |
GC_init_linux_data_start(); |
GC_init_linux_data_start(); |
# endif |
# endif |
# if defined(NETBSD) && defined(__ELF__) |
# if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) |
GC_init_netbsd_elf(); |
GC_init_netbsd_elf(); |
# endif |
# endif |
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) |
|| defined(HPUX_THREADS) || defined(SOLARIS_THREADS) |
|
GC_thr_init(); |
GC_thr_init(); |
# endif |
# endif |
# ifdef SOLARIS_THREADS |
# ifdef GC_SOLARIS_THREADS |
/* We need dirty bits in order to find live stack sections. */ |
/* We need dirty bits in order to find live stack sections. */ |
GC_dirty_init(); |
GC_dirty_init(); |
# endif |
# endif |
# if !defined(THREADS) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ |
# if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \ |
|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|| defined(GC_SOLARIS_THREADS) |
|| defined(HPUX_THREADS) |
|
if (GC_stackbottom == 0) { |
if (GC_stackbottom == 0) { |
GC_stackbottom = GC_get_stack_base(); |
GC_stackbottom = GC_get_stack_base(); |
# if defined(LINUX) && defined(IA64) |
# if defined(LINUX) && defined(IA64) |
GC_register_stackbottom = GC_get_register_stack_base(); |
GC_register_stackbottom = GC_get_register_stack_base(); |
# endif |
# endif |
|
} else { |
|
# if defined(LINUX) && defined(IA64) |
|
if (GC_register_stackbottom == 0) { |
|
WARN("GC_register_stackbottom should be set with GC_stackbottom", 0); |
|
/* The following is likely to fail, since we rely on */ |
|
/* alignment properties that may not hold with a user set */ |
|
/* GC_stackbottom. */ |
|
GC_register_stackbottom = GC_get_register_stack_base(); |
|
} |
|
# endif |
} |
} |
# endif |
# endif |
GC_ASSERT(sizeof (ptr_t) == sizeof(word)); |
GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word)); |
GC_ASSERT(sizeof (signed_word) == sizeof(word)); |
GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word)); |
GC_ASSERT(sizeof (struct hblk) == HBLKSIZE); |
GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE); |
# ifndef THREADS |
# ifndef THREADS |
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) |
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) |
ABORT( |
ABORT( |
Line 556 void GC_init_inner() |
|
Line 690 void GC_init_inner() |
|
|
|
/* Add initial guess of root sets. Do this first, since sbrk(0) */ |
/* Add initial guess of root sets. Do this first, since sbrk(0) */ |
/* might be used. */ |
/* might be used. */ |
GC_register_data_segments(); |
if (GC_REGISTER_MAIN_STATIC_DATA()) GC_register_data_segments(); |
GC_init_headers(); |
GC_init_headers(); |
GC_bl_init(); |
GC_bl_init(); |
GC_mark_init(); |
GC_mark_init(); |
Line 571 void GC_init_inner() |
|
Line 705 void GC_init_inner() |
|
initial_heap_sz = divHBLKSZ(initial_heap_sz); |
initial_heap_sz = divHBLKSZ(initial_heap_sz); |
} |
} |
} |
} |
|
{ |
|
char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE"); |
|
if (sz_str != NULL) { |
|
word max_heap_sz = (word)atol(sz_str); |
|
if (max_heap_sz < initial_heap_sz * HBLKSIZE) { |
|
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); |
|
} |
|
} |
if (!GC_expand_hp_inner(initial_heap_sz)) { |
if (!GC_expand_hp_inner(initial_heap_sz)) { |
GC_err_printf0("Can't start up: not enough memory\n"); |
GC_err_printf0("Can't start up: not enough memory\n"); |
EXIT(); |
EXIT(); |
Line 595 void GC_init_inner() |
|
Line 741 void GC_init_inner() |
|
PCR_IL_Unlock(); |
PCR_IL_Unlock(); |
GC_pcr_install(); |
GC_pcr_install(); |
# endif |
# endif |
/* Get black list set up */ |
# if !defined(SMALL_CONFIG) |
if (!GC_dont_precollect) GC_gcollect_inner(); |
if (!GC_no_win32_dlls && 0 != GETENV("GC_ENABLE_INCREMENTAL")) { |
|
GC_ASSERT(!GC_incremental); |
|
GC_setpagesize(); |
|
# ifndef GC_SOLARIS_THREADS |
|
GC_dirty_init(); |
|
# endif |
|
GC_ASSERT(GC_words_allocd == 0) |
|
GC_incremental = TRUE; |
|
} |
|
# endif /* !SMALL_CONFIG */ |
|
COND_DUMP; |
|
/* Get black list set up and/or incrmental GC started */ |
|
if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner(); |
GC_is_initialized = TRUE; |
GC_is_initialized = TRUE; |
# ifdef STUBBORN_ALLOC |
# ifdef STUBBORN_ALLOC |
GC_stubborn_init(); |
GC_stubborn_init(); |
Line 629 void GC_enable_incremental GC_PROTO(()) |
|
Line 787 void GC_enable_incremental GC_PROTO(()) |
|
LOCK(); |
LOCK(); |
if (GC_incremental) goto out; |
if (GC_incremental) goto out; |
GC_setpagesize(); |
GC_setpagesize(); |
# ifdef MSWIN32 |
if (GC_no_win32_dlls) goto out; |
{ |
# ifndef GC_SOLARIS_THREADS |
extern GC_bool GC_is_win32s(); |
maybe_install_looping_handler(); /* Before write fault handler! */ |
|
GC_dirty_init(); |
/* VirtualProtect is not functional under win32s. */ |
|
if (GC_is_win32s()) goto out; |
|
} |
|
# endif /* MSWIN32 */ |
|
# ifndef SOLARIS_THREADS |
|
GC_dirty_init(); |
|
# endif |
# endif |
if (!GC_is_initialized) { |
if (!GC_is_initialized) { |
GC_init_inner(); |
GC_init_inner(); |
} |
} |
|
if (GC_incremental) goto out; |
if (GC_dont_gc) { |
if (GC_dont_gc) { |
/* Can't easily do it. */ |
/* Can't easily do it. */ |
UNLOCK(); |
UNLOCK(); |
|
|
} |
} |
|
|
int GC_write(buf, len) |
int GC_write(buf, len) |
char * buf; |
GC_CONST char * buf; |
size_t len; |
size_t len; |
{ |
{ |
BOOL tmp; |
BOOL tmp; |
Line 728 int GC_tmp; /* Should really be local ... */ |
|
Line 881 int GC_tmp; /* Should really be local ... */ |
|
# endif |
# endif |
#endif |
#endif |
|
|
#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) && !defined(MACOS) |
#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) \ |
|
&& !defined(MACOS) && !defined(ECOS) && !defined(NOSYS) |
int GC_write(fd, buf, len) |
int GC_write(fd, buf, len) |
int fd; |
int fd; |
char *buf; |
GC_CONST char *buf; |
size_t len; |
size_t len; |
{ |
{ |
register int bytes_written = 0; |
register int bytes_written = 0; |
register int result; |
register int result; |
|
|
while (bytes_written < len) { |
while (bytes_written < len) { |
# ifdef SOLARIS_THREADS |
# ifdef GC_SOLARIS_THREADS |
result = syscall(SYS_write, fd, buf + bytes_written, |
result = syscall(SYS_write, fd, buf + bytes_written, |
len - bytes_written); |
len - bytes_written); |
# else |
# else |
|
|
} |
} |
#endif /* UN*X */ |
#endif /* UN*X */ |
|
|
|
#ifdef ECOS |
|
int GC_write(fd, buf, len) |
|
{ |
|
_Jv_diag_write (buf, len); |
|
return len; |
|
} |
|
#endif |
|
|
|
#ifdef NOSYS |
|
int GC_write(fd, buf, len) |
|
{ |
|
/* No writing. */ |
|
return len; |
|
} |
|
#endif |
|
|
|
|
#if defined(MSWIN32) || defined(MSWINCE) |
#if defined(MSWIN32) || defined(MSWINCE) |
# define WRITE(f, buf, len) GC_write(buf, len) |
# define WRITE(f, buf, len) GC_write(buf, len) |
#else |
#else |
Line 838 GC_warn_proc GC_current_warn_proc = GC_default_warn_pr |
|
Line 1009 GC_warn_proc GC_current_warn_proc = GC_default_warn_pr |
|
return(result); |
return(result); |
} |
} |
|
|
|
# if defined(__STDC__) || defined(__cplusplus) |
|
GC_word GC_set_free_space_divisor (GC_word value) |
|
# else |
|
GC_word GC_set_free_space_divisor (value) |
|
GC_word value; |
|
# endif |
|
{ |
|
GC_word old = GC_free_space_divisor; |
|
GC_free_space_divisor = value; |
|
return old; |
|
} |
|
|
#ifndef PCR |
#ifndef PCR |
void GC_abort(msg) |
void GC_abort(msg) |
Line 854 GC_CONST char * msg; |
|
Line 1036 GC_CONST char * msg; |
|
/* It's arguably nicer to sleep, but that makes it harder */ |
/* It's arguably nicer to sleep, but that makes it harder */ |
/* to look at the thread if the debugger doesn't know much */ |
/* to look at the thread if the debugger doesn't know much */ |
/* about threads. */ |
/* about threads. */ |
for(;;); |
for(;;) {} |
} |
} |
# ifdef MSWIN32 |
# ifdef MSWIN32 |
DebugBreak(); |
DebugBreak(); |
Line 864 GC_CONST char * msg; |
|
Line 1046 GC_CONST char * msg; |
|
} |
} |
#endif |
#endif |
|
|
#ifdef NEED_CALLINFO |
|
|
|
void GC_print_callers (info) |
|
struct callinfo info[NFRAMES]; |
|
{ |
|
register int i; |
|
|
|
# if NFRAMES == 1 |
|
GC_err_printf0("\tCaller at allocation:\n"); |
|
# else |
|
GC_err_printf0("\tCall chain at allocation:\n"); |
|
# endif |
|
for (i = 0; i < NFRAMES; i++) { |
|
if (info[i].ci_pc == 0) break; |
|
# if NARGS > 0 |
|
{ |
|
int j; |
|
|
|
GC_err_printf0("\t\targs: "); |
|
for (j = 0; j < NARGS; j++) { |
|
if (j != 0) GC_err_printf0(", "); |
|
GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]), |
|
~(info[i].ci_arg[j])); |
|
} |
|
GC_err_printf0("\n"); |
|
} |
|
# endif |
|
GC_err_printf1("\t\t##PC##= 0x%X\n", info[i].ci_pc); |
|
} |
|
} |
|
|
|
#endif /* SAVE_CALL_CHAIN */ |
|
|
|
/* Needed by SRC_M3, gcj, and should perhaps be the official interface */ |
|
/* to GC_dont_gc. */ |
|
void GC_enable() |
void GC_enable() |
{ |
{ |
|
LOCK(); |
GC_dont_gc--; |
GC_dont_gc--; |
|
UNLOCK(); |
} |
} |
|
|
void GC_disable() |
void GC_disable() |
{ |
{ |
|
LOCK(); |
GC_dont_gc++; |
GC_dont_gc++; |
|
UNLOCK(); |
} |
} |
|
|
#if !defined(NO_DEBUGGING) |
#if !defined(NO_DEBUGGING) |
|
|
GC_print_hblkfreelist(); |
GC_print_hblkfreelist(); |
GC_printf0("\n***Blocks in use:\n"); |
GC_printf0("\n***Blocks in use:\n"); |
GC_print_block_list(); |
GC_print_block_list(); |
|
GC_printf0("\n***Finalization statistics:\n"); |
|
GC_print_finalization_stats(); |
} |
} |
|
|
#endif /* NO_DEBUGGING */ |
#endif /* NO_DEBUGGING */ |