]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/gc.c
hla: for rti13 queue all callbacks.
[simgear.git] / simgear / nasal / gc.c
index a8c0976eedeb46de7604068da871493df4a55823..e9d9b7b8ba60587f9618eca6e25fab55a3a8a5f5 100644 (file)
@@ -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; i<c->ntemps; 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; i<vr->size; 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; i<r.ref.ptr.vec->rec->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<<hr->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; i<r.ref.ptr.code->nConstants; i++)
-            mark(r.ref.ptr.code->constants[i]);
+        mark(PTR(r).code->srcFile);
+        for(i=0; i<PTR(r).code->nConstants; 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();
 }