void GC_register_data_segments(void) { struct Process *proc; struct CommandLineInterface *cli; BPTR myseglist; ULONG *data; # 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 */ myseglist = proc->pr_SegList; if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) { if (proc->pr_CLI != NULL) { /* 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 */ 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); } } /* for */ # ifdef __GNUC__ if (!found_segment) { ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library"); } # endif }
GC_API void GC_CALL GC_add_roots(void *b, void *e) { DCL_LOCK_STATE; if (!EXPECT(GC_is_initialized, TRUE)) GC_init(); LOCK(); GC_add_roots_inner((ptr_t)b, (ptr_t)e, FALSE); UNLOCK(); }
/* We hold the allocation lock. */ void GC_thr_init(void) { # ifndef GC_DARWIN_THREADS int dummy; # endif GC_thread t; if (GC_thr_initialized) return; GC_thr_initialized = TRUE; # ifdef HANDLE_FORK /* Prepare for a possible fork. */ pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc, GC_fork_child_proc); # endif /* HANDLE_FORK */ # if defined(INCLUDE_LINUX_THREAD_DESCR) /* Explicitly register the region including the address */ /* of a thread local variable. This should include thread */ /* locals for the main thread, except for those allocated */ /* in response to dlopen calls. */ { ptr_t thread_local_addr = (ptr_t)(&dummy_thread_local); ptr_t main_thread_start, main_thread_end; if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start, &main_thread_end)) { ABORT("Failed to find mapping for main thread thread locals"); } GC_add_roots_inner(main_thread_start, main_thread_end, FALSE); } # endif /* Add the initial thread, so we can stop it. */ t = GC_new_thread(pthread_self()); # ifdef GC_DARWIN_THREADS t -> stop_info.mach_thread = mach_thread_self(); # else t -> stop_info.stack_ptr = (ptr_t)(&dummy); # endif t -> flags = DETACHED | MAIN_THREAD; GC_stop_init(); /* Set GC_nprocs. */ { char * nprocs_string = GETENV("GC_NPROCS"); GC_nprocs = -1; if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string); } if (GC_nprocs <= 0) { # if defined(GC_HPUX_THREADS) GC_nprocs = pthread_num_processors_np(); # endif # if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \ || defined(GC_SOLARIS_THREADS) || defined(GC_GNU_THREADS) GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1; # endif # if defined(GC_IRIX_THREADS) GC_nprocs = sysconf(_SC_NPROC_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1; # endif # if defined(GC_NETBSD_THREADS) GC_nprocs = get_ncpu(); # endif # if defined(GC_OPENBSD_THREADS) GC_nprocs = 1; # endif # if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) int ncpus = 1; size_t len = sizeof(ncpus); sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
/* 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; }
/* this function is called repeatedly by GC_register_map_entries. */ GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e) { int i; GC_bool rebuild = FALSE; GC_ASSERT(I_HOLD_LOCK()); GC_ASSERT((word)b % sizeof(word) == 0 && (word)e % sizeof(word) == 0); for (i = 0; i < n_root_sets; i++) { ptr_t r_start, r_end; if (GC_static_roots[i].r_tmp) { /* The remaining roots are skipped as they are all temporary. */ # ifdef GC_ASSERTIONS int j; for (j = i + 1; j < n_root_sets; j++) { GC_ASSERT(GC_static_roots[j].r_tmp); } # endif break; } r_start = GC_static_roots[i].r_start; r_end = GC_static_roots[i].r_end; if (!EXPECT((word)e <= (word)r_start || (word)r_end <= (word)b, TRUE)) { # ifdef DEBUG_ADD_DEL_ROOTS GC_log_printf("Removing %p .. %p from root section %d (%p .. %p)\n", (void *)b, (void *)e, i, (void *)r_start, (void *)r_end); # endif if ((word)r_start < (word)b) { GC_root_size -= r_end - b; GC_static_roots[i].r_end = b; /* No need to rebuild as hash does not use r_end value. */ if ((word)e < (word)r_end) { int j; if (rebuild) { GC_rebuild_root_index(); rebuild = FALSE; } GC_add_roots_inner(e, r_end, FALSE); /* updates n_root_sets */ for (j = i + 1; j < n_root_sets; j++) if (GC_static_roots[j].r_tmp) break; if (j < n_root_sets-1 && !GC_static_roots[n_root_sets-1].r_tmp) { /* Exchange the roots to have all temporary ones at the end. */ ptr_t tmp_r_start = GC_static_roots[j].r_start; ptr_t tmp_r_end = GC_static_roots[j].r_end; GC_static_roots[j].r_start = GC_static_roots[n_root_sets-1].r_start; GC_static_roots[j].r_end = GC_static_roots[n_root_sets-1].r_end; GC_static_roots[j].r_tmp = FALSE; GC_static_roots[n_root_sets-1].r_start = tmp_r_start; GC_static_roots[n_root_sets-1].r_end = tmp_r_end; GC_static_roots[n_root_sets-1].r_tmp = TRUE; rebuild = TRUE; } } } else { if ((word)e < (word)r_end) { GC_root_size -= e - r_start; GC_static_roots[i].r_start = e; } else { GC_remove_root_at_pos(i); i--; } rebuild = TRUE; } } } if (rebuild) GC_rebuild_root_index(); }