X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fcheneygc.c;h=10b4d4af3c9595df2f476591f633c7e2ddcc00a7;hb=ab9c6bbaaa409e815a1c9696885c9621b429aed6;hp=b9fd6b2c0863f0d1138df3febf4f97e12e948cbd;hpb=56caa7055d1a1d228842cf4fb05dc4b53f9131b0;p=sbcl.git diff --git a/src/runtime/cheneygc.c b/src/runtime/cheneygc.c index b9fd6b2..10b4d4a 100644 --- a/src/runtime/cheneygc.c +++ b/src/runtime/cheneygc.c @@ -17,8 +17,8 @@ #include #include #include -#include "runtime.h" #include "sbcl.h" +#include "runtime.h" #include "os.h" #include "gc.h" #include "gc-internal.h" @@ -29,6 +29,8 @@ #include "interr.h" #include "genesis/static-symbols.h" #include "genesis/primitive-objects.h" +#include "thread.h" +#include "arch.h" /* So you need to debug? */ #if 0 @@ -46,7 +48,6 @@ lispobj *new_space; lispobj *new_space_free_pointer; static void scavenge_newspace(void); -static void scavenge_interrupt_contexts(void); /* collecting garbage */ @@ -56,49 +57,24 @@ static double tv_diff(struct timeval *x, struct timeval *y) { return (((double) x->tv_sec + (double) x->tv_usec * 1.0e-6) - - ((double) y->tv_sec + (double) y->tv_usec * 1.0e-6)); + ((double) y->tv_sec + (double) y->tv_usec * 1.0e-6)); } #endif -#define BYTES_ZERO_BEFORE_END (1<<12) - -/* FIXME do we need this? Doesn't it duplicate lisp code in - * scrub-control-stack? */ - -static void -zero_stack(void) -{ - u32 *ptr = (u32 *)current_control_stack_pointer; - search: - do { - if (*ptr) - goto fill; - ptr++; - } while (((unsigned long)ptr) & (BYTES_ZERO_BEFORE_END-1)); - return; - fill: - do { - *ptr++ = 0; - } while (((unsigned long)ptr) & (BYTES_ZERO_BEFORE_END-1)); - - goto search; -} - - void * -gc_general_alloc(int bytes, int unboxed_p, int quick_p) { +gc_general_alloc(long bytes, int page_type_flag, int quick_p) { lispobj *new=new_space_free_pointer; - new_space_free_pointer+=(bytes/4); + new_space_free_pointer+=(bytes/N_WORD_BYTES); return new; } -lispobj copy_large_unboxed_object(lispobj object, int nwords) { +lispobj copy_large_unboxed_object(lispobj object, long nwords) { return copy_object(object,nwords); } -lispobj copy_unboxed_object(lispobj object, int nwords) { +lispobj copy_unboxed_object(lispobj object, long nwords) { return copy_object(object,nwords); } -lispobj copy_large_object(lispobj object, int nwords) { +lispobj copy_large_object(lispobj object, long nwords) { return copy_object(object,nwords); } @@ -106,7 +82,7 @@ lispobj copy_large_object(lispobj object, int nwords) { * last_generation argument. That's meaningless for us, since we're * not a generational GC. So we ignore it. */ void -collect_garbage(unsigned ignore) +collect_garbage(generation_index_t ignore) { #ifdef PRINTNOISE struct timeval start_tv, stop_tv; @@ -114,27 +90,28 @@ collect_garbage(unsigned ignore) double real_time, system_time, user_time; double percent_retained, gc_rate; unsigned long size_discarded; - unsigned long size_retained; #endif + unsigned long size_retained; lispobj *current_static_space_free_pointer; - unsigned long static_space_size; - unsigned long control_stack_size, binding_stack_size; + unsigned long static_space_size; + unsigned long control_stack_size, binding_stack_size; sigset_t tmp, old; + struct thread *th=arch_os_get_current_thread(); #ifdef PRINTNOISE printf("[Collecting garbage ... \n"); - + getrusage(RUSAGE_SELF, &start_rusage); gettimeofday(&start_tv, (struct timezone *) 0); #endif - - sigemptyset(&tmp); - sigaddset_blockable(&tmp); - sigprocmask(SIG_BLOCK, &tmp, &old); + + /* it's possible that signals are blocked already if this was called + * from a signal handler (e.g. with the sigsegv gc_trigger stuff) */ + block_blockable_signals(0, &old); current_static_space_free_pointer = - (lispobj *) ((unsigned long) - SymbolValue(STATIC_SPACE_FREE_POINTER)); + (lispobj *) ((unsigned long) + SymbolValue(STATIC_SPACE_FREE_POINTER,0)); /* Set up from space and new space pointers. */ @@ -144,14 +121,14 @@ collect_garbage(unsigned ignore) #ifdef PRINTNOISE fprintf(stderr,"from_space = %lx\n", - (unsigned long) current_dynamic_space); + (unsigned long) current_dynamic_space); #endif if (current_dynamic_space == (lispobj *) DYNAMIC_0_SPACE_START) - new_space = (lispobj *)DYNAMIC_1_SPACE_START; + new_space = (lispobj *)DYNAMIC_1_SPACE_START; else if (current_dynamic_space == (lispobj *) DYNAMIC_1_SPACE_START) - new_space = (lispobj *) DYNAMIC_0_SPACE_START; + new_space = (lispobj *) DYNAMIC_0_SPACE_START; else { - lose("GC lossage. Current dynamic space is bogus!\n"); + lose("GC lossage. Current dynamic space is bogus!\n"); } new_space_free_pointer = new_space; @@ -163,50 +140,50 @@ collect_garbage(unsigned ignore) #ifdef PRINTNOISE printf("Scavenging interrupt contexts ...\n"); #endif - scavenge_interrupt_contexts(); + scavenge_interrupt_contexts(th); #ifdef PRINTNOISE printf("Scavenging interrupt handlers (%d bytes) ...\n", - (int)sizeof(interrupt_handlers)); + (int)sizeof(interrupt_handlers)); #endif scavenge((lispobj *) interrupt_handlers, - sizeof(interrupt_handlers) / sizeof(lispobj)); - + sizeof(interrupt_handlers) / sizeof(lispobj)); + /* _size quantities are in units of sizeof(lispobj) - i.e. 4 */ - control_stack_size = - current_control_stack_pointer- - (lispobj *)CONTROL_STACK_START; + control_stack_size = + current_control_stack_pointer- + (lispobj *)th->control_stack_start; #ifdef PRINTNOISE printf("Scavenging the control stack at %p (%ld words) ...\n", - ((lispobj *)CONTROL_STACK_START), - control_stack_size); + ((lispobj *)th->control_stack_start), + control_stack_size); #endif - scavenge(((lispobj *)CONTROL_STACK_START), control_stack_size); - + scavenge(((lispobj *)th->control_stack_start), control_stack_size); + - binding_stack_size = - current_binding_stack_pointer - - (lispobj *)BINDING_STACK_START; + binding_stack_size = + current_binding_stack_pointer - + (lispobj *)th->binding_stack_start; #ifdef PRINTNOISE printf("Scavenging the binding stack %x - %x (%d words) ...\n", - BINDING_STACK_START,current_binding_stack_pointer, - (int)(binding_stack_size)); + th->binding_stack_start,current_binding_stack_pointer, + (int)(binding_stack_size)); #endif - scavenge(((lispobj *)BINDING_STACK_START), binding_stack_size); - - static_space_size = - current_static_space_free_pointer - (lispobj *) STATIC_SPACE_START; + scavenge(((lispobj *)th->binding_stack_start), binding_stack_size); + + static_space_size = + current_static_space_free_pointer - (lispobj *) STATIC_SPACE_START; #ifdef PRINTNOISE printf("Scavenging static space %x - %x (%d words) ...\n", - STATIC_SPACE_START,current_static_space_free_pointer, - (int)(static_space_size)); + STATIC_SPACE_START,current_static_space_free_pointer, + (int)(static_space_size)); #endif scavenge(((lispobj *)STATIC_SPACE_START), static_space_size); /* Scavenge newspace. */ #ifdef PRINTNOISE printf("Scavenging new space (%d bytes) ...\n", - (int)((new_space_free_pointer - new_space) * sizeof(lispobj))); + (int)((new_space_free_pointer - new_space) * sizeof(lispobj))); #endif scavenge_newspace(); @@ -217,34 +194,48 @@ collect_garbage(unsigned ignore) /* Scan the weak pointers. */ #ifdef PRINTNOISE + printf("Scanning weak hash tables ...\n"); +#endif + scan_weak_hash_tables(); + + /* Scan the weak pointers. */ +#ifdef PRINTNOISE printf("Scanning weak pointers ...\n"); #endif scan_weak_pointers(); - /* Flip spaces. */ #ifdef PRINTNOISE printf("Flipping spaces ...\n"); #endif - os_zero((os_vm_address_t) current_dynamic_space, - (os_vm_size_t) DYNAMIC_SPACE_SIZE); + /* Maybe FIXME: it's possible that we could significantly reduce + * RSS by zeroing the from_space or madvise(MADV_DONTNEED) or + * similar os-dependent tricks here */ +#ifdef LISP_FEATURE_HPUX + /* hpux cant handle unmapping areas that are not 100% mapped */ + clear_auto_gc_trigger(); +#endif + os_zero((os_vm_address_t) from_space, + (os_vm_size_t) dynamic_space_size); current_dynamic_space = new_space; dynamic_space_free_pointer = new_space_free_pointer; #ifdef PRINTNOISE size_discarded = (from_space_free_pointer - from_space) * sizeof(lispobj); - size_retained = (new_space_free_pointer - new_space) * sizeof(lispobj); #endif + size_retained = (new_space_free_pointer - new_space) * sizeof(lispobj); + + os_flush_icache((os_vm_address_t)new_space, size_retained); /* Zero stack. */ #ifdef PRINTNOISE printf("Zeroing empty part of control stack ...\n"); #endif - zero_stack(); - - sigprocmask(SIG_SETMASK, &old, 0); + scrub_control_stack(); + set_auto_gc_trigger(size_retained+bytes_consed_between_gcs); + thread_sigmask(SIG_SETMASK, &old, 0); #ifdef PRINTNOISE @@ -252,35 +243,24 @@ collect_garbage(unsigned ignore) getrusage(RUSAGE_SELF, &stop_rusage); printf("done.]\n"); - + percent_retained = (((float) size_retained) / - ((float) size_discarded)) * 100.0; + ((float) size_discarded)) * 100.0; printf("Total of %ld bytes out of %ld bytes retained (%3.2f%%).\n", - size_retained, size_discarded, percent_retained); + size_retained, size_discarded, percent_retained); real_time = tv_diff(&stop_tv, &start_tv); user_time = tv_diff(&stop_rusage.ru_utime, &start_rusage.ru_utime); system_time = tv_diff(&stop_rusage.ru_stime, &start_rusage.ru_stime); -#if 0 - printf("Statistics:\n"); - printf("%10.2f sec of real time\n", real_time); - printf("%10.2f sec of user time,\n", user_time); - printf("%10.2f sec of system time.\n", system_time); -#else printf("Statistics: %10.2fs real, %10.2fs user, %10.2fs system.\n", - real_time, user_time, system_time); -#endif + real_time, user_time, system_time); gc_rate = ((float) size_retained / (float) (1<<20)) / real_time; - + printf("%10.2f M bytes/sec collected.\n", gc_rate); #endif - /* os_flush_icache((os_vm_address_t) 0, sizeof(unsigned long)); */ - /* Maybe FIXME: it's possible that we could significantly reduce - * RSS by zeroing the from_space or madvise(MADV_DONTNEED) or - * similar os-dependent tricks here */ } @@ -293,139 +273,16 @@ scavenge_newspace(void) here = new_space; while (here < new_space_free_pointer) { - /* printf("here=%lx, new_space_free_pointer=%lx\n", - here,new_space_free_pointer); */ - next = new_space_free_pointer; - scavenge(here, next - here); - here = next; + /* printf("here=%lx, new_space_free_pointer=%lx\n", + here,new_space_free_pointer); */ + next = new_space_free_pointer; + scavenge(here, next - here); + scav_weak_hash_tables(); + here = next; } /* printf("done with newspace\n"); */ } -/* scavenging interrupt contexts */ - -static int boxed_registers[] = BOXED_REGISTERS; - -static void -scavenge_interrupt_context(os_context_t *context) -{ - int i; -#ifdef reg_LIP - unsigned long lip; - unsigned long lip_offset; - int lip_register_pair; -#endif - unsigned long pc_code_offset; -#ifdef ARCH_HAS_LINK_REGISTER - unsigned long lr_code_offset; -#endif -#ifdef ARCH_HAS_NPC_REGISTER - unsigned long npc_code_offset; -#endif -#ifdef DEBUG_SCAVENGE_VERBOSE - fprintf(stderr, "Scavenging interrupt context at 0x%x\n",context); -#endif - /* Find the LIP's register pair and calculate its offset */ - /* before we scavenge the context. */ -#ifdef reg_LIP - lip = *os_context_register_addr(context, reg_LIP); - /* 0x7FFFFFFF or 0x7FFFFFFFFFFFFFFF ? */ - lip_offset = 0x7FFFFFFF; - lip_register_pair = -1; - for (i = 0; i < (sizeof(boxed_registers) / sizeof(int)); i++) { - unsigned long reg; - long offset; - int index; - - index = boxed_registers[i]; - reg = *os_context_register_addr(context, index); - /* would be using PTR if not for integer length issues */ - if ((reg & ~((1L<code must always be the - * last slot in the object - - * FIXME (2) it also appears in purify.c, and it has a different value - * for SPARC users in that bit - */ - -#define FUN_RAW_ADDR_OFFSET (6*sizeof(lispobj) - FUN_POINTER_LOWTAG) - -/* Note: on the sparc we don't have to do anything special for fdefns, */ -/* 'cause the raw-addr has a function lowtag. */ -#ifndef LISP_FEATURE_SPARC -static int -scav_fdefn(lispobj *where, lispobj object) -{ - struct fdefn *fdefn; - - fdefn = (struct fdefn *)where; - - if ((char *)(fdefn->fun + FUN_RAW_ADDR_OFFSET) - == (char *)((unsigned long)(fdefn->raw_addr))) { - scavenge(where + 1, sizeof(struct fdefn)/sizeof(lispobj) - 1); - fdefn->raw_addr = - (u32) ((char *) LOW_WORD(fdefn->fun)) + FUN_RAW_ADDR_OFFSET; - return sizeof(struct fdefn) / sizeof(lispobj); - } - else - return 1; -} -#endif - - - -/* vector-like objects */ - -/* #define NWORDS(x,y) (CEILING((x),(y)) / (y)) */ - -static int -scav_vector(lispobj *where, lispobj object) -{ - if (HeaderValue(object) == subtype_VectorValidHashing) { - *where = - (subtype_VectorMustRehash<= (void *)end)) + return NULL; + return (gc_search_space(start, + (((lispobj *)pointer)+2)-start, + (lispobj *)pointer)); +} +lispobj * +search_static_space(void *pointer) +{ + lispobj* start = (lispobj*)STATIC_SPACE_START; + lispobj* end = (lispobj*)SymbolValue(STATIC_SPACE_FREE_POINTER,0); + if ((pointer < (void *)start) || (pointer >= (void *)end)) + return NULL; + return (gc_search_space(start, + (((lispobj *)pointer)+2)-start, + (lispobj *)pointer)); +} + +lispobj * +search_dynamic_space(void *pointer) +{ + lispobj *start = (lispobj *) current_dynamic_space; + lispobj *end = (lispobj *) dynamic_space_free_pointer; + if ((pointer < (void *)start) || (pointer >= (void *)end)) + return NULL; + return (gc_search_space(start, + (((lispobj *)pointer)+2)-start, + (lispobj *)pointer)); +} /* initialization. if gc_init can be moved to after core load, we could * combine these two functions */ @@ -563,7 +401,6 @@ void gc_init(void) { gc_init_tables(); - scavtab[SIMPLE_VECTOR_WIDETAG] = scav_vector; scavtab[WEAK_POINTER_WIDETAG] = scav_weak_pointer; } @@ -584,33 +421,29 @@ gc_initialize_pointers(void) /* noise to manipulate the gc trigger stuff */ +/* Functions that substantially change the dynamic space free pointer + * (collect_garbage, purify) are responsible also for resetting the + * auto_gc_trigger */ void set_auto_gc_trigger(os_vm_size_t dynamic_usage) { - os_vm_address_t addr=(os_vm_address_t)current_dynamic_space - + dynamic_usage; - - long length = DYNAMIC_SPACE_SIZE - dynamic_usage; - - if (addr < (os_vm_address_t)dynamic_space_free_pointer) { - fprintf(stderr, - "set_auto_gc_trigger: tried to set gc trigger too low! (%d < %p)\n", - (unsigned int)dynamic_usage, - (os_vm_address_t)dynamic_space_free_pointer - - (os_vm_address_t)current_dynamic_space); - lose("lost"); - } - else if (length < 0) { - fprintf(stderr, - "set_auto_gc_trigger: tried to set gc trigger too high! (%p)\n", - dynamic_usage); - lose("lost"); - } - - addr=os_round_up_to_page(addr); - length=os_trunc_size_to_page(length); - -#if defined(SUNOS) || defined(SOLARIS) - os_invalidate(addr,length); + os_vm_address_t addr; + os_vm_size_t length; + + addr = os_round_up_to_page((os_vm_address_t)current_dynamic_space + + dynamic_usage); + if (addr < (os_vm_address_t)dynamic_space_free_pointer) + lose("set_auto_gc_trigger: tried to set gc trigger too low! (%ld < 0x%08lx)\n", + (unsigned long)dynamic_usage, + (unsigned long)((os_vm_address_t)dynamic_space_free_pointer + - (os_vm_address_t)current_dynamic_space)); + + length = os_trunc_size_to_page(dynamic_space_size - dynamic_usage); + if (length < 0) + lose("set_auto_gc_trigger: tried to set gc trigger too high! (0x%08lx)\n", + (unsigned long)dynamic_usage); + +#if defined(SUNOS) || defined(SOLARIS) || defined(LISP_FEATURE_HPUX) + os_invalidate(addr, length); #else os_protect(addr, length, 0); #endif @@ -620,19 +453,62 @@ void set_auto_gc_trigger(os_vm_size_t dynamic_usage) void clear_auto_gc_trigger(void) { - if (current_auto_gc_trigger!=NULL){ -#if defined(SUNOS) || defined(SOLARIS)/* don't want to force whole space into swapping mode... */ - os_vm_address_t addr=(os_vm_address_t)current_auto_gc_trigger; - os_vm_size_t length= - DYNAMIC_SPACE_SIZE + (os_vm_address_t)current_dynamic_space - addr; + os_vm_address_t addr; + os_vm_size_t length; + + if (current_auto_gc_trigger == NULL) + return; - os_validate(addr,length); + addr = (os_vm_address_t)current_auto_gc_trigger; + length = dynamic_space_size + (os_vm_address_t)current_dynamic_space - addr; + +#if defined(SUNOS) || defined(SOLARIS) || defined(LISP_FEATURE_HPUX) + /* don't want to force whole space into swapping mode... */ + os_validate(addr, length); #else - os_protect((os_vm_address_t)current_dynamic_space, - DYNAMIC_SPACE_SIZE, - OS_VM_PROT_ALL); + os_protect(addr, length, OS_VM_PROT_ALL); #endif - current_auto_gc_trigger = NULL; + current_auto_gc_trigger = NULL; +} + +static boolean +gc_trigger_hit(void *addr) +{ + if (current_auto_gc_trigger == NULL) + return 0; + else{ + return (addr >= (void *)current_auto_gc_trigger && + addr <((void *)current_dynamic_space + dynamic_space_size)); + } +} + +boolean +cheneygc_handle_wp_violation(os_context_t *context, void *addr) +{ + if(!foreign_function_call_active && gc_trigger_hit(addr)){ + struct thread *thread=arch_os_get_current_thread(); + clear_auto_gc_trigger(); + /* Don't flood the system with interrupts if the need to gc is + * already noted. This can happen for example when SUB-GC + * allocates or after a gc triggered in a WITHOUT-GCING. */ + if (SymbolValue(GC_PENDING,thread) == NIL) { + if (SymbolValue(GC_INHIBIT,thread) == NIL) { + if (arch_pseudo_atomic_atomic(context)) { + /* set things up so that GC happens when we finish + * the PA section */ + SetSymbolValue(GC_PENDING,T,thread); + arch_set_pseudo_atomic_interrupted(context); + maybe_save_gc_mask_and_block_deferrables + (os_context_sigmask_addr(context)); + } else { + maybe_gc(context); + } + } else { + SetSymbolValue(GC_PENDING,T,thread); + } + } + return 1; } + return 0; }