fix bugs
[IRC.git] / Robust / src / Runtime / task.c
1 #ifdef TASK
2 #include "runtime.h"
3 #include "structdefs.h"
4 #include "mem.h"
5 #include "checkpoint.h"
6 #include "Queue.h"
7 #include "SimpleHash.h"
8 #include "GenericHashtable.h"
9 #include <sys/select.h>
10 #include <sys/types.h>
11 #include <sys/mman.h>
12 #include <string.h>
13 #include <signal.h>
14
15 extern int injectfailures;
16 extern float failurechance;
17 extern int debugtask;
18 extern int instaccum;
19
20 #ifdef CONSCHECK
21 #include "instrument.h"
22 #endif
23
24 struct genhashtable * activetasks;
25 struct parameterwrapper * objectqueues[NUMCLASSES];
26 struct genhashtable * failedtasks;
27 struct taskparamdescriptor * currtpd;
28 struct RuntimeHash * forward;
29 struct RuntimeHash * reverse;
30
31 int main(int argc, char **argv) {
32 #ifdef BOEHM_GC
33   GC_init(); // Initialize the garbage collector
34 #endif
35 #ifdef CONSCHECK
36   initializemmap();
37 #endif
38   processOptions();
39   initializeexithandler();
40   /* Create table for failed tasks */
41   failedtasks=genallocatehashtable((unsigned int (*)(void *)) &hashCodetpd, 
42                                    (int (*)(void *,void *)) &comparetpd);
43   /* Create queue of active tasks */
44   activetasks=genallocatehashtable((unsigned int (*)(void *)) &hashCodetpd, 
45                                    (int (*)(void *,void *)) &comparetpd);
46   
47   /* Process task information */
48   processtasks();
49
50   /* Create startup object */
51   createstartupobject(argc, argv);
52
53   /* Start executing the tasks */
54   executetasks();
55 }
56
57 void createstartupobject(int argc, char ** argv) {
58   int i;
59   
60   /* Allocate startup object     */
61 #ifdef PRECISE_GC
62   struct ___StartupObject___ *startupobject=(struct ___StartupObject___*) allocate_new(NULL, STARTUPTYPE);
63   struct ArrayObject * stringarray=allocate_newarray(NULL, STRINGARRAYTYPE, argc-1); 
64 #else
65   struct ___StartupObject___ *startupobject=(struct ___StartupObject___*) allocate_new(STARTUPTYPE);
66   struct ArrayObject * stringarray=allocate_newarray(STRINGARRAYTYPE, argc-1); 
67 #endif
68   /* Build array of strings */
69   startupobject->___parameters___=stringarray;
70   for(i=1;i<argc;i++) {
71     int length=strlen(argv[i]);
72 #ifdef PRECISE_GC
73     struct ___String___ *newstring=NewString(NULL, argv[i],length);
74 #else
75     struct ___String___ *newstring=NewString(argv[i],length);
76 #endif
77     ((void **)(((char *)& stringarray->___length___)+sizeof(int)))[i-1]=newstring;
78   }
79   
80   /* Set initialized flag for startup object */
81   flagorand(startupobject,1,0xFFFFFFFF);
82 }
83
84 int hashCodetpd(struct taskparamdescriptor *ftd) {
85   int hash=(int)ftd->task;
86   int i;                                                
87   for(i=0;i<ftd->numParameters;i++){ 
88     hash^=(int)ftd->parameterArray[i];
89   }
90   return hash;
91 }
92
93 int comparetpd(struct taskparamdescriptor *ftd1, struct taskparamdescriptor *ftd2) {
94   int i;
95   if (ftd1->task!=ftd2->task)
96     return 0;
97   for(i=0;i<ftd1->numParameters;i++)
98     if(ftd1->parameterArray[i]!=ftd2->parameterArray[i])
99       return 0;
100 #ifdef OPTIONAL
101   for(i=0;i<ftd1->numParameters;i++) {
102     if(ftd1->failed[i]!=ftd2->failed[i])
103       return 0;
104   }
105 #endif
106   return 1;
107 }
108
109 /* This function sets a tag. */
110 #ifdef PRECISE_GC
111 void tagset(void *ptr, struct ___Object___ * obj, struct ___TagDescriptor___ * tagd) {
112 #else
113 void tagset(struct ___Object___ * obj, struct ___TagDescriptor___ * tagd) {
114 #endif
115   struct ___Object___ * tagptr=obj->___tags___;
116   if (tagptr==NULL) {
117     obj->___tags___=(struct ___Object___ *)tagd;
118   } else {
119     /* Have to check if it is already set */
120     if (tagptr->type==TAGTYPE) {
121       struct ___TagDescriptor___ * td=(struct ___TagDescriptor___ *) tagptr;
122       if (td==tagd)
123         return;
124 #ifdef PRECISE_GC
125       int ptrarray[]={2, (int) ptr, (int) obj, (int)tagd};
126       struct ArrayObject * ao=allocate_newarray(&ptrarray,TAGARRAYTYPE,TAGARRAYINTERVAL);
127       obj=(struct ___Object___ *)ptrarray[2];
128       tagd=(struct ___TagDescriptor___ *)ptrarray[3];
129       td=(struct ___TagDescriptor___ *) obj->___tags___;
130 #else
131       struct ArrayObject * ao=allocate_newarray(TAGARRAYTYPE,TAGARRAYINTERVAL);
132 #endif
133       ARRAYSET(ao, struct ___TagDescriptor___ *, 0, td);
134       ARRAYSET(ao, struct ___TagDescriptor___ *, 1, tagd);
135       obj->___tags___=(struct ___Object___ *) ao;
136       ao->___cachedCode___=2;
137     } else {
138       /* Array Case */
139       int i;
140       struct ArrayObject *ao=(struct ArrayObject *) tagptr;
141       for(i=0;i<ao->___cachedCode___;i++) {
142         struct ___TagDescriptor___ * td=ARRAYGET(ao, struct ___TagDescriptor___*, i);
143         if (td==tagd)
144           return;
145       }
146       if (ao->___cachedCode___<ao->___length___) {
147         ARRAYSET(ao, struct ___TagDescriptor___ *, ao->___cachedCode___, tagd);
148         ao->___cachedCode___++;
149       } else {
150 #ifdef PRECISE_GC
151         int ptrarray[]={2,(int) ptr, (int) obj, (int) tagd};
152         struct ArrayObject * aonew=allocate_newarray(&ptrarray,TAGARRAYTYPE,TAGARRAYINTERVAL+ao->___length___);
153         obj=(struct ___Object___ *)ptrarray[2];
154         tagd=(struct ___TagDescriptor___ *) ptrarray[3];
155         ao=(struct ArrayObject *)obj->___tags___;
156 #else
157         struct ArrayObject * aonew=allocate_newarray(TAGARRAYTYPE,TAGARRAYINTERVAL+ao->___length___);
158 #endif
159         aonew->___cachedCode___=ao->___length___+1;
160         for(i=0;i<ao->___length___;i++) {
161           ARRAYSET(aonew, struct ___TagDescriptor___*, i, ARRAYGET(ao, struct ___TagDescriptor___*, i));
162         }
163         ARRAYSET(aonew, struct ___TagDescriptor___ *, ao->___length___, tagd);
164       }
165     }
166   }
167
168   {
169     struct ___Object___ * tagset=tagd->flagptr;
170     if(tagset==NULL) {
171       tagd->flagptr=obj;
172     } else if (tagset->type!=OBJECTARRAYTYPE) {
173 #ifdef PRECISE_GC
174       int ptrarray[]={2, (int) ptr, (int) obj, (int)tagd};
175       struct ArrayObject * ao=allocate_newarray(&ptrarray,OBJECTARRAYTYPE,OBJECTARRAYINTERVAL);
176       obj=(struct ___Object___ *)ptrarray[2];
177       tagd=(struct ___TagDescriptor___ *)ptrarray[3];
178 #else
179       struct ArrayObject * ao=allocate_newarray(OBJECTARRAYTYPE,OBJECTARRAYINTERVAL);
180 #endif
181       ARRAYSET(ao, struct ___Object___ *, 0, tagd->flagptr);
182       ARRAYSET(ao, struct ___Object___ *, 1, obj);
183       ao->___cachedCode___=2;
184       tagd->flagptr=(struct ___Object___ *)ao;
185     } else {
186       struct ArrayObject *ao=(struct ArrayObject *) tagset;
187       if (ao->___cachedCode___<ao->___length___) {
188         ARRAYSET(ao, struct ___Object___*, ao->___cachedCode___++, obj);
189       } else {
190         int i;
191 #ifdef PRECISE_GC
192         int ptrarray[]={2, (int) ptr, (int) obj, (int)tagd};
193         struct ArrayObject * aonew=allocate_newarray(&ptrarray,OBJECTARRAYTYPE,OBJECTARRAYINTERVAL+ao->___length___);
194         obj=(struct ___Object___ *)ptrarray[2];
195         tagd=(struct ___TagDescriptor___ *)ptrarray[3];
196         ao=(struct ArrayObject *)tagd->flagptr;
197 #else
198         struct ArrayObject * aonew=allocate_newarray(OBJECTARRAYTYPE,OBJECTARRAYINTERVAL);
199 #endif
200         aonew->___cachedCode___=ao->___cachedCode___+1;
201         for(i=0;i<ao->___length___;i++) {
202           ARRAYSET(aonew, struct ___Object___*, i, ARRAYGET(ao, struct ___Object___*, i));
203         }
204         ARRAYSET(aonew, struct ___Object___ *, ao->___cachedCode___, obj);
205         tagd->flagptr=(struct ___Object___ *) ao;
206       }
207     }
208   }
209 }
210
211 /* This function clears a tag. */
212 #ifdef PRECISE_GC
213 void tagclear(void *ptr, struct ___Object___ * obj, struct ___TagDescriptor___ * tagd) {
214 #else
215 void tagclear(struct ___Object___ * obj, struct ___TagDescriptor___ * tagd) {
216 #endif
217   /* We'll assume that tag is alway there.
218      Need to statically check for this of course. */
219   struct ___Object___ * tagptr=obj->___tags___;
220
221   if (tagptr->type==TAGTYPE) {
222     if ((struct ___TagDescriptor___ *)tagptr==tagd)
223       obj->___tags___=NULL;
224     else
225       printf("ERROR 1 in tagclear\n");
226   } else {
227     struct ArrayObject *ao=(struct ArrayObject *) tagptr;
228     int i;
229     for(i=0;i<ao->___cachedCode___;i++) {
230       struct ___TagDescriptor___ * td=ARRAYGET(ao, struct ___TagDescriptor___ *, i);
231       if (td==tagd) {
232         ao->___cachedCode___--;
233         if (i<ao->___cachedCode___)
234           ARRAYSET(ao, struct ___TagDescriptor___ *, i, ARRAYGET(ao, struct ___TagDescriptor___ *, ao->___cachedCode___));
235         ARRAYSET(ao, struct ___TagDescriptor___ *, ao->___cachedCode___, NULL);
236         if (ao->___cachedCode___==0)
237           obj->___tags___=NULL;
238         goto PROCESSCLEAR;
239       }
240     }
241     printf("ERROR 2 in tagclear\n");
242   }
243  PROCESSCLEAR:
244   {
245     struct ___Object___ *tagset=tagd->flagptr;
246     if (tagset->type!=OBJECTARRAYTYPE) {
247       if (tagset==obj)
248         tagd->flagptr=NULL;
249       else
250         printf("ERROR 3 in tagclear\n");
251     } else {
252       struct ArrayObject *ao=(struct ArrayObject *) tagset;
253       int i;
254       for(i=0;i<ao->___cachedCode___;i++) {
255         struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, i);
256         if (tobj==obj) {
257           ao->___cachedCode___--;
258           if (i<ao->___cachedCode___)
259             ARRAYSET(ao, struct ___Object___ *, i, ARRAYGET(ao, struct ___Object___ *, ao->___cachedCode___));
260           ARRAYSET(ao, struct ___Object___ *, ao->___cachedCode___, NULL);
261           if (ao->___cachedCode___==0)
262             tagd->flagptr=NULL;
263           goto ENDCLEAR;
264         }
265       }
266       printf("ERROR 4 in tagclear\n");
267     }
268   }
269  ENDCLEAR:
270   return;
271   
272 }
273  
274 /* This function allocates a new tag. */
275 #ifdef PRECISE_GC
276 struct ___TagDescriptor___ * allocate_tag(void *ptr, int index) {
277   struct ___TagDescriptor___ * v=(struct ___TagDescriptor___ *) mygcmalloc((struct garbagelist *) ptr, classsize[TAGTYPE]);
278 #else
279 struct ___TagDescriptor___ * allocate_tag(int index) {
280   struct ___TagDescriptor___ * v=FREEMALLOC(classsize[TAGTYPE]);
281 #endif
282   v->type=TAGTYPE;
283   v->flag=index;
284   return v;
285
286
287
288
289 /* This function updates the flag for object ptr.  It or's the flag
290    with the or mask and and's it with the andmask. */
291
292 void flagbody(struct ___Object___ *ptr, int flag);
293 #ifdef OPTIONAL
294 void enqueueoptional(struct ___Object___ * currobj, int numfailedfses, int * failedfses, struct taskdescriptor * task, int index);
295 #endif
296  
297  int flagcomp(const int *val1, const int *val2) {
298    return (*val1)-(*val2);
299  } 
300
301 void flagorand(void * ptr, int ormask, int andmask) {
302 #ifdef OPTIONAL
303   struct ___Object___ * obj = (struct ___Object___ *)ptr;
304   if(obj->numfses){/*store the information about fses*/
305     int flag, i, j,counter, offset=0;
306     for(i=0;i<obj->numfses;i++) {
307       int oldoffset;
308       counter=obj->fses[offset++];
309       oldoffset=offset;
310       for(j=0;j<counter;j++) {
311         flag=obj->fses[offset];
312         obj->fses[offset++]=(flag|ormask)&andmask;
313       }
314       qsort(&obj->fses[oldoffset], sizeof(int), counter, (int (*)(const void *, const void *)) &flagcomp);
315     }
316     enqueueoptional(obj, 0, NULL, NULL, 0);
317   }
318   else
319 #endif
320     {
321       int oldflag=((int *)ptr)[1];
322       int flag=ormask|oldflag;
323       flag&=andmask;
324       flagbody(ptr, flag);
325     }
326 }
327  
328 void intflagorand(void * ptr, int ormask, int andmask) {
329 #ifdef OPTIONAL
330   struct ___Object___ * obj = (struct ___Object___ *)ptr;
331   if(obj->numfses) {/*store the information about fses*/
332     int flag, i, j,counter, offset=0;
333     for(i=0;i<obj->numfses;i++) {
334       int oldoffset;
335       counter=obj->fses[offset++];
336       oldoffset=offset;
337       for(j=0;j<counter;j++) {
338         flag=obj->fses[offset];
339         obj->fses[offset++]=(flag|ormask)&andmask;
340       }
341       qsort(&obj->fses[oldoffset], sizeof(int), counter, (int (*)(const void *, const void *)) &flagcomp);
342     }
343     enqueueoptional(obj, 0, NULL, NULL, 0);
344   }
345   else
346 #endif
347     {
348       int oldflag=((int *)ptr)[1];
349       int flag=ormask|oldflag;
350       flag&=andmask;
351       if (flag==oldflag) /* Don't do anything */
352         return;
353       else flagbody(ptr, flag);
354     }
355 }
356
357 void flagorandinit(void * ptr, int ormask, int andmask) {
358   int oldflag=((int *)ptr)[1];
359   int flag=ormask|oldflag;
360   flag&=andmask;
361   flagbody(ptr,flag);
362 }
363
364 void flagbody(struct ___Object___ *ptr, int flag) {
365   struct parameterwrapper *flagptr=(struct parameterwrapper *)ptr->flagptr;
366   ptr->flag=flag;
367   
368   /*Remove object from all queues */
369   while(flagptr!=NULL) {
370     struct parameterwrapper *next;
371     int UNUSED, UNUSED2, UNUSED3;
372     ObjectHashget(flagptr->objectset, (int) ptr, (int *) &next, &UNUSED, &UNUSED2, &UNUSED3);
373     ObjectHashremove(flagptr->objectset, (int)ptr);
374     flagptr=next;
375   }
376   
377   {
378     struct QueueItem *tmpptr;
379     struct parameterwrapper * parameter=objectqueues[ptr->type];
380     int i;
381     struct parameterwrapper * prevptr=NULL;
382     struct ___Object___ *tagptr=ptr->___tags___;
383     
384     /* Outer loop iterates through all parameter queues an object of
385        this type could be in.  */
386     
387     while(parameter!=NULL) {
388       /* Check tags */
389       if (parameter->numbertags>0) {
390         if (tagptr==NULL)
391           goto nextloop;//that means the object has no tag but that param needs tag
392         else if(tagptr->type==TAGTYPE) {//one tag
393           struct ___TagDescriptor___ * tag=(struct ___TagDescriptor___*) tagptr;
394           for(i=0;i<parameter->numbertags;i++) {
395             //slotid is parameter->tagarray[2*i];
396             int tagid=parameter->tagarray[2*i+1];
397             if (tagid!=tagptr->flag)
398               goto nextloop; /*We don't have this tag */          
399            }
400         } else {//multiple tags
401           struct ArrayObject * ao=(struct ArrayObject *) tagptr;
402           for(i=0;i<parameter->numbertags;i++) {
403             //slotid is parameter->tagarray[2*i];
404             int tagid=parameter->tagarray[2*i+1];
405             int j;
406             for(j=0;j<ao->___cachedCode___;j++) {
407               if (tagid==ARRAYGET(ao, struct ___TagDescriptor___*, i)->flag)
408                 goto foundtag;
409             }
410             goto nextloop;
411           foundtag:
412             ;
413           }
414         }
415       }
416       
417       /* Check flags */
418       for(i=0;i<parameter->numberofterms;i++) {
419         int andmask=parameter->intarray[i*2];
420         int checkmask=parameter->intarray[i*2+1];
421         if ((flag&andmask)==checkmask) {
422           enqueuetasks(parameter, prevptr, ptr, NULL, 0);
423           prevptr=parameter;
424           break;
425         }
426       }
427     nextloop:
428       parameter=parameter->next;
429     }
430     ptr->flagptr=prevptr;
431   }
432 }
433  
434 #ifdef OPTIONAL
435
436 int checktags(struct ___Object___ * currobj, struct fsanalysiswrapper * fswrapper) {
437   /* Check Tags */
438   struct ___Object___ * tagptr = currobj->___tags___;
439   if(fswrapper->numtags>0){
440     if (tagptr==NULL)
441       return 0; //that means the object has no tag but that param
442     //needs tag
443     else if(tagptr->type==TAGTYPE) {//one tag
444       if(fswrapper->numtags!=1) 
445         return 0; //we don't have the right number of tags
446       struct ___TagDescriptor___ * tag=(struct ___TagDescriptor___*) tagptr;
447       if (fswrapper->tags[0]!=tagptr->flag)
448         return 0;
449     } else {  //multiple tags
450       struct ArrayObject * ao=(struct ArrayObject *) tagptr;
451       int tag_counter=0;
452       int foundtag=0;
453       
454       if(ao->___length___!=fswrapper->numtags) 
455         return 0;//we don't have the right number of tags
456       for(tag_counter=0;tag_counter<fswrapper->numtags;tag_counter++) {
457         int tagid=fswrapper->tags[tag_counter];
458         int j;
459         for(j=0;j<ao->___cachedCode___;j++) {
460           if (tagid==ARRAYGET(ao, struct ___TagDescriptor___*, tag_counter)->flag)
461             return 1;
462         }
463         return 0;
464       }
465     }
466   }
467   return 1;
468 }
469
470 int getlength(int *flist, int len) {
471   int count=0;
472   int i;
473   for(i=0;i<len;i++) {
474     int size=flist[count];
475     count+=1+size;
476   }
477   return count;
478 }
479
480 int * domergeor(int *flist1, int len1, int *flist2, int len2) {
481   int size1=getlength(flist1, len1);
482   int size2=getlength(flist2, len2);
483   int *merge=RUNMALLOC((size1+size2)*sizeof(int));
484   memcpy(merge, flist1, size1*sizeof(int));
485   memcpy(&merge[size1], flist2, size2*sizeof(int));
486   return merge;
487 }
488
489 int domerge(int * flist1, int len1, int *flist2, int len2, int *merge) {
490   int count=0;
491   int i=0;
492   int j=0;
493   while(i<len1||j<len2) {
494     if (i<len1&&(j==len2||flist1[i]<flist2[j])) {
495       if(merge!=NULL) {
496         merge[count]=flist1[i];
497       }
498       i++;
499       count++;
500     } else if (j<len2&&(i==len1||flist2[j]<flist1[i])) {
501       if(merge!=NULL) {
502         merge[count]=flist2[j];
503       }
504       j++;
505       count++;
506     } else if (i<len1&&j<len2&&flist1[i]==flist2[j]) {
507       if(merge!=NULL) {
508         merge[count]=flist1[i];
509       }
510       i++;
511       j++;
512       count++;
513     }
514   }
515   return count;
516 }
517
518 /* Merge flags from ftlmerge into ftl. */
519 void mergeitems(struct failedtasklist *ftl, struct failedtasklist *ftlmerge) {
520   int length=0;
521   int i,j;
522   int *mergedlist;
523   int offset=0;
524   for(i=0;i<ftl->numflags;i++) {
525     int len=ftl->flags[offset++];
526     int offsetmerge=0;
527     for(j=0;j<ftlmerge->numflags;j++) {
528       int lenmerge=ftlmerge->flags[offsetmerge++];
529       length+=1+domerge(&ftl->flags[offset],len,&ftlmerge->flags[offsetmerge],lenmerge, NULL);
530       offsetmerge+=lenmerge;
531     }
532     offset+=len;
533   }
534   mergedlist=RUNMALLOC(sizeof(int)*length);
535   
536   offset=0;
537   length=0;
538   for(i=0;i<ftl->numflags;i++) {
539     int len=ftl->flags[offset++];
540     int offsetmerge=0;
541     for(j=0;j<ftlmerge->numflags;j++) {
542       int lenmerge=ftlmerge->flags[offsetmerge++];
543       int size=domerge(&ftl->flags[offset],len,&ftlmerge->flags[offsetmerge],lenmerge,&mergedlist[length+1]);
544       mergedlist[length]=size;
545       length+=size+1;
546     }
547   }
548   RUNFREE(ftl->flags);
549   ftl->flags=mergedlist;
550   ftl->numflags*=ftlmerge->numflags;
551 }
552
553 void mergefailedlists(struct failedtasklist **andlist, struct failedtasklist *list) {
554   struct failedtasklist *tmpptr;
555   while((*andlist)!=NULL) {
556     struct failedtasklist *searchftl=list;
557     while(searchftl!=NULL) {
558       if ((*andlist)->task==searchftl->task&&
559           (*andlist)->index==searchftl->index) {
560         mergeitems(*andlist, searchftl);
561         break;
562       }
563       searchftl=searchftl->next;
564     }
565     if (searchftl==NULL) {
566       //didn't find andlist
567       tmpptr=*andlist;
568       *andlist=(*andlist)->next;//splice item out of list
569       RUNFREE(tmpptr->flags); //free the item
570       RUNFREE(tmpptr);
571     } else {
572       andlist=&((*andlist)->next); //iterate to next item
573     }
574   }
575   //free the list we're searching
576   while(list!=NULL) {
577     tmpptr=list->next;
578     RUNFREE(list->flags);
579     RUNFREE(list);
580     list=tmpptr;
581   }
582 }
583
584 struct failedtasklist * processfailstate(struct classanalysiswrapper * classwrapper, struct taskdescriptor *task, int index, struct ___Object___ * currobj, int flagstate) {
585   struct failedtasklist *list=NULL;
586   int i,h;
587   struct fsanalysiswrapper *fswrapper=NULL;
588   for(h=0;h<classwrapper->numfsanalysiswrappers;h++) {
589     struct fsanalysiswrapper * tmp=classwrapper->fsanalysiswrapperarray[h];
590     if (tmp->flags==flagstate&&checktags(currobj, tmp)) {
591       //we only match exactly here
592       fswrapper=tmp;
593       break;
594     }
595   }
596   if (fswrapper==NULL)
597     return list;
598   for(i=0;i<fswrapper->numtaskfailures;i++) {
599     int j;
600     struct taskfailure * taskfail=fswrapper->taskfailurearray[i];
601     if (taskfail->task==task&&taskfail->index==index) {
602       int start=0;
603       while(start<taskfail->numoptionaltaskdescriptors) {
604         struct taskdescriptor *currtask=NULL;
605         struct failedtasklist *tmpftl;
606         int currindex;
607         int totallength=0;
608         int *enterflags;
609         int numenterflags, offset;
610         struct parameterwrapper *pw;
611         for(j=start;j<taskfail->numoptionaltaskdescriptors;j++) {
612           struct optionaltaskdescriptor *otd=taskfail->optionaltaskdescriptorarray[j];
613           if(currtask==NULL) {
614             currtask=otd->task;
615             currindex=otd->index;
616           } else if (currtask!=otd->task||currindex!=otd->index)
617             break;
618           totallength+=otd->numenterflags;
619         }
620         pw=currtask->descriptorarray[currindex]->queue;
621         enterflags=RUNMALLOC(totallength*sizeof(int));
622         numenterflags=j-start;
623         offset=0;
624         for(start;start<j;start++) {
625           struct optionaltaskdescriptor *otd=taskfail->optionaltaskdescriptorarray[start];
626           enterflags[offset++]=otd->numenterflags;
627           memcpy(&enterflags[offset], otd->enterflags, otd->numenterflags*sizeof(int));
628           offset+=otd->numenterflags;
629         }
630         tmpftl=RUNMALLOC(sizeof(struct failedtasklist));
631         tmpftl->next=list;
632         tmpftl->task=currtask;
633         tmpftl->numflags=numenterflags;
634         tmpftl->flags=enterflags;
635         list=tmpftl;
636       }
637     }
638   }
639   return list;
640 }
641
642 struct failedtasklist * processnormfailstate(struct classanalysiswrapper * classwrapper, struct ___Object___ * currobj, int flagstate) {
643   struct failedtasklist *list=NULL;
644   int i,h;
645   int start=0;
646   struct fsanalysiswrapper *fswrapper=NULL;
647   for(h=0;h<classwrapper->numfsanalysiswrappers;h++) {
648     struct fsanalysiswrapper * tmp=classwrapper->fsanalysiswrapperarray[h];
649     if (tmp->flags==flagstate&&checktags(currobj, tmp)) {
650       //we only match exactly here
651       fswrapper=tmp;
652       break;
653     }
654   }
655   if(fswrapper==NULL)
656     return NULL;
657
658   while(start<fswrapper->numoptionaltaskdescriptors) {
659     struct taskdescriptor *currtask=NULL;
660     struct failedtasklist *tmpftl;
661     int j;
662     int currindex;
663     int totallength=0;
664     int *enterflags;
665     int numenterflags, offset;
666     struct parameterwrapper *pw;
667     for(j=start;j<fswrapper->numoptionaltaskdescriptors;j++) {
668       struct optionaltaskdescriptor *otd=fswrapper->optionaltaskdescriptorarray[j];
669       if(currtask==NULL) {
670         currtask=otd->task;
671         currindex=otd->index;
672       } else if (currtask!=otd->task||currindex!=otd->index)
673         break;
674       totallength+=otd->numenterflags;
675     }
676     pw=currtask->descriptorarray[currindex]->queue;
677     enterflags=RUNMALLOC(totallength*sizeof(int));
678     numenterflags=j-start;
679     offset=0;
680     for(start;start<j;start++) {
681       struct optionaltaskdescriptor *otd=fswrapper->optionaltaskdescriptorarray[start];
682       enterflags[offset++]=otd->numenterflags;
683       memcpy(&enterflags[offset], otd->enterflags, otd->numenterflags*sizeof(int));
684       offset+=otd->numenterflags;
685     }
686     tmpftl=RUNMALLOC(sizeof(struct failedtasklist));
687     tmpftl->next=list;
688     tmpftl->task=currtask;
689     tmpftl->numflags=numenterflags;
690     tmpftl->flags=enterflags;
691     list=tmpftl;
692   }
693   return list;
694 }
695
696
697
698 void enqueuelist(struct ___Object___ * currobj, struct failedtasklist * andlist) {
699   while(andlist!=NULL) {
700     struct failedtasklist *tmp=andlist;
701     struct parameterwrapper *pw=andlist->task->descriptorarray[andlist->index]->queue;
702     struct parmaeterwrapper *next;
703     int * flags;
704     int numflags;
705     int isnonfailed;
706     
707     if (enqueuetasks(pw, currobj->flagptr, currobj, tmp->flags, tmp->numflags))
708       currobj->flagptr=pw;
709     
710     andlist=andlist->next;
711     RUNFREE(tmp);
712   }
713 }
714
715 void enqueueoptional(struct ___Object___ * currobj, int numfailedfses, int * failedfses, struct taskdescriptor * task, int index) {
716   struct classanalysiswrapper * classwrapper=NULL; 
717   
718   /*test what optionaltaskdescriptors are available, find the class
719     corresponding*/
720   if (classanalysiswrapperarray[currobj->type]!=NULL) {
721     classwrapper = classanalysiswrapperarray[currobj->type];
722   } else
723     return;
724   
725   if(task!=NULL) { 
726     /* We have a failure */
727     if (failedfses==NULL) {
728       /* Failed in normal state */
729       /*first time the method is invoked*/
730       int i,h;
731       struct fsanalysiswrapper *fswrapper=NULL;
732
733       for(h=0;h<classwrapper->numfsanalysiswrappers;h++) {
734         struct fsanalysiswrapper * tmp=classwrapper->fsanalysiswrapperarray[h];
735         if (tmp->flags==currobj->flag&&checktags(currobj, tmp)) {
736           //we only match exactly here
737           fswrapper=tmp;
738           break;
739         }
740       }
741       if(fswrapper==NULL) //nothing to do in this state
742         return;
743       for(i=0;i<fswrapper->numtaskfailures;i++) {
744         int j;
745         struct taskfailure * taskfail=fswrapper->taskfailurearray[i];
746         if (taskfail->task==task&&taskfail->index==index) {
747           int start=0;
748           while(start<taskfail->numoptionaltaskdescriptors) {
749             struct taskdescriptor *currtask=NULL;
750             int currindex;
751             int totallength=0;
752             int *enterflags;
753             int numenterflags, offset;
754             struct parameterwrapper *pw;
755             for(j=start;j<taskfail->numoptionaltaskdescriptors;j++) {
756               struct optionaltaskdescriptor *otd=taskfail->optionaltaskdescriptorarray[j];
757               if(currtask==NULL) {
758                 currtask=otd->task;
759                 currindex=otd->index;
760               } else if (currtask!=otd->task||currindex!=otd->index)
761                 break;
762               totallength+=otd->numenterflags;
763             }
764             pw=currtask->descriptorarray[currindex]->queue;
765             enterflags=RUNMALLOC(totallength*sizeof(int));
766             numenterflags=j-start;
767
768             offset=0;
769             for(start;start<j;start++) {
770               struct optionaltaskdescriptor *otd=taskfail->optionaltaskdescriptorarray[start];
771               enterflags[offset++]=otd->numenterflags;
772               memcpy(&enterflags[offset], otd->enterflags, otd->numenterflags*sizeof(int));
773               offset+=otd->numenterflags;
774             }
775             //Enqueue this one
776             if (enqueuetasks(pw, currobj->flagptr, currobj, enterflags, numenterflags))
777               currobj->flagptr=pw;
778           }
779         }
780       }
781     } else {
782       /* Failed in failed state */
783       int i;
784       int offset=0;
785       for(i=0;i<numfailedfses;i++) {
786         int numfses=failedfses[offset++];
787         int j;
788         struct failedtasklist *andlist=NULL;
789         for(j=0;j<numfses;j++) {
790           int flagstate=failedfses[offset++];
791           struct failedtasklist *currlist=processfailstate(classwrapper, task, index, currobj, flagstate);
792           if (andlist==NULL)
793             andlist=currlist;
794           else
795             mergefailedlists(&andlist, currlist);
796         }
797         enqueuelist(currobj, andlist);
798       }
799     }
800   } else {
801     /* No failure, but we are in a failed state */
802     struct parameterwrapper *flagptr=(struct parameterwrapper *)currobj->flagptr;
803
804     /*Remove object from all queues */
805     while(flagptr!=NULL) {
806       struct parameterwrapper *next;
807       int UNUSED, UNUSED2, UNUSED3;
808       ObjectHashget(flagptr->objectset, (int) currobj, (int *) &next, &UNUSED, &UNUSED2, &UNUSED3);
809       ObjectHashremove(flagptr->objectset, (int)currobj);
810       flagptr=next;
811     }
812
813     /* Failed in failed state */
814     int i;
815     int offset=0;
816     for(i=0;i<currobj->numfses;i++) {
817       int numfses=currobj->fses[offset++];
818       int j;
819       struct failedtasklist *andlist=NULL;
820       for(j=0;j<numfses;j++) {
821         int flagstate=currobj->fses[offset++];
822         struct failedtasklist *currlist=processnormfailstate(classwrapper, currobj, flagstate);
823         if (andlist==NULL)
824           andlist=currlist;
825         else
826           mergefailedlists(&andlist, currlist);
827       }
828       enqueuelist(currobj, andlist);
829     }
830   }
831
832  
833  
834 #endif
835  
836 int enqueuetasks(struct parameterwrapper *parameter, struct parameterwrapper *prevptr, struct ___Object___ *ptr, int * enterflags, int numenterflags) {
837   void * taskpointerarray[MAXTASKPARAMS];
838 #ifdef OPTIONAL
839   int failed[MAXTASKPARAMS];
840 #endif
841   int j;
842   int numparams=parameter->task->numParameters;
843   int numiterators=parameter->task->numTotal-1;
844   int retval=1;
845   int addnormal=1;
846   int adderror=1;
847
848   struct taskdescriptor * task=parameter->task;
849
850 #ifdef OPTIONAL  
851   if (ObjectHashcontainskey(parameter->objectset, (int) ptr)) {
852     /* The object is already here...or it with the existing item */
853     int * oldflags;
854     int oldnumflags;
855     int oldptr;
856     int oldstatus;
857     int *mergedflags;
858     ObjectHashget(parameter->objectset, (int) ptr, & oldptr, (int *) &oldflags, &oldnumflags, &oldstatus);
859     mergedflags=domergeor(oldflags, oldnumflags, enterflags, numenterflags);
860     ObjectHashupdate(parameter->objectset, (int) ptr, oldptr, mergedflags, oldnumflags+numenterflags, oldstatus||(enterflags==NULL));
861
862     RUNFREE(oldflags);
863     RUNFREE(enterflags);
864
865     //only add if truly needed
866     if (oldstatus)
867       addnormal=0;
868     if (oldnumflags>0)
869       adderror=0;
870
871     retval=0;
872   } else {
873 #endif
874     ObjectHashadd(parameter->objectset, (int) ptr, (int) prevptr, (int) enterflags, numenterflags, enterflags==NULL);//this add the object to parameterwrapper
875 #ifdef OPTIONAL
876   }
877 #endif
878  
879   /* Add enqueued object to parameter vector */
880   taskpointerarray[parameter->slot]=ptr;
881 #ifdef OPTIONAL
882   failed[parameter->slot]=(enterflags!=NULL);
883 #endif
884
885   /* Reset iterators */
886   for(j=0;j<numiterators;j++) {
887     toiReset(&parameter->iterators[j]);
888   }
889
890   /* Find initial state */
891   for(j=0;j<numiterators;j++) {
892   backtrackinit:
893     if(toiHasNext(&parameter->iterators[j], taskpointerarray OPTARG(failed)))
894       toiNext(&parameter->iterators[j], taskpointerarray OPTARG(failed));
895     else if (j>0) {
896       /* Need to backtrack */
897       toiReset(&parameter->iterators[j]);
898       j--;
899       goto backtrackinit;
900     } else {
901       /* Nothing to enqueue */
902       return retval;
903     }
904   }
905
906   
907   while(1) {
908     /* Enqueue current state */
909     int launch = 0;
910     struct taskparamdescriptor *tpd=RUNMALLOC(sizeof(struct taskparamdescriptor));
911     tpd->task=task;
912     tpd->numParameters=numiterators+1;
913     tpd->parameterArray=RUNMALLOC(sizeof(void *)*(numiterators+1));
914 #ifdef OPTIONAL
915     tpd->failed=RUNMALLOC(sizeof(int)*(numiterators+1));
916 #endif
917     for(j=0;j<=numiterators;j++){
918       tpd->parameterArray[j]=taskpointerarray[j];//store the actual parameters
919 #ifdef OPTIONAL
920       tpd->failed[j]=failed[j];
921 #endif
922     }
923     /* Enqueue task */
924     if ((!gencontains(failedtasks, tpd)&&!gencontains(activetasks,tpd))) {
925       genputtable(activetasks, tpd, tpd);
926     } else {
927       RUNFREE(tpd->parameterArray);
928       RUNFREE(tpd);
929     }
930     
931     /* This loop iterates to the next parameter combination */
932     if (numiterators==0)
933       return retval;
934
935     for(j=numiterators-1; j<numiterators;j++) {
936     backtrackinc:
937       if(toiHasNext(&parameter->iterators[j], taskpointerarray OPTARG(failed)))
938         toiNext(&parameter->iterators[j], taskpointerarray OPTARG(failed));
939       else if (j>0) {
940         /* Need to backtrack */
941         toiReset(&parameter->iterators[j]);
942         j--;
943         goto backtrackinc;
944       } else {
945         /* Nothing more to enqueue */
946         return retval;
947       }
948     }
949   }
950   return retval;
951 }
952  
953 /* Handler for signals. The signals catch null pointer errors and
954    arithmatic errors. */
955
956 void myhandler(int sig, siginfo_t *info, void *uap) {
957   sigset_t toclear;
958 #ifdef DEBUG
959   printf("sig=%d\n",sig);
960   printf("signal\n");
961 #endif
962   sigemptyset(&toclear);
963   sigaddset(&toclear, sig);
964   sigprocmask(SIG_UNBLOCK, &toclear,NULL); 
965   longjmp(error_handler,1);
966 }
967
968 fd_set readfds;
969 int maxreadfd;
970 struct RuntimeHash *fdtoobject;
971
972 void addreadfd(int fd) {
973   if (fd>=maxreadfd)
974     maxreadfd=fd+1;
975   FD_SET(fd, &readfds);
976 }
977
978 void removereadfd(int fd) {
979   FD_CLR(fd, &readfds);
980   if (maxreadfd==(fd+1)) {
981     maxreadfd--;
982     while(maxreadfd>0&&!FD_ISSET(maxreadfd-1, &readfds))
983       maxreadfd--;
984   }
985 }
986
987 #ifdef PRECISE_GC
988 #define OFFSET 2
989 #else
990 #define OFFSET 0
991 #endif
992
993 #ifdef OPTIONAL
994  int * fsescopy(int *src, int len) {
995    int *dst;
996    if (src==NULL)
997      return NULL;
998    dst=RUNMALLOC(len*sizeof(int));
999    memcpy(dst, src, len*sizeof(int));
1000    return dst;
1001  }
1002 #endif
1003
1004 void executetasks() {
1005   void * taskpointerarray[MAXTASKPARAMS+OFFSET];
1006 #ifdef OPTIONAL
1007   int * fsesarray[MAXTASKPARAMS];
1008   int * oldfsesarray[MAXTASKPARAMS];
1009   int numfsesarray[MAXTASKPARAMS];
1010 #endif  
1011
1012   /* Set up signal handlers */
1013   struct sigaction sig;
1014   sig.sa_sigaction=&myhandler;
1015   sig.sa_flags=SA_SIGINFO;
1016   sigemptyset(&sig.sa_mask);
1017
1018   /* Catch bus errors, segmentation faults, and floating point exceptions*/
1019   sigaction(SIGBUS,&sig,0);
1020   sigaction(SIGSEGV,&sig,0);
1021   sigaction(SIGFPE,&sig,0);
1022   sigaction(SIGPIPE,&sig,0);
1023
1024   /* Zero fd set */
1025   FD_ZERO(&readfds);
1026   maxreadfd=0;
1027   fdtoobject=allocateRuntimeHash(100);
1028
1029   /* Map first block of memory to protected, anonymous page */
1030   mmap(0, 0x1000, 0, MAP_SHARED|MAP_FIXED|MAP_ANON, -1, 0);
1031
1032   newtask:
1033   while((hashsize(activetasks)>0)||(maxreadfd>0)) {
1034
1035     /* Check if any filedescriptors have IO pending */
1036     if (maxreadfd>0) {
1037       int i;
1038       struct timeval timeout={0,0};
1039       fd_set tmpreadfds;
1040       int numselect;
1041       tmpreadfds=readfds;
1042       numselect=select(maxreadfd, &tmpreadfds, NULL, NULL, &timeout);
1043       if (numselect>0) {
1044         /* Process ready fd's */
1045         int fd;
1046         for(fd=0;fd<maxreadfd;fd++) {
1047           if (FD_ISSET(fd, &tmpreadfds)) {
1048             /* Set ready flag on object */
1049             void * objptr;
1050             //      printf("Setting fd %d\n",fd);
1051             if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
1052               intflagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
1053             }
1054           }
1055         }
1056       }
1057     }
1058
1059     /* See if there are any active tasks */
1060     if (hashsize(activetasks)>0) {
1061       int i;
1062       currtpd=(struct taskparamdescriptor *) getfirstkey(activetasks);
1063       genfreekey(activetasks, currtpd);
1064       
1065       /* Check if this task has failed, allow a task that contains optional objects to fire */
1066       if (gencontains(failedtasks, currtpd)) {
1067         // Free up task parameter descriptor
1068         RUNFREE(currtpd->parameterArray);
1069         RUNFREE(currtpd);
1070         goto newtask;
1071       }
1072       int numparams=currtpd->task->numParameters;
1073       int numtotal=currtpd->task->numTotal;
1074       
1075       /* Make sure that the parameters are still in the queues */
1076       for(i=0;i<numparams;i++) {
1077         void * parameter=currtpd->parameterArray[i];
1078         struct parameterdescriptor * pd=currtpd->task->descriptorarray[i];
1079         struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
1080         int j;
1081         /* Check that object is still in queue */
1082 #ifdef OPTIONAL
1083         {
1084           int UNUSED, UNUSED2;
1085           int *flags;
1086           int numflags, isnonfailed;
1087           int failed=currtpd->failed[i];
1088           if (!ObjectHashget(pw->objectset, (int) parameter, &UNUSED, (int *) &flags, &numflags, &isnonfailed)) {
1089             RUNFREE(currtpd->parameterArray);
1090             RUNFREE(currtpd->failed);
1091             RUNFREE(currtpd);
1092             goto newtask;
1093           } else {
1094             if (failed&&(flags!=NULL)) {
1095               //Failed parameter
1096               fsesarray[i]=flags;
1097               numfsesarray[i]=numflags;
1098             } else if (!failed && isnonfailed) {
1099               //Non-failed parameter
1100               fsesarray[i]=NULL;
1101               numfsesarray[i]=0;
1102             } else {
1103               RUNFREE(currtpd->parameterArray);
1104               RUNFREE(currtpd->failed);
1105               RUNFREE(currtpd);
1106               goto newtask;
1107             }
1108           }
1109         }
1110 #else
1111         {
1112           if (!ObjectHashcontainskey(pw->objectset, (int) parameter)) {
1113             RUNFREE(currtpd->parameterArray);
1114             RUNFREE(currtpd);
1115             goto newtask;
1116           }
1117         }
1118 #endif
1119       parameterpresent:
1120         ;
1121         /* Check that object still has necessary tags */
1122         for(j=0;j<pd->numbertags;j++) {
1123           int slotid=pd->tagarray[2*j]+numparams;
1124           struct ___TagDescriptor___ *tagd=currtpd->parameterArray[slotid];
1125           if (!containstag(parameter, tagd)) {
1126             RUNFREE(currtpd->parameterArray);
1127             RUNFREE(currtpd);
1128             goto newtask;
1129           }
1130         }
1131         
1132         taskpointerarray[i+OFFSET]=parameter;
1133       }
1134       /* Copy the tags */
1135       for(;i<numtotal;i++) {
1136         taskpointerarray[i+OFFSET]=currtpd->parameterArray[i];
1137       }
1138
1139       {
1140         /* Checkpoint the state */
1141         forward=allocateRuntimeHash(100);
1142         reverse=allocateRuntimeHash(100);
1143         void ** checkpoint=makecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, forward, reverse);
1144         int x;
1145         if (x=setjmp(error_handler)) {
1146           int counter;
1147           /* Recover */
1148 #ifdef DEBUG
1149           printf("Fatal Error=%d, Recovering!\n",x);
1150 #endif
1151           genputtable(failedtasks,currtpd,currtpd);
1152           restorecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, checkpoint, forward, reverse);
1153
1154 #ifdef OPTIONAL
1155           for(counter=0; counter<currtpd->task->numParameters; counter++){
1156             //enqueue as failed
1157             enqueueoptional(currtpd->parameterArray[counter], numfsesarray[counter], fsesarray[counter], currtpd->task, counter);
1158
1159             //free fses copies
1160             if (fsesarray[counter]!=NULL)
1161               RUNFREE(fsesarray[counter]);
1162           }
1163 #endif
1164           freeRuntimeHash(forward);
1165           freeRuntimeHash(reverse);
1166           freemalloc();
1167           forward=NULL;
1168           reverse=NULL;
1169         } else {
1170           if (injectfailures) {
1171             if ((((double)random())/RAND_MAX)<failurechance) {
1172               printf("\nINJECTING TASK FAILURE to %s\n", currtpd->task->name);
1173               longjmp(error_handler,10);
1174             }
1175           }
1176           /* Actually call task */
1177 #ifdef PRECISE_GC
1178           ((int *)taskpointerarray)[0]=currtpd->task->numParameters;
1179           taskpointerarray[1]=NULL;
1180 #endif
1181 #ifdef OPTIONAL
1182           //get the task flags set
1183           for(i=0;i<numparams;i++) {
1184             oldfsesarray[i]=((struct ___Object___ *)taskpointerarray[i+OFFSET])->fses;
1185             fsesarray[i]=fsescopy(fsesarray[i], numfsesarray[i]);
1186             ((struct ___Object___ *)taskpointerarray[i+OFFSET])->fses=fsesarray[i];         
1187           }
1188 #endif
1189           if(debugtask){
1190             printf("ENTER %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
1191             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
1192             printf("EXIT %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
1193           } else
1194             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
1195
1196 #ifdef OPTIONAL
1197           for(i=0;i<numparams;i++) {
1198             //free old fses
1199             if(oldfsesarray[i]!=NULL)
1200               RUNFREE(oldfsesarray[i]);
1201           }
1202 #endif
1203           
1204           freeRuntimeHash(forward);
1205           freeRuntimeHash(reverse);
1206           freemalloc();
1207           // Free up task parameter descriptor
1208           RUNFREE(currtpd->parameterArray);
1209           RUNFREE(currtpd);
1210           forward=NULL;
1211           reverse=NULL;
1212         }
1213       }
1214     }
1215   }
1216 }
1217  
1218 /* This function processes an objects tags */
1219 void processtags(struct parameterdescriptor *pd, int index, struct parameterwrapper *parameter, int * iteratorcount, int *statusarray, int numparams) {
1220   int i;
1221   
1222   for(i=0;i<pd->numbertags;i++) {
1223     int slotid=pd->tagarray[2*i];
1224     int tagid=pd->tagarray[2*i+1];
1225     
1226     if (statusarray[slotid+numparams]==0) {
1227       parameter->iterators[*iteratorcount].istag=1;
1228       parameter->iterators[*iteratorcount].tagid=tagid;
1229       parameter->iterators[*iteratorcount].slot=slotid+numparams;
1230       parameter->iterators[*iteratorcount].tagobjectslot=index;
1231       statusarray[slotid+numparams]=1;
1232       (*iteratorcount)++;
1233     }
1234   }
1235 }
1236
1237
1238 void processobject(struct parameterwrapper *parameter, int index, struct parameterdescriptor *pd, int *iteratorcount, int * statusarray, int numparams) {
1239   int i;
1240   int tagcount=0;
1241   struct ObjectHash * objectset=((struct parameterwrapper *)pd->queue)->objectset;
1242
1243   parameter->iterators[*iteratorcount].istag=0;
1244   parameter->iterators[*iteratorcount].slot=index;
1245   parameter->iterators[*iteratorcount].objectset=objectset;
1246   statusarray[index]=1;
1247
1248   for(i=0;i<pd->numbertags;i++) {
1249     int slotid=pd->tagarray[2*i];
1250     int tagid=pd->tagarray[2*i+1];
1251     if (statusarray[slotid+numparams]!=0) {
1252       /* This tag has already been enqueued, use it to narrow search */
1253       parameter->iterators[*iteratorcount].tagbindings[tagcount]=slotid+numparams;
1254       tagcount++;
1255     }
1256   }
1257   parameter->iterators[*iteratorcount].numtags=tagcount;
1258
1259   (*iteratorcount)++;
1260 }
1261
1262 /* This function builds the iterators for a task & parameter */
1263
1264 void builditerators(struct taskdescriptor * task, int index, struct parameterwrapper * parameter) {
1265   int statusarray[MAXTASKPARAMS];
1266   int i;
1267   int numparams=task->numParameters;
1268   int iteratorcount=0;
1269   for(i=0;i<MAXTASKPARAMS;i++) statusarray[i]=0;
1270
1271   statusarray[index]=1; /* Initial parameter */
1272   /* Process tags for initial iterator */
1273   
1274   processtags(task->descriptorarray[index], index, parameter, & iteratorcount, statusarray, numparams);
1275   
1276   while(1) {
1277   loopstart:
1278     /* Check for objects with existing tags */
1279     for(i=0;i<numparams;i++) {
1280       if (statusarray[i]==0) {
1281         struct parameterdescriptor *pd=task->descriptorarray[i];
1282         int j;
1283         for(j=0;j<pd->numbertags;j++) {
1284           int slotid=pd->tagarray[2*j];
1285           if(statusarray[slotid+numparams]!=0) {
1286             processobject(parameter, i, pd, &iteratorcount, statusarray, numparams);
1287             processtags(pd, i, parameter, &iteratorcount, statusarray, numparams);
1288             goto loopstart;
1289           }
1290         }
1291       }
1292     }
1293
1294     /* Next do objects w/ unbound tags*/
1295
1296     for(i=0;i<numparams;i++) {
1297       if (statusarray[i]==0) {
1298         struct parameterdescriptor *pd=task->descriptorarray[i];
1299         if (pd->numbertags>0) {
1300           processobject(parameter, i, pd, &iteratorcount, statusarray, numparams);
1301           processtags(pd, i, parameter, &iteratorcount, statusarray, numparams);
1302           goto loopstart;
1303         }
1304       }
1305     }
1306
1307     /* Nothing with a tag enqueued */
1308
1309     for(i=0;i<numparams;i++) {
1310       if (statusarray[i]==0) {
1311         struct parameterdescriptor *pd=task->descriptorarray[i];
1312         processobject(parameter, i, pd, &iteratorcount, statusarray, numparams);
1313         processtags(pd, i, parameter, &iteratorcount, statusarray, numparams);
1314         goto loopstart;
1315       }
1316     }
1317
1318     /* Nothing left */
1319     return;
1320   }
1321 }
1322
1323
1324  
1325
1326 /* This function processes the task information to create queues for
1327    each parameter type. */
1328
1329 void processtasks() {
1330   int i;
1331   for(i=0;i<numtasks;i++) {
1332     struct taskdescriptor * task=taskarray[i];
1333     int j;
1334
1335     for(j=0;j<task->numParameters;j++) {
1336       struct parameterdescriptor *param=task->descriptorarray[j];
1337       struct parameterwrapper * parameter=RUNMALLOC(sizeof(struct parameterwrapper));
1338       struct parameterwrapper ** ptr=&objectqueues[param->type];
1339
1340       param->queue=parameter;
1341       parameter->objectset=allocateObjectHash(10);
1342       parameter->numberofterms=param->numberterms;
1343       parameter->intarray=param->intarray;
1344       parameter->numbertags=param->numbertags;
1345       parameter->tagarray=param->tagarray;
1346       parameter->task=task;
1347       /* Link new queue in */
1348       while((*ptr)!=NULL)
1349         ptr=&((*ptr)->next);
1350       (*ptr)=parameter;
1351     }
1352
1353     /* Build iterators for parameters */
1354     for(j=0;j<task->numParameters;j++) {
1355       struct parameterdescriptor *param=task->descriptorarray[j];
1356       struct parameterwrapper *parameter=param->queue;      
1357       parameter->slot=j;
1358       builditerators(task, j, parameter);
1359     }
1360   }
1361 }
1362
1363 void toiReset(struct tagobjectiterator * it) {
1364   if (it->istag) {
1365     it->tagobjindex=0;
1366   } else if (it->numtags>0) {
1367     it->tagobjindex=0;
1368 #ifdef OPTIONAL
1369     it->failedstate=0;
1370 #endif
1371   } else {
1372     ObjectHashiterator(it->objectset, &it->it);
1373 #ifdef OPTIONAL
1374     it->failedstate=0;
1375 #endif
1376   }
1377 }
1378
1379 int toiHasNext(struct tagobjectiterator *it, void ** objectarray OPTARG(int * failed)) {
1380   if (it->istag) {
1381     /* Iterate tag */
1382     /* Get object with tags */
1383     struct ___Object___ *obj=objectarray[it->tagobjectslot];
1384     struct ___Object___ *tagptr=obj->___tags___;
1385     if (tagptr->type==TAGTYPE) {
1386       if ((it->tagobjindex==0)&& /* First object */
1387           (it->tagid==((struct ___TagDescriptor___ *)tagptr)->flag)) /* Right tag type */
1388         return 1;
1389       else
1390         return 0;
1391     } else {
1392       struct ArrayObject *ao=(struct ArrayObject *) tagptr;
1393       int tagindex=it->tagobjindex;
1394       for(;tagindex<ao->___cachedCode___;tagindex++) {
1395         struct ___TagDescriptor___ *td=ARRAYGET(ao, struct ___TagDescriptor___ *, tagindex);
1396         if (td->flag==it->tagid) {
1397           it->tagobjindex=tagindex; /* Found right type of tag */
1398           return 1;
1399         }
1400       }
1401       return 0;
1402     }
1403   } else if (it->numtags>0) {
1404     /* Use tags to locate appropriate objects */
1405     struct ___TagDescriptor___ *tag=objectarray[it->tagbindings[0]];
1406     struct ___Object___ *objptr=tag->flagptr;
1407     int i;
1408     if (objptr->type!=OBJECTARRAYTYPE) {
1409       if (it->tagobjindex>0)
1410         return 0;
1411       if (!ObjectHashcontainskey(it->objectset, (int) objptr))
1412         return 0;
1413       for(i=1;i<it->numtags;i++) {
1414         struct ___TagDescriptor___ *tag2=objectarray[it->tagbindings[i]];
1415         if (!containstag(objptr,tag2))
1416           return 0;
1417       }
1418 #ifdef OPTIONAL
1419       if (it->failedstate==1) {
1420         int UNUSED, UNUSED2;
1421         int * flags;
1422         int isnonfailed;
1423         ObjectHashget(it->objectset, (int) objptr, &UNUSED, (int *) &flags, &UNUSED2, &isnonfailed);
1424         if (flags!=NULL) {
1425           return 1;
1426         } else {
1427           it->tagobjindex++;
1428           it->failedstate=0;
1429           return 0;
1430         }
1431       } else {
1432         int UNUSED, UNUSED2;
1433         int * flags;
1434         int isnonfailed;
1435         ObjectHashget(it->objectset, (int) objptr, &UNUSED, (int *) &flags, &UNUSED2, &isnonfailed);
1436         if (!isnonfailed) {
1437           it->failedstate=1;
1438         }
1439         return 1;
1440       }
1441 #endif      
1442       return 1;
1443     } else {
1444       struct ArrayObject *ao=(struct ArrayObject *) objptr;
1445       int tagindex;
1446       int i;
1447 #ifdef OPTIONAL
1448       if (it->failedstate==1) {
1449         int UNUSED, UNUSED2;
1450         int * flags;
1451         int isnonfailed;
1452         struct ___Object___ *objptr=ARRAYGET(ao, struct ___Object___*, it->tagobjindex);
1453         ObjectHashget(it->objectset, (int) objptr, &UNUSED, (int *) &flags, &UNUSED2, &isnonfailed);
1454         if (flags!=NULL) {
1455           return 1;
1456         } else {
1457           it->failedstate=0;
1458           it->tagobjindex++;
1459         }
1460       }
1461 #endif
1462       for(tagindex=it->tagobjindex;tagindex<ao->___cachedCode___;tagindex++) {
1463         struct ___Object___ *objptr=ARRAYGET(ao, struct ___Object___*, tagindex);
1464         if (!ObjectHashcontainskey(it->objectset, (int) objptr))
1465           continue;
1466         for(i=1;i<it->numtags;i++) {
1467           struct ___TagDescriptor___ *tag2=objectarray[it->tagbindings[i]];
1468           if (!containstag(objptr,tag2))
1469             goto nexttag;
1470         }
1471 #ifdef OPTIONAL
1472         {
1473           int UNUSED, UNUSED2;
1474           int flags, isnonfailed;
1475           struct ___Object___ *objptr=ARRAYGET(ao, struct ___Object___*, tagindex);
1476           ObjectHashget(it->objectset, (int) objptr, &UNUSED, &flags, &UNUSED2, &isnonfailed);
1477           if (!isnonfailed) {
1478             it->failedstate=1;
1479           }
1480         }
1481 #endif
1482         it->tagobjindex=tagindex;
1483         return 1;
1484       nexttag:
1485         ;
1486       }
1487       it->tagobjindex=tagindex;
1488       return 0;
1489     }
1490   } else {
1491 #ifdef OPTIONAL
1492     if (it->failedstate==1) {
1493       if (Objdata2(&it->it))
1494         return 1;
1495       else {
1496         it->failedstate=0;
1497         Objnext(&it->it);
1498       }
1499     }
1500     if (ObjhasNext(&it->it)) {
1501       if (!Objdata4(&it->it)) {
1502         //failed state only
1503         it->failedstate=1;
1504       }
1505       return 1;
1506     } else
1507       return 0;
1508 #else
1509     return ObjhasNext(&it->it);
1510 #endif
1511   }
1512 }
1513
1514 int containstag(struct ___Object___ *ptr, struct ___TagDescriptor___ *tag) {
1515   int j;
1516   struct ___Object___ * objptr=tag->flagptr;
1517   if (objptr->type==OBJECTARRAYTYPE) {
1518     struct ArrayObject *ao=(struct ArrayObject *)objptr;
1519     for(j=0;j<ao->___cachedCode___;j++) {
1520       if (ptr==ARRAYGET(ao, struct ___Object___*, j))
1521         return 1;
1522     }
1523     return 0;
1524   } else
1525     return objptr==ptr;
1526 }
1527
1528 void toiNext(struct tagobjectiterator *it , void ** objectarray OPTARG(int * failed)) {
1529   /* hasNext has all of the intelligence */
1530   if(it->istag) {
1531     /* Iterate tag */
1532     /* Get object with tags */
1533     struct ___Object___ *obj=objectarray[it->tagobjectslot];
1534     struct ___Object___ *tagptr=obj->___tags___;
1535     if (tagptr->type==TAGTYPE) {
1536       it->tagobjindex++;
1537       objectarray[it->slot]=tagptr;
1538     } else {
1539       struct ArrayObject *ao=(struct ArrayObject *) tagptr;
1540       objectarray[it->slot]=ARRAYGET(ao, struct ___TagDescriptor___ *, it->tagobjindex++);
1541     }
1542   } else if (it->numtags>0) {
1543     /* Use tags to locate appropriate objects */
1544     struct ___TagDescriptor___ *tag=objectarray[it->tagbindings[0]];
1545     struct ___Object___ *objptr=tag->flagptr;
1546     if (objptr->type!=OBJECTARRAYTYPE) {
1547 #ifdef OPTIONAL
1548     failed[it->slot]=it->failedstate;
1549     objectarray[it->slot]=objptr;
1550     if (it->failedstate==0) {
1551       it->failedstate=1;
1552     } else {
1553       it->failedstate=0;
1554       it->tagobjindex++;
1555     }
1556 #else
1557       it->tagobjindex++;
1558       objectarray[it->slot]=objptr;
1559 #endif
1560     } else {
1561       struct ArrayObject *ao=(struct ArrayObject *) objptr;
1562 #ifdef OPTIONAL
1563     failed[it->slot]=it->failedstate;
1564     objectarray[it->slot]=ARRAYGET(ao, struct ___Object___ *, it->tagobjindex);
1565     if (it->failedstate==0) {
1566       it->failedstate=1;
1567     } else {
1568       it->failedstate=0;
1569       it->tagobjindex++;
1570     }
1571 #else
1572       objectarray[it->slot]=ARRAYGET(ao, struct ___Object___ *, it->tagobjindex++);
1573 #endif
1574     }
1575   } else {
1576     /* Iterate object */
1577     objectarray[it->slot]=(void *)Objkey(&it->it);
1578 #ifdef OPTIONAL
1579     failed[it->slot]=it->failedstate;
1580     if (it->failedstate==0) {
1581       it->failedstate=1;
1582     } else {
1583       it->failedstate=0;
1584       Objnext(&it->it);
1585     }
1586 #else
1587     Objnext(&it->it);
1588 #endif
1589   }
1590 }
1591 #endif