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.85 2000/06/09 22:43:04 mast Exp $"); + RCSID("$Id: gc.c,v 1.86 2000/06/10 18:09:17 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:1048:   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 removing the things from beg down to pos, to let    * them be handled again after gc_rec_last. (It's possible to be    * smarter here and put those things after gc_rec_last to avoid    * recursing through them again, but then it becomes tricky to know    * where the "stack top" is.) */       struct marker *p, *q; +  int cycle = beg->cycle;   #ifdef GC_CYCLE_DEBUG -  fprintf(stderr, "%*sgc_cycle_push, break cycle: %8p, [%8p] ", +  fprintf(stderr, "%*sbreak cycle: %8p, [%8p] ",    gc_cycle_indent, "", beg->data, gc_rec_last);    describe_marker(beg);   #endif   #ifdef PIKE_DEBUG    if (beg == pos)    gc_fatal(beg->data, 0, "Cycle already broken at requested position.\n");   #endif    -  if (beg->cycle) { +  if (cycle) {   #ifdef PIKE_DEBUG -  if (pos->cycle == beg->cycle || gc_rec_last->cycle == beg->cycle) -  gc_fatal(beg->data, 0, "Same cycle on both sides of broken link.\n"); +  if (pos->cycle == cycle || gc_rec_last->cycle == 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) {}    }    else    for (p = &rec_list; p->link != beg; p = p->link) {}    -  /* for (q = gc_rec_last; q->link; q = q->link) {} */ -  /* q->link = p->link; */ +     q = p->link;    p->link = pos;       while (q != pos) { -  q->flags &= ~(GC_CYCLE_CHECKED|GC_RECURSING|GC_WEAK_REF); +  q->flags &= ~(GC_CYCLE_CHECKED|GC_RECURSING|GC_WEAK_REF|GC_FOLLOWED_NONSTRONG);    q->cycle = 0;   #ifdef GC_CYCLE_DEBUG -  fprintf(stderr, "%*sgc_cycle_push, reset: " +  fprintf(stderr, "%*sreset marker: "    "%8p, ", gc_cycle_indent, "", q->data);    describe_marker(q);   #endif   #ifdef PIKE_DEBUG -  +  if (q->flags & (GC_GOT_DEAD_REF|GC_GOT_EXTRA_REF)) +  gc_fatal(q->data, 0, "Didn't expect an extra ref at reset.\n");    p = q->link;    q->link = (struct marker *) -1;    q = p;   #else    q = q->link;   #endif    }   }      int gc_cycle_push(void *x, struct marker *m, int weak)
pike.git/src/gc.c:1124: Inside #if defined(PIKE_DEBUG)
   if(o == (struct object *) x) goto on_gc_internal_lists;    for(p = gc_internal_program; p; p = p->next)    if(p == (struct program *) x) goto on_gc_internal_lists;    for(m = gc_internal_mapping; m; m = m->next)    if(m == (struct mapping *) x) goto on_gc_internal_lists;    for(l = gc_internal_multiset; l; l = l->next)    if(l == (struct multiset *) x) goto on_gc_internal_lists;    gc_fatal(x, 0, "gc_cycle_check() called for thing not on gc_internal lists.\n");    on_gc_internal_lists:    } +  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 (gc_rec_last->flags & GC_LIVE_RECURSE) {   #ifdef PIKE_DEBUG    if (!(gc_rec_last->flags & GC_LIVE))    gc_fatal(x, 0, "Doing live recursion from a dead thing.\n");   #endif       if (m->flags & GC_CYCLE_CHECKED) {    if (!(m->flags & GC_LIVE)) {
pike.git/src/gc.c:1361: Inside #if defined(GC_CYCLE_DEBUG)
  #ifdef GC_CYCLE_DEBUG    fprintf(stderr, "%*sgc_cycle_push, live recurse: %8p, [%8p] ",    gc_cycle_indent, "", x, gc_rec_last);    describe_marker(m);    gc_cycle_indent += 2;   #endif    gc_rec_last = m;    return 1;   }    + /* Add an extra ref when a dead thing is popped. It's taken away in +  * the free pass. This is done to not refcount garb the cycles +  * themselves recursively, which in bad cases can consume a lot of C +  * stack. */ + #define ADD_REF_IF_DEAD(M) \ +  if (!(M->flags & GC_LIVE)) { \ +  DO_IF_DEBUG( \ +  if (M->flags & GC_GOT_DEAD_REF) \ +  gc_fatal(M->data, 0, "A thing already got an extra dead cycle ref.\n"); \ +  ); \ +  gc_add_extra_ref(M->data); \ +  M->flags |= GC_GOT_DEAD_REF; \ +  } +    static void pop_cycle_to_kill_list()   {    struct marker *base, *p, *q;       for (base = gc_rec_last;    base->cycle == base->link->cycle;    base = base->link) {}    p = base;       while ((q = p->link)) {   #ifdef PIKE_DEBUG    if (q == (struct marker *) -1)    gc_fatal(p->data, 0, "Followed link to oblivion.\n");    if (q->cycle != base->link->cycle)    gc_fatal(q->data, 0, "Popping more than one cycle from rec_list.\n");    if (!(q->flags & GC_RECURSING))    gc_fatal(q->data, 0, "Marker being cycle popped doesn't have GC_RECURSING.\n"); -  +  if (q->flags & GC_GOT_DEAD_REF) +  gc_fatal(q->data, 0, "Didn't expect a dead extra ref.\n");   #endif    q->flags &= ~GC_RECURSING; -  +     if (q->flags & GC_LIVE_OBJ) {    /* This extra ref is taken away in the kill pass. */    gc_add_extra_ref(q->data);   #ifdef GC_CYCLE_DEBUG    fprintf(stderr, "%*spop_cycle_to_kill_list: %8p, [%8p] ",    gc_cycle_indent, "", q->data, base);    describe_marker(q);   #endif    p = q;    }    else { -  +  ADD_REF_IF_DEAD(q);   #ifdef GC_CYCLE_DEBUG    fprintf(stderr, "%*spop_cycle_to_kill_list, ignore: %8p, [%8p] ",    gc_cycle_indent, "", q->data, base);    describe_marker(q);   #endif    p->link = q->link;    }    }       p->link = kill_list;
pike.git/src/gc.c:1434:    if (!(m->flags & GC_RECURSING)) {    m->flags &= ~GC_LIVE_RECURSE;   #ifdef GC_CYCLE_DEBUG    fprintf(stderr, "%*sgc_cycle_pop, pop ignored: %8p, [%8p] ",    gc_cycle_indent, "", a, gc_rec_last);    describe_marker(m);   #endif    return;    }    -  if (!(m->flags & GC_LIVE)) { -  /* This extra ref is taken away in the free pass. This is done to -  * not refcount garb the cycles themselves recursively, which in bad -  * cases can consume a lot of C stack. */ -  gc_add_extra_ref(m->data); +    #ifdef PIKE_DEBUG    if (m->flags & GC_GOT_DEAD_REF) -  gc_fatal(a, 0, "A thing already got an extra dead cycle ref.\n"); +  gc_fatal(a, 0, "Didn't expect a dead extra ref.\n");   #endif -  m->flags |= GC_GOT_DEAD_REF; -  } +        if (m->cycle) {    /* Part of a cycle. Leave for now so we pop the whole cycle at once. */    m->flags &= ~GC_WEAK_REF;   #ifdef GC_CYCLE_DEBUG    fprintf(stderr, "%*sgc_cycle_pop, in cycle: %8p, [%8p] ",    gc_cycle_indent, "", a, gc_rec_last);    describe_marker(m);   #endif    if (!(gc_rec_last->flags & GC_RECURSING))    for (gc_rec_last = &rec_list;    gc_rec_last->link != m && gc_rec_last->link->cycle != m->cycle;    gc_rec_last = gc_rec_last->link) {}    if (gc_rec_last->cycle != m->cycle)    /* Time to pop the cycle. */    pop_cycle_to_kill_list();    }       else {    struct marker *p; -  +  ADD_REF_IF_DEAD(m);    m->flags &= ~(GC_RECURSING|GC_WEAK_REF);    if (gc_rec_last->flags & GC_RECURSING) p = gc_rec_last;    else p = &rec_list;    for (; p->link != m; p = p->link) {   #ifdef PIKE_DEBUG    if (!p->link || m->link)    gc_fatal(a, 0, "Thing not in cycle not last on rec_list.\n");   #endif    }    p->link = 0;
pike.git/src/gc.c:1512:    if (!(m->flags & GC_RECURSING)) {    m->flags &= ~GC_LIVE_RECURSE;   #ifdef GC_CYCLE_DEBUG    fprintf(stderr, "%*sgc_cycle_pop_object, pop ign: %8p, [%8p] ",    gc_cycle_indent, "", o, gc_rec_last);    describe_marker(m);   #endif    return;    }    -  if (!(m->flags & GC_LIVE)) { -  /* This extra ref is taken away in the free pass. This is done to -  * not refcount garb the cycles themselves recursively, which in bad -  * cases can consume a lot of C stack. */ -  gc_add_extra_ref(o); +    #ifdef PIKE_DEBUG    if (m->flags & GC_GOT_DEAD_REF) -  gc_fatal(o, 0, "An object already got an extra dead cycle ref.\n"); +  gc_fatal(o, 0, "Didn't expect a dead extra ref.\n");   #endif -  m->flags |= GC_GOT_DEAD_REF; -  } +        if (m->cycle) {    /* Part of a cycle. Leave for now so we pop the whole cycle at once. */    m->flags &= ~GC_WEAK_REF;   #ifdef GC_CYCLE_DEBUG    fprintf(stderr,"%*sgc_cycle_pop_object, in cycle: %8p, [%8p] ",    gc_cycle_indent, "", o, gc_rec_last);    describe_marker(m);   #endif    if (!(gc_rec_last->flags & GC_RECURSING))
pike.git/src/gc.c:1562:    p->link = 0;       if (m->flags & GC_LIVE_OBJ) {    gc_add_extra_ref(o); /* This extra ref is taken away in the kill pass. */    m->link = kill_list;    kill_list = m;   #ifdef GC_CYCLE_DEBUG    fprintf(stderr, "%*sgc_cycle_pop_object, for kill: %8p, [%8p] ",    gc_cycle_indent, "", o, gc_rec_last);    describe_marker(m); + #endif    }    else { -  +  ADD_REF_IF_DEAD(m); + #ifdef GC_CYCLE_DEBUG    fprintf(stderr,"%*sgc_cycle_pop_object: %8p, [%8p] ",    gc_cycle_indent, "", o, gc_rec_last);    describe_marker(m);   #endif    }    }   }      void gc_set_rec_last(struct marker *m)   {