remove some codes for scheduling
[IRC.git] / Robust / src / Runtime / garbage.c
index 0b97ee339fd4b20655cc10f458ff3e741036fe80..16aca4c23a0f823b32bc5f1c987ddf314148e0a7 100644 (file)
@@ -5,6 +5,14 @@
 #include "SimpleHash.h"
 #include "GenericHashtable.h"
 #include <string.h>
+#if defined(THREADS) || defined(DSTM)
+#include "thread.h"
+#endif
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
 
 #define NUMPTRS 100
 
 #define HEAPSIZE(x,y) (((int)((x)/0.6))+y)
 
 #ifdef TASK
-extern struct Queue * activetasks;
+extern struct genhashtable * activetasks;
 extern struct parameterwrapper * objectqueues[NUMCLASSES];
 extern struct genhashtable * failedtasks;
+extern struct taskparamdescriptor *currtpd;
 extern struct RuntimeHash *forward;
 extern struct RuntimeHash *reverse;
 extern struct RuntimeHash *fdtoobject;
 #endif
 
+#if defined(THREADS) || defined(DSTM)
+int needtocollect=0;
+struct listitem * list=NULL;
+int listcount=0;
+#endif
+
+#ifdef DSTM
+#define ENQUEUE(orig, dst) \
+if ((!(((unsigned int)orig)&0x1))) {\
+if (orig>to_heapbase&&orig<to_heaptop) {\
+dst=NULL;\
+} else if (orig>curr_heapbase&&orig<curr_heaptop) {\
+void *copy;\
+if (gc_createcopy(orig,&copy))\
+enqueue(orig);\
+dst=copy;\
+}\
+}
+#else
+#define ENQUEUE(orig, dst) \
+void *copy; \
+if (gc_createcopy(orig,&copy))\
+enqueue(orig);\
+dst=copy
+#endif
+
 struct pointerblock {
   void * ptrs[NUMPTRS];
   struct pointerblock *next;
 };
 
+void * curr_heapbase=0;
+void * curr_heapptr=0;
+void * curr_heapgcpoint=0;
+void * curr_heaptop=0;
+
+void * to_heapbase=0;
+void * to_heapptr=0;
+void * to_heaptop=0;
+long lastgcsize=0;
+
 struct pointerblock *head=NULL;
 int headindex=0;
 struct pointerblock *tail=NULL;
 int tailindex=0;
 struct pointerblock *spare=NULL;
 
-
 void enqueue(void *ptr) {
   if (headindex==NUMPTRS) {
     struct pointerblock * tmp;
@@ -68,24 +112,75 @@ int moreItems() {
   return 1;
 }
 
+#ifdef TASK
+struct pointerblock *taghead=NULL;
+int tagindex=0;
+
+void enqueuetag(struct ___TagDescriptor___ *ptr) {
+  if (tagindex==NUMPTRS) {
+    struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
+    tmp->next=taghead;
+    taghead=tmp;
+    tagindex=0;
+  }
+  taghead->ptrs[tagindex++]=ptr;
+}
+#endif
+
+
 void collect(struct garbagelist * stackptr) {
+#if defined(THREADS)||defined(DSTM)
+  needtocollect=1;
+  pthread_mutex_lock(&gclistlock);
+  while(1) {
+    if ((listcount+1)==threadcount) {
+      break; /* Have all other threads stopped */
+    }
+    pthread_cond_wait(&gccond, &gclistlock);
+  }
+#endif
+
   if (head==NULL) {
     headindex=0;
     tailindex=0;
     head=tail=malloc(sizeof(struct pointerblock));
   }
+
+#ifdef TASK
+  if (taghead==NULL) {
+    tagindex=0;
+    taghead=malloc(sizeof(struct pointerblock));
+    taghead->next=NULL;
+  }
+#endif
+
   /* Check current stack */
+#if defined(THREADS)||defined(DSTM)
+ {
+   struct listitem *listptr=list;
+   while(1) {
+#endif
+     
   while(stackptr!=NULL) {
     int i;
     for(i=0;i<stackptr->size;i++) {
       void * orig=stackptr->array[i];
-      void * copy;
-      if (gc_createcopy(orig,&copy))
-       enqueue(orig);
-      stackptr->array[i]=copy;
+      ENQUEUE(orig, stackptr->array[i]);
     }
     stackptr=stackptr->next;
   }
+#if defined(THREADS)||defined(DSTM)
+  /* Go to next thread */
+  if (listptr!=NULL) {
+    void * orig=listptr->locklist;
+    ENQUEUE(orig, listptr->locklist);
+    stackptr=listptr->stackptr;
+    listptr=listptr->next;
+  } else
+    break;
+   }
+ }
+#endif
   
 #ifdef TASK
   {
@@ -94,18 +189,14 @@ void collect(struct garbagelist * stackptr) {
     for(i=0;i<NUMCLASSES;i++) {
       struct parameterwrapper * p=objectqueues[i];
       while(p!=NULL) {
-       struct RuntimeHash * set=p->objectset;
-       struct RuntimeNode * ptr=set->listhead;
+       struct ObjectHash * set=p->objectset;
+       struct ObjectNode * ptr=set->listhead;
        while(ptr!=NULL) {
          void *orig=(void *)ptr->key;
-         void *copy;
-         if (gc_createcopy(orig, &copy))
-           enqueue(orig);
-         ptr->key=(int)copy;
-         
+         ENQUEUE(orig, *((void **)(&ptr->key)));
          ptr=ptr->lnext;
        }
-       RuntimeHashrehash(set); /* Rehash the table */
+       ObjectHashrehash(set); /* Rehash the table */
        p=p->next;
       }
     }
@@ -115,11 +206,7 @@ void collect(struct garbagelist * stackptr) {
     struct RuntimeNode * ptr=forward->listhead;
     while(ptr!=NULL) {
       void * orig=(void *)ptr->key;
-      void *copy;
-      if (gc_createcopy(orig, &copy))
-       enqueue(orig);
-      ptr->key=(int)copy;
-
+      ENQUEUE(orig, *((void **)(&ptr->key)));
       ptr=ptr->lnext;
     }
     RuntimeHashrehash(forward); /* Rehash the table */
@@ -129,11 +216,7 @@ void collect(struct garbagelist * stackptr) {
     struct RuntimeNode * ptr=reverse->listhead;
     while(ptr!=NULL) {
       void *orig=(void *)ptr->data;
-      void *copy;
-      if (gc_createcopy(orig, &copy))
-       enqueue(orig);
-      ptr->data=(int)copy;
-
+      ENQUEUE(orig, *((void**)(&ptr->data)));
       ptr=ptr->lnext;
     }
   }
@@ -142,42 +225,46 @@ void collect(struct garbagelist * stackptr) {
     struct RuntimeNode * ptr=fdtoobject->listhead;
     while(ptr!=NULL) {
       void *orig=(void *)ptr->data;
-      void *copy;
-      if (gc_createcopy(orig, &copy))
-       enqueue(orig);
-      ptr->data=(int)copy;
-
+      ENQUEUE(orig, *((void**)(&ptr->data)));
       ptr=ptr->lnext;
     }
   }
 
-
   {
+    /* Update current task descriptor */
+    int i;
+    for(i=0;i<currtpd->numParameters;i++) {
+      void *orig=currtpd->parameterArray[i];
+      ENQUEUE(orig, currtpd->parameterArray[i]);
+    }
+
+  }
+
     /* Update active tasks */
-    struct QueueItem * ptr=activetasks->head;
-    while (ptr!=NULL) {
-      struct taskparamdescriptor *tpd=ptr->objectptr;
+  {
+    struct genpointerlist * ptr=activetasks->list;
+    while(ptr!=NULL) {
+      struct taskparamdescriptor *tpd=ptr->src;
       int i;
       for(i=0;i<tpd->numParameters;i++) {
-       void *orig=tpd->parameterArray[i];
-       void *copy;
-       if (gc_createcopy(orig, &copy))
-         enqueue(orig);
-       tpd->parameterArray[i]=copy;
+       void * orig=tpd->parameterArray[i];
+       ENQUEUE(orig, tpd->parameterArray[i]);
       }
-      ptr=ptr->next;
+      ptr=ptr->inext;
     }
+    genrehash(activetasks);
   }
+
     /* Update failed tasks */
   {
     struct genpointerlist * ptr=failedtasks->list;
     while(ptr!=NULL) {
-      void *orig=ptr->src;
-      void *copy;
-      if (gc_createcopy(orig, &copy))
-       enqueue(orig);
-      ptr->src=copy;
-      ptr->object=copy;
+      struct taskparamdescriptor *tpd=ptr->src;
+      int i;
+      for(i=0;i<tpd->numParameters;i++) {
+       void * orig=tpd->parameterArray[i];
+       ENQUEUE(orig, tpd->parameterArray[i]);
+      }
       ptr=ptr->inext;
     }
     genrehash(failedtasks);
@@ -188,7 +275,16 @@ void collect(struct garbagelist * stackptr) {
     void * ptr=dequeue();
     void *cpy=((void **)ptr)[1];
     int type=((int *)cpy)[0];
-    int * pointer=pointerarray[type];
+    unsigned int * pointer;
+#ifdef TASK
+    if(type==TAGTYPE) {
+      /* Enqueue Tag */
+      /* Nothing is inside */
+      enqueuetag(ptr);
+      continue;
+    }
+#endif
+    pointer=pointerarray[type];
     if (pointer==0) {
       /* Array of primitives */
       /* Do nothing */
@@ -200,35 +296,88 @@ void collect(struct garbagelist * stackptr) {
       int i;
       for(i=0;i<length;i++) {
        void *objptr=((void **)(((char *)& ao->___length___)+sizeof(int)))[i];
-       void * copy;
-       if (gc_createcopy(objptr, &copy))
-         enqueue(objptr);
-       ((void **)(((char *)& ao_cpy->___length___)+sizeof(int)))[i]=copy;
+       ENQUEUE(objptr, ((void **)(((char *)& ao_cpy->___length___)+sizeof(int)))[i]);
       }
     } else {
       int size=pointer[0];
       int i;
       for(i=1;i<=size;i++) {
-       int offset=pointer[i];
+       unsigned int offset=pointer[i];
        void * objptr=*((void **)(((int)ptr)+offset));
-       void * copy;
-       if (gc_createcopy(objptr, &copy))
-         enqueue(objptr);
-       *((void **) (((int)cpy)+offset))=copy;
+       ENQUEUE(objptr, *((void **) (((int)cpy)+offset)));
       }
     }
   }
+#ifdef TASK
+  fixtags();
+#endif
+
+#if defined(THREADS)||defined(DSTM)
+  needtocollect=0;
+  pthread_mutex_unlock(&gclistlock);
+#endif
 }
 
-void * curr_heapbase=0;
-void * curr_heapptr=0;
-void * curr_heapgcpoint=0;
-void * curr_heaptop=0;
+#ifdef TASK
 
-void * to_heapbase=0;
-void * to_heapptr=0;
-void * to_heaptop=0;
-long lastgcsize=0;
+/* Fix up the references from tags.  This can't be done earlier,
+   because we don't want tags to keep objects alive */
+void fixtags() {
+  while(taghead!=NULL) {
+    int i;
+    struct pointerblock *tmp=taghead->next;
+    for(i=0;i<tagindex;i++) {
+      struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
+      struct ___Object___ *obj=tagd->flagptr;
+      struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
+      if (obj==NULL) {
+       /* Zero object case */
+      } else if (obj->type==-1) {
+       /* Single object case */
+       copy->flagptr=((struct ___Object___**)obj)[1];
+      } else if (obj->type==OBJECTARRAYTYPE) {
+       /* Array case */
+       struct ArrayObject *ao=(struct ArrayObject *) obj;
+       int livecount=0;
+       int j;
+       int k=0;
+       struct ArrayObject *aonew;
+       
+       /* Count live objects */
+       for(j=0;j<ao->___cachedCode___;j++) {
+         struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
+         if (tobj->type==-1)
+           livecount++;
+       }
+       
+       livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
+       aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
+       memcpy(aonew, ao, sizeof(struct ArrayObject));
+       aonew->type=OBJECTARRAYTYPE;
+       aonew->___length___=livecount;
+       copy->flagptr=aonew;
+       for(j=0;j<ao->___cachedCode___;j++) {
+         struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
+         if (tobj->type==-1) {
+           struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
+           ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
+         }
+       }
+       aonew->___cachedCode___=k;
+       for(;k<livecount;k++) {
+         ARRAYSET(aonew, struct ___Object___*, k, NULL);
+       }
+      } else {
+       /* No object live anymore */
+       copy->flagptr=NULL;
+      }
+    }
+    free(taghead);
+    taghead=tmp;
+    tagindex=NUMPTRS;
+  }
+}
+#endif
 
 void * tomalloc(int size) {
   void * ptr=to_heapptr;
@@ -238,8 +387,61 @@ void * tomalloc(int size) {
   return ptr;
 }
 
+#if defined(THREADS)||defined(DSTM)
+
+void checkcollect(void * ptr) {
+  if (needtocollect) {
+    struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
+    pthread_mutex_lock(&gclock); // Wait for GC
+    restartaftergc(tmp);
+    pthread_mutex_unlock(&gclock);
+
+  }
+}
+
+struct listitem * stopforgc(struct garbagelist * ptr) {
+  struct listitem * litem=malloc(sizeof(struct listitem));
+  litem->stackptr=ptr;
+  litem->locklist=pthread_getspecific(threadlocks);
+  litem->prev=NULL;
+  pthread_mutex_lock(&gclistlock);
+  litem->next=list;
+  if(list!=NULL)
+    list->prev=litem;
+  list=litem;
+  listcount++;
+  pthread_cond_signal(&gccond);
+  pthread_mutex_unlock(&gclistlock);
+  return litem;
+}
+
+void restartaftergc(struct listitem * litem) {
+  pthread_mutex_lock(&gclistlock);
+  pthread_setspecific(threadlocks, litem->locklist);
+  if (litem->prev==NULL) {
+    list=litem->next;
+  } else {
+    litem->prev->next=litem->next;
+  }
+  if (litem->next!=NULL) {
+    litem->next->prev=litem->prev;
+  }
+  listcount--;
+  pthread_mutex_unlock(&gclistlock);
+  free(litem);
+}
+#endif
+
 void * mygcmalloc(struct garbagelist * stackptr, int size) {
-  void *ptr=curr_heapptr;
+  void *ptr;
+#if defined(THREADS)||defined(DSTM)
+  if (pthread_mutex_trylock(&gclock)!=0) {
+    struct listitem *tmp=stopforgc(stackptr);
+    pthread_mutex_lock(&gclock);
+    restartaftergc(tmp);
+  }
+#endif
+  ptr=curr_heapptr;
   if ((size%4)!=0)
     size+=(4-(size%4));
   curr_heapptr+=size;
@@ -255,7 +457,11 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
       to_heapbase=malloc(INITIALHEAPSIZE);
       to_heaptop=to_heapbase+INITIALHEAPSIZE;
       to_heapptr=to_heapbase;
-      return curr_heapbase;
+      ptr=curr_heapbase;
+#if defined(THREADS)||defined(DSTM)
+      pthread_mutex_unlock(&gclock);
+#endif
+      return ptr;
     }
 
     /* Grow the to heap if necessary */
@@ -300,14 +506,25 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
       to_heapptr=to_heapbase;
       
       /* Not enough room :(, redo gc */
-      if (curr_heapptr>curr_heapgcpoint)
+      if (curr_heapptr>curr_heapgcpoint) {
+#if defined(THREADS)||defined(DSTM)
+       pthread_mutex_unlock(&gclock);
+#endif
        return mygcmalloc(stackptr, size);
+      }
       
       bzero(tmp, curr_heaptop-tmp);
+#if defined(THREADS)||defined(DSTM)
+      pthread_mutex_unlock(&gclock);
+#endif
       return tmp;
     }
-  } else
+  } else {
+#if defined(THREADS)||defined(DSTM)
+    pthread_mutex_unlock(&gclock);
+#endif
     return ptr;
+  }
 }