X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fgc.c;h=e9d9b7b8ba60587f9618eca6e25fab55a3a8a5f5;hb=85e58b4a49d3c3b74afed3c766b47b65a6a95a66;hp=a8c0976eedeb46de7604068da871493df4a55823;hpb=966331dac7da0f9ec03ffeb052dd2cd72829b2eb;p=simgear.git diff --git a/simgear/nasal/gc.c b/simgear/nasal/gc.c index a8c0976e..e9d9b7b8 100644 --- a/simgear/nasal/gc.c +++ b/simgear/nasal/gc.c @@ -2,10 +2,7 @@ #include "data.h" #include "code.h" -#define MIN_BLOCK_SIZE 256 - -// "type" for an object freed by the collector -#define T_GCFREED 123 // DEBUG +#define MIN_BLOCK_SIZE 32 static void reap(struct naPool* p); static void mark(naRef r); @@ -25,6 +22,15 @@ static void freeDead() globals->ndead = 0; } +static void marktemps(struct Context* c) +{ + int i; + naRef r = naNil(); + for(i=0; intemps; i++) { + SETPTR(r, c->temps[i]); + mark(r); + } +} // Must be called with the big lock! static void garbageCollect() @@ -43,7 +49,7 @@ static void garbageCollect() for(i=0; i < c->opTop; i++) mark(c->opStack[i]); mark(c->dieArg); - mark(c->temps); + marktemps(c); c = c->nextAll; } @@ -72,16 +78,21 @@ static void garbageCollect() void naModLock() { - naCheckBottleneck(); LOCK(); globals->nThreads++; UNLOCK(); + naCheckBottleneck(); } void naModUnlock() { LOCK(); globals->nThreads--; + // We might be the "last" thread needed for collection. Since + // we're releasing our modlock to do something else for a while, + // wake someone else up to do it. + if(globals->waitCount == globals->nThreads) + naSemUp(globals->sem, 1); UNLOCK(); } @@ -102,7 +113,7 @@ static void bottleneck() if(g->waitCount >= g->nThreads - 1) { freeDead(); if(g->needGC) garbageCollect(); - if(g->waitCount) naSemUpAll(g->sem, g->waitCount); + if(g->waitCount) naSemUp(g->sem, g->waitCount); g->bottleneck = 0; } } @@ -114,43 +125,26 @@ void naCheckBottleneck() static void naCode_gcclean(struct naCode* o) { - naFree(o->byteCode); o->byteCode = 0; naFree(o->constants); o->constants = 0; - naFree(o->argSyms); o->argSyms = 0; - naFree(o->optArgSyms); o->argSyms = 0; } static void naGhost_gcclean(struct naGhost* g) { - if(g->ptr) g->gtype->destroy(g->ptr); + if(g->ptr && g->gtype->destroy) g->gtype->destroy(g->ptr); g->ptr = 0; } static void freeelem(struct naPool* p, struct naObj* o) { - // Free any intrinsic (i.e. non-garbage collected) storage the - // object might have + // Clean up any intrinsic storage the object might have... switch(p->type) { - case T_STR: - naStr_gcclean((struct naStr*)o); - break; - case T_VEC: - naVec_gcclean((struct naVec*)o); - break; - case T_HASH: - naHash_gcclean((struct naHash*)o); - break; - case T_CODE: - naCode_gcclean((struct naCode*)o); - break; - case T_GHOST: - naGhost_gcclean((struct naGhost*)o); - break; + case T_STR: naStr_gcclean ((struct naStr*) o); break; + case T_VEC: naVec_gcclean ((struct naVec*) o); break; + case T_HASH: naiGCHashClean ((struct naHash*) o); break; + case T_CODE: naCode_gcclean ((struct naCode*) o); break; + case T_GHOST: naGhost_gcclean((struct naGhost*)o); break; } - - // And add it to the free list - o->type = T_GCFREED; // DEBUG - p->free[p->nfree++] = o; + p->free[p->nfree++] = o; // ...and add it to the free list } static void newBlock(struct naPool* p, int need) @@ -173,7 +167,6 @@ static void newBlock(struct naPool* p, int need) for(i=0; i < need; i++) { struct naObj* o = (struct naObj*)(newb->block + i*p->elemsz); o->mark = 0; - o->type = T_GCFREED; // DEBUG p->free[p->nfree++] = o; } p->freetop += need; @@ -218,6 +211,15 @@ struct naObj** naGC_get(struct naPool* p, int n, int* nout) return result; } +static void markvec(naRef r) +{ + int i; + struct VecRec* vr = PTR(r).vec->rec; + if(!vr) return; + for(i=0; isize; i++) + mark(vr->array[i]); +} + // Sets the reference bit on the object, and recursively on all // objects reachable from it. Uses the processor stack for recursion... static void mark(naRef r) @@ -227,52 +229,37 @@ static void mark(naRef r) if(IS_NUM(r) || IS_NIL(r)) return; - if(r.ref.ptr.obj->mark == 1) + if(PTR(r).obj->mark == 1) return; - // Verify that the object hasn't been freed incorrectly: - if(r.ref.ptr.obj->type == T_GCFREED) *(int*)0=0; // DEBUG - - r.ref.ptr.obj->mark = 1; - switch(r.ref.ptr.obj->type) { - case T_VEC: - if(r.ref.ptr.vec->rec) - for(i=0; irec->size; i++) - mark(r.ref.ptr.vec->rec->array[i]); - break; - case T_HASH: - if(r.ref.ptr.hash->rec != 0) { - struct HashRec* hr = r.ref.ptr.hash->rec; - for(i=0; i < (1<lgalloced); i++) { - struct HashNode* hn = hr->table[i]; - while(hn) { - mark(hn->key); - mark(hn->val); - hn = hn->next; - } - } - } - break; + PTR(r).obj->mark = 1; + switch(PTR(r).obj->type) { + case T_VEC: markvec(r); break; + case T_HASH: naiGCMarkHash(r); break; case T_CODE: - mark(r.ref.ptr.code->srcFile); - for(i=0; inConstants; i++) - mark(r.ref.ptr.code->constants[i]); + mark(PTR(r).code->srcFile); + for(i=0; inConstants; i++) + mark(PTR(r).code->constants[i]); break; case T_FUNC: - mark(r.ref.ptr.func->code); - mark(r.ref.ptr.func->namespace); - mark(r.ref.ptr.func->next); + mark(PTR(r).func->code); + mark(PTR(r).func->namespace); + mark(PTR(r).func->next); break; } } +void naiGCMark(naRef r) +{ + mark(r); +} + // Collects all the unreachable objects into a free list, and // allocates more space if needed. static void reap(struct naPool* p) { struct Block* b; int elem, freesz, total = poolsize(p); - p->nfree = 0; freesz = total < MIN_BLOCK_SIZE ? MIN_BLOCK_SIZE : total; freesz = (3 * freesz / 2) + (globals->nThreads * OBJ_CACHE_SZ); if(p->freesz < freesz) { @@ -281,6 +268,9 @@ static void reap(struct naPool* p) p->free = p->free0 = naAlloc(sizeof(void*) * p->freesz); } + p->nfree = 0; + p->free = p->free0; + for(b = p->blocks; b; b = b->next) for(elem=0; elem < b->size; elem++) { struct naObj* o = (struct naObj*)(b->block + elem * p->elemsz); @@ -289,6 +279,8 @@ static void reap(struct naPool* p) o->mark = 0; } + p->freetop = p->nfree; + // allocs of this type until the next collection globals->allocCount += total/2; @@ -301,7 +293,14 @@ static void reap(struct naPool* p) if(need > 0) newBlock(p, need); } - p->freetop = p->nfree; +} + +// Does the swap, returning the old value +static void* doswap(void** target, void* val) +{ + void* old = *target; + *target = val; + return old; } // Atomically replaces target with a new pointer, and adds the old one @@ -309,10 +308,11 @@ static void reap(struct naPool* p) // giant lock. void naGC_swapfree(void** target, void* val) { + void* old; LOCK(); + old = doswap(target, val); while(globals->ndead >= globals->deadsz) bottleneck(); - globals->deadBlocks[globals->ndead++] = *target; - *target = val; + globals->deadBlocks[globals->ndead++] = old; UNLOCK(); }