/** * User should at least prepare this example function in order to use garbage collector: * * objectCFree * ----------- * This function walks through all the pointers in the object struct that prepared by user * * return: * obj object that gone through */ void objectCFree(Object *obj) { ((ObjectC *)obj)->ptrC1 = _gc_free((Object *)((ObjectC *)obj)->ptrC1); ((ObjectC *)obj)->ptrC2 = _gc_free((Object *)((ObjectC *)obj)->ptrC2); ((ObjectC *)obj)->ptrC3 = _gc_free((Object *)((ObjectC *)obj)->ptrC3); }
void gc_keep_root(void) { PObject *obj; int i; if (_vmpnt) { //get the root set obj = PNT(_vm.thlist); do { PThread *pth = (PThread *)obj; VThread vth = pth->th; debug( "Scanning thread %x %i\n", pth, pth->header.flags); if (vth && vosThGetStatus(vth) == VTHREAD_INACTIVE) { //terminated, remove from list...it will die if no references remain pth->prev->next = pth->next; pth->next->prev = pth->prev; GCH_FLAG_SET(pth, GC_USED); //free workspace //if PThread has references, it's ok. But it can't be restarted _gc_free(vth); pth->th = NULL; } else { GC_MARK(pth); if (pth->frame) GC_KEEP(pth->frame); } obj = PNT(pth->next); } while (obj != PNT(_vm.thlist)); for (i = 0; i < _vm.nmodules; i++) { PModule *mod = VM_MODULE(i); GC_MARK(mod); if (PMODULE_IS_LOADED(mod)) { GC_KEEP_MANY(mod->globals, mod->nfo.nums.nglobals); } else { GC_KEEP(mod->nfo.frame); } } //-----> irqs could be modifing irq struct here: no worries SYSLOCK(); //slots & irqstack for (i = 0; i < _vm.irqn; i++) { GC_KEEP(_vm.irqstack[i].fn); GC_KEEP_NOTNULL(_vm.irqstack[i].args); } for (i = 0; i < EXT_SLOTS; i++) { if (_vm.irqslots[0][i].fn) { GC_KEEP(_vm.irqslots[0][i].fn); GC_KEEP_NOTNULL(_vm.irqslots[0][i].args); } if (_vm.irqslots[1][i].fn) { GC_KEEP(_vm.irqslots[1][i].fn); GC_KEEP_NOTNULL(_vm.irqslots[1][i].args); } } if (_vm.irqcur) { GC_KEEP(_vm.irqcur->fn); GC_KEEP_NOTNULL(_vm.irqcur->args); } if (_vm.timers) { obj = _vm.timers; do { GC_KEEP(obj); obj = (PObject *)((PSysObject *)obj)->sys.timer.next; } while (obj != _vm.timers); } SYSUNLOCK(); //-----> irq could be modifing irq struct here: // - it can add something to irqslots: np, the objects added must be in an active frame (gc lock is on, no new frame can be created) // - it can add something to irqstack from pin irq: np, the objects are sitting in irqslots // - it can add something to irqstack from timers: that timer was in the timer list, so it is already kept // - it can be the irqthread at 2 different times: // - it modifies _vm.irqcur after putting it in a new frame: if happens up there, np. if happens now, already kept // - it does _vm.irqn--: if happens up there, the removed irqfn is in irqcur. if happens here, already kept } }
void gc_sweep(void) { PObject *start = (PObject *)hbase; PObject *cur = start; PObject *prev = (PObject *)hedge; uint32_t flags; uint32_t prev_is_free = 0; debug( "\n\n<<<<<<<SWEEP started\n"); /*heapwalk and create free list */ hblocks = 0; hfblocks = 0; hfreemem = 0; while (cur != (PObject *)hedge) { flags = GCH_FLAG(cur); //debug("cur is %x with flag %i\n", cur, flags); switch (flags) { case GC_FREE: /*case GC_USED_UNMARKED:*/ gc_sweep_free: hfreemem += GCH_SIZE(cur); debug("sweeping %x\n", cur); //debug("found free block: %i (%i,%i) %i\n",cur,hblocks,hfblocks,GCH_FLAG(cur)); if (prev_is_free && (GCH_SIZE(prev) + GCH_SIZE(cur) <= 0xffff)) { /* coalesce */ GCH_SIZE_SET(prev, GCH_SIZE(prev) + GCH_SIZE(cur)); //debug("...coalesced with prev %i~%i size %i\n",prev,cur,GCH_SIZE(prev)); prev_is_free = (GCH_SIZE(prev) < 0xffff); } else { prev_is_free = (GCH_SIZE(cur) < 0xffff); GCH_NEXT_SET(prev, cur); /*unset mark flags. First time, sets hedge->next */ prev = cur; hfblocks++; //debug("...splitted prev %i~%i size %i (%i,%i)\n",prev,cur,GCH_SIZE(prev),hblocks,hfblocks); } break; case GC_USED_UNMARKED: if (PHEADERTYPE(cur) == PSYSOBJ) { if (((PSysObject *)cur)->type == PSYS_TIMER) { //if we are here, timer is not in timers and not reachable...free vos mem _gc_free( ((PSysObject *)cur)->sys.timer.vtm); } else if (((PSysObject *)cur)->type == PSYS_SEMAPHORE){ //if it's a lost semaphore, still active, anything can happen :-o _gc_free( ((PSysObject *)cur)->sys.sem); } } goto gc_sweep_free; case GC_USED_MARKED: prev_is_free = 0; GCH_FLAG_SET(cur, GC_USED); hblocks++; //debug("found marked block: %i (%i,%i) %i\n",cur,hblocks,hfblocks,GCH_FLAG(cur)); break; case GC_STAGED: /* don't touch flags */ prev_is_free = 0; hblocks++; //debug("found staged block: %i (%i,%i) %i\n",cur,hblocks,hfblocks,GCH_FLAG(cur)); break; } /* skip current */ cur = (PObject *)(((uint8_t *)(cur)) + GCH_SIZE(cur)); } if (prev_is_free) { /* coalesce with hedge */ hfreemem -= GCH_SIZE(prev); GCH_NEXT_SET(prev, GCH_NEXT(hedge)); hedge = (uint8_t *)prev; //debug("coalesced with hedge\n"); } else { GCH_NEXT_SET(prev, hedge); //debug("not coalesced with hedge\n"); hfblocks++; } debug( "S%i\n", hfreemem); hfreemem += ((uint32_t)hend - (uint32_t)hedge); debug( "S%i\n", hfreemem); GCH_SIZE_SET(PNT(hedge), MIN(0xffff, hfreemem)); gc_trace(); debug( "<<<<<<<<SWEEP stopped (%i,%i)\n\n\n", hblocks, hfblocks); }
void gc_free(void *pnt) { gc_wait(); _gc_free(pnt); gc_signal(); }