get rid of error message about needtocollect
[IRC.git] / Robust / src / Runtime / garbage.c
1 #include "garbage.h"
2 #include "runtime.h"
3 #include "structdefs.h"
4 #include "Queue.h"
5 #include "SimpleHash.h"
6 #include "chash.h"
7 #include "GenericHashtable.h"
8 #include <string.h>
9 #if defined(THREADS) || defined(DSTM) || defined(STM)
10 #include "thread.h"
11 #endif
12
13 #ifdef DMALLOC
14 #include "dmalloc.h"
15 #endif
16 #ifdef DSTM
17 #include "dstm.h"
18 #endif
19 #ifdef STM
20 #include "tm.h"
21 #endif
22
23 #define NUMPTRS 100
24
25 #define INITIALHEAPSIZE 32*1024*1024
26 #define GCPOINT(x) ((int)((x)*0.9))
27 /* This define takes in how full the heap is initially and returns a new heap size to use */
28 #define HEAPSIZE(x,y) (((int)((x)/0.6))+y)
29
30 #ifdef TASK
31 extern struct genhashtable * activetasks;
32 #ifndef MULTICORE
33 extern struct parameterwrapper * objectqueues[NUMCLASSES];
34 #endif
35 extern struct genhashtable * failedtasks;
36 extern struct taskparamdescriptor *currtpd;
37 extern struct ctable *forward;
38 extern struct ctable *reverse;
39 extern struct RuntimeHash *fdtoobject;
40 #endif
41
42 #if defined(THREADS) || defined(DSTM) || defined(SINGLETM)
43 int needtocollect=0;
44 struct listitem * list=NULL;
45 int listcount=0;
46 #endif
47
48 //Need to check if pointers are transaction pointers
49 //this also catches the special flag value of 1 for local copies
50 #ifdef DSTM
51 #define ENQUEUE(orig, dst) \
52   if ((!(((unsigned int)orig)&0x1))) { \
53     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
54       void *copy; \
55       if (gc_createcopy(orig,&copy)) \
56         enqueue(orig);\
57       dst=copy; \
58     } \
59   }
60 #elif defined(FASTCHECK)
61 #define ENQUEUE(orig, dst) \
62   if (((unsigned int)orig)!=1) { \
63     void *copy; \
64     if (gc_createcopy(orig,&copy)) \
65       enqueue(orig);\
66     dst=copy; }
67 #else
68 #define ENQUEUE(orig, dst) \
69   void *copy; \
70   if (gc_createcopy(orig,&copy)) \
71     enqueue(orig);\
72   dst=copy
73 #endif
74
75 struct pointerblock {
76   void * ptrs[NUMPTRS];
77   struct pointerblock *next;
78 };
79
80 void * curr_heapbase=0;
81 void * curr_heapptr=0;
82 void * curr_heapgcpoint=0;
83 void * curr_heaptop=0;
84
85 void * to_heapbase=0;
86 void * to_heapptr=0;
87 void * to_heaptop=0;
88 long lastgcsize=0;
89
90 struct pointerblock *head=NULL;
91 int headindex=0;
92 struct pointerblock *tail=NULL;
93 int tailindex=0;
94 struct pointerblock *spare=NULL;
95
96 void enqueue(void *ptr) {
97   if (headindex==NUMPTRS) {
98     struct pointerblock * tmp;
99     if (spare!=NULL) {
100       tmp=spare;
101       spare=NULL;
102     } else
103       tmp=malloc(sizeof(struct pointerblock));
104     head->next=tmp;
105     head=tmp;
106     headindex=0;
107   }
108   head->ptrs[headindex++]=ptr;
109 }
110
111 void * dequeue() {
112   if (tailindex==NUMPTRS) {
113     struct pointerblock *tmp=tail;
114     tail=tail->next;
115     tailindex=0;
116     if (spare!=NULL)
117       free(tmp);
118     else
119       spare=tmp;
120   }
121   return tail->ptrs[tailindex++];
122 }
123
124 int moreItems() {
125   if ((head==tail)&&(tailindex==headindex))
126     return 0;
127   return 1;
128 }
129
130 #ifdef TASK
131 struct pointerblock *taghead=NULL;
132 int tagindex=0;
133
134 void enqueuetag(struct ___TagDescriptor___ *ptr) {
135   if (tagindex==NUMPTRS) {
136     struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
137     tmp->next=taghead;
138     taghead=tmp;
139     tagindex=0;
140   }
141   taghead->ptrs[tagindex++]=ptr;
142 }
143 #endif
144
145
146 void collect(struct garbagelist * stackptr) {
147 #if defined(THREADS)||defined(DSTM)
148   needtocollect=1;
149   pthread_mutex_lock(&gclistlock);
150   while(1) {
151     if ((listcount+1)==threadcount) {
152       break; /* Have all other threads stopped */
153     }
154     pthread_cond_wait(&gccond, &gclistlock);
155   }
156 #endif
157
158   if (head==NULL) {
159     headindex=0;
160     tailindex=0;
161     head=tail=malloc(sizeof(struct pointerblock));
162   }
163
164 #ifdef TASK
165   if (taghead==NULL) {
166     tagindex=0;
167     taghead=malloc(sizeof(struct pointerblock));
168     taghead->next=NULL;
169   }
170 #endif
171
172   /* Check current stack */
173 #if defined(THREADS)||defined(DSTM)
174   {
175     struct listitem *listptr=list;
176     while(1) {
177 #endif
178
179   while(stackptr!=NULL) {
180     int i;
181     for(i=0; i<stackptr->size; i++) {
182       void * orig=stackptr->array[i];
183       ENQUEUE(orig, stackptr->array[i]);
184     }
185     stackptr=stackptr->next;
186   }
187 #if defined(THREADS)||defined(DSTM)
188   /* Go to next thread */
189   if (listptr!=NULL) {
190     void * orig=listptr->locklist;
191     ENQUEUE(orig, listptr->locklist);
192     stackptr=listptr->stackptr;
193     listptr=listptr->next;
194   } else
195     break;
196 }
197 }
198 #endif
199
200 #ifdef FASTCHECK
201   ENQUEUE(___fcrevert___, ___fcrevert___);
202 #endif
203
204 #ifdef TASK
205   {
206     /* Update objectsets */
207     int i;
208     for(i=0; i<NUMCLASSES; i++) {
209 #ifdef MULTICORE
210 #else
211       struct parameterwrapper * p=objectqueues[i];
212       while(p!=NULL) {
213         struct ObjectHash * set=p->objectset;
214         struct ObjectNode * ptr=set->listhead;
215         while(ptr!=NULL) {
216           void *orig=(void *)ptr->key;
217           ENQUEUE(orig, *((void **)(&ptr->key)));
218           ptr=ptr->lnext;
219         }
220         ObjectHashrehash(set); /* Rehash the table */
221         p=p->next;
222       }
223 #endif
224     }
225   }
226
227 #ifndef FASTCHECK
228   if (forward!=NULL) {
229     struct cnode * ptr=forward->listhead;
230     while(ptr!=NULL) {
231       void * orig=(void *)ptr->key;
232       ENQUEUE(orig, *((void **)(&ptr->key)));
233       ptr=ptr->lnext;
234     }
235     crehash(forward); /* Rehash the table */
236   }
237
238   if (reverse!=NULL) {
239     struct cnode * ptr=reverse->listhead;
240     while(ptr!=NULL) {
241       void *orig=(void *)ptr->val;
242       ENQUEUE(orig, *((void**)(&ptr->val)));
243       ptr=ptr->lnext;
244     }
245   }
246 #endif
247
248   {
249     struct RuntimeNode * ptr=fdtoobject->listhead;
250     while(ptr!=NULL) {
251       void *orig=(void *)ptr->data;
252       ENQUEUE(orig, *((void**)(&ptr->data)));
253       ptr=ptr->lnext;
254     }
255   }
256
257   {
258     /* Update current task descriptor */
259     int i;
260     for(i=0; i<currtpd->numParameters; i++) {
261       void *orig=currtpd->parameterArray[i];
262       ENQUEUE(orig, currtpd->parameterArray[i]);
263     }
264
265   }
266
267   /* Update active tasks */
268   {
269     struct genpointerlist * ptr=activetasks->list;
270     while(ptr!=NULL) {
271       struct taskparamdescriptor *tpd=ptr->src;
272       int i;
273       for(i=0; i<tpd->numParameters; i++) {
274         void * orig=tpd->parameterArray[i];
275         ENQUEUE(orig, tpd->parameterArray[i]);
276       }
277       ptr=ptr->inext;
278     }
279     genrehash(activetasks);
280   }
281
282   /* Update failed tasks */
283   {
284     struct genpointerlist * ptr=failedtasks->list;
285     while(ptr!=NULL) {
286       struct taskparamdescriptor *tpd=ptr->src;
287       int i;
288       for(i=0; i<tpd->numParameters; i++) {
289         void * orig=tpd->parameterArray[i];
290         ENQUEUE(orig, tpd->parameterArray[i]);
291       }
292       ptr=ptr->inext;
293     }
294     genrehash(failedtasks);
295   }
296 #endif
297
298   while(moreItems()) {
299     void * ptr=dequeue();
300     void *cpy=((void **)ptr)[1];
301     int type=((int *)cpy)[0];
302     unsigned int * pointer;
303 #ifdef TASK
304     if(type==TAGTYPE) {
305       /* Enqueue Tag */
306       /* Nothing is inside */
307       enqueuetag(ptr);
308       continue;
309     }
310 #endif
311     pointer=pointerarray[type];
312     if (pointer==0) {
313       /* Array of primitives */
314       /* Do nothing */
315 #if defined(DSTM)||defined(FASTCHECK)
316       struct ArrayObject *ao=(struct ArrayObject *) ptr;
317       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
318       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
319       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
320 #endif
321     } else if (((int)pointer)==1) {
322       /* Array of pointers */
323       struct ArrayObject *ao=(struct ArrayObject *) ptr;
324       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
325 #if (defined(DSTM)||defined(FASTCHECK))
326       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
327       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
328 #endif
329       int length=ao->___length___;
330       int i;
331       for(i=0; i<length; i++) {
332         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
333         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
334       }
335     } else {
336       int size=pointer[0];
337       int i;
338       for(i=1; i<=size; i++) {
339         unsigned int offset=pointer[i];
340         void * objptr=*((void **)(((int)ptr)+offset));
341         ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
342       }
343     }
344   }
345 #ifdef TASK
346   fixtags();
347 #endif
348
349 #if defined(THREADS)||defined(DSTM)
350   needtocollect=0;
351   pthread_mutex_unlock(&gclistlock);
352 #endif
353 }
354
355 #ifdef TASK
356 /* Fix up the references from tags.  This can't be done earlier,
357    because we don't want tags to keep objects alive */
358 void fixtags() {
359   while(taghead!=NULL) {
360     int i;
361     struct pointerblock *tmp=taghead->next;
362     for(i=0; i<tagindex; i++) {
363       struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
364       struct ___Object___ *obj=tagd->flagptr;
365       struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
366       if (obj==NULL) {
367         /* Zero object case */
368       } else if (obj->type==-1) {
369         /* Single object case */
370         copy->flagptr=((struct ___Object___**)obj)[1];
371       } else if (obj->type==OBJECTARRAYTYPE) {
372         /* Array case */
373         struct ArrayObject *ao=(struct ArrayObject *) obj;
374         int livecount=0;
375         int j;
376         int k=0;
377         struct ArrayObject *aonew;
378
379         /* Count live objects */
380         for(j=0; j<ao->___cachedCode___; j++) {
381           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
382           if (tobj->type==-1)
383             livecount++;
384         }
385
386         livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
387         aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
388         memcpy(aonew, ao, sizeof(struct ArrayObject));
389         aonew->type=OBJECTARRAYTYPE;
390         aonew->___length___=livecount;
391         copy->flagptr=aonew;
392         for(j=0; j<ao->___cachedCode___; j++) {
393           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
394           if (tobj->type==-1) {
395             struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
396             ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
397           }
398         }
399         aonew->___cachedCode___=k;
400         for(; k<livecount; k++) {
401           ARRAYSET(aonew, struct ___Object___*, k, NULL);
402         }
403       } else {
404         /* No object live anymore */
405         copy->flagptr=NULL;
406       }
407     }
408     free(taghead);
409     taghead=tmp;
410     tagindex=NUMPTRS;
411   }
412 }
413 #endif
414
415 void * tomalloc(int size) {
416   void * ptr=to_heapptr;
417   if ((size&7)!=0)
418     size+=(8-(size%8));
419   to_heapptr+=size;
420   return ptr;
421 }
422
423 #if defined(THREADS)||defined(DSTM)
424 void checkcollect(void * ptr) {
425   struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
426   pthread_mutex_lock(&gclock); // Wait for GC
427   restartaftergc(tmp);
428   pthread_mutex_unlock(&gclock);
429 }
430
431 #ifdef DSTM
432 void checkcollect2(void * ptr) {
433   int ptrarray[]={1, (int)ptr, (int) revertlist};
434   struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
435   pthread_mutex_lock(&gclock); // Wait for GC
436   restartaftergc(tmp);
437   pthread_mutex_unlock(&gclock);
438   revertlist=(struct ___Object___*)ptrarray[2];
439 }
440 #endif
441
442
443 struct listitem * stopforgc(struct garbagelist * ptr) {
444   struct listitem * litem=malloc(sizeof(struct listitem));
445   litem->stackptr=ptr;
446   litem->locklist=pthread_getspecific(threadlocks);
447   litem->prev=NULL;
448   pthread_mutex_lock(&gclistlock);
449   litem->next=list;
450   if(list!=NULL)
451     list->prev=litem;
452   list=litem;
453   listcount++;
454   pthread_cond_signal(&gccond);
455   pthread_mutex_unlock(&gclistlock);
456   return litem;
457 }
458
459 void restartaftergc(struct listitem * litem) {
460   pthread_mutex_lock(&gclistlock);
461   pthread_setspecific(threadlocks, litem->locklist);
462   if (litem->prev==NULL) {
463     list=litem->next;
464   } else {
465     litem->prev->next=litem->next;
466   }
467   if (litem->next!=NULL) {
468     litem->next->prev=litem->prev;
469   }
470   listcount--;
471   pthread_mutex_unlock(&gclistlock);
472   free(litem);
473 }
474 #endif
475
476 void * mygcmalloc(struct garbagelist * stackptr, int size) {
477   void *ptr;
478 #if defined(THREADS)||defined(DSTM)||defined(STM)
479   if (pthread_mutex_trylock(&gclock)!=0) {
480     struct listitem *tmp=stopforgc(stackptr);
481     pthread_mutex_lock(&gclock);
482     restartaftergc(tmp);
483   }
484 #endif
485   ptr=curr_heapptr;
486   if ((size&7)!=0)
487     size+=(8-(size%8));
488   curr_heapptr+=size;
489   if (curr_heapptr>curr_heapgcpoint) {
490     if (curr_heapbase==0) {
491       /* Need to allocate base heap */
492       curr_heapbase=malloc(INITIALHEAPSIZE);
493       bzero(curr_heapbase, INITIALHEAPSIZE);
494       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
495       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
496       curr_heapptr=curr_heapbase+size;
497
498       to_heapbase=malloc(INITIALHEAPSIZE);
499       to_heaptop=to_heapbase+INITIALHEAPSIZE;
500       to_heapptr=to_heapbase;
501       ptr=curr_heapbase;
502 #if defined(THREADS)||defined(DSTM)||defined(STM)
503       pthread_mutex_unlock(&gclock);
504 #endif
505       return ptr;
506     }
507
508     /* Grow the to heap if necessary */
509     {
510       int curr_heapsize=curr_heaptop-curr_heapbase;
511       int to_heapsize=to_heaptop-to_heapbase;
512       int last_heapsize=0;
513       if (lastgcsize>0) {
514         last_heapsize=HEAPSIZE(lastgcsize, size);
515         if ((last_heapsize&7)!=0)
516           last_heapsize+=(8-(last_heapsize%8));
517       }
518       if (curr_heapsize>last_heapsize)
519         last_heapsize=curr_heapsize;
520       if (last_heapsize>to_heapsize) {
521         free(to_heapbase);
522         to_heapbase=malloc(last_heapsize);
523         if (to_heapbase==NULL) {
524           printf("Error Allocating enough memory\n");
525           exit(-1);
526         }
527         to_heaptop=to_heapbase+last_heapsize;
528         to_heapptr=to_heapbase;
529       }
530     }
531
532     /* Do our collection */
533     collect(stackptr);
534
535     /* Update stat on previous gc size */
536     lastgcsize=(to_heapptr-to_heapbase)+size;
537
538     /* Flip to/curr heaps */
539     {
540       void * tmp=to_heapbase;
541       to_heapbase=curr_heapbase;
542       curr_heapbase=tmp;
543
544       tmp=to_heaptop;
545       to_heaptop=curr_heaptop;
546       curr_heaptop=tmp;
547
548       tmp=to_heapptr;
549       curr_heapptr=to_heapptr+size;
550       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
551       to_heapptr=to_heapbase;
552
553       /* Not enough room :(, redo gc */
554       if (curr_heapptr>curr_heapgcpoint) {
555 #if defined(THREADS)||defined(DSTM)||defined(STM)
556         pthread_mutex_unlock(&gclock);
557 #endif
558         return mygcmalloc(stackptr, size);
559       }
560
561       bzero(tmp, curr_heaptop-tmp);
562 #if defined(THREADS)||defined(DSTM)||defined(STM)
563       pthread_mutex_unlock(&gclock);
564 #endif
565       return tmp;
566     }
567   } else {
568 #if defined(THREADS)||defined(DSTM)||defined(STM)
569     pthread_mutex_unlock(&gclock);
570 #endif
571     return ptr;
572   }
573 }
574
575
576 int gc_createcopy(void * orig, void ** copy_ptr) {
577   if (orig==0) {
578     *copy_ptr=NULL;
579     return 0;
580   } else {
581     int type=((int *)orig)[0];
582     if (type==-1) {
583       *copy_ptr=((void **)orig)[1];
584       return 0;
585     }
586     if (type<NUMCLASSES) {
587       /* We have a normal object */
588       int size=classsize[type];
589       void *newobj=tomalloc(size);
590       memcpy(newobj, orig, size);
591       ((int *)orig)[0]=-1;
592       ((void **)orig)[1]=newobj;
593       *copy_ptr=newobj;
594       return 1;
595     } else {
596       /* We have an array */
597       struct ArrayObject *ao=(struct ArrayObject *)orig;
598       int elementsize=classsize[type];
599       int length=ao->___length___;
600       int size=sizeof(struct ArrayObject)+length*elementsize;
601       void *newobj=tomalloc(size);
602       memcpy(newobj, orig, size);
603       ((int *)orig)[0]=-1;
604       ((void **)orig)[1]=newobj;
605       *copy_ptr=newobj;
606       return 1;
607     }
608   }
609 }