X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fcheneygc.c;h=10b4d4af3c9595df2f476591f633c7e2ddcc00a7;hb=ab9c6bbaaa409e815a1c9696885c9621b429aed6;hp=4948da85d0e69a469da9deb6e0e42bec2bad62de;hpb=e01e7a01b67b98a47730a08dfa5d0d58518486ea;p=sbcl.git diff --git a/src/runtime/cheneygc.c b/src/runtime/cheneygc.c index 4948da8..10b4d4a 100644 --- a/src/runtime/cheneygc.c +++ b/src/runtime/cheneygc.c @@ -30,6 +30,7 @@ #include "genesis/static-symbols.h" #include "genesis/primitive-objects.h" #include "thread.h" +#include "arch.h" /* So you need to debug? */ #if 0 @@ -47,10 +48,6 @@ lispobj *new_space; lispobj *new_space_free_pointer; static void scavenge_newspace(void); -static void scavenge_interrupt_contexts(void); -extern struct interrupt_data * global_interrupt_data; - -extern unsigned long bytes_consed_between_gcs; /* collecting garbage */ @@ -60,37 +57,12 @@ 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) -{ - lispobj *ptr = 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(long 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/N_WORD_BYTES); return new; @@ -110,7 +82,7 @@ lispobj copy_large_object(lispobj object, long 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; @@ -121,30 +93,25 @@ collect_garbage(unsigned ignore) #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(); - struct interrupt_data *data= - th ? th->interrupt_data : global_interrupt_data; - #ifdef PRINTNOISE printf("[Collecting garbage ... \n"); - + getrusage(RUSAGE_SELF, &start_rusage); gettimeofday(&start_tv, (struct timezone *) 0); #endif - - /* it's possible that signals are blocked already if this was called + + /* it's possible that signals are blocked already if this was called * from a signal handler (e.g. with the sigsegv gc_trigger stuff) */ - sigemptyset(&tmp); - sigaddset_blockable(&tmp); - sigprocmask(SIG_BLOCK, &tmp, &old); + block_blockable_signals(0, &old); current_static_space_free_pointer = - (lispobj *) ((unsigned long) - SymbolValue(STATIC_SPACE_FREE_POINTER,0)); + (lispobj *) ((unsigned long) + SymbolValue(STATIC_SPACE_FREE_POINTER,0)); /* Set up from space and new space pointers. */ @@ -154,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; @@ -173,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 *) data->interrupt_handlers, - sizeof(data->interrupt_handlers) / sizeof(lispobj)); - + scavenge((lispobj *) interrupt_handlers, + sizeof(interrupt_handlers) / sizeof(lispobj)); + /* _size quantities are in units of sizeof(lispobj) - i.e. 4 */ - control_stack_size = - current_control_stack_pointer- - (lispobj *)th->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 *)th->control_stack_start), - control_stack_size); + ((lispobj *)th->control_stack_start), + control_stack_size); #endif scavenge(((lispobj *)th->control_stack_start), control_stack_size); - - binding_stack_size = - current_binding_stack_pointer - - (lispobj *)th->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", - th->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 *)th->binding_stack_start), binding_stack_size); - - static_space_size = - current_static_space_free_pointer - (lispobj *) STATIC_SPACE_START; + + 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(); @@ -227,21 +194,30 @@ 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 - /* Maybe FIXME: it's possible that we could significantly reduce - * RSS by zeroing the from_space or madvise(MADV_DONTNEED) or + /* 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); + (os_vm_size_t) dynamic_space_size); current_dynamic_space = new_space; dynamic_space_free_pointer = new_space_free_pointer; @@ -257,9 +233,9 @@ collect_garbage(unsigned ignore) #ifdef PRINTNOISE printf("Zeroing empty part of control stack ...\n"); #endif - zero_stack(); + scrub_control_stack(); set_auto_gc_trigger(size_retained+bytes_consed_between_gcs); - sigprocmask(SIG_SETMASK, &old, 0); + thread_sigmask(SIG_SETMASK, &old, 0); #ifdef PRINTNOISE @@ -267,22 +243,22 @@ 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); printf("Statistics: %10.2fs real, %10.2fs user, %10.2fs system.\n", - real_time, user_time, system_time); + 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 } @@ -297,143 +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 on 32-bit platforms; - 0x7FFFFFFFFFFFFFFF on 64-bit platforms */ - lip_offset = (((unsigned long)1) << (N_WORD_BITS - 1)) - 1; - 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<interrupt_contexts[i]; - scavenge_interrupt_context(context); - } -} - - /* debugging code */ void @@ -447,71 +296,57 @@ print_garbage(lispobj *from_space, lispobj *from_space_free_pointer) total_words_not_copied = 0; start = from_space; while (start < from_space_free_pointer) { - lispobj object; - int forwardp, type, nwords; - lispobj header; - - object = *start; - forwardp = is_lisp_pointer(object) && new_space_p(object); - - if (forwardp) { - int tag; - lispobj *pointer; - - tag = lowtag_of(object); - - switch (tag) { - case LIST_POINTER_LOWTAG: - nwords = 2; - break; - case INSTANCE_POINTER_LOWTAG: - printf("Don't know about instances yet!\n"); - nwords = 1; - break; - case FUN_POINTER_LOWTAG: - nwords = 1; - break; - case OTHER_POINTER_LOWTAG: - pointer = (lispobj *) native_pointer(object); - header = *pointer; - type = widetag_of(header); - nwords = (sizetab[type])(pointer); - break; - default: nwords=1; /* shut yer whinging, gcc */ - } - } else { - type = widetag_of(object); - nwords = (sizetab[type])(start); - total_words_not_copied += nwords; - printf("%4d words not copied at 0x%16lx; ", - nwords, (unsigned long) start); - printf("Header word is 0x%08x\n", - (unsigned int) object); - } - start += nwords; + lispobj object; + int forwardp, type, nwords; + lispobj header; + + object = *start; + forwardp = is_lisp_pointer(object) && new_space_p(object); + + if (forwardp) { + int tag; + lispobj *pointer; + + tag = lowtag_of(object); + + switch (tag) { + case LIST_POINTER_LOWTAG: + nwords = 2; + break; + case INSTANCE_POINTER_LOWTAG: + printf("Don't know about instances yet!\n"); + nwords = 1; + break; + case FUN_POINTER_LOWTAG: + nwords = 1; + break; + case OTHER_POINTER_LOWTAG: + pointer = (lispobj *) native_pointer(object); + header = *pointer; + type = widetag_of(header); + nwords = (sizetab[type])(pointer); + break; + default: nwords=1; /* shut yer whinging, gcc */ + } + } else { + type = widetag_of(object); + nwords = (sizetab[type])(start); + total_words_not_copied += nwords; + printf("%4d words not copied at 0x%16lx; ", + nwords, (unsigned long) start); + printf("Header word is 0x%08x\n", + (unsigned int) object); + } + start += nwords; } printf("%d total words not copied.\n", total_words_not_copied); } -/* vector-like objects */ - -static long -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)); + return NULL; + return (gc_search_space(start, + (((lispobj *)pointer)+2)-start, + (lispobj *)pointer)); } lispobj * @@ -541,10 +376,10 @@ 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)); + return NULL; + return (gc_search_space(start, + (((lispobj *)pointer)+2)-start, + (lispobj *)pointer)); } lispobj * @@ -553,10 +388,10 @@ 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)); + 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 @@ -566,7 +401,6 @@ void gc_init(void) { gc_init_tables(); - scavtab[SIMPLE_VECTOR_WIDETAG] = scav_vector; scavtab[WEAK_POINTER_WIDETAG] = scav_weak_pointer; } @@ -588,34 +422,28 @@ 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 resettting the + * (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! (%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)); - lose("lost"); - } - else if (length < 0) { - fprintf(stderr, - "set_auto_gc_trigger: tried to set gc trigger too high! (0x%08lx)\n", - (unsigned long)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 @@ -625,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; }