# undef GC_BUILD
-#ifdef DBG_HDRS_ALL
+#if defined(DBG_HDRS_ALL) || defined(MAKE_BACK_GRAPH)
# define GC_DEBUG
#endif
# include "gc_local_alloc.h"
# endif
# include "private/gc_priv.h" /* For output, locking, MIN_WORDS, */
- /* and some statistics. */
+ /* and some statistics. */
# include "private/gcconfig.h"
# if defined(MSWIN32) || defined(MSWINCE)
# define GC_printf1 printf
# endif
-# ifdef SOLARIS_THREADS
+# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
# include <thread.h>
# include <synch.h>
# endif
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)
+# if defined(GC_PTHREADS)
# include <pthread.h>
# endif
-# ifdef WIN32_THREADS
-# ifndef MSWINCE
-# include <process.h>
-# define GC_CreateThread(a,b,c,d,e,f) ((HANDLE) _beginthreadex(a,b,c,d,e,f))
-# endif
+# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
static CRITICAL_SECTION incr_cs;
# endif
+#ifdef __STDC__
+# include <stdarg.h>
+#endif
+
/* Allocation Statistics */
int stubborn_count = 0;
}
# endif
-sexpr small_cons (x, y)
-sexpr x;
-sexpr y;
-{
- register sexpr r;
-
- collectable_count++;
- r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
- r -> sexpr_car = x;
- r -> sexpr_cdr = y;
- return(r);
-}
-
-sexpr small_cons_uncollectable (x, y)
-sexpr x;
-sexpr y;
-{
- register sexpr r;
-
- uncollectable_count++;
- r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
- r -> sexpr_car = x;
- r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
- return(r);
-}
-
#ifdef GC_GCJ_SUPPORT
#include "gc_mark.h"
-#include "private/dbg_mlc.h" /* For USR_PTR_FROM_BASE */
#include "gc_gcj.h"
/* The following struct emulates the vtable in gcj. */
sexpr x;
if (1 == env) {
/* Object allocated with debug allocator. */
- addr = (word *)USR_PTR_FROM_BASE(addr);
+ addr = (word *)GC_USR_PTR_FROM_BASE(addr);
}
x = (sexpr)(addr + 1); /* Skip the vtable pointer. */
mark_stack_ptr = GC_MARK_AND_PUSH(
return(mark_stack_ptr);
}
+#endif /* GC_GCJ_SUPPORT */
+
+#ifdef THREAD_LOCAL_ALLOC
+
+#undef GC_REDIRECT_TO_LOCAL
+#include "gc_local_alloc.h"
+
+sexpr local_cons (x, y)
+sexpr x;
+sexpr y;
+{
+ register sexpr r;
+ register int *p;
+ register int my_extra = extra_count;
+ static int my_random = 0;
+
+ collectable_count++;
+ r = (sexpr) GC_LOCAL_MALLOC(sizeof(struct SEXPR) + my_extra);
+# ifdef GC_GCJ_SUPPORT
+ if (collectable_count % 2 == 0) {
+ r = (sexpr) GC_LOCAL_GCJ_MALLOC(sizeof(struct SEXPR) + sizeof(GC_word) + my_extra,
+ &gcj_class_struct1);
+ r = (sexpr) ((GC_word *)r + 1);
+ }
+# endif
+ if (r == 0) {
+ (void)GC_printf0("Out of memory\n");
+ exit(1);
+ }
+ for (p = (int *)r;
+ ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
+ if (*p) {
+ (void)GC_printf1("Found nonzero at 0x%lx (local) - allocator is broken\n",
+ (unsigned long)p);
+ FAIL;
+ }
+ *p = 13;
+ }
+ r -> sexpr_car = x;
+ r -> sexpr_cdr = y;
+ my_extra++;
+ if ( my_extra >= 5000 || my_extra == 200 && ++my_random % 37 != 0) {
+ extra_count = 0;
+ } else {
+ extra_count = my_extra;
+ }
+ return(r);
+}
+#endif /* THREAD_LOCAL_ALLOC */
+
+sexpr small_cons (x, y)
+sexpr x;
+sexpr y;
+{
+ register sexpr r;
+
+ collectable_count++;
+ r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
+ if (r == 0) {
+ (void)GC_printf0("Out of memory\n");
+ exit(1);
+ }
+ r -> sexpr_car = x;
+ r -> sexpr_cdr = y;
+ return(r);
+}
+
+sexpr small_cons_uncollectable (x, y)
+sexpr x;
+sexpr y;
+{
+ register sexpr r;
+
+ uncollectable_count++;
+ r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
+ if (r == 0) {
+ (void)GC_printf0("Out of memory\n");
+ exit(1);
+ }
+ r -> sexpr_car = x;
+ r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
+ return(r);
+}
+
+#ifdef GC_GCJ_SUPPORT
+
+
sexpr gcj_cons(x, y)
sexpr x;
sexpr y;
sexpr reverse(x)
sexpr x;
{
+# ifdef TEST_WITH_SYSTEM_MALLOC
+ malloc(100000);
+# endif
return( reverse1(x, nil) );
}
}
#endif /* GC_GCJ_SUPPORT */
+#ifdef THREAD_LOCAL_ALLOC
+/* Return reverse(x) concatenated with y */
+sexpr local_reverse1(x, y)
+sexpr x, y;
+{
+ if (is_nil(x)) {
+ return(y);
+ } else {
+ return( local_reverse1(cdr(x), local_cons(car(x), y)) );
+ }
+}
+
+sexpr local_reverse(x)
+sexpr x;
+{
+ return( local_reverse1(x, nil) );
+}
+
+sexpr local_ints(low, up)
+int low, up;
+{
+ if (low > up) {
+ return(nil);
+ } else {
+ return(local_cons(local_cons(INT_TO_SEXPR(low), nil), local_ints(low+1, up)));
+ }
+}
+#endif /* THREAD_LOCAL_ALLOC */
+
/* To check uncollectable allocation we build lists with disguised cdr */
/* pointers, and make sure they don't go away. */
sexpr uncollectable_ints(low, up)
}
}
-/* Try to force a to be strangely aligned */
-struct {
- char dummy;
- sexpr aa;
-} A;
-#define a A.aa
-
/*
* A tiny list reversal test to check thread creation.
*/
#ifdef THREADS
-# ifdef WIN32_THREADS
- unsigned __stdcall tiny_reverse_test(void * arg)
+# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
+ DWORD __stdcall tiny_reverse_test(void * arg)
# else
void * tiny_reverse_test(void * arg)
# endif
{
- check_ints(reverse(reverse(ints(1,10))), 1, 10);
+ int i;
+ for (i = 0; i < 5; ++i) {
+ check_ints(reverse(reverse(ints(1,10))), 1, 10);
+# ifdef THREAD_LOCAL_ALLOC
+ check_ints(local_reverse(local_reverse(local_ints(1,10))), 1, 10);
+# endif
+ }
return 0;
}
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
- || defined(SOLARIS_PTHREADS) || defined(HPUX_THREADS)
+# if defined(GC_PTHREADS)
void fork_a_thread()
{
pthread_t t;
}
}
-# elif defined(WIN32_THREADS)
+# elif defined(GC_WIN32_THREADS)
void fork_a_thread()
{
- unsigned thread_id;
+ DWORD thread_id;
HANDLE h;
h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
if (h == (HANDLE)NULL) {
}
}
-/* # elif defined(SOLARIS_THREADS) */
+/* # elif defined(GC_SOLARIS_THREADS) */
# else
#endif
+/* Try to force a to be strangely aligned */
+struct {
+ char dummy;
+ sexpr aa;
+} A;
+#define a A.aa
+
/*
* Repeatedly reverse lists built out of very different sized cons cells.
* Check that we didn't lose anything.
h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
# ifdef GC_GCJ_SUPPORT
h[1999] = gcj_ints(1,200);
- h[1999] = gcj_reverse(h[1999]);
+ for (i = 0; i < 51; ++i)
+ h[1999] = gcj_reverse(h[1999]);
+ /* Leave it as the reveresed list for now. */
# else
h[1999] = ints(1,200);
# endif
/* 49 integers. Thus this is thread safe without locks, */
/* assuming atomic pointer assignments. */
a = reverse(reverse(a));
+# ifdef THREAD_LOCAL_ALLOC
+ a = local_reverse(local_reverse(a));
+# endif
# if !defined(AT_END) && !defined(THREADS)
/* This is not thread safe, since realloc explicitly deallocates */
if (i & 1) {
b = c = 0;
}
+#undef a
+
/*
* The rest of this builds balanced binary trees, checks that they don't
* disappear, and tests finalization.
# ifdef PCR
PCR_ThCrSec_EnterSys();
# endif
-# ifdef SOLARIS_THREADS
+# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
static mutex_t incr_lock;
mutex_lock(&incr_lock);
# endif
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)
+# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
-# endif
-# ifdef WIN32_THREADS
- EnterCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ EnterCriticalSection(&incr_cs);
+# endif
# endif
if ((int)(GC_word)client_data != t -> level) {
(void)GC_printf0("Wrong finalization data - collector is broken\n");
FAIL;
}
finalized_count++;
+ t -> level = -1; /* detect duplicate finalization immediately */
# ifdef PCR
PCR_ThCrSec_ExitSys();
# endif
-# ifdef SOLARIS_THREADS
+# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
mutex_unlock(&incr_lock);
# endif
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)
+# if defined(GC_PTHREADS)
pthread_mutex_unlock(&incr_lock);
-# endif
-# ifdef WIN32_THREADS
- LeaveCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ LeaveCriticalSection(&incr_cs);
+# endif
# endif
}
# ifdef PCR
PCR_ThCrSec_EnterSys();
# endif
-# ifdef SOLARIS_THREADS
+# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
static mutex_t incr_lock;
mutex_lock(&incr_lock);
# endif
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
- || defined(HPUX_THREADS)
+# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
-# endif
-# ifdef WIN32_THREADS
- EnterCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ EnterCriticalSection(&incr_cs);
+# endif
# endif
/* Losing a count here causes erroneous report of failure. */
finalizable_count++;
# ifdef PCR
PCR_ThCrSec_ExitSys();
# endif
-# ifdef SOLARIS_THREADS
+# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
mutex_unlock(&incr_lock);
# endif
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
- || defined(HPUX_THREADS)
+# if defined(GC_PTHREADS)
pthread_mutex_unlock(&incr_lock);
-# endif
-# ifdef WIN32_THREADS
- LeaveCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ LeaveCriticalSection(&incr_cs);
+# endif
# endif
}
chktree(t -> rchild, n-1);
}
-# if defined(SOLARIS_THREADS) && !defined(_SOLARIS_PTHREADS)
+# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
thread_key_t fl_key;
void * alloc8bytes()
#else
-# if defined(GC_SOLARIS_PTHREADS) || defined(GC_IRIX_THREADS) \
- || defined(GC_LINUX_THREADS) || defined(GC_HPUX_THREADS) \
- || defined(GC_SOLARIS_THREADS)
+# if defined(GC_PTHREADS)
pthread_key_t fl_key;
void * alloc8bytes()
fail_count++;
}
+static void uniq(void *p, ...) {
+ va_list a;
+ void *q[100];
+ int n = 0, i, j;
+ q[n++] = p;
+ va_start(a,p);
+ for (;(q[n] = va_arg(a,void *));n++) ;
+ va_end(a);
+ for (i=0; i<n; i++)
+ for (j=0; j<i; j++)
+ if (q[i] == q[j]) {
+ GC_printf0(
+ "Apparently failed to mark form some function arguments.\n"
+ "Perhaps GC_push_regs was configured incorrectly?\n"
+ );
+ FAIL;
+ }
+}
+
#endif /* __STDC__ */
#ifdef THREADS
FAIL;
}
if (!TEST_FAIL_COUNT(1)) {
-# if!(defined(RS6000) || defined(POWERPC) || defined(IA64))
+# if!(defined(RS6000) || defined(POWERPC) || defined(IA64)) || defined(M68K)
/* ON RS6000s function pointers point to a descriptor in the */
/* data segment, so there should have been no failures. */
+ /* The same applies to IA64. Something similar seems to */
+ /* be going on with NetBSD/M68K. */
(void)GC_printf0("GC_is_visible produced wrong failure indication\n");
FAIL;
# endif
"GC_is_valid_displacement produced incorrect result\n");
FAIL;
}
+# if defined(__STDC__) && !defined(MSWIN32) && !defined(MSWINCE)
+ /* Harder to test under Windows without a gc.h declaration. */
+ {
+ size_t i;
+ extern void *GC_memalign();
+
+ GC_malloc(17);
+ for (i = sizeof(GC_word); i < 512; i *= 2) {
+ GC_word result = (GC_word) GC_memalign(i, 17);
+ if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
+ }
+ }
+# endif
# ifndef ALL_INTERIOR_POINTERS
# if defined(RS6000) || defined(POWERPC)
if (!TEST_FAIL_COUNT(1)) {
GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc);
# endif
+ /* Make sure that fn arguments are visible to the collector. */
+# ifdef __STDC__
+ uniq(
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ (void *)0);
+# endif
/* Repeated list reversal test. */
reverse_test();
# ifdef PRINTSTATS
LOCK();
n_tests++;
UNLOCK();
+# if defined(THREADS) && defined(HANDLE_FORK)
+ if (fork() == 0) {
+ GC_gcollect();
+ tiny_reverse_test(0);
+ GC_gcollect();
+ GC_printf0("Finished a child process\n");
+ exit(0);
+ }
+# endif
/* GC_printf1("Finished %x\n", pthread_self()); */
}
}
# else
if (sizeof(char *) > 4) {
- max_heap_sz = 15000000;
+ max_heap_sz = 19000000;
} else {
max_heap_sz = 11000000;
}
# endif
+# ifndef ALIGN_DOUBLE
+ /* We end up needing more small object pages. */
+ max_heap_sz += 2000000;
+# endif
# ifdef GC_DEBUG
max_heap_sz *= 2;
# ifdef SAVE_CALL_CHAIN
max_heap_sz *= 3;
# ifdef SAVE_CALL_COUNT
- max_heap_sz *= SAVE_CALL_COUNT/4;
+ max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
# endif
# endif
# endif
#if !defined(PCR) && !defined(GC_SOLARIS_THREADS) \
- && !defined(GC_WIN32_THREADS) \
- && !defined(GC_IRIX_THREADS) && !defined(GC_LINUX_THREADS) \
- && !defined(GC_HPUX_THREADS) || defined(LINT)
+ && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
+ || defined(LINT)
#if defined(MSWIN32) && !defined(__MINGW32__)
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPTSTR cmd, int n)
#else
/* Cheat and let stdio initialize toolbox for us. */
printf("Testing GC Macintosh port.\n");
# endif
- GC_INIT(); /* Only needed if gc is dynamic library. */
+ GC_INIT(); /* Only needed on a few platforms. */
(void) GC_set_warn_proc(warn_proc);
-# if defined(MPROTECT_VDB) || defined(PROC_VDB)
+# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
+ && !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
# if defined(MPROTECT_VDB)
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
# else
+# ifdef PROC_VDB
(void)GC_printf0("Reading dirty bits from /proc\n");
+# else
+ (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+# endif
# endif
# endif
run_one_test();
}
# endif
-#ifdef GC_WIN32_THREADS
+#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
-unsigned __stdcall thr_run_one_test(void *arg)
+DWORD __stdcall thr_run_one_test(void *arg)
{
run_one_test();
return 0;
return ret;
}
-unsigned __stdcall thr_window(void *arg)
+DWORD __stdcall thr_window(void *arg)
{
WNDCLASS win_class = {
CS_NOCLOSE,
# ifdef MSWINCE
HANDLE win_thr_h;
# endif
- unsigned thread_id;
+ DWORD thread_id;
# if 0
GC_enable_incremental();
# endif
+ GC_init();
InitializeCriticalSection(&incr_cs);
(void) GC_set_warn_proc(warn_proc);
# ifdef MSWINCE
}
#endif
-#if defined(GC_SOLARIS_THREADS) || defined(GC_IRIX_THREADS) \
- || defined(GC_HPUX_THREADS) || defined(GC_LINUX_THREADS)
+#if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS)
void * thr_run_one_test(void * arg)
{
run_one_test();
# define GC_free GC_debug_free
#endif
-#ifdef GC_SOLARIS_THREADS
+#if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
main()
{
thread_t th1;
n_tests = 0;
GC_INIT(); /* Only needed if gc is dynamic library. */
- GC_enable_incremental();
+# ifndef MAKE_BACK_GRAPH
+ GC_enable_incremental();
+# endif
(void) GC_set_warn_proc(warn_proc);
if (thr_keycreate(&fl_key, GC_free) != 0) {
(void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
return(0);
}
#else /* pthreads */
+
+#ifndef GC_PTHREADS
+ --> bad news
+#endif
+
main()
{
pthread_t th1;
/* Since the initial cant always grow later. */
*((volatile char *)&code - 1024*1024) = 0; /* Require 1 Mb */
# endif /* GC_IRIX_THREADS */
+# if defined(GC_HPUX_THREADS)
+ /* 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_printf0("pthread_default_stacksize_np failed.\n");
+ }
+# endif /* GC_HPUX_THREADS */
+ GC_INIT();
+
pthread_attr_init(&attr);
-# if defined(GC_IRIX_THREADS) || defined(GC_HPUX_THREADS)
+# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
pthread_attr_setstacksize(&attr, 1000000);
# endif
n_tests = 0;
-# if defined(MPROTECT_VDB) && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC)
+# if (defined(MPROTECT_VDB)) \
+ && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) \
+ && !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
- (void) GC_printf0("Emulating dirty bits with mprotect/signals\n");
+# if defined(MPROTECT_VDB)
+ (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
+# else
+# ifdef PROC_VDB
+ (void)GC_printf0("Reading dirty bits from /proc\n");
+# else
+ (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+# endif
+# endif
# endif
(void) GC_set_warn_proc(warn_proc);
if ((code = pthread_key_create(&fl_key, 0)) != 0) {
GC_printf1("Completed %d collections\n", GC_gc_no);
return(0);
}
-#endif /* pthreads */
-#endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS || HPUX_THREADS */
+#endif /* GC_PTHREADS */
+#endif /* GC_SOLARIS_THREADS || GC_PTHREADS */