pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:22:   #include "time_stuff.h"   #include "constants.h"   #include "interpret.h"      #include "gc.h"   #include "main.h"   #include <math.h>      #include "block_alloc.h"    - RCSID("$Id: gc.c,v 1.94 2000/06/12 19:35:08 mast Exp $"); + RCSID("$Id: gc.c,v 1.95 2000/06/12 21:41:41 mast Exp $");      /* Run garbage collect approximately every time    * 20 percent of all arrays, objects and programs is    * garbage.    */      #define GC_CONST 20   #define MIN_ALLOC_THRESHOLD 1000   #define MAX_ALLOC_THRESHOLD 10000000   #define MULTIPLIER 0.9
pike.git/src/gc.c:107:    * through in the cycle check pass. gc_rec_last points at the    * innermost marker being visited. A new marker is linked in after    * gc_rec_last, except when that's inside a cycle, in which case it's    * linked in after that cycle. A cycle is always treated as one atomic    * unit, e.g. it's either popped whole or not at all.    *    * Two ranges of markers next to each other may swap places to break a    * cyclic reference at a chosen point. Some markers thus get a place    * earlier on the list even though their corresponding stack frames    * are later than some other markers they have references to. These -  * markers are given the GC_DONT_POP flag to make them stay on the -  * list when they're popped from the stack. They'll get popped -  * eventually since all markers in the gap between the top one and -  * it's previous gc_rec_last point are popped. +  * markers are flagged to make them stay on the list when they're +  * popped from the stack. They'll get popped eventually since all +  * markers in the gap between the top one and it's previous +  * gc_rec_last point are popped.    *    * Markers for live objects are linked into the beginning of kill_list    * when they're popped from rec_list.    *    * The cycle check functions might recurse another round through the    * markers that have been recursed already, to propagate the GC_LIVE    * flag to things that have been found to be referenced from live    * objects. rec_list is not touched at all in this extra round.    */   
pike.git/src/gc.c:401:    }      #ifdef DEBUG_MALLOC    dmalloc_describe_location(memblock, location, indent);   #endif   }      static void describe_marker(struct marker *m)   {    if (m) -  fprintf(stderr, "marker at %p: flags=0x%04x, refs=%d, weak=%d, " +  fprintf(stderr, "marker at %p: flags=0x%06x, refs=%d, weak=%d, "    "xrefs=%d, cycle=%d, link=%p\n",    m, m->flags, m->refs, m->weak_refs,    m->xrefs, m->cycle, m->link);    else    fprintf(stderr, "no marker\n");   }      void debug_gc_fatal(void *a, int flags, const char *fmt, ...)   {    va_list args;
pike.git/src/gc.c:740:    m = find_marker(a);    if (Pike_in_gc == GC_PASS_PRETOUCH) {    if (m) gc_fatal(a, 0, "Object touched twice.\n");    get_marker(a)->flags |= GC_TOUCHED;    }    else if (Pike_in_gc == GC_PASS_POSTTOUCH) {    if (m) {    if (!(m->flags & GC_TOUCHED))    gc_fatal(a, 2, "An existing but untouched marker found "    "for object in linked lists.\n"); -  else if (m->flags & (GC_RECURSING|GC_LIVE_RECURSE|GC_DONT_POP| -  GC_WEAK_REF|GC_STRONG_REF)) +  else if (m->flags & (GC_ON_STACK|GC_IN_REC_LIST|GC_DONT_POP| +  GC_LIVE_RECURSE|GC_WEAK_REF|GC_STRONG_REF))    gc_fatal(a, 2, "Marker still got flag from recurse list.\n");    else if (m->flags & GC_REFERENCED)    return;    else if (m->flags & GC_XREFERENCED)    gc_fatal(a, 3, "A thing with external references "    "got missed by mark pass.\n");    else if (!(m->flags & GC_CYCLE_CHECKED))    gc_fatal(a, 2, "A thing was missed by "    "both mark and cycle check pass.\n");    else if (!(m->flags & GC_IS_REFERENCED))
pike.git/src/gc.c:1050:   } while (0)   #else   #define CYCLE_DEBUG_MSG(M, TXT) do {} while (0)   #endif      static void break_cycle (struct marker *beg, struct marker *pos)   {    /* There's a cycle from beg to gc_rec_last which should be broken at    * pos. Do it by switching places of the markers before and after pos. */    struct marker *p, *q; -  CYCLE_DEBUG_MSG(pos, "break_cycle"); +    #ifdef PIKE_DEBUG    if (beg == pos)    gc_fatal(beg->data, 0, "Cycle already broken at requested position.\n");   #endif       if (beg->cycle) {   #ifdef PIKE_DEBUG    if (pos->cycle == beg->cycle || gc_rec_last->cycle == beg->cycle)    gc_fatal(pos->data, 0, "Same cycle on both sides of broken link.\n");   #endif    for (p = &rec_list; p->link->cycle != beg->cycle; p = p->link) {}    beg = p->link;    }    else    for (p = &rec_list; p->link != beg; p = p->link) {}    -  +  CYCLE_DEBUG_MSG(beg, "break_cycle, break from"); +  CYCLE_DEBUG_MSG(pos, "break_cycle, break at"); +     p->link = pos;       for (p = beg; p->link != pos; p = p->link) {}       for (q = pos;; q = q->link) { -  q->flags |= GC_DONT_POP; +  q->flags |= GC_MOVED_BACK|GC_DONT_POP;    CYCLE_DEBUG_MSG(q, "break_cycle, mark for don't pop");    if (q == gc_rec_last) break;    }       {    struct marker *m = q->link;    q->link = beg;    p->link = m;    }   }
pike.git/src/gc.c:1171:       return 0;    }      #ifdef PIKE_DEBUG    if (weak < 0 && gc_rec_last->flags & GC_FOLLOWED_NONSTRONG)    gc_fatal(x, 0, "Followed strong link too late.\n");    if (weak >= 0) gc_rec_last->flags |= GC_FOLLOWED_NONSTRONG;   #endif    -  if (m->flags & GC_RECURSING) { /* A cyclic reference is found. */ +  if (m->flags & GC_IN_REC_LIST) { /* A cyclic reference is found. */   #ifdef PIKE_DEBUG    if (m == &rec_list || gc_rec_last == &rec_list)    gc_fatal(x, 0, "Cyclic ref involves dummy rec_list marker.\n");   #endif       if (m != gc_rec_last) {    struct marker *p, *weak_ref = 0, *nonstrong_ref = 0;    if (!weak) {    struct marker *q;    for (q = m, p = m->link; p; q = p, p = p->link) {
pike.git/src/gc.c:1252:    if (cycle == gc_rec_last->cycle)    CYCLE_DEBUG_MSG(m, "gc_cycle_push, old cycle");    else {    CYCLE_DEBUG_MSG(m, "gc_cycle_push, cycle");    for (p = m;; p = p->link) {    p->cycle = cycle;    CYCLE_DEBUG_MSG(p, "gc_cycle_push, mark cycle");    if (p == gc_rec_last) break;    }}}} /* Mmm.. lisp ;) */    -  else { /* A forward reference. */ -  /* It might be a reference to a marker that has been swapped +  else /* A forward reference. */ +  if (m->flags & GC_ON_STACK) { +  /* It's a reference to a marker that has been swapped    * further down the list by break_cycle(). In that case we -  * must mark this path to stay on the list. */ -  struct marker *q = 0; +  * must mark gc_rec_last to stay on the list. */ +  CYCLE_DEBUG_MSG(m, "gc_cycle_push, mark for don't pop"); +  gc_rec_last->flags |= GC_DONT_POP; +  } +  else    CYCLE_DEBUG_MSG(m, "gc_cycle_push, forward ref"); -  for (p = rec_list.link; p != gc_rec_last; p = p->link) -  if (p->flags & GC_DONT_POP) q = p; -  if (q) -  for (p = q->link;; p = p->link) { -  p->flags |= GC_DONT_POP; -  CYCLE_DEBUG_MSG(p, "gc_cycle_push, mark for don't pop"); -  if (p == gc_rec_last) break; +     }    } -  } -  } +        else    if (!(m->flags & GC_CYCLE_CHECKED)) {    struct marker *p;    m->flags |= gc_rec_last->flags & GC_LIVE;    if (weak) {    if (weak > 0) m->flags |= GC_WEAK_REF;    else m->flags |= GC_STRONG_REF;    }   #ifdef PIKE_DEBUG    cycle_checked++; -  +  if (m->flags & GC_ON_STACK) +  gc_fatal(x, 0, "Recursing twice into thing.\n");    if (m->flags & GC_LIVE_RECURSE)    gc_fatal(x, 0, "GC_LIVE_RECURSE set in normal recursion.\n");   #endif       p = gc_rec_last;    if (gc_rec_last->cycle)    for (; p->link && p->link->cycle == gc_rec_last->cycle; p = p->link) {}    m->link = p->link;    p->link = m; -  m->flags |= GC_CYCLE_CHECKED|GC_RECURSING; +  m->flags |= GC_CYCLE_CHECKED|GC_ON_STACK|GC_IN_REC_LIST;    m->cycle = 0;      #ifdef GC_CYCLE_DEBUG    if (weak > 0) CYCLE_DEBUG_MSG(m, "gc_cycle_push, recurse weak");    else if (weak < 0) CYCLE_DEBUG_MSG(m, "gc_cycle_push, recurse strong");    else CYCLE_DEBUG_MSG(m, "gc_cycle_push, recurse");    gc_cycle_indent += 2;   #endif    gc_rec_last = m;    return 1;
pike.git/src/gc.c:1369: Inside #if defined(PIKE_DEBUG)
   if (m->flags & (GC_REFERENCED))    gc_fatal(a, 1, "Got a referenced marker to gc_cycle_pop.\n");    if (m->flags & GC_XREFERENCED)    gc_fatal(a, 1, "Doing cycle check in externally referenced thing "    "missed in mark pass.\n");   #endif   #ifdef GC_CYCLE_DEBUG    gc_cycle_indent -= 2;   #endif    -  if (!(m->flags & GC_RECURSING) || m->flags & GC_LIVE_RECURSE) { +  if (m->flags & GC_LIVE_RECURSE) {    m->flags &= ~GC_LIVE_RECURSE; -  CYCLE_DEBUG_MSG(m, "gc_cycle_pop, pop ignored"); +  CYCLE_DEBUG_MSG(m, "gc_cycle_pop, live pop");    return;    }      #ifdef PIKE_DEBUG -  +  if (!(m->flags & GC_ON_STACK)) +  gc_fatal(a, 0, "Marker being popped isn't on stack.\n");    if (m->flags & GC_GOT_DEAD_REF)    gc_fatal(a, 0, "Didn't expect a dead extra ref.\n");   #endif       if (m->flags & GC_DONT_POP) {   #ifdef PIKE_DEBUG    if (!m->link)    gc_fatal(a, 0, "Found GC_DONT_POP marker on top of stack.\n");   #endif    CYCLE_DEBUG_MSG(m, "gc_cycle_pop, keep on stack"); -  +  if (!(m->flags & GC_MOVED_BACK)) { +  gc_rec_last->flags |= GC_DONT_POP; +  CYCLE_DEBUG_MSG(gc_rec_last, "gc_cycle_pop, propagate don't pop"); +  }    return;    }       q = gc_rec_last;    while (1) {    p = q->link;   #ifdef PIKE_DEBUG    if (p->flags & GC_LIVE_RECURSE)    gc_fatal(p->data, 0, "Marker still got GC_LIVE_RECURSE at pop.\n");   #endif       if (!p->cycle && !(p->flags & GC_LIVE_OBJ)) {    ADD_REF_IF_DEAD(p); -  p->flags &= ~(GC_RECURSING|GC_DONT_POP|GC_WEAK_REF|GC_STRONG_REF); +  p->flags &= ~(GC_ON_STACK|GC_IN_REC_LIST|GC_DONT_POP| +  GC_WEAK_REF|GC_STRONG_REF);    q->link = p->link;    DO_IF_DEBUG(p->link = (struct marker *) -1);    CYCLE_DEBUG_MSG(p, "gc_cycle_pop, pop off");    }       else { -  p->flags &= ~(GC_DONT_POP|GC_WEAK_REF|GC_STRONG_REF); +  p->flags &= ~(GC_ON_STACK|GC_DONT_POP| +  GC_WEAK_REF|GC_STRONG_REF);    q = p;    }    if (p == m) break;    }       if (gc_rec_last != q) {    if (!q->cycle || gc_rec_last->cycle != q->cycle) {    /* If the thing(s) are part of a cycle that we aren't leaving,    * we let them stay on the list so the whole cycle is popped at    * once. Otherwise it's time to move live objects to the kill
pike.git/src/gc.c:1432:       base = gc_rec_last;    if (gc_rec_last->cycle)    for (; base->link->cycle == gc_rec_last->cycle; base = base->link) {}       q = base;    while ((p = q->link)) {   #ifdef PIKE_DEBUG    if (p->cycle && cycle && p->cycle != cycle)    gc_fatal(p->data, 0, "Popping more than one cycle from rec_list.\n"); -  if (!(p->flags & GC_RECURSING)) -  gc_fatal(p->data, 0, "Marker being cycle popped doesn't have GC_RECURSING.\n"); +  if (!(p->flags & GC_IN_REC_LIST)) +  gc_fatal(p->data, 0, "Marker being cycle popped doesn't have GC_IN_REC_LIST.\n");    if (p->flags & GC_GOT_DEAD_REF)    gc_fatal(p->data, 0, "Didn't expect a dead extra ref.\n");   #endif -  p->flags &= ~GC_RECURSING; +  p->flags &= ~GC_IN_REC_LIST;       if (p->flags & GC_LIVE_OBJ) {    /* This extra ref is taken away in the kill pass. */    gc_add_extra_ref(p->data);    q = p;    CYCLE_DEBUG_MSG(p, "gc_cycle_pop, put on kill list");    }    else {    ADD_REF_IF_DEAD(p);    q->link = p->link;