summaryrefslogtreecommitdiff
path: root/extra
diff options
context:
space:
mode:
authorivmai <ivmai>2009-09-19 11:43:14 +0000
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 21:06:47 +0400
commitc16052b287c5573a677aaa295ac145f7df001862 (patch)
tree7b0d65d633c04acaae811b93a178f30e8f908794 /extra
parentfa40c00794cf621101182ffe60e56449fb580e8a (diff)
downloadbdwgc-c16052b287c5573a677aaa295ac145f7df001862.tar.gz
2009-09-19 Ivan Maidanski <ivmai@mail.ru>
(ivmai147.diff) * add_gc_prefix.c: Move the file to the new "extra" directory. * AmigaOS.c: Ditto. * gcname.c: Ditto. * if_mach.c: Ditto. * if_not_there.c: Ditto. * MacOS.c: Ditto. * msvc_dbg.c: Ditto. * setjmp_t.c: Ditto. * threadlibs.c: Ditto. * EMX_MAKEFILE: Prepend setjmp_t.c with "extra" directory. * Makefile: Prepend AmigaOS.c, MacOS.c, add_gc_prefix.c, gcname.c, if_mach.c, if_not_there.c, msvc_dbg.c, setjmp_t.c, threadlibs.c with "extra" directory. * Makefile.am: Ditto. * Makefile.direct: Ditto. * Makefile.dj: Ditto. * Makefile.in: Ditto. * NT_MAKEFILE: Prepend msvc_dbg.obj with "extra" directory. * NT_STATIC_THREADS_MAKEFILE: Ditto. * NT_X64_STATIC_THREADS_MAKEFILE: Ditto. * NT_X64_THREADS_MAKEFILE: Ditto. * NT_THREADS_MAKEFILE: Prepend msvc_dbg.c with "extra" directory. * gc.mak: Ditto. * PCR-Makefile: Prepend if_mach.c, if_not_there.c with "extra" directory. * SMakefile.amiga: Prepend AmigaOS.c, setjmp_t.c with "extra" directory. * doc/simple_example.html: Update for threadlibs.c. * os_dep.c: Prepend included AmigaOS.c with "extra" directory.
Diffstat (limited to 'extra')
-rw-r--r--extra/AmigaOS.c623
-rw-r--r--extra/MacOS.c156
-rw-r--r--extra/add_gc_prefix.c20
-rw-r--r--extra/gcname.c13
-rw-r--r--extra/if_mach.c25
-rw-r--r--extra/if_not_there.c38
-rw-r--r--extra/msvc_dbg.c353
-rw-r--r--extra/setjmp_t.c135
-rw-r--r--extra/threadlibs.c63
9 files changed, 1426 insertions, 0 deletions
diff --git a/extra/AmigaOS.c b/extra/AmigaOS.c
new file mode 100644
index 00000000..d1715039
--- /dev/null
+++ b/extra/AmigaOS.c
@@ -0,0 +1,623 @@
+
+
+/******************************************************************
+
+ AmigaOS-spesific routines for GC.
+ This file is normally included from os_dep.c
+
+******************************************************************/
+
+
+#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
+# include "gc_priv.h"
+# include <stdio.h>
+# include <signal.h>
+# define GC_AMIGA_DEF
+# define GC_AMIGA_SB
+# define GC_AMIGA_DS
+# define GC_AMIGA_AM
+#endif
+
+
+#ifdef GC_AMIGA_DEF
+
+# ifndef __GNUC__
+# include <exec/exec.h>
+# endif
+# include <proto/exec.h>
+# include <proto/dos.h>
+# include <dos/dosextens.h>
+# include <workbench/startup.h>
+
+#endif
+
+
+
+
+#ifdef GC_AMIGA_SB
+
+/******************************************************************
+ Find the base of the stack.
+******************************************************************/
+
+ptr_t GC_get_main_stack_base()
+{
+ struct Process *proc = (struct Process*)SysBase->ThisTask;
+
+ /* Reference: Amiga Guru Book Pages: 42,567,574 */
+ if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
+ && proc->pr_CLI != NULL) {
+ /* first ULONG is StackSize */
+ /*longPtr = proc->pr_ReturnAddr;
+ size = longPtr[0];*/
+
+ return (char *)proc->pr_ReturnAddr + sizeof(ULONG);
+ } else {
+ return (char *)proc->pr_Task.tc_SPUpper;
+ }
+}
+
+#if 0 /* old version */
+ptr_t GC_get_stack_base()
+{
+ extern struct WBStartup *_WBenchMsg;
+ extern long __base;
+ extern long __stack;
+ struct Task *task;
+ struct Process *proc;
+ struct CommandLineInterface *cli;
+ long size;
+
+ if ((task = FindTask(0)) == 0) {
+ GC_err_puts("Cannot find own task structure\n");
+ ABORT("task missing");
+ }
+ proc = (struct Process *)task;
+ cli = BADDR(proc->pr_CLI);
+
+ if (_WBenchMsg != 0 || cli == 0) {
+ size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower;
+ } else {
+ size = cli->cli_DefaultStack * 4;
+ }
+ return (ptr_t)(__base + GC_max(size, __stack));
+}
+#endif
+
+
+#endif
+
+
+#ifdef GC_AMIGA_DS
+/******************************************************************
+ Register data segments.
+******************************************************************/
+
+ void GC_register_data_segments()
+ {
+ struct Process *proc;
+ struct CommandLineInterface *cli;
+ BPTR myseglist;
+ ULONG *data;
+
+ int num;
+
+
+# ifdef __GNUC__
+ ULONG dataSegSize;
+ GC_bool found_segment = FALSE;
+ extern char __data_size[];
+
+ dataSegSize=__data_size+8;
+ /* Can`t find the Location of __data_size, because
+ it`s possible that is it, inside the segment. */
+
+# endif
+
+ proc= (struct Process*)SysBase->ThisTask;
+
+ /* Reference: Amiga Guru Book Pages: 538ff,565,573
+ and XOper.asm */
+ if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
+ if (proc->pr_CLI == NULL) {
+ myseglist = proc->pr_SegList;
+ } else {
+ /* ProcLoaded 'Loaded as a command: '*/
+ cli = BADDR(proc->pr_CLI);
+ myseglist = cli->cli_Module;
+ }
+ } else {
+ ABORT("Not a Process.");
+ }
+
+ if (myseglist == NULL) {
+ ABORT("Arrrgh.. can't find segments, aborting");
+ }
+
+ /* xoper hunks Shell Process */
+
+ num=0;
+ for (data = (ULONG *)BADDR(myseglist); data != NULL;
+ data = (ULONG *)BADDR(data[0])) {
+ if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
+ ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
+# ifdef __GNUC__
+ if (dataSegSize == data[-1]) {
+ found_segment = TRUE;
+ }
+# endif
+ GC_add_roots_inner((char *)&data[1],
+ ((char *)&data[1]) + data[-1], FALSE);
+ }
+ ++num;
+ } /* for */
+# ifdef __GNUC__
+ if (!found_segment) {
+ ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");
+ }
+# endif
+ }
+
+#if 0 /* old version */
+ void GC_register_data_segments()
+ {
+ extern struct WBStartup *_WBenchMsg;
+ struct Process *proc;
+ struct CommandLineInterface *cli;
+ BPTR myseglist;
+ ULONG *data;
+
+ if ( _WBenchMsg != 0 ) {
+ if ((myseglist = _WBenchMsg->sm_Segment) == 0) {
+ GC_err_puts("No seglist from workbench\n");
+ return;
+ }
+ } else {
+ if ((proc = (struct Process *)FindTask(0)) == 0) {
+ GC_err_puts("Cannot find process structure\n");
+ return;
+ }
+ if ((cli = BADDR(proc->pr_CLI)) == 0) {
+ GC_err_puts("No CLI\n");
+ return;
+ }
+ if ((myseglist = cli->cli_Module) == 0) {
+ GC_err_puts("No seglist from CLI\n");
+ return;
+ }
+ }
+
+ for (data = (ULONG *)BADDR(myseglist); data != 0;
+ data = (ULONG *)BADDR(data[0])) {
+# ifdef AMIGA_SKIP_SEG
+ if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
+ ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
+# else
+ {
+# endif /* AMIGA_SKIP_SEG */
+ GC_add_roots_inner((char *)&data[1],
+ ((char *)&data[1]) + data[-1], FALSE);
+ }
+ }
+ }
+#endif /* old version */
+
+
+#endif
+
+
+
+#ifdef GC_AMIGA_AM
+
+#ifndef GC_AMIGA_FASTALLOC
+
+void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){
+ return (*AllocFunction)(size);
+}
+
+void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
+ =GC_amiga_allocwrapper;
+
+#else
+
+
+
+
+void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2));
+
+void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
+ =GC_amiga_allocwrapper_firsttime;
+
+
+/******************************************************************
+ Amiga-spesific routines to obtain memory, and force GC to give
+ back fast-mem whenever possible.
+ These hacks makes gc-programs go many times faster when
+ the amiga is low on memory, and are therefore strictly necesarry.
+
+ -Kjetil S. Matheussen, 2000.
+******************************************************************/
+
+
+
+/* List-header for all allocated memory. */
+
+struct GC_Amiga_AllocedMemoryHeader{
+ ULONG size;
+ struct GC_Amiga_AllocedMemoryHeader *next;
+};
+struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL);
+
+
+
+/* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */
+
+ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR;
+
+
+/* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */
+#ifndef GC_AMIGA_ONLYFAST
+BOOL GC_amiga_dontalloc=FALSE;
+#endif
+
+#ifdef GC_AMIGA_PRINTSTATS
+int succ=0,succ2=0;
+int nsucc=0,nsucc2=0;
+int nullretries=0;
+int numcollects=0;
+int chipa=0;
+int allochip=0;
+int allocfast=0;
+int cur0=0;
+int cur1=0;
+int cur10=0;
+int cur50=0;
+int cur150=0;
+int cur151=0;
+int ncur0=0;
+int ncur1=0;
+int ncur10=0;
+int ncur50=0;
+int ncur150=0;
+int ncur151=0;
+#endif
+
+/* Free everything at program-end. */
+
+void GC_amiga_free_all_mem(void){
+ struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
+ struct GC_Amiga_AllocedMemoryHeader *temp;
+
+#ifdef GC_AMIGA_PRINTSTATS
+ printf("\n\n"
+ "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n",
+ allochip,allocfast
+ );
+ printf(
+ "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
+ chipa
+ );
+ printf("\n");
+ printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
+ printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
+ printf("\n");
+ printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
+ printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
+ printf("\n");
+ printf(
+ "Number of retries before succeding a chip->fast force:\n"
+ "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
+ cur0,cur1,cur10,cur50,cur150,cur151
+ );
+ printf(
+ "Number of retries before giving up a chip->fast force:\n"
+ "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
+ ncur0,ncur1,ncur10,ncur50,ncur150,ncur151
+ );
+#endif
+
+ while(gc_am!=NULL){
+ temp=gc_am->next;
+ FreeMem(gc_am,gc_am->size);
+ gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
+ }
+}
+
+#ifndef GC_AMIGA_ONLYFAST
+
+/* All memory with address lower than this one is chip-mem. */
+
+char *chipmax;
+
+
+/*
+ * Allways set to the last size of memory tried to be allocated.
+ * Needed to ensure allocation when the size is bigger than 100000.
+ *
+ */
+size_t latestsize;
+
+#endif
+
+
+/*
+ * The actual function that is called with the GET_MEM macro.
+ *
+ */
+
+void *GC_amiga_get_mem(size_t size){
+ struct GC_Amiga_AllocedMemoryHeader *gc_am;
+
+#ifndef GC_AMIGA_ONLYFAST
+ if(GC_amiga_dontalloc==TRUE){
+// printf("rejected, size: %d, latestsize: %d\n",size,latestsize);
+ return NULL;
+ }
+
+ // We really don't want to use chip-mem, but if we must, then as little as possible.
+ if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
+#endif
+
+ gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF);
+ if(gc_am==NULL) return NULL;
+
+ gc_am->next=GC_AMIGAMEM;
+ gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
+ GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
+
+// printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize);
+
+#ifdef GC_AMIGA_PRINTSTATS
+ if((char *)gc_am<chipmax){
+ allochip+=size;
+ }else{
+ allocfast+=size;
+ }
+#endif
+
+ return gc_am+1;
+
+}
+
+
+
+
+#ifndef GC_AMIGA_ONLYFAST
+
+/* Tries very hard to force GC to find fast-mem to return. Done recursively
+ * to hold the rejected memory-pointers reachable from the collector in an
+ * easy way.
+ *
+ */
+#ifdef GC_AMIGA_RETRY
+void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec){
+ void *ret;
+
+ ret=(*AllocFunction)(size);
+
+#ifdef GC_AMIGA_PRINTSTATS
+ if((char *)ret>chipmax || ret==NULL){
+ if(ret==NULL){
+ nsucc++;
+ nsucc2+=size;
+ if(rec==0) ncur0++;
+ if(rec==1) ncur1++;
+ if(rec>1 && rec<10) ncur10++;
+ if(rec>=10 && rec<50) ncur50++;
+ if(rec>=50 && rec<150) ncur150++;
+ if(rec>=150) ncur151++;
+ }else{
+ succ++;
+ succ2+=size;
+ if(rec==0) cur0++;
+ if(rec==1) cur1++;
+ if(rec>1 && rec<10) cur10++;
+ if(rec>=10 && rec<50) cur50++;
+ if(rec>=50 && rec<150) cur150++;
+ if(rec>=150) cur151++;
+ }
+ }
+#endif
+
+ if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
+ ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
+// GC_free(ret2);
+ }
+
+ return ret;
+}
+#endif
+
+
+/* The allocating-functions defined inside the amiga-blocks in gc.h is called
+ * via these functions.
+ */
+
+
+void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
+ void *ret,*ret2;
+
+ GC_amiga_dontalloc=TRUE; // Pretty tough thing to do, but its indeed necesarry.
+ latestsize=size;
+
+ ret=(*AllocFunction)(size);
+
+ if(((char *)ret) <= chipmax){
+ if(ret==NULL){
+ //Give GC access to allocate memory.
+#ifdef GC_AMIGA_GC
+ if(!GC_dont_gc){
+ GC_gcollect();
+#ifdef GC_AMIGA_PRINTSTATS
+ numcollects++;
+#endif
+ ret=(*AllocFunction)(size);
+ }
+#endif
+ if(ret==NULL){
+ GC_amiga_dontalloc=FALSE;
+ ret=(*AllocFunction)(size);
+ if(ret==NULL){
+ WARN("Out of Memory! Returning NIL!\n", 0);
+ }
+ }
+#ifdef GC_AMIGA_PRINTSTATS
+ else{
+ nullretries++;
+ }
+ if(ret!=NULL && (char *)ret<=chipmax) chipa+=size;
+#endif
+ }
+#ifdef GC_AMIGA_RETRY
+ else{
+ /* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
+ /* Using gctest to check the effectiviness of doing this, does seldom give a very good result. */
+ /* However, real programs doesn't normally rapidly allocate and deallocate. */
+// printf("trying to force... %d bytes... ",size);
+ if(
+ AllocFunction!=GC_malloc_uncollectable
+#ifdef ATOMIC_UNCOLLECTABLE
+ && AllocFunction!=GC_malloc_atomic_uncollectable
+#endif
+ ){
+ ret2=GC_amiga_rec_alloc(size,AllocFunction,0);
+ }else{
+ ret2=(*AllocFunction)(size);
+#ifdef GC_AMIGA_PRINTSTATS
+ if((char *)ret2<chipmax || ret2==NULL){
+ nsucc++;
+ nsucc2+=size;
+ ncur0++;
+ }else{
+ succ++;
+ succ2+=size;
+ cur0++;
+ }
+#endif
+ }
+ if(((char *)ret2)>chipmax){
+// printf("Succeeded.\n");
+ GC_free(ret);
+ ret=ret2;
+ }else{
+ GC_free(ret2);
+// printf("But did not succeed.\n");
+ }
+ }
+#endif
+ }
+
+ GC_amiga_dontalloc=FALSE;
+
+ return ret;
+}
+
+
+
+void (*GC_amiga_toany)(void)=NULL;
+
+void GC_amiga_set_toany(void (*func)(void)){
+ GC_amiga_toany=func;
+}
+
+#endif // !GC_AMIGA_ONLYFAST
+
+
+void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
+ void *ret;
+
+ ret=(*AllocFunction)(size);
+
+ if(ret==NULL){
+ // Enable chip-mem allocation.
+// printf("ret==NULL\n");
+#ifdef GC_AMIGA_GC
+ if(!GC_dont_gc){
+ GC_gcollect();
+#ifdef GC_AMIGA_PRINTSTATS
+ numcollects++;
+#endif
+ ret=(*AllocFunction)(size);
+ }
+#endif
+ if(ret==NULL){
+#ifndef GC_AMIGA_ONLYFAST
+ GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
+ if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
+ GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
+ return GC_amiga_allocwrapper_any(size,AllocFunction);
+#endif
+ }
+#ifdef GC_AMIGA_PRINTSTATS
+ else{
+ nullretries++;
+ }
+#endif
+ }
+
+ return ret;
+}
+
+void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
+ atexit(&GC_amiga_free_all_mem);
+ chipmax=(char *)SysBase->MaxLocMem; // For people still having SysBase in chip-mem, this might speed up a bit.
+ GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
+ return GC_amiga_allocwrapper_fast(size,AllocFunction);
+}
+
+
+#endif //GC_AMIGA_FASTALLOC
+
+
+
+/*
+ * The wrapped realloc function.
+ *
+ */
+void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
+#ifndef GC_AMIGA_FASTALLOC
+ return GC_realloc(old_object,new_size_in_bytes);
+#else
+ void *ret;
+ latestsize=new_size_in_bytes;
+ ret=GC_realloc(old_object,new_size_in_bytes);
+ if(ret==NULL && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
+ /* Out of fast-mem. */
+#ifdef GC_AMIGA_GC
+ if(!GC_dont_gc){
+ GC_gcollect();
+#ifdef GC_AMIGA_PRINTSTATS
+ numcollects++;
+#endif
+ ret=GC_realloc(old_object,new_size_in_bytes);
+ }
+#endif
+ if(ret==NULL){
+#ifndef GC_AMIGA_ONLYFAST
+ GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
+ if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
+ GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
+ ret=GC_realloc(old_object,new_size_in_bytes);
+#endif
+ }
+#ifdef GC_AMIGA_PRINTSTATS
+ else{
+ nullretries++;
+ }
+#endif
+ }
+ if(ret==NULL){
+ WARN("Out of Memory! Returning NIL!\n", 0);
+ }
+#ifdef GC_AMIGA_PRINTSTATS
+ if(((char *)ret)<chipmax && ret!=NULL){
+ chipa+=new_size_in_bytes;
+ }
+#endif
+ return ret;
+#endif
+}
+
+#endif //GC_AMIGA_AM
+
+
diff --git a/extra/MacOS.c b/extra/MacOS.c
new file mode 100644
index 00000000..b56bea78
--- /dev/null
+++ b/extra/MacOS.c
@@ -0,0 +1,156 @@
+/*
+ MacOS.c
+
+ Some routines for the Macintosh OS port of the Hans-J. Boehm, Alan J. Demers
+ garbage collector.
+
+ <Revision History>
+
+ 11/22/94 pcb StripAddress the temporary memory handle for 24-bit mode.
+ 11/30/94 pcb Tracking all memory usage so we can deallocate it all at once.
+ 02/10/96 pcb Added routine to perform a final collection when
+unloading shared library.
+
+ by Patrick C. Beard.
+ */
+/* Boehm, February 15, 1996 2:55 pm PST */
+
+#include <Resources.h>
+#include <Memory.h>
+#include <LowMem.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gc.h"
+#include "gc_priv.h"
+
+// use 'CODE' resource 0 to get exact location of the beginning of global space.
+
+typedef struct {
+ unsigned long aboveA5;
+ unsigned long belowA5;
+ unsigned long JTSize;
+ unsigned long JTOffset;
+} *CodeZeroPtr, **CodeZeroHandle;
+
+void* GC_MacGetDataStart()
+{
+ CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
+ if (code0) {
+ long belowA5Size = (**code0).belowA5;
+ ReleaseResource((Handle)code0);
+ return (LMGetCurrentA5() - belowA5Size);
+ }
+ fprintf(stderr, "Couldn't load the jump table.");
+ exit(-1);
+ return 0;
+}
+
+/* track the use of temporary memory so it can be freed all at once. */
+
+typedef struct TemporaryMemoryBlock TemporaryMemoryBlock, **TemporaryMemoryHandle;
+
+struct TemporaryMemoryBlock {
+ TemporaryMemoryHandle nextBlock;
+ char data[];
+};
+
+static TemporaryMemoryHandle theTemporaryMemory = NULL;
+static Boolean firstTime = true;
+
+void GC_MacFreeTemporaryMemory(void);
+
+Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
+{
+ static Boolean firstTime = true;
+ OSErr result;
+ TemporaryMemoryHandle tempMemBlock;
+ Ptr tempPtr = nil;
+
+ tempMemBlock = (TemporaryMemoryHandle)TempNewHandle(size + sizeof(TemporaryMemoryBlock), &result);
+ if (tempMemBlock && result == noErr) {
+ HLockHi((Handle)tempMemBlock);
+ tempPtr = (**tempMemBlock).data;
+ if (clearMemory) memset(tempPtr, 0, size);
+ tempPtr = StripAddress(tempPtr);
+
+ // keep track of the allocated blocks.
+ (**tempMemBlock).nextBlock = theTemporaryMemory;
+ theTemporaryMemory = tempMemBlock;
+ }
+
+# if !defined(SHARED_LIBRARY_BUILD)
+ // install an exit routine to clean up the memory used at the end.
+ if (firstTime) {
+ atexit(&GC_MacFreeTemporaryMemory);
+ firstTime = false;
+ }
+# endif
+
+ return tempPtr;
+}
+
+extern word GC_fo_entries;
+
+static void perform_final_collection()
+{
+ unsigned i;
+ word last_fo_entries = 0;
+
+ /* adjust the stack bottom, because CFM calls us from another stack
+ location. */
+ GC_stackbottom = (ptr_t)&i;
+
+ /* try to collect and finalize everything in sight */
+ for (i = 0; i < 2 || GC_fo_entries < last_fo_entries; i++) {
+ last_fo_entries = GC_fo_entries;
+ GC_gcollect();
+ }
+}
+
+
+void GC_MacFreeTemporaryMemory()
+{
+# if defined(SHARED_LIBRARY_BUILD)
+ /* if possible, collect all memory, and invoke all finalizers. */
+ perform_final_collection();
+# endif
+
+ if (theTemporaryMemory != NULL) {
+ long totalMemoryUsed = 0;
+ TemporaryMemoryHandle tempMemBlock = theTemporaryMemory;
+ while (tempMemBlock != NULL) {
+ TemporaryMemoryHandle nextBlock = (**tempMemBlock).nextBlock;
+ totalMemoryUsed += GetHandleSize((Handle)tempMemBlock);
+ DisposeHandle((Handle)tempMemBlock);
+ tempMemBlock = nextBlock;
+ }
+ theTemporaryMemory = NULL;
+
+# if !defined(SHARED_LIBRARY_BUILD)
+ if (GC_print_stats) {
+ fprintf(stdout, "[total memory used: %ld bytes.]\n",
+ totalMemoryUsed);
+ fprintf(stdout, "[total collections: %ld.]\n", GC_gc_no);
+ }
+# endif
+ }
+}
+
+#if __option(far_data)
+
+ void* GC_MacGetDataEnd()
+ {
+ CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
+ if (code0) {
+ long aboveA5Size = (**code0).aboveA5;
+ ReleaseResource((Handle)code0);
+ return (LMGetCurrentA5() + aboveA5Size);
+ }
+ fprintf(stderr, "Couldn't load the jump table.");
+ exit(-1);
+ return 0;
+ }
+
+#endif /* __option(far_data) */
diff --git a/extra/add_gc_prefix.c b/extra/add_gc_prefix.c
new file mode 100644
index 00000000..a7fd4fc4
--- /dev/null
+++ b/extra/add_gc_prefix.c
@@ -0,0 +1,20 @@
+# include <stdio.h>
+# include <gc.h>
+
+int main(argc, argv, envp)
+int argc;
+char ** argv;
+char ** envp;
+{
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (GC_ALPHA_VERSION == GC_NOT_ALPHA) {
+ printf("gc%d.%d/%s ", GC_VERSION_MAJOR, GC_VERSION_MINOR, argv[i]);
+ } else {
+ printf("gc%d.%dalpha%d/%s ", GC_VERSION_MAJOR,
+ GC_VERSION_MINOR, GC_ALPHA_VERSION, argv[i]);
+ }
+ }
+ return(0);
+}
diff --git a/extra/gcname.c b/extra/gcname.c
new file mode 100644
index 00000000..55b7c9fb
--- /dev/null
+++ b/extra/gcname.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <gc.h>
+
+int main()
+{
+ if (GC_ALPHA_VERSION == GC_NOT_ALPHA) {
+ printf("gc%d.%d", GC_VERSION_MAJOR, GC_VERSION_MINOR);
+ } else {
+ printf("gc%d.%dalpha%d", GC_VERSION_MAJOR,
+ GC_VERSION_MINOR, GC_ALPHA_VERSION);
+ }
+ return 0;
+}
diff --git a/extra/if_mach.c b/extra/if_mach.c
new file mode 100644
index 00000000..d6e0a70d
--- /dev/null
+++ b/extra/if_mach.c
@@ -0,0 +1,25 @@
+/* Conditionally execute a command based on machine and OS from gcconfig.h */
+
+# include "private/gcconfig.h"
+# include <stdio.h>
+# include <string.h>
+# include <unistd.h>
+
+int main(int argc, char **argv, char **envp)
+{
+ if (argc < 4) goto Usage;
+ if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
+ if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
+ && strcmp(OS_TYPE, argv[2]) != 0) return(0);
+ fprintf(stderr, "^^^^Starting command^^^^\n");
+ fflush(stdout);
+ execvp(argv[3], argv+3);
+ perror("Couldn't execute");
+
+Usage:
+ fprintf(stderr, "Usage: %s mach_type os_type command\n", argv[0]);
+ fprintf(stderr, "Currently mach_type = %s, os_type = %s\n",
+ MACH_TYPE, OS_TYPE);
+ return(1);
+}
+
diff --git a/extra/if_not_there.c b/extra/if_not_there.c
new file mode 100644
index 00000000..7af6fba4
--- /dev/null
+++ b/extra/if_not_there.c
@@ -0,0 +1,38 @@
+/* Conditionally execute a command based if the file argv[1] doesn't exist */
+/* Except for execvp, we stick to ANSI C. */
+# include "private/gcconfig.h"
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+#ifdef __DJGPP__
+#include <dirent.h>
+#endif /* __DJGPP__ */
+
+int main(int argc, char **argv, char **envp)
+{
+ FILE * f;
+#ifdef __DJGPP__
+ DIR * d;
+#endif /* __DJGPP__ */
+ if (argc < 3) goto Usage;
+ if ((f = fopen(argv[1], "rb")) != 0
+ || (f = fopen(argv[1], "r")) != 0) {
+ fclose(f);
+ return(0);
+ }
+#ifdef __DJGPP__
+ if ((d = opendir(argv[1])) != 0) {
+ closedir(d);
+ return(0);
+ }
+#endif
+ printf("^^^^Starting command^^^^\n");
+ fflush(stdout);
+ execvp(argv[2], argv+2);
+ exit(1);
+
+Usage:
+ fprintf(stderr, "Usage: %s file_name command\n", argv[0]);
+ return(1);
+}
+
diff --git a/extra/msvc_dbg.c b/extra/msvc_dbg.c
new file mode 100644
index 00000000..2420a44b
--- /dev/null
+++ b/extra/msvc_dbg.c
@@ -0,0 +1,353 @@
+/*
+ Copyright (c) 2004 Andrei Polushin
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+#ifndef _M_AMD64
+
+/* X86_64 is ccurrently missing some meachine-dependent code below. */
+
+#include "private/msvc_dbg.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#pragma pack(push, 8)
+#include <imagehlp.h>
+#pragma pack(pop)
+
+#pragma comment(lib, "dbghelp.lib")
+#pragma optimize("gy", off)
+
+#ifdef _WIN64
+ typedef ULONG_PTR ULONG_ADDR;
+#else
+ typedef ULONG ULONG_ADDR;
+#endif
+
+static HANDLE GetSymHandle()
+{
+ static HANDLE symHandle = NULL;
+ if (!symHandle) {
+ BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE);
+ if (bRet) {
+ DWORD dwOptions = SymGetOptions();
+ dwOptions &= ~SYMOPT_UNDNAME;
+ dwOptions |= SYMOPT_LOAD_LINES;
+ SymSetOptions(dwOptions);
+ }
+ }
+ return symHandle;
+}
+
+static void* CALLBACK FunctionTableAccess(HANDLE hProcess, ULONG_ADDR dwAddrBase)
+{
+ return SymFunctionTableAccess(hProcess, dwAddrBase);
+}
+
+static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
+{
+ MEMORY_BASIC_INFORMATION memoryInfo;
+ ULONG_ADDR dwAddrBase = SymGetModuleBase(hProcess, dwAddress);
+ if (dwAddrBase) {
+ return dwAddrBase;
+ }
+ if (VirtualQueryEx(hProcess, (void*)(ULONG_PTR)dwAddress, &memoryInfo, sizeof(memoryInfo))) {
+ char filePath[_MAX_PATH];
+ char curDir[_MAX_PATH];
+ char exePath[_MAX_PATH];
+ DWORD size = GetModuleFileNameA((HINSTANCE)memoryInfo.AllocationBase, filePath, sizeof(filePath));
+
+ // Save and restore current directory around SymLoadModule, see KB article Q189780
+ GetCurrentDirectoryA(sizeof(curDir), curDir);
+ GetModuleFileNameA(NULL, exePath, sizeof(exePath));
+#if defined(_MSC_VER) && _MSC_VER == 1200
+ /* use strcat for VC6 */
+ strcat(exePath, "\\..");
+#else
+ strcat_s(exePath, sizeof(exePath), "\\..");
+#endif /* _MSC_VER >= 1200 */
+ SetCurrentDirectoryA(exePath);
+#ifdef _DEBUG
+ GetCurrentDirectoryA(sizeof(exePath), exePath);
+#endif
+ SymLoadModule(hProcess, NULL, size ? filePath : NULL, NULL, (ULONG_ADDR)(ULONG_PTR)memoryInfo.AllocationBase, 0);
+ SetCurrentDirectoryA(curDir);
+ }
+ return (ULONG_ADDR)(ULONG_PTR)memoryInfo.AllocationBase;
+}
+
+static ULONG_ADDR CheckAddress(void* address)
+{
+ ULONG_ADDR dwAddress = (ULONG_ADDR)(ULONG_PTR)address;
+ GetModuleBase(GetSymHandle(), dwAddress);
+ return dwAddress;
+}
+
+size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames)
+{
+ HANDLE hProcess = GetSymHandle();
+ HANDLE hThread = GetCurrentThread();
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_FULL;
+ if (!GetThreadContext(hThread, &context)) {
+ return 0;
+ }
+ // GetThreadContext might return invalid context for the current thread
+#if defined(_M_IX86)
+ __asm mov context.Ebp, ebp
+#endif
+ return GetStackFramesFromContext(hProcess, hThread, &context, skip + 1, frames, maxFrames);
+}
+
+size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread, CONTEXT* context, size_t skip, void* frames[], size_t maxFrames)
+{
+ size_t frameIndex;
+ DWORD machineType;
+ STACKFRAME stackFrame = { 0 };
+ stackFrame.AddrPC.Mode = AddrModeFlat;
+#if defined(_M_IX86)
+ machineType = IMAGE_FILE_MACHINE_I386;
+ stackFrame.AddrPC.Offset = context->Eip;
+ stackFrame.AddrStack.Mode = AddrModeFlat;
+ stackFrame.AddrStack.Offset = context->Esp;
+ stackFrame.AddrFrame.Mode = AddrModeFlat;
+ stackFrame.AddrFrame.Offset = context->Ebp;
+#elif defined(_M_MRX000)
+ machineType = IMAGE_FILE_MACHINE_R4000;
+ stackFrame.AddrPC.Offset = context->Fir;
+#elif defined(_M_ALPHA)
+ machineType = IMAGE_FILE_MACHINE_ALPHA;
+ stackFrame.AddrPC.Offset = (unsigned long)context->Fir;
+#elif defined(_M_PPC)
+ machineType = IMAGE_FILE_MACHINE_POWERPC;
+ stackFrame.AddrPC.Offset = context->Iar;
+#elif defined(_M_IA64)
+ machineType = IMAGE_FILE_MACHINE_IA64;
+ stackFrame.AddrPC.Offset = context->StIIP;
+#elif defined(_M_ALPHA64)
+ machineType = IMAGE_FILE_MACHINE_ALPHA64;
+ stackFrame.AddrPC.Offset = context->Fir;
+#else
+#error Unknown CPU
+#endif
+ for (frameIndex = 0; frameIndex < maxFrames; ) {
+ BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame, &context, NULL, FunctionTableAccess, GetModuleBase, NULL);
+ if (!bRet) {
+ break;
+ }
+ if (skip) {
+ skip--;
+ } else {
+ frames[frameIndex++] = (void*)(ULONG_PTR)stackFrame.AddrPC.Offset;
+ }
+ }
+ return frameIndex;
+}
+
+size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size)
+{
+ if (size) *moduleName = 0;
+ {
+ const char* sourceName;
+ IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) };
+ if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address), &moduleInfo)) {
+ return 0;
+ }
+ sourceName = strrchr(moduleInfo.ImageName, '\\');
+ if (sourceName) {
+ sourceName++;
+ } else {
+ sourceName = moduleInfo.ImageName;
+ }
+ if (size) {
+ strncpy(moduleName, sourceName, size)[size - 1] = 0;
+ }
+ return strlen(sourceName);
+ }
+}
+
+size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size)
+{
+ void* address = NULL;
+ GetStackFrames(skip + 1, &address, 1);
+ if (address) {
+ return GetModuleNameFromAddress(address, moduleName, size);
+ }
+ return 0;
+}
+
+size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes)
+{
+ if (size) *symbolName = 0;
+ if (offsetBytes) *offsetBytes = 0;
+ __try {
+ ULONG_ADDR dwOffset = 0;
+ union {
+ IMAGEHLP_SYMBOL sym;
+ char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME];
+ } u;
+ u.sym.SizeOfStruct = sizeof(u.sym);
+ u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym);
+
+ if (!SymGetSymFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset, &u.sym)) {
+ return 0;
+ } else {
+ const char* sourceName = u.sym.Name;
+ char undName[1024];
+ if (UnDecorateSymbolName(u.sym.Name, undName, sizeof(undName), UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) {
+ sourceName = undName;
+ } else if (SymUnDName(&u.sym, undName, sizeof(undName))) {
+ sourceName = undName;
+ }
+ if (offsetBytes) {
+ *offsetBytes = dwOffset;
+ }
+ if (size) {
+ strncpy(symbolName, sourceName, size)[size - 1] = 0;
+ }
+ return strlen(sourceName);
+ }
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ SetLastError(GetExceptionCode());
+ }
+ return 0;
+}
+
+size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size, size_t* offsetBytes)
+{
+ void* address = NULL;
+ GetStackFrames(skip + 1, &address, 1);
+ if (address) {
+ return GetSymbolNameFromAddress(address, symbolName, size, offsetBytes);
+ }
+ return 0;
+}
+
+size_t GetFileLineFromAddress(void* address, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes)
+{
+ if (size) *fileName = 0;
+ if (lineNumber) *lineNumber = 0;
+ if (offsetBytes) *offsetBytes = 0;
+ {
+ char* sourceName;
+ IMAGEHLP_LINE line = { sizeof (line) };
+ ULONG_PTR dwOffset = 0;
+ if (!SymGetLineFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset, &line)) {
+ return 0;
+ }
+ if (lineNumber) {
+ *lineNumber = line.LineNumber;
+ }
+ if (offsetBytes) {
+ *offsetBytes = dwOffset;
+ }
+ sourceName = line.FileName;
+ // TODO: resolve relative filenames, found in 'source directories' registered with MSVC IDE.
+ if (size) {
+ strncpy(fileName, sourceName, size)[size - 1] = 0;
+ }
+ return strlen(sourceName);
+ }
+}
+
+size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes)
+{
+ void* address = NULL;
+ GetStackFrames(skip + 1, &address, 1);
+ if (address) {
+ return GetFileLineFromAddress(address, fileName, size, lineNumber, offsetBytes);
+ }
+ return 0;
+}
+
+size_t GetDescriptionFromAddress(void* address, const char* format, char* buffer, size_t size)
+{
+ char*const begin = buffer;
+ char*const end = buffer + size;
+ size_t line_number = 0;
+ char str[128];
+
+ if (size) {
+ *buffer = 0;
+ }
+ buffer += GetFileLineFromAddress(address, buffer, size, &line_number, NULL);
+ size = end < buffer ? 0 : end - buffer;
+
+ if (line_number) {
+ wsprintf(str, "(%d) : ", line_number);
+ if (size) {
+ strncpy(buffer, str, size)[size - 1] = 0;
+ }
+ buffer += strlen(str);
+ size = end < buffer ? 0 : end - buffer;
+ }
+
+ if (size) {
+ strncpy(buffer, "at ", size)[size - 1] = 0;
+ }
+ buffer += strlen("at ");
+ size = end < buffer ? 0 : end - buffer;
+
+ buffer += GetSymbolNameFromAddress(address, buffer, size, NULL);
+ size = end < buffer ? 0 : end - buffer;
+
+ if (size) {
+ strncpy(buffer, " in ", size)[size - 1] = 0;
+ }
+ buffer += strlen(" in ");
+ size = end < buffer ? 0 : end - buffer;
+
+ buffer += GetModuleNameFromAddress(address, buffer, size);
+ size = end < buffer ? 0 : end - buffer;
+
+ return buffer - begin;
+}
+
+size_t GetDescriptionFromStack(void*const frames[], size_t count, const char* format, char* description[], size_t size)
+{
+ char*const begin = (char*)description;
+ char*const end = begin + size;
+ char* buffer = begin + (count + 1) * sizeof(char*);
+ size_t i;
+ for (i = 0; i < count; ++i) {
+ if (description) description[i] = buffer;
+ size = end < buffer ? 0 : end - buffer;
+ buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
+ }
+ if (description) description[count] = NULL;
+ return buffer - begin;
+}
+
+/* Compatibility with <execinfo.h> */
+
+int backtrace(void* addresses[], int count)
+{
+ return GetStackFrames(1, addresses, count);
+}
+
+char** backtrace_symbols(void*const* addresses, int count)
+{
+ size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
+ char** symbols = (char**)malloc(size);
+ GetDescriptionFromStack(addresses, count, NULL, symbols, size);
+ return symbols;
+}
+
+#endif /* !_M_AMD64 */
diff --git a/extra/setjmp_t.c b/extra/setjmp_t.c
new file mode 100644
index 00000000..5a171df0
--- /dev/null
+++ b/extra/setjmp_t.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to 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.
+ */
+
+/* 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 */
+/* contrived such that any decent compiler should put x in */
+/* a callee-save register with -O. Thus it is 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. */
+#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. */
+#define INCL_DOSFILEMGR
+#define INCL_DOSMISC
+#define INCL_DOSERRORS
+#include <os2.h>
+
+int
+getpagesize()
+{
+ 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;
+ }
+ return((int)(result[0]));
+}
+#endif
+
+struct {char a_a; char * a_b;} a;
+
+int * nested_sp()
+{
+ int dummy;
+
+ return(&dummy);
+}
+
+int main()
+{
+ 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);
+}
+
+int g(x)
+int x;
+{
+ return(x);
+}
diff --git a/extra/threadlibs.c b/extra/threadlibs.c
new file mode 100644
index 00000000..f2ab5825
--- /dev/null
+++ b/extra/threadlibs.c
@@ -0,0 +1,63 @@
+# include "gc_config_macros.h"
+# include "private/gcconfig.h"
+# include <stdio.h>
+
+int main()
+{
+# if defined(GC_USE_LD_WRAP)
+ printf("-Wl,--wrap -Wl,dlopen "
+ "-Wl,--wrap -Wl,pthread_create -Wl,--wrap -Wl,pthread_join "
+ "-Wl,--wrap -Wl,pthread_detach "
+ "-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
+# endif
+# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) \
+ || defined(GC_GNU_THREADS)
+# ifdef GC_USE_DLOPEN_WRAP
+ printf("-ldl ");
+# endif
+ printf("-lpthread\n");
+# endif
+# if defined(GC_FREEBSD_THREADS)
+# ifdef GC_USE_DLOPEN_WRAP
+ printf("-ldl ");
+# endif
+# if (__FREEBSD_version >= 500000)
+ printf("-lpthread\n");
+# else
+ printf("-pthread\n");
+# endif
+# endif
+# if defined(GC_NETBSD_THREADS)
+ printf("-lpthread -lrt\n");
+# endif
+
+# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
+ printf("-lpthread -lrt\n");
+# endif
+# if defined(GC_SOLARIS_THREADS)
+ printf("-lthread -lposix4\n");
+ /* Is this right for recent versions? */
+# endif
+# if defined(GC_WIN32_THREADS) && defined(CYGWIN32)
+ printf("-lpthread\n");
+# endif
+# if defined(GC_WIN32_PTHREADS)
+# ifdef PTW32_STATIC_LIB
+ /* assume suffix s for static version of the win32 pthread library */
+ printf("-lpthreadGC2s -lws2_32\n");
+# else
+ printf("-lpthreadGC2\n");
+# endif
+# endif
+# if defined(GC_OSF1_THREADS)
+ printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */
+# endif
+ /* You need GCC 3.0.3 to build this one! */
+ /* DG/UX native gcc doesnt know what "-pthread" is */
+# if defined(GC_DGUX386_THREADS)
+ printf("-ldl -pthread\n");
+# endif
+ return 0;
+}
+