memory.c
Go to the documentation of this file.
00001 /****************************************************************/
00002 /* memory.c:    memory manager for eulisp                       */
00003 /*      Copyright(c) Toshihiro MATSUI
00004 /*                   Electrotechnical Laboratory,1986.
00005 /****************************************************************/
00006 static char *rcsid="@(#)$Id$";
00007 
00008 #if vxworks
00009 #include        <sys/types.h>
00010 #else
00011 #include        <sys/types.h>
00012 #include        <sys/times.h>
00013 #endif
00014 
00015 #if alpha
00016 #include        <stdlib.h>
00017 #include        <unistd.h>
00018 #endif
00019 
00020 #include        "eus.h"
00021 #if Solaris2
00022 #include        <synch.h>
00023 #include        <thread.h>
00024 #endif
00025 
00026 #if 0 /* moved to eus.h */
00027 #define nextbuddy(p) ((bpointer)((eusinteger_t)p+(buddysize[p->h.bix]*sizeof(pointer))))
00028 #define marked(p)  (p->h.mark)
00029 #define markon(p)  p->h.mark=1
00030 #define markoff(p) p->h.mark=0
00031 #endif
00032 #define myctx (euscontexts[thr_self()])
00033 
00034 /* Written by I.Hara 01/12/95 */
00035 #if Solaris2 || Linux
00036 extern eusinteger_t _end();
00037 #elif SunOS4_1
00038 extern edata;
00039 #else
00040 extern edata(),_end();
00041 #endif
00042 
00043 #if alpha
00044 static eusinteger_t top_addr, bottom_addr;
00045 #endif
00046 
00047 extern pointer QPARAGC;
00048 extern pointer K_DISPOSE;
00049 
00050 char *maxmemory=(char *)0x0;
00051 #if (WORD_SIZE == 64)
00052 char *minmemory=(char *)0xffffffffffffffff;
00053 #else
00054 char *minmemory=(char *)0xffffffff;
00055 #endif
00056 long freeheap=0,totalheap=0;    /*size of heap left and allocated*/
00057 struct chunk *chunklist=NULL;
00058 /* timers */
00059 long gccount,marktime,sweeptime;
00060 long alloccount[MAXBUDDY];
00061 
00062 /*disposal processing*/
00063 #define MAXDISPOSE 256
00064 static  pointer dispose[MAXDISPOSE];
00065 static  int dispose_count;
00066 
00067 int newchunk(k)
00068 register int k;
00069 { register int s;
00070   register struct chunk *cp;  
00071   eusinteger_t tail;
00072 #if defined(BIX_DEBUG) || defined(DEBUG_COUNT)
00073   static int count = 0;
00074 
00075   count++;
00076 #endif
00077 //      fprintf(stderr, "\x1b[1;31mnewchunk(%d)\x1b[0m\n", k);
00078   if (k<DEFAULTCHUNKINDEX) k=DEFAULTCHUNKINDEX;
00079   if (QDEBUG && debug) fprintf(stderr,";; newchunk: k=%d\n",k);
00080   s=buddysize[k];
00081   cp=(struct chunk *)((long)malloc((s+2)*sizeof(pointer)+(sizeof(pointer)-1)) & ~(sizeof(pointer)-1));
00082 #if defined(RGC)
00083   set_heap_range((unsigned int)cp,
00084       (unsigned int)cp + (s+2)*sizeof(pointer)+(sizeof(pointer)-1));
00085 #endif
00086 #if Linux || Cygwin || Darwin
00087   if (minmemory > (char *)cp) minmemory = (char *)cp;
00088   if (maxmemory < (char *)sbrk(0)) maxmemory = (char *)sbrk(0);
00089   if (maxmemory < (char *)cp+(s+2)*sizeof(pointer)+(sizeof(pointer)-1)) maxmemory = ((char *)cp+(s+2)*sizeof(pointer)+(sizeof(pointer)-1));
00090 #else
00091   maxmemory=(char *)sbrk(0);
00092 #endif
00093   if (QDEBUG && debug) fprintf(stderr,";; maxmemory=%p\n",maxmemory);
00094   if (cp==NULL) return(ERR);    /*can't allocate new memory*/
00095 #if alpha
00096   if( chunklist == NULL ) {
00097     top_addr = (eusinteger_t)cp;
00098 /*printf( "first topaddr = 0x%lx\n", top_addr );*/
00099 }
00100   if( (eusinteger_t)cp < top_addr ) {
00101     top_addr = (eusinteger_t)chunklist;
00102 /*printf( "topaddr = 0x%lx\n", top_addr );*/
00103 }
00104 #endif
00105   
00106 #if defined(RGC)// && !defined(__USE_MARK_BITMAP)
00107   /* sort by address */
00108   if (chunklist == NULL) {
00109     cp->nextchunk = NULL;
00110     chunklist = cp;
00111   } else {
00112     struct chunk *ccp;
00113     for (ccp = chunklist; ccp->nextchunk < cp && ccp->nextchunk != NULL; 
00114         ccp = ccp->nextchunk);
00115     cp->nextchunk = ccp->nextchunk;
00116     ccp->nextchunk = cp;
00117   }
00118 #else
00119   cp->nextchunk=chunklist;      /*link to chunk list*/
00120   chunklist=cp;
00121 #endif
00122 
00123   cp->chunkbix=k;
00124   cp->rootcell.h.mark=0;
00125   cp->rootcell.h.smark=0;
00126   cp->rootcell.h.pmark=0;
00127   cp->rootcell.h.b=1;           /*initial buddy marks*/
00128   cp->rootcell.h.m=0;
00129   cp->rootcell.h.nodispose=0;
00130   cp->rootcell.h.bix=k;
00131 #ifndef RGC
00132   cp->rootcell.b.nextbcell=0;
00133 #else
00134   cp->rootcell.b.nextbcell = buddy[k].bp;
00135 #endif
00136 #if alpha
00137   tail = (eusinteger_t)cp + (s+2)*sizeof(pointer);
00138   if( tail > bottom_addr ) {
00139     bottom_addr = tail;
00140 /*printf( "bottom_addr = 0x%lx\n", bottom_addr );*/
00141 }
00142 #endif
00143 #ifdef RGC
00144   /* the color of free cells are GRAY */
00145   cp->rootcell.h.bix |= FREETAG;
00146   cp->rootcell.h.cix = -1; /* free tag */
00147   if((char *)cp < minmemory)
00148     minmemory = (char *)cp;
00149 #endif
00150   cp->rootcell.h.cix = -1; /* free tag */
00151   buddy[k].bp= &cp->rootcell;
00152   buddy[k].count++;
00153   totalheap += s; freeheap += s;
00154   return(k);
00155   }
00156 
00157 void splitheap(k,buddy) /*heart of the allocator*/
00158 register int k;
00159 register struct buddyfree *buddy;
00160 { register bpointer b1,b2,bnext;
00161 #if defined(BIX_DEBUG) || defined(DEBUG_COUNT)
00162   static int count;
00163 
00164   count++;
00165 #endif
00166 
00167   b1= buddy[k].bp;      /*root buddy pointer*/
00168   bnext=b1->b.nextbcell;
00169   buddy[k].bp= bnext;   /*remove first element*/
00170   buddy[k].count--;
00171   b2= (bpointer)((long)b1+buddysize[k-1]*sizeof(pointer));
00172   if (k==2) {   /*b1 and b2 are of the same size*/
00173     b1->b.nextbcell=b2;
00174     b2->b.nextbcell=buddy[k-1].bp;
00175     buddy[k-1].bp=b1;
00176     buddy[k-1].count +=2;
00177 #ifdef RGC
00178     b2->h.bix = 1 | FREETAG;
00179     b2->h.cix = -1; /* free tag */
00180 #else
00181     b2->h.bix= 1;
00182     b2->h.cix = -1; /* free tag */
00183 #endif
00184   } else {
00185     b1->b.nextbcell= buddy[k-1].bp;
00186     buddy[k-1].bp=b1;
00187     buddy[k-1].count++;
00188     b2->b.nextbcell=buddy[k-2].bp;
00189     buddy[k-2].bp=b2;
00190     buddy[k-2].count++;
00191 #ifdef RGC
00192     b2->h.bix = (k-2 | FREETAG);
00193     b2->h.cix = -1; /* free tag */
00194 #else
00195     b2->h.bix= k-2;
00196     b2->h.cix = -1; /* free tag */
00197 #endif
00198   }
00199   b2->h.m=b1->h.m;
00200   b1->h.m=b1->h.b;
00201   b1->h.b=0; 
00202 #ifdef RGC
00203   b1->h.bix = (k-1 | FREETAG);
00204 #else
00205   b1->h.bix= k-1; 
00206 #endif
00207   b2->h.b=1;
00208   b2->h.mark=b2->h.smark=b2->h.pmark=0;
00209   b1->h.nodispose=b2->h.nodispose=0;}
00210 
00211 bpointer root_alloc_big(ctx, req)
00212 register context *ctx;
00213 register int req;       /*index to buddy: must be greater than 0*/
00214 { register int i, k;
00215   register bpointer b,b2;
00216   numunion nu;
00217   pointer gcm;
00218 
00219 #if THREADED
00220   mutex_lock(&alloc_lock); 
00221 #endif
00222 
00223   ctx->alloc_big_count++;
00224 
00225     k=req;
00226     while (buddy[k].bp==0) k++; /*find blocks of adequate size*/
00227     if (k>=MAXBUDDY) {          /*no bigger free cell*/
00228       if (buddysize[req]<totalheap/8) { /*relatively small cell is requested;*/
00229         gc();                   /* then try garbage collection*/
00230         gcm=speval(GCMARGIN);
00231         while (freeheap < (totalheap*min(5.0,fltval(gcm))))
00232           newchunk(req); /*still not enough space*/
00233         for (k=req; buddy[k].bp==0; ) k++;}
00234       if (k>=MAXBUDDY) {
00235         k=newchunk(req);
00236         if (k==ERR) { 
00237 #if THREADED
00238           mutex_unlock(&alloc_lock);
00239 #endif
00240           error(E_ALLOCATION);}}}
00241 
00242     while (req<k) { splitheap(k--,buddy); if (k>req) k--;}
00243     k=buddysize[req]-1;
00244     b=buddy[req].bp;
00245     b2=b->b.nextbcell;
00246     for (i=0; i<k; i++) b->b.c[i]=0;
00247     ctx->lastalloc=makepointer(b);
00248     buddy[req].bp=b2;
00249     buddy[req].count--;
00250 #ifdef DEBUG
00251   printf( "root_alloc_big: alloc 1 block (%d), 0x%lx\n", req, b );
00252 #endif
00253     freeheap -= buddysize[req];
00254     alloccount[req]++;
00255 #if THREADED
00256   mutex_unlock(&alloc_lock); 
00257 #endif
00258   return(b);}
00259 
00260 void root_alloc_small(ctx, req)
00261 register context *ctx;
00262 register int req;       /*index to buddy: must be greater than 0*/
00263 { register int i, j, k,kk;
00264   register bpointer b, b2;
00265   register struct buddyfree *tb=ctx->thr_buddy;
00266   static long buddyfill[MAXTHRBUDDY+1]={0,500,300,20,15,10,0};
00267   numunion nu;
00268   int collected=0;
00269 
00270 #if THREADED
00271   mutex_lock(&alloc_lock); 
00272 #endif
00273   
00274   ctx->alloc_small_count++;
00275 
00276   alloc_again:
00277   for (i=1; i<MAXTHRBUDDY; i++) {
00278     k=kk=buddyfill[i] - tb[i].count; /*how many cells are needed*/
00279     while (buddy[i].count < k) {   /*Do we have enough free in the root?*/
00280 /*      fprintf(stderr, "free_count=%d; k=%d\n",buddy[i].count,k);  */
00281         j=i+1;
00282         while (buddy[j].bp==0) j++;
00283         if (j>=MAXBUDDY) {      /*no free cell*/
00284           if (!collected) {
00285             /* fprintf(stderr, "GC: free=%d total=%d, margin=%f\n",
00286                         freeheap, totalheap, fltval(speval(GCMARGIN))); */
00287             gc(); collected=1;
00288             goto alloc_again;}
00289           while (freeheap<(totalheap*min(5.0,fltval(speval(GCMARGIN))))) {
00290             j=newchunk(DEFAULTCHUNKINDEX); /*still not enough space*/
00291             if (j==ERR) { 
00292 #if THREADED
00293               mutex_unlock(&alloc_lock); 
00294 #endif
00295               error(E_ALLOCATION);}} }
00296         if (j>=MAXBUDDY) {      /*hard fragmentation seen*/
00297           j=newchunk(DEFAULTCHUNKINDEX);
00298           if (j==ERR) { 
00299 #if THREADED
00300             mutex_unlock(&alloc_lock);
00301 #endif
00302             error(E_ALLOCATION);}} 
00303         splitheap(j, buddy);}
00304     /*sufficient free cells collected in the root free list*/
00305     if (k>0) {
00306       b=buddy[i].bp;
00307       while (k>0) { b2=b; b->h.cix=0; b=b->b.nextbcell; k--;}
00308       b2->b.nextbcell=tb[i].bp;
00309       tb[i].bp=buddy[i].bp;
00310       buddy[i].bp=b;
00311       buddy[i].count -= kk;
00312       tb[i].count=buddyfill[i];
00313       freeheap -= buddysize[i]*kk;
00314       alloccount[i] += kk;
00315 #ifdef DEBUG
00316       printf( "root_alloc_small: alloc %d block(s) (%d)\n", kk, i);
00317 #endif
00318       }}
00319 #if THREADED
00320   mutex_unlock(&alloc_lock); 
00321 #endif
00322   /*return(b);*/
00323   }
00324 
00325 #ifndef RGC
00326 pointer gc_alloc(s,e,cid,nils)  /*allocate heap of 's' longwords*/
00327 register int s,nils;
00328 int e,cid;
00329 { register int req=1,i,ss;
00330   register pointer p;
00331   register pointer *v;
00332   register bpointer b,b2;
00333   register context *ctx=myctx;
00334   register struct buddyfree *tb= ctx->thr_buddy;
00335 #if defined(DEBUG) || defined(DEBUG_COUNT)
00336   static int count=0;
00337 
00338   count++;
00339 
00340   if( nils > s ) {
00341       printf( "alloc:%d:nils(=%d) > s(=%d)!!\n", count, nils, s );
00342   }
00343 #endif
00344   ss=max(3,s+1);         /*one more word for the allocation information*/
00345   while (buddysize[req]<ss) req++;
00346 #ifdef DEBUG
00347   printf( "alloc:%d:s=%d, e=%d, cid=%d, nils=%d\n",
00348          count, s, e, cid, nils );
00349 #endif
00350   if (req>=MAXTHRBUDDY)  b=root_alloc_big(ctx, req);
00351   else { /*small cell is requested*/
00352     if (tb[req].count==0) {/*find a cell in the local free list*/
00353       root_alloc_small(ctx, req);
00354 #ifdef DEBUG
00355       printf( "alloc:" );
00356       dump_bcell(req,ctx->thr_buddy);
00357 #endif
00358   }
00359 #if THREADED
00360     rw_rdlock(&gc_lock);
00361 #endif
00362 #ifdef DEBUG
00363     fflush( stdout );
00364     printf( "alloc:%d:", count );
00365     dump_bcell( req, tb );
00366 #endif
00367     b=tb[req].bp;
00368     ctx->lastalloc=makepointer(b);
00369     ss=buddysize[req]-1;
00370     tb[req].bp=b->b.nextbcell;
00371 #if defined(DEBUG) || defined(UALLOC_DEBUG)
00372     printf( "alloc:%d:allocate for user[%d(buddysize=%d)] = 0x%lx: new list top = 0x%lx\n",
00373            count, req, buddysize[req], b, tb[req].bp );
00374 #endif
00375     for (i=0; i<ss; i++) b->b.c[i]=0;
00376     tb[req].count--;
00377 #if THREADED
00378     rw_unlock(&gc_lock);
00379 #endif
00380     }
00381   b->h.elmtype=e;
00382   b->h.cix=cid;
00383   b->h.extra=0;
00384   b->h.nodispose=0;
00385   p=makepointer(b);
00386   v=p->c.obj.iv;
00387 #ifdef DEBUG
00388   printf( "alloc:%d:fill NIL:nils = %d, s = %d\n",
00389          count, nils, s );
00390 #endif
00391   i=0;
00392   while (i<nils) v[i++]=NIL;    /*fill NILs in user's  slots*/
00393 /* while (nils<s) v[nils++]=NIL; */
00394   i=buddysize[req]-1;
00395   while (s<i) v[s++]=NULL;      /*fill NULLs in buddy-cells extra slots*/
00396 #ifdef DEBUG
00397   printf( "alloc:%d:after filling NIL:", count );
00398   dump_bcell( req, tb );
00399 #endif
00400 
00401   return(p);}
00402 
00403 #endif /* RGC */
00404 
00405 
00406 /****************************************************************/
00407 /* gc: garbage collector
00408 /****************************************************************/
00409 
00410 #define DEFAULT_MAX_GCSTACK 65536*2
00411 pointer *gcstack, *gcsplimit, *gcsp;
00412 #define gcpush(v) (*lgcsp++=((pointer)v))
00413 #define gcpop() (*--lgcsp)
00414 #if Solaris2 
00415 #define out_of_heap(p) ((int)p<(int)_end || (pointer)0x20000000<p)
00416 #else /* Solaris2 */
00417 #if Linux || Cygwin || Darwin
00418 #if (WORD_SIZE == 64)
00419 #define out_of_heap(p) ((unsigned long)p<(unsigned long)minmemory || (pointer)maxmemory <p)
00420 #else
00421 #define out_of_heap(p) ((unsigned int)p<(unsigned int)minmemory || (pointer)maxmemory <p)
00422 #endif
00423 #else /* Linux || Cygwin || Darwin */
00424 #if alpha
00425 #if THREADED
00426 #define out_of_heap(p) ((long)p<4 || bottom_addr<(long)p)
00427 #else
00428 #define out_of_heap(p) ((long)p<(long)edata || (pointer)0x000003ff00000000<p)
00429 #endif
00430 #else /* alpha */
00431 #if SunOS4_1
00432 #define out_of_heap(p) ((int)p<(int)edata || (pointer)0x20000000<p)
00433 #else
00434 #if (WORD_SIZE == 64)
00435 #define out_of_heap(p) ((long)p<(long)edata || (pointer)0x20000000<p)
00436 #else
00437 #define out_of_heap(p) ((int)p<(int)edata || (pointer)0x20000000<p)
00438 #endif
00439 #endif /* SunOS4_1 */
00440 #endif /* alpha */
00441 #endif /* Linux || Cygwin || Darwin */
00442 #endif /* Solaris2 */
00443 
00444 
00445 pointer mark_root, marking, marking2;
00446 
00447 void mark(p)
00448 register pointer p;
00449 { register int i,s;
00450   register bpointer bp;
00451   register pointer p2;
00452   register pointer *lgcsp=gcstack;
00453   register pointer *lgcsplimit=gcsplimit;
00454 
00455   mark_root=p;
00456   gcpush(p);
00457 markloop:
00458   if (lgcsp<=gcstack) return;
00459   p=gcpop();
00460 markagain:
00461   if (out_of_heap(p)) goto markloop;
00462 
00463   bp=bpointerof(p);
00464   if (marked(bp)) goto markloop;        /*already marked*/
00465   markon(bp);                   /*mark it first to avoid endless marking*/
00466 #ifdef MARK_DEBUG
00467   printf( "mark: markon 0x%lx\n", bp );
00468 #endif
00469   if (pisclosure(p)) goto markloop;     /*avoid marking contents of closure*/
00470   marking=p;
00471 /*  printf("%x, %x, %d, %d, %d\n", p, bp, bp->h.elmtype, bp->h.bix, buddysize[bp->h.bix] );*/
00472   if (bp->h.elmtype==ELM_FIXED) {       /*contents are all pointers*/
00473     s=buddysize[bp->h.bix]-1;
00474     while (lgcsp+s>gcsplimit) { 
00475       newgcstack(lgcsp); lgcsp=gcsp;}
00476     for (i=0; i<s; i++) {
00477         p2=p->c.obj.iv[i];
00478         if (ispointer(p2)) /* && !marked(bpointerof(p2)))*/  gcpush(p2); }
00479     goto markloop;}
00480   else if (bp->h.elmtype==ELM_POINTER) { /*varing number of pointers*/
00481     s=buddysize[bp->h.bix]-2;
00482     while (lgcsp+s>gcsplimit) { 
00483       newgcstack(lgcsp); lgcsp=gcsp;}
00484     for (i=0; i<s; i++) {
00485         p2=p->c.vec.v[i];
00486         if (ispointer(p2)) /* && !marked(bpointerof(p2)))*/   gcpush(p2); }
00487       goto markloop;}
00488   else goto markloop;
00489   }
00490 
00491 
00492 void newgcstack(oldsp)
00493 register pointer *oldsp;
00494 { register pointer *oldstack, *stk, *newstack, *newgcsp;
00495   long top, oldsize, newsize;
00496 
00497   oldstack=stk=gcstack;
00498   oldsize=gcsplimit-gcstack;
00499   newsize=oldsize*2;
00500   top=oldsp-gcstack;
00501   newgcsp=newstack=(pointer *)malloc(newsize * sizeof(pointer)+16);
00502   if(isatty(0)) {
00503     fprintf(stderr, "\n;; extending gcstack %p[%ld] --> %p[%ld] top=%lx\n",
00504             oldstack, oldsize, newstack, newsize, top);}
00505   while (stk<oldsp) *newgcsp++= *stk++;
00506   gcstack=newstack;
00507   gcsplimit= &gcstack[newsize-10];
00508   gcsp= &gcstack[top];
00509   cfree(oldstack);
00510   }
00511 
00512 int mark_state;
00513 context *mark_ctx;
00514 long mark_stack_root;
00515 long mark_buddy_q;
00516 
00517 void markall()
00518 { register pointer *p,*spsave;
00519   register int i,j;
00520   register context *ctx;
00521   register bpointer q;
00522 /*#if defined(DEBUG_COUNT) || defined(MARK_DEBUG)*/
00523   static int count = 0;
00524 
00525   count++;
00526 /*#endif*/
00527 
00528   mark_state=1;
00529 #ifdef MARK_DEBUG
00530   printf( "markall:%d: mark(SYSTEM_OBJECTS)\n", count );
00531 #endif
00532   mark(sysobj);         /*mark internally reachable objects*/
00533   mark_state=2;
00534 #ifdef MARK_DEBUG
00535   printf( "markall:%d: mark(PACKAGE_LIST)\n", count );
00536 #endif
00537   mark(pkglist);        /*mark all packages*/
00538   for (i=0; i<MAXTHREAD; i++) {
00539     /*mark everything reachable from stacks in euscontexts*/
00540     if ((ctx=euscontexts[i])) {
00541       mark_ctx=ctx; mark_state=3;
00542 #ifdef MARK_DEBUG
00543       printf( "markall:%d: mark(threadobj %d)\n", count, i );
00544 #endif
00545       mark(ctx->threadobj);
00546       mark_state=4;
00547       mark_stack_root=(long)ctx->stack;
00548 
00549       /* mark from thread's stack */
00550       for (p=ctx->stack; p<ctx->vsp; p++) {
00551         mark_state=(long)p;
00552 #if (WORD_SIZE == 64)
00553         if ((((eusinteger_t)(*p) & 7L)==0L) && 
00554 #else
00555         if ((((eusinteger_t)(*p) & 3)==0) && 
00556 #endif
00557             ((ctx->stack>(pointer *)*p) || ((pointer *)*p>ctx->stacklimit)))
00558                 { mark(*p); } ;}
00559       mark_state=0x10000;
00560 
00561       /* mark free list already acquired in local buddy list */
00562       for (j=1; j<MAXTHRBUDDY; j++) {
00563         q=ctx->thr_buddy[j].bp;
00564         mark_buddy_q=(long)q;
00565         while (q) { markon(q);
00566 #ifdef MARK_DEBUG
00567                     printf( "markall:%d: markon 0x%ld\n", count, q );
00568 #endif
00569  q=q->b.nextbcell; mark_state++;}
00570         }
00571       mark_state=0x20000;
00572 
00573       /* mark thread special variables */
00574 #ifdef MARK_DEBUG
00575       printf( "markall:%d: mark(SPECIALS)\n", count );
00576 #endif
00577       mark(ctx->specials);
00578 
00579       q=bpointerof(ctx->lastalloc);
00580       if (q && ispointer(q)) /* markon(q); */
00581 #ifdef MARK_DEBUG
00582         printf( "markall:%d: mark(lastalloc)\n", count );
00583 #endif
00584         mark(ctx->lastalloc);
00585       }}
00586   mark_state=5;
00587   for (i=0; i<MAXCLASS; i++) {
00588     if (ispointer(classtab[i].def)) mark(classtab[i].def); }
00589   mark_state=0;
00590   }
00591 
00592 #ifndef RGC
00593 void reclaim(p)
00594 register bpointer p;
00595 { register int rbix,stat;
00596   register pointer s;
00597   s=makepointer(p);
00598   if (pisfilestream(s)) {
00599     if (!isint(s->c.fstream.fname) && s->c.fstream.direction!=NIL) {
00600       if (s->c.fstream.fd==makeint(0) || s->c.fstream.fd==makeint(1)) {
00601         fprintf(stderr,";; gc! bogus stream at %lx fd=%ld\n",
00602                 (unsigned long int)s,intval(s->c.fstream.fd));}
00603 #if (WORD_SIZE == 64)
00604       else if (s->c.fstream.fd == 0) {
00605         // Sometimes, s->c.fstream.fd is 0.
00606         // c.fstream.fd should be eus integer which least 2bits is 10.
00607         // So, the condition that s->c.fstream.fd is 0 is obviously bug.
00608         fprintf(stderr, ";; closing fstream was failed, %p, %d\n", s, s->cix);
00609       }
00610       else if ((s->c.stream.buffer == NULL) ||
00611                ((unsigned long)(s->c.stream.buffer) & 0x7L) != 0x0L ||
00612                s->c.stream.buffer->cix == -1) {
00613         // stream buffer already reclaimed?????
00614         // very dirty code for avoiding segmentation falut.
00615         // there are some bugs before here.
00616         fprintf(stderr, ";; bad stream buffer, %p\n", s->c.stream.buffer);
00617       }
00618 #endif
00619       else if ((closestream(s)==0) && debug)
00620         fprintf(stderr,";; gc: dangling stream(address=%lx fd=%ld) is closed\n",
00621                 (unsigned long int)s,intval(s->c.fstream.fd)); } }
00622   p->h.cix= -1;
00623   rbix=p->h.bix;
00624   p->b.nextbcell=buddy[rbix].bp;
00625   buddy[rbix].bp=p; buddy[rbix].count++;
00626   freeheap+=buddysize[rbix];}
00627 #endif
00628 
00629 static bpointer mergecell(p,cbix)
00630 register bpointer p;
00631 int cbix;
00632 /*the cell pointed by 'p' must not be marked*/
00633 /*mergecell kindly returns next uncollectable cell address*/
00634 { register bpointer np,p2;
00635 #if defined(DEBUG_COUNT) || defined(MERGE_DEBUG)
00636   static int count = 0;
00637 
00638   count++;
00639 #endif
00640   np=nextbuddy(p);
00641   while (p->h.b==0 && (int)p->h.bix<cbix) {
00642     if (marked(np)) return(np);
00643     if (np->h.nodispose==1) return(np);
00644     p2=mergecell(np,cbix);      /*merge neighbor cell*/
00645     if (np->h.b==1) {           /*can be merged*/
00646       p->h.b=p->h.m;            /*merge them into bigger cell*/
00647       p->h.m=np->h.m;
00648       p->h.bix++;
00649 #ifdef MERGE_DEBUG
00650       printf( "mergecell:%d:p=0x%lx, np=0x%lx\n", count, p, np );
00651 #endif
00652       np=p2;}
00653     else {
00654 #ifdef MERGE_DEBUG
00655         printf( "mergecell:%d:call reclaim:np=0x%lx\n", count, np );
00656 #endif
00657       reclaim(np);
00658       return(p2);}}
00659   return(np);}
00660   
00661 static void sweep(cp,gcmerge)
00662 register struct chunk *cp;
00663 register int gcmerge;
00664 { register int s;
00665   register bpointer p,np,tail;
00666 #if defined(DEBUG_COUNT) || defined(SWEEP_DEBUG) || defined(MARK_DEBUG)
00667   static int count = 0;
00668   int count2 = 0;
00669 
00670   count++;
00671 #endif
00672   s=buddysize[cp->chunkbix];
00673   p= &cp->rootcell;
00674   tail=(bpointer)((eusinteger_t)p+(s<<WORDSHIFT));/* ???? */
00675 #ifdef SWEEP_DEBUG
00676   printf( "sweep:%d:top=0x%lx, tail=0x%lx\n", count, p, tail );
00677 #endif
00678   while (p<tail) {
00679 #ifdef SWEEP_DEBUG
00680       printf( "sweep:%d,%d:p=0x%lx:NIL->cix=%d\n", count, count2++, p, NIL->cix );
00681 #endif
00682     if (marked(p)) {  /*don't reclaim*/
00683       markoff(p);
00684 #ifdef MARK_DEBUG
00685                      printf( "sweep:%d,%d: markoff 0x%lx\n", count, count2, p );
00686 #endif
00687 
00688  p=nextbuddy(p);}       /*don't collect*/
00689     else {
00690       if (p->h.nodispose==1) {
00691         /* fprintf(stderr,";; dispose %x\n", p); */
00692         if (dispose_count>=MAXDISPOSE) 
00693           fprintf(stderr, "no more space for disposal processing\n");
00694         else dispose[dispose_count++]=makepointer(p);
00695         p=nextbuddy(p); }
00696       else if (gcmerge>freeheap) { /* no merge */
00697         np=nextbuddy(p);
00698         reclaim(p);
00699         p=np;} 
00700       else {
00701         np=mergecell(p,cp->chunkbix);   /*update free buddy list*/
00702         reclaim(p);
00703         p=np;} } }
00704   }  
00705 
00706 void call_disposers()
00707 { int i;
00708   context *ctx=current_ctx;
00709   pointer p,a,curclass;
00710   /*if (debug) fprintf(stderr, ";; disposal call=%d\n", dispose_count);*/
00711   for (i=0; i<dispose_count; i++) {
00712     p=dispose[i];
00713     p->nodispose=0;
00714     a=(pointer)findmethod(ctx,K_DISPOSE,classof(p), &curclass); 
00715     if (debug) fprintf(stderr, ";; (send %p :dispose)\n", p);
00716     if (a!=NIL) csend(ctx,p,K_DISPOSE,0);
00717     }}
00718 
00719 void sweepall()
00720 { 
00721   context *ctx;
00722   register struct chunk *chp;
00723   register int i, gcmerge;
00724   numunion nu;
00725 
00726   dispose_count=0;
00727   ctx=euscontexts[thr_self()];
00728   gcmerge=totalheap * min(1.0,fltval(speval(GCMARGIN)))
00729                     * max(0.1,fltval(speval(GCMERGE)));
00730 
00731   for (i=0; i<MAXBUDDY-1; i++) {
00732     buddy[i].bp=0;      /*purge buddies*/
00733     buddy[i].count=0;   /*clear free cell count*/
00734     }
00735   freeheap=0;
00736   for (chp=chunklist; chp!=0; chp=chp->nextchunk) sweep(chp,gcmerge);
00737   call_disposers();
00738 
00739   }
00740 
00741 #if THREADED
00742 void suspend_all_threads()
00743 { register int i, self, stat;
00744   
00745   self=thr_self();
00746   for (i=0; i<MAXTHREAD; i++) 
00747     if (i!=self && euscontexts[i]) {
00748       stat=thr_suspend(i);
00749       if (stat) fprintf(stderr, "gc cannot suspend thread %d\n",i);  }
00750   }
00751 
00752 void resume_all_threads()
00753 { register int i, self, stat;
00754   
00755   self=thr_self();
00756   for (i=0; i<MAXTHREAD; i++) 
00757     if (i!=self && euscontexts[i]) {
00758       stat=thr_continue(i);
00759       if (stat) fprintf(stderr, "gc cannot resume thread %d\n",i);  }
00760   }
00761 
00762 #endif
00763 
00764 #if vxworks
00765 void gc()
00766 { if (debug)  fprintf(stderr,"\n;; gc:");
00767   breakck;
00768   gccount++;
00769   markall();
00770   sweepall();
00771   if (debug) {
00772     fprintf(stderr," free/total=%d/%d stack=%d ",
00773                 freeheap,totalheap,markctx->vsp-markctx->stack);
00774     }
00775   breakck;  }
00776 #else 
00777 
00778 void gc()
00779 { struct tms tbuf1,tbuf2,tbuf3;
00780   int i, r;
00781   context *ctx=euscontexts[thr_self()];
00782 
00783   if (debug)  fprintf(stderr,"\n;; gc: thread=%d ",thr_self());
00784   breakck;
00785   gccount++;
00786   times(&tbuf1);
00787 
00788 #if THREADED
00789 /*  mutex_lock(&alloc_lock);  is not needed since gc is assumed to be called
00790     from alloc_small or alloc_big and they have already locked alloc_lock.*/
00791   r = mutex_trylock(&mark_lock);
00792   if ( r != 0 ) {
00793     if (debug) fprintf(stderr, ";; gc:mutex_lock %d ", r);
00794     return;
00795   }
00796   rw_wrlock(&gc_lock);
00797   suspend_all_threads();
00798 #endif
00799 
00800   markall();
00801 
00802   times(&tbuf2);
00803   marktime+=(tbuf2.tms_utime-tbuf1.tms_utime);
00804   sweepall();
00805   times(&tbuf3);
00806   sweeptime+=(tbuf3.tms_utime-tbuf2.tms_utime);
00807 
00808 #if THREADED
00809   resume_all_threads();
00810   rw_unlock(&gc_lock);
00811   mutex_unlock(&mark_lock);
00812 /*  mutex_unlock(&alloc_lock); */
00813 #endif
00814   if (debug) {
00815     fprintf(stderr," free/total=%ld/%ld stack=%d ",
00816             freeheap,totalheap,(int)(myctx->vsp - myctx->stack));
00817     fprintf(stderr," mark=%ld sweep=%ld\n", marktime,sweeptime);
00818   }
00819   if (speval(QGCHOOK)!=NIL) {
00820     pointer gchook=speval(QGCHOOK);
00821     vpush(makeint(freeheap)); vpush(makeint(totalheap));
00822     ufuncall(ctx,gchook,gchook,(pointer)(ctx->vsp-2),ctx->bindfp,2);
00823     ctx->vsp -= 2;
00824     }
00825   breakck;
00826 }
00827 #endif
00828 
00829 #ifdef DEBUG
00830 dump_bcell( k, b )
00831 int k;
00832 struct buddyfree *b;
00833 {
00834     bpointer bp;
00835     int i;
00836 
00837     printf( "buddy[%d] = { %d, (", k, b[k].count );
00838     bp = b[k].bp;
00839     for( i = 0; i < b[k].count; i++ ) {
00840         printf( "0x%lx ->", bp );
00841         bp = bp->b.nextbcell;
00842     }
00843     printf( ")}\n" );
00844 }
00845 #endif
00846 
00847 #ifdef STACK_DEBUG
00848 pointer p_print( v, ctx )
00849 pointer v;
00850 context *ctx;
00851 {
00852     printf( "vpush:0x%lx->[0x%lx]\n", v, ctx->vsp );
00853 
00854     return v;
00855 }
00856 #endif


euslisp
Author(s): Toshihiro Matsui
autogenerated on Thu Jun 6 2019 18:05:53