This is sgbc.c in view mode; [Download] [Up]
/* Copyright William Schelter. All rights reserved. Stratified Garbage Collection (SGC) Write protects pages to tell which ones have been written to recently, for more efficient garbage collection. */ #ifdef BSD #include <sys/mman.h> #define PROT_READ_WRITE (PROT_READ | PROT_WRITE |PROT_EXEC) #endif #ifdef AIX3 #include <sys/vmuser.h> #define PROT_READ RDONLY #define PROT_READ_WRITE UDATAKEY int mprotect(); #endif #include <signal.h> void segmentation_catcher(); #define sgc_mark_pack_list(u) \ do {register object xtmp = u; \ while (xtmp != Cnil) \ {if (ON_WRITABLE_PAGE(xtmp)) xtmp->d.m = TRUE; \ sgc_mark_object(xtmp->c.c_car); \ xtmp=xtmp->c.c_cdr;}}while(0) #ifdef SDEBUG object sdebug; joe1(){;} #endif sgc_mark_cons(x) object x; { cs_check(x); /* x is already marked. */ BEGIN: #ifdef SDEBUG if(x==sdebug) joe1(); #endif sgc_mark_object(x->c.c_car); #ifdef OLD IF_WRITABLE(x->c.c_car, goto MARK_CAR;); goto MARK_CDR; MARK_CAR: if (x->c.c_car->c.m ==0) {if (type_of(x->c.c_car) == t_cons) { x->c.c_car->c.m = TRUE; sgc_mark_cons(x->c.c_car); } else sgc_mark_object1(x->c.c_car);} #endif MARK_CDR: x = x->c.c_cdr; IF_WRITABLE(x, goto WRITABLE_CDR;); return; WRITABLE_CDR: if (x->d.m) return; if (type_of(x) == t_cons) { x->c.m = TRUE; goto BEGIN; } sgc_mark_object1(x); } /* Whenever two arrays are linked together by displacement, if one is live, the other will be made live */ #define sgc_mark_displaced_field(ar) sgc_mark_object(ar->a.a_displaced) /* structures and arrays of type t, need to be marked if their bodies are not write protected even if the headers are. So we should keep these on pages particular to them. Actually we will change structure sets to touch the structure header, that way we won't have to keep the headers in memory. This takes only 1.47 as opposed to 1.33 microseconds per set. */ sgc_mark_object1(x) object x; { int i, j; object *p; char *cp; object y; cs_check(x); BEGIN: #ifdef SDEBUG if (x == OBJNULL || !ON_WRITABLE_PAGE(x)) return; IF_WRITABLE(x,goto OK); joe(); OK: if (x->d.m) return; if(x==sdebug) joe1(); #endif x->d.m = TRUE; switch (type_of(x)) { case t_fixnum: break; case t_ratio: sgc_mark_object(x->rat.rat_num); x = x->rat.rat_den; IF_WRITABLE(x,if(x->d.m==0) goto BEGIN); case t_shortfloat: break; case t_longfloat: break; case t_complex: sgc_mark_object(x->cmp.cmp_imag); x = x->cmp.cmp_real; IF_WRITABLE(x,if(x->d.m==0) goto BEGIN); case t_character: break; case t_symbol: IF_WRITABLE(x->s.s_plist,if(x->s.s_plist->d.m==0) {x->s.s_plist->d.m=TRUE; sgc_mark_cons(x->s.s_plist);}); sgc_mark_object(x->s.s_gfdef); sgc_mark_object(x->s.s_dbind); /* do {int xxx= (((int)(char *)(x->s.s_dbind)-0)>>12); if((xxx & (-16384) ==0) && (sgc_type_map[xxx] & (4 | 1))) {if((x->s.s_dbind)->d.m==0) sgc_mark_object1(x->s.s_dbind);}} while(0); */ if (x->s.s_self == NULL) break; /* to do */ if ((int)what_to_collect >= (int)t_contiguous) { if (inheap(x->s.s_self)) { if (what_to_collect == t_contiguous) mark_contblock(x->s.s_self, x->s.s_fillp); } else if(SGC_RELBLOCK_P(x->s.s_self)) x->s.s_self = copy_relblock(x->s.s_self, x->s.s_fillp); } break; case t_package: sgc_mark_object(x->p.p_name); sgc_mark_object(x->p.p_nicknames); sgc_mark_object(x->p.p_shadowings); sgc_mark_object(x->p.p_uselist); sgc_mark_object(x->p.p_usedbylist); if (what_to_collect != t_contiguous) break; if (x->p.p_internal != NULL) mark_contblock((char *)(x->p.p_internal), x->p.p_internal_size*sizeof(object)); if (x->p.p_external != NULL) mark_contblock((char *)(x->p.p_external), x->p.p_external_size*sizeof(object)); break; case t_cons: /* sgc_mark_object(x->c.c_car); x = x->c.c_cdr; goto BEGIN; */ sgc_mark_cons(x); break; case t_hashtable: sgc_mark_object(x->ht.ht_rhsize); sgc_mark_object(x->ht.ht_rhthresh); if (x->ht.ht_self == NULL) break; for (i = 0, j = x->ht.ht_size; i < j; i++) { sgc_mark_object(x->ht.ht_self[i].hte_key); sgc_mark_object(x->ht.ht_self[i].hte_value); } if ((short)what_to_collect >= (short)t_contiguous) { if (inheap(x->ht.ht_self)) { if (what_to_collect == t_contiguous) mark_contblock((char *)(x->ht.ht_self), j * sizeof(struct htent)); } else if(SGC_RELBLOCK_P(x->ht.ht_self)) x->ht.ht_self = (struct htent *) copy_relblock((char *)(x->ht.ht_self), j * sizeof(struct htent)); } break; case t_array: if ((x->a.a_displaced) != Cnil) sgc_mark_displaced_field(x); if ((int)what_to_collect >= (int)t_contiguous && x->a.a_dims != NULL) { if (inheap(x->a.a_dims)) { if (what_to_collect == t_contiguous) mark_contblock((char *)(x->a.a_dims), sizeof(int)*x->a.a_rank); } else if(SGC_RELBLOCK_P(x->a.a_dims)) x->a.a_dims = (int *) copy_relblock((char *)(x->a.a_dims), sizeof(int)*x->a.a_rank); } if ((enum aelttype)x->a.a_elttype == aet_ch) goto CASE_STRING; if ((enum aelttype)x->a.a_elttype == aet_bit) goto CASE_BITVECTOR; if ((enum aelttype)x->a.a_elttype == aet_object) goto CASE_GENERAL; CASE_SPECIAL: cp = (char *)(x->fixa.fixa_self); if (cp == NULL) break; /* set j to the size in char of the body of the array */ switch((enum aelttype)x->a.a_elttype){ case aet_lf: j= sizeof(longfloat)*x->lfa.lfa_dim; if (((int)what_to_collect >= (int)t_contiguous) && !(inheap(cp)) && SGC_RELBLOCK_P(x->a.a_self)) ROUND_RB_POINTERS_DOUBLE; break; case aet_char: case aet_uchar: j=sizeof(char)*x->a.a_dim; break; case aet_short: case aet_ushort: j=sizeof(short)*x->a.a_dim; break; default: j=sizeof(fixnum)*x->fixa.fixa_dim;} goto COPY; CASE_GENERAL: p = x->a.a_self; if (p == NULL) break; if (x->a.a_displaced->c.c_car == Cnil) for (i = 0, j = x->a.a_dim; i < j; i++) if (ON_WRITABLE_PAGE(&p[i])) sgc_mark_object(p[i]); cp = (char *)p; j *= sizeof(object); COPY: if ((int)what_to_collect >= (int)t_contiguous) { if (inheap(cp)) { if (what_to_collect == t_contiguous) mark_contblock(cp, j); } else if (!SGC_RELBLOCK_P(cp)) ; else if (x->a.a_displaced == Cnil) x->a.a_self = (object *)copy_relblock(cp, j); else if (x->a.a_displaced->c.c_car == Cnil) { i = (int)(object *)copy_relblock(cp, j) - (int)(x->a.a_self); adjust_displaced(x, i); } } break; case t_vector: if ((x->v.v_displaced) != Cnil) sgc_mark_displaced_field(x); if ((enum aelttype)x->v.v_elttype == aet_object) goto CASE_GENERAL; else goto CASE_SPECIAL; case t_bignum: if ((int)what_to_collect >= (int)t_contiguous) { j = x->big.big_length; cp = (char *)x->big.big_self; if (cp == NULL) break; if (j != lg(MP(x)) && /* we don't bother to zero this register, and its contents may get over written */ ! (x == big_register_1 && (int)(cp) <= top && (int) cp >= bot)) printf("bad length 0x%x ",x); j = j * sizeof(int); cp = (char *)MP(x); if (inheap(cp)) { if (what_to_collect == t_contiguous) mark_contblock(cp, j); } else x->big.big_self = (long *)copy_relblock(cp, j);} break; CASE_STRING: case t_string: if ((x->st.st_displaced) != Cnil) sgc_mark_displaced_field(x); j = x->st.st_dim; cp = x->st.st_self; if (cp == NULL) break; COPY_STRING: if ((int)what_to_collect >= (int)t_contiguous) { if (inheap(cp)) { if (what_to_collect == t_contiguous) mark_contblock(cp, j); } else if (!SGC_RELBLOCK_P(cp)) ; else if (x->st.st_displaced == Cnil) x->st.st_self = copy_relblock(cp, j); else if (x->st.st_displaced->c.c_car == Cnil) { i = copy_relblock(cp, j) - cp; adjust_displaced(x, i); } } break; CASE_BITVECTOR: case t_bitvector: if ((x->bv.bv_displaced) != Cnil) sgc_mark_displaced_field(x); /* We make bitvectors multiple of sizeof(int) in size allocated Assume 8 = number of bits in char */ #define W_SIZE (8*sizeof(int)) j= sizeof(int) * ((x->bv.bv_offset + x->bv.bv_dim + W_SIZE -1)/W_SIZE); cp = x->bv.bv_self; if (cp == NULL) break; goto COPY_STRING; case t_structure: sgc_mark_object(x->str.str_def); p = x->str.str_self; if (p == NULL) break; {object def=x->str.str_def; unsigned char * s_type = &SLOT_TYPE(def,0); unsigned short *s_pos= & SLOT_POS(def,0); for (i = 0, j = S_DATA(def)->length; i < j; i++) if (s_type[i]==0 && ON_WRITABLE_PAGE(& STREF(object,x,s_pos[i])) ) sgc_mark_object(STREF(object,x,s_pos[i])); if ((int)what_to_collect >= (int)t_contiguous) { if (inheap(x->str.str_self)) { if (what_to_collect == t_contiguous) mark_contblock((char *)p, S_DATA(def)->size); } else if(SGC_RELBLOCK_P(p)) x->str.str_self = (object *) copy_relblock((char *)p, S_DATA(def)->size); }} break; case t_stream: switch (x->sm.sm_mode) { case smm_input: case smm_output: case smm_io: case smm_probe: sgc_mark_object(x->sm.sm_object0); sgc_mark_object(x->sm.sm_object1); if (saving_system) {FILE *fp = x->sm.sm_fp; if (fp != 0 && fp != stdin && fp !=stdout ) {fclose(fp); x->sm.sm_fp=0; }} else if (what_to_collect == t_contiguous && x->sm.sm_fp && x->sm.sm_buffer) mark_contblock(x->sm.sm_buffer, BUFSIZ); break; case smm_synonym: sgc_mark_object(x->sm.sm_object0); break; case smm_broadcast: case smm_concatenated: sgc_mark_object(x->sm.sm_object0); break; case smm_two_way: case smm_echo: sgc_mark_object(x->sm.sm_object0); sgc_mark_object(x->sm.sm_object1); break; case smm_string_input: case smm_string_output: sgc_mark_object(x->sm.sm_object0); break; #ifdef USER_DEFINED_STREAMS case smm_user_defined: sgc_mark_object(x->sm.sm_object0); sgc_mark_object(x->sm.sm_object1); break; #endif default: error("mark stream botch"); } break; case t_random: break; case t_readtable: if (x->rt.rt_self == NULL) break; if (what_to_collect == t_contiguous) mark_contblock((char *)(x->rt.rt_self), RTABSIZE*sizeof(struct rtent)); for (i = 0; i < RTABSIZE; i++) { sgc_mark_object(x->rt.rt_self[i].rte_macro); if (x->rt.rt_self[i].rte_dtab != NULL) { /**/ if (what_to_collect == t_contiguous) mark_contblock((char *)(x->rt.rt_self[i].rte_dtab), RTABSIZE*sizeof(object)); for (j = 0; j < RTABSIZE; j++) sgc_mark_object(x->rt.rt_self[i].rte_dtab[j]); /**/ } } break; case t_pathname: sgc_mark_object(x->pn.pn_host); sgc_mark_object(x->pn.pn_device); sgc_mark_object(x->pn.pn_directory); sgc_mark_object(x->pn.pn_name); sgc_mark_object(x->pn.pn_type); sgc_mark_object(x->pn.pn_version); break; case t_cfun: case t_sfun: case t_vfun: case t_gfun: sgc_mark_object(x->cf.cf_name); sgc_mark_object(x->cf.cf_data); break; case t_cfdata: if (x->cfd.cfd_self != NULL) {int i=x->cfd.cfd_fillp; while(i-- > 0) sgc_mark_object(x->cfd.cfd_self[i]);} if (x->cfd.cfd_start == NULL) break; if (what_to_collect == t_contiguous) { if (!MAYBE_DATA_P((x->cfd.cfd_start)) || get_mark_bit((int *)(x->cfd.cfd_start))) break; mark_contblock(x->cfd.cfd_start, x->cfd.cfd_size);} break; case t_cclosure: sgc_mark_object(x->cc.cc_name); sgc_mark_object(x->cc.cc_env); sgc_mark_object(x->cc.cc_data); if (what_to_collect == t_contiguous) { if (x->cc.cc_turbo != NULL) mark_contblock((char *)(x->cc.cc_turbo-1), (1+fix(*(x->cc.cc_turbo-1)))*sizeof(object)); } break; case t_spice: break; case t_fat_string: mark_fat_string(x); break; case t_dclosure: break; default: #ifdef DEBUG if (debug) printf("\ttype = %d\n", type_of(x)); #endif error("mark botch"); } } sgc_mark_stack_carefully(top,bottom,offset) int *bottom,*top; {int p,m,pageoffset; object x; struct typemanager *tm; register int *j; /* if either of these happens we are marking the C stack and need to use a local */ if (top==0) top = (int *) &top ; if (bottom==0) bottom= (int *)⊤ /* On machines which align local pointers on multiple of 2 rather than 4 we need to mark twice */ if (offset) {sgc_mark_stack_carefully(bottom,(((char *) top) +offset),0);} for (j=top ; j >= bottom ; j--) {if (VALID_DATA_ADDRESS_P(*j) && type_map[(p=page(*j))]< (char)t_end) {pageoffset=((char *)*j - pagetochar(p)); tm=tm_of((enum type) type_map[p]); x= (object) ((char *)(*j) - ((pageoffset=((char *)*j - pagetochar(p))) % tm->tm_size)); if ((pageoffset < (tm->tm_size * tm->tm_nppage)) && (m=x->d.m) != FREE) {if (m==TRUE) continue; if (m!=0) {fprintf(stdout, "**bad value %d of d.m in gbc page %d skipping mark**" ,m,p);fflush(stdout); continue; }; sgc_mark_object(x);}}}} sgc_mark_phase() { STATIC object *p; STATIC int i, j, k, n; STATIC struct package *pp; STATIC object s, l, *lp; STATIC bds_ptr bdp; STATIC frame_ptr frp; STATIC ihs_ptr ihsp; STATIC char *cp; sgc_mark_object(Cnil); sgc_mark_object(Ct); /* mark all non recent data on writable pages */ {int t,i=page(heap_end); struct typemanager *tm; char *p; while (--i >= 0) {if (WRITABLE_PAGE_P(i) && (t=type_map[i]) < (int) t_end); else continue; tm=tm_of(t); p=pagetochar(i); if ( t == t_cons) for (j = tm->tm_nppage; --j >= 0; p += sizeof(struct cons)) {object x = (object) p; if (SGC_OR_M(x)) continue; if (x->d.t==t_cons) {x->d.m = TRUE; sgc_mark_cons(x);} else sgc_mark_object1(x); } else {int size=tm->tm_size; for (j = tm->tm_nppage; --j >= 0; p += size) {object x = (object) p; if (SGC_OR_M(x)) continue; sgc_mark_object1(x); }}}} sgc_mark_stack_carefully(vs_top-1,vs_org,0); clear_stack(vs_top,vs_limit); sgc_mark_stack_carefully(MVloc,MVloc+(sizeof(MVloc)/sizeof(object)),0); /* for (p = vs_org; p < vs_top; p++) { if (p && (inheap(*p))) sgc_mark_object(*p); } */ #ifdef DEBUG if (debug) { printf("value stack marked\n"); fflush(stdout); } #endif for (bdp = bds_org; bdp<=bds_top; bdp++) { sgc_mark_object(bdp->bds_sym); sgc_mark_object(bdp->bds_val); } for (frp = frs_org; frp <= frs_top; frp++) sgc_mark_object(frp->frs_val); for (ihsp = ihs_org; ihsp <= ihs_top; ihsp++) sgc_mark_object(ihsp->ihs_function); for (i = 0; i < mark_origin_max; i++) sgc_mark_object(*mark_origin[i]); for (i = 0; i < mark_origin_block_max; i++) for (j = 0; j < mark_origin_block[i].mob_size; j++) sgc_mark_object(mark_origin_block[i].mob_addr[j]); for (pp = pack_pointer; pp != NULL; pp = pp->p_link) sgc_mark_object((object)pp); #ifdef KCLOVM if (ovm_process_created) sgc_mark_all_stacks(); #endif if (debug) { printf("symbol navigation\n"); fflush(stdout); } {int size; for (pp = pack_pointer; pp != NULL; pp = pp->p_link) { size = pp->p_internal_size; if (pp->p_internal != NULL) for (i = 0; i < size; i++) sgc_mark_pack_list(pp->p_internal[i]); size = pp->p_external_size; if (pp->p_external != NULL) for (i = 0; i < size; i++) sgc_mark_pack_list(pp->p_external[i]); }} mark_c_stack(0,N_RECURSION_REQD,sgc_mark_stack_carefully); } sgc_sweep_phase() { STATIC int i, j, k; STATIC object x; STATIC char *p; STATIC int *ip; STATIC struct typemanager *tm; STATIC object f; int size; Cnil->s.m = FALSE; Ct->s.m = FALSE; #ifdef DEBUG if (debug) printf("type map\n"); #endif for (i = 0; i < maxpage; i++) { if (type_map[i] == (int)t_contiguous) { if (debug) { printf("-"); /* fflush(stdout); */ continue; } } if (type_map[i] >= (int)t_end) continue; tm = tm_of((enum type)type_map[i]); /* general sweeper */ #ifdef DEBUG if (debug) { printf("%c", tm->tm_name[0]); /* fflush(stdout); */ } #endif if (!WRITABLE_PAGE_P(i)) continue; p = pagetochar(i); f = tm->tm_free; k = 0; size=tm->tm_size; if (SGC_PAGE_P(i)) { for (j = tm->tm_nppage; --j >= 0; p += size) { x = (object)p; if (x->d.m == FREE) continue; else if (x->d.m) { x->d.m = FALSE; continue; } if(x->d.s == SGC_NORMAL) continue; /* it is ok to free x */ #ifdef OLD_DISPLACE /* old_displace: from might be free, to not */ if(x->d.t >=t_array && x->d.t <= t_bitvector) { /* case t_array: case t_vector: case t_string: case t_bitvector: */ if (x->a.a_displaced->c.c_car != Cnil) {undisplace(x); /* The cons x->a.a_displaced cons has been saved, so as to save the pointer to x->a.a_displaced->c.c_car; However any arrays in its cdr, must have been freed, or we would not be freeing x. To avoid having a cons with trash in the cdr we set the cdr to nil */ x->a.a_displaced->c.c_cdr = Cnil;} } #endif OLD_DISPLACE ((struct freelist *)x)->f_link = f; x->d.m = FREE; x->d.s = (int)SGC_RECENT; f = x; k++; } tm->tm_free = f; tm->tm_nfree += k; } else /*non sgc_page */ for (j = tm->tm_nppage; --j >= 0; p += size) { x = (object)p; if (x->d.m == TRUE) x->d.m=FALSE; } NEXT_PAGE: ; } #ifdef DEBUG if (debug) { putchar('\n'); fflush(stdout); } #endif } sgc_contblock_sweep_phase() { STATIC int i, j; STATIC char *s, *e, *p, *q; STATIC struct contblock *cbp; cb_pointer = NULL; ncb = 0; for (i = 0; i < maxpage;) { if (type_map[i] != (int)t_contiguous || !SGC_PAGE_P(i)) { i++; continue; } for (j = i+1; j < maxpage && type_map[j] == (int)t_contiguous && SGC_PAGE_P(j) ; j++) ; s = pagetochar(i); e = pagetochar(j); for (p = s; p < e;) { if (get_mark_bit((int *)p)) { p += 4; continue; } q = p + 4; while (q < e) { if (!get_mark_bit((int *)q)) { q += 4; continue; } break; } insert_contblock(p, q - p); p = q + 4; } i = j + 1; } #ifdef DEBUG if (debug) { for (cbp = cb_pointer; cbp != NULL; cbp = cbp->cb_link) printf("%d-byte contblock\n", cbp->cb_size); fflush(stdout); } #endif } #define PAGE_ROUND_UP(adr) \ ((char *)(PAGESIZE*(((int)(adr)+PAGESIZE -1) >> PAGEWIDTH))) char *old_rb_pointer; char *old_rb_start; #undef tm int bug1,bug2; #ifdef SDEBUG sgc_count(yy) object yy; {int count=0; object y=yy; while(y) {count++; y=F_LINK(y);} printf("[length %x = %d]",yy,count); fflush(stdout); } #endif /* count writable pages excluding the hole */ sgc_count_writable(end) int end; { int j = first_protectable_page -1; int count = 0; int hp_end= page(heap_end); while(j++ < hp_end) if (WRITABLE_PAGE_P(j)) count++; j= page(rb_start); while(j++ < end) if (WRITABLE_PAGE_P(j)) count++; return count;} sgc_count_type(t) int t; {int j = first_protectable_page -1; int end = page(core_end); int count=0; while(j++ < end) if (type_map[j]==t && SGC_PAGE_P(j)) count++; return count;} sgc_start() {int i; int np; int bug; short free_map[MAXPAGE]; object f, fr[(int)t_end]; struct typemanager *tm; int npages; if (sgc_type_map[page((&sgc_type_map[0]))] != SGC_PERM_WRITABLE ) {perm_writable(&sgc_type_map[0],sizeof(sgc_type_map)); } if (sgc_enabled) return 1; sgc_type_map[0]=0; AGAIN: i=npages=page(core_end); while (i--> 0) sgc_type_map[i] = sgc_type_map[i] & SGC_PERM_WRITABLE ; for (i= t_start; i < t_contiguous ; i++) if (TM_BASE_TYPE_P(i) && (np=(tm=tm_of(i))->tm_sgc)) FIND_FREE_PAGES: { int maxp=0; int j; int minfree = tm->tm_sgc_minfree; int count,tm_sgc; bzero(free_map,npages*sizeof(short)); f = tm->tm_free; count=0; while (f!=0) {free_map[j=page(f)]++; if (j>=maxp) maxp=j; #ifdef DEBUG count++; #endif f= F_LINK(f); } #ifdef DEBUG if (count!=tm->tm_nfree) {printf("[Count differed type(%d)nfree= %d in freelist %d]\n" ,tm->tm_type,tm->tm_nfree, count);fflush(stdout);} #endif for(j=0,count=0; j <= maxp ;j++) {if (free_map[j] >= minfree) {sgc_type_map[j] |= (SGC_PAGE_FLAG | SGC_TEMP_WRITABLE); ++count; if (count >= tm->tm_sgc_max) break; }} /* don't do any more allocations for this type if saving system */ if (saving_system) continue; if (count < tm->tm_sgc) /* try to get some more free pages of type i */ { int n = tm->tm_sgc - count; int again=0,nfree = tm->tm_nfree; char *p=alloc_page(n); if (tm->tm_nfree > nfree) again=1; /* gc freed some objects */ while (n-- > 0) {(sgc_enabled=1,add_page_to_freelist(p,tm),sgc_enabled=0); p += PAGESIZE;} if (again) goto FIND_FREE_PAGES; }} /* Now allocate the sgc relblock. We do this as the tail end of the ordinary rb. */ {int want; char *new; tm=tm_of(t_relocatable); want =((int) (rb_end - rb_pointer) >> PAGEWIDTH); if (want < tm->tm_sgc) want = tm->tm_sgc; FINALE: {old_rb_start=rb_start; if(!saving_system) { new=alloc_relblock(want*PAGESIZE); new= PAGE_ROUND_UP(new); /* old_rb_pointer=new; */ rb_start=rb_pointer=new; }}} /* the relblock has been allocated */ /* now move the sgc free lists into place. alt_free should contain the others */ for (i= t_start; i < t_contiguous ; i++) if ((bug1= TM_BASE_TYPE_P(i)) && (np=(tm=tm_of(i))->tm_sgc)) {object f=tm->tm_free ,x,y,next; int count=0; x=y=0; bug2=(tm_table[i].tm_type == (enum type) i); while (f!=0) {next=F_LINK(f); #ifdef SDEBUG if (f->d.m!=FREE) printf("Not FREE in freelist f=%d",f); #endif if (ON_SGC_PAGE(f)) { F_LINK(f) =x; f->d.s = SGC_RECENT; x=f; count++; } else {F_LINK(f)=y; f->d.s = SGC_NORMAL; y=f;} f=next; } tm->tm_free = x; tm->tm_alt_free = y; tm->tm_alt_nfree = tm->tm_nfree - count; tm->tm_nfree=count; } /* Whew. We have now allocated the sgc space and modified the tm_table; Turn memory protection on for the pages which are writable. */ memory_protect(1); sgc_enabled=1; if(siVnotify_gbc->s.s_dbind != Cnil) {printf("[SGC on]"); fflush(stdout);} } sgc_quit() { struct typemanager *tm; int i,np; memory_protect(0); if(siVnotify_gbc->s.s_dbind != Cnil) {printf("[SGC off]"); fflush(stdout);} if (sgc_enabled==0) return 0; sgc_enabled=0; rb_start = old_rb_start; for (i= t_start; i < t_contiguous ; i++) if (TM_BASE_TYPE_P(i)) {tm=tm_of(i); if (np=tm->tm_sgc) {object f,y; f=tm->tm_free; if (f==0) tm->tm_free=tm->tm_alt_free; else /* tack the alt_free onto the end of free */ { #ifdef SDEBUG int count=0; f=tm->tm_free; while(y= F_LINK(f)) {if(y->d.s != SGC_RECENT) printf("[bad %d]",y); count++; f=y;} count=0; if (f=tm->tm_alt_free) while(y= F_LINK(f)) { if(y->d.s != SGC_NORMAL) printf("[alt_bad %d]",y); count++; f=y;} #endif f=tm->tm_free; while(y= F_LINK(f)) f=y; F_LINK(f)=tm->tm_alt_free; } /* tm->tm_free has all of the free objects */ tm->tm_nfree += tm->tm_alt_nfree; tm->tm_alt_nfree = 0; tm->tm_alt_free = 0; /* remove the recent flag from any objects on sgc pages */ {int hp=page(heap_end); int i,j; char t = (char) tm->tm_type; char *p; for (i=0 ; i < hp; i++) if (type_map[i]==t && (sgc_type_map[i] & SGC_PAGE_FLAG)) for (p= pagetochar(i),j = tm->tm_nppage; j > 0; --j, p += tm->tm_size) {((object) p)->d.s = SGC_NORMAL;}} }} } void make_writable(beg,i) int beg,i; {if (i > beg) {beg=ROUND_DOWN_PAGE_NO(beg); i=ROUND_UP_PAGE_NO(i); {int k=beg; while(k <i ) sgc_type_map[k++] |= SGC_TEMP_WRITABLE; } sgc_mprotect(beg, i-beg, SGC_WRITABLE); ;} } int debug_fault =0; int fault_count =0; extern char *etext; void memprotect_handler(sig, code, scp, addr) int sig, code; struct sigcontext *scp; char *addr; {int p; int j=page_multiple; #ifdef GET_FAULT_ADDR addr=GET_FAULT_ADDR(sig,code,scp,addr); debug_fault = (int) addr; #ifdef DEBUG_MPROTECT printf("fault:0x%x [%d] (%d)",addr,page(addr),addr >= core_end); #endif if (addr >= core_end || (unsigned int)addr < DBEGIN) {if (fault_count > 300) error("fault count to high"); fault_count ++; INSTALL_MPROTECT_HANDLER; return;} #endif p = page(addr); p = ROUND_DOWN_PAGE_NO(p); if (p >= first_protectable_page && addr < core_end && !(WRITABLE_PAGE_P(p))) {/* CHECK_RANGE(p,1); */ #ifdef DEBUG_MPROTECT printf("mprotect(0x%x,%x,0x%x)\n",pagetochar(p),page_multiple * PAGESIZE, sbrk(0)); fflush(stdout); #endif mprotect(pagetochar(p),page_multiple * PAGESIZE, PROT_READ_WRITE); while (--j >= 0) sgc_type_map[p+j]= sgc_type_map[p+j] | SGC_TEMP_WRITABLE; #ifndef BSD INSTALL_MPROTECT_HANDLER; #endif return; } #ifndef BSD INSTALL_MPROTECT_HANDLER; #endif /* if (SIGSEGV == SIGPROTV) */ END: segmentation_catcher(); return; } sgc_mprotect(pbeg,n,writable) { /* CHECK_RANGE(pbeg,n); */ #ifdef DEBUG_MPROTECT printf("prot[%d,%d,(%d),%s]\n",pbeg,pbeg+n,writable & SGC_WRITABLE, (writable & SGC_WRITABLE ? "writable" : "not writable")); fflush(stdout); #endif if(mprotect(pagetochar(pbeg),n*PAGESIZE, (writable & SGC_WRITABLE ? PROT_READ_WRITE : PROT_READ))) FEerror("Couldn't protect");} /* for page numbers from beg below end, if one page in a a page_multiple grouping is writable,the rest must be */ fix_for_page_multiple(beg,end) {int i,j; char *p; int writable; beg = ROUND_DOWN_PAGE_NO(beg); for (i = beg ; i < end; i = i+ page_multiple){ p = sgc_type_map + i; j = page_multiple; writable = ((*p++) & SGC_WRITABLE); if (writable) /* all pages must be */ { while (--j) if (((*p++) & SGC_WRITABLE) == 0) goto FIXIT;} else { while (--j) if ((*p++) & SGC_WRITABLE ) goto FIXIT;} continue; FIXIT: j = page_multiple; p = sgc_type_map + i; while (--j >= 0 ) { (*p++) |= SGC_WRITABLE;}}} memory_protect(on) int on; { int i,beg,end= page(core_end); int writable=1; extern void install_segmentation_catcher(); if (first_protectable_page==0) { for (i=page_multiple; i< maxpage ; i++) if (type_map[i]!=t_other) break; else { /* We want page(0) to be non writable since that is the only check for 0 pointer in sgc */ sgc_type_map[i] = SGC_PERM_WRITABLE;} first_protectable_page= ROUND_DOWN_PAGE_NO(i);} if(page_multiple > 1) fix_for_page_multiple(first_protectable_page,end); /* turning it off */ if (on==0) {sgc_mprotect((first_protectable_page), (end - first_protectable_page), SGC_WRITABLE); install_segmentation_catcher(); return;} /* write protect some pages by first write protecting them all and then selectively disabling */ /* sgc_mprotect((first_protectable_page), (end - first_protectable_page), 0); */ INSTALL_MPROTECT_HANDLER; beg=first_protectable_page; writable = WRITABLE_PAGE_P(beg); for (i=beg ; ++i<= end; ) {int wri = WRITABLE_PAGE_P(i); if ((wri==0 && writable) || (writable ==0 && wri) || i == end) /* it is changing */ {if (writable) make_writable(beg,i); else sgc_mprotect(beg,i-beg,writable); writable = wri; beg = i;} } } void siLsgc_on() {if (vs_base==vs_top) {vs_base[0]=(sgc_enabled ? Ct :Cnil); vs_top=vs_base+1; return;} check_arg(1); if(vs_base[0]==Cnil) {sgc_quit();} else {sgc_start();}} /* make permanently writable pages containing pointers p thru p+n-1 */ void perm_writable(p,n) char *p; int n; {int beg=page(p); int end=page(PAGE_ROUND_UP(p+n)); int i,must_protect=0; beg = ROUND_DOWN_PAGE_NO(beg); end = ROUND_UP_PAGE_NO(end); for (i=beg ; i < end ; i++) {if (sgc_enabled & !(WRITABLE_PAGE_P(i))) must_protect = 1; sgc_type_map [i] |= SGC_PERM_WRITABLE;} if(must_protect) make_writable(beg,end);} system_error() {FEerror("System error");}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.