📄 amigaos.c
字号:
/****************************************************************** 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_FASTALLOCvoid *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;#elsevoid *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_ONLYFASTBOOL GC_amiga_dontalloc=FALSE;#endif#ifdef GC_AMIGA_PRINTSTATSint 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_RETRYvoid *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_ONLYFASTvoid *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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -