fix optional arguments...lots of changes
[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   if (ObjectHashcontainskey(parameter->objectset, (int) ptr)) {
851     /* The object is already here...or it with the existing item */
852     int * oldflags;
853     int oldnumflags;
854     int oldptr;
855     int oldstatus;
856     int *mergedflags;
857     ObjectHashget(parameter->objectset, (int) ptr, & oldptr, (int *) &oldflags, &oldnumflags, &oldstatus);
858     mergedflags=domergeor(oldflags, oldnumflags, enterflags, numenterflags);
859     ObjectHashupdate(parameter->objectset, (int) ptr, oldptr, mergedflags, oldnumflags+numenterflags, oldstatus||(enterflags==NULL));
860
861     RUNFREE(oldflags);
862     RUNFREE(enterflags);
863
864     //only add if truly needed
865     if (oldstatus)
866       addnormal=0;
867     if (oldnumflags>0)
868       adderror=0;
869
870     retval=0;
871   } else {
872     ObjectHashadd(parameter->objectset, (int) ptr, (int) prevptr, (int) enterflags, numenterflags, enterflags==NULL);//this add the object to parameterwrapper
873   }
874  
875   /* Add enqueued object to parameter vector */
876   taskpointerarray[parameter->slot]=ptr;
877 #ifdef OPTIONAL
878   failed[parameter->slot]=(enterflags!=NULL);
879 #endif
880
881   /* Reset iterators */
882   for(j=0;j<numiterators;j++) {
883     toiReset(&parameter->iterators[j]);
884   }
885
886   /* Find initial state */
887   for(j=0;j<numiterators;j++) {
888   backtrackinit:
889     if(toiHasNext(&parameter->iterators[j], taskpointerarray OPTARG(failed)))
890       toiNext(&parameter->iterators[j], taskpointerarray OPTARG(failed));
891     else if (j>0) {
892       /* Need to backtrack */
893       toiReset(&parameter->iterators[j]);
894       j--;
895       goto backtrackinit;
896     } else {
897       /* Nothing to enqueue */
898       return retval;
899     }
900   }
901
902   
903   while(1) {
904     /* Enqueue current state */
905     int launch = 0;
906     struct taskparamdescriptor *tpd=RUNMALLOC(sizeof(struct taskparamdescriptor));
907     tpd->task=task;
908     tpd->numParameters=numiterators+1;
909     tpd->parameterArray=RUNMALLOC(sizeof(void *)*(numiterators+1));
910 #ifdef OPTIONAL
911     tpd->failed=RUNMALLOC(sizeof(int)*(numiterators+1));
912 #endif
913     for(j=0;j<=numiterators;j++){
914       tpd->parameterArray[j]=taskpointerarray[j];//store the actual parameters
915 #ifdef OPTIONAL
916       tpd->failed[j]=failed[j];
917 #endif
918     }
919     /* Enqueue task */
920     if ((!gencontains(failedtasks, tpd)&&!gencontains(activetasks,tpd))) {
921       genputtable(activetasks, tpd, tpd);
922     } else {
923       RUNFREE(tpd->parameterArray);
924       RUNFREE(tpd);
925     }
926     
927     /* This loop iterates to the next parameter combination */
928     if (numiterators==0)
929       return retval;
930
931     for(j=numiterators-1; j<numiterators;j++) {
932     backtrackinc:
933       if(toiHasNext(&parameter->iterators[j], taskpointerarray OPTARG(failed)))
934         toiNext(&parameter->iterators[j], taskpointerarray OPTARG(failed));
935       else if (j>0) {
936         /* Need to backtrack */
937         toiReset(&parameter->iterators[j]);
938         j--;
939         goto backtrackinc;
940       } else {
941         /* Nothing more to enqueue */
942         return retval;
943       }
944     }
945   }
946   return retval;
947 }
948  
949 /* Handler for signals. The signals catch null pointer errors and
950    arithmatic errors. */
951
952 void myhandler(int sig, siginfo_t *info, void *uap) {
953   sigset_t toclear;
954 #ifdef DEBUG
955   printf("sig=%d\n",sig);
956   printf("signal\n");
957 #endif
958   sigemptyset(&toclear);
959   sigaddset(&toclear, sig);
960   sigprocmask(SIG_UNBLOCK, &toclear,NULL); 
961   longjmp(error_handler,1);
962 }
963
964 fd_set readfds;
965 int maxreadfd;
966 struct RuntimeHash *fdtoobject;
967
968 void addreadfd(int fd) {
969   if (fd>=maxreadfd)
970     maxreadfd=fd+1;
971   FD_SET(fd, &readfds);
972 }
973
974 void removereadfd(int fd) {
975   FD_CLR(fd, &readfds);
976   if (maxreadfd==(fd+1)) {
977     maxreadfd--;
978     while(maxreadfd>0&&!FD_ISSET(maxreadfd-1, &readfds))
979       maxreadfd--;
980   }
981 }
982
983 #ifdef PRECISE_GC
984 #define OFFSET 2
985 #else
986 #define OFFSET 0
987 #endif
988
989 #ifdef OPTIONAL
990  int * fsescopy(int *src, int len) {
991    int *dst;
992    if (src==NULL)
993      return NULL;
994    dst=RUNMALLOC(len*sizeof(int));
995    memcpy(dst, src, len*sizeof(int));
996    return dst;
997  }
998 #endif
999
1000 void executetasks() {
1001   void * taskpointerarray[MAXTASKPARAMS+OFFSET];
1002 #ifdef OPTIONAL
1003   int * fsesarray[MAXTASKPARAMS];
1004   int * oldfsesarray[MAXTASKPARAMS];
1005   int numfsesarray[MAXTASKPARAMS];
1006 #endif  
1007
1008   /* Set up signal handlers */
1009   struct sigaction sig;
1010   sig.sa_sigaction=&myhandler;
1011   sig.sa_flags=SA_SIGINFO;
1012   sigemptyset(&sig.sa_mask);
1013
1014   /* Catch bus errors, segmentation faults, and floating point exceptions*/
1015   sigaction(SIGBUS,&sig,0);
1016   sigaction(SIGSEGV,&sig,0);
1017   sigaction(SIGFPE,&sig,0);
1018   sigaction(SIGPIPE,&sig,0);
1019
1020   /* Zero fd set */
1021   FD_ZERO(&readfds);
1022   maxreadfd=0;
1023   fdtoobject=allocateRuntimeHash(100);
1024
1025   /* Map first block of memory to protected, anonymous page */
1026   mmap(0, 0x1000, 0, MAP_SHARED|MAP_FIXED|MAP_ANON, -1, 0);
1027
1028   newtask:
1029   while((hashsize(activetasks)>0)||(maxreadfd>0)) {
1030
1031     /* Check if any filedescriptors have IO pending */
1032     if (maxreadfd>0) {
1033       int i;
1034       struct timeval timeout={0,0};
1035       fd_set tmpreadfds;
1036       int numselect;
1037       tmpreadfds=readfds;
1038       numselect=select(maxreadfd, &tmpreadfds, NULL, NULL, &timeout);
1039       if (numselect>0) {
1040         /* Process ready fd's */
1041         int fd;
1042         for(fd=0;fd<maxreadfd;fd++) {
1043           if (FD_ISSET(fd, &tmpreadfds)) {
1044             /* Set ready flag on object */
1045             void * objptr;
1046             //      printf("Setting fd %d\n",fd);
1047             if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
1048               intflagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
1049             }
1050           }
1051         }
1052       }
1053     }
1054
1055     /* See if there are any active tasks */
1056     if (hashsize(activetasks)>0) {
1057       int i;
1058       currtpd=(struct taskparamdescriptor *) getfirstkey(activetasks);
1059       genfreekey(activetasks, currtpd);
1060       
1061       /* Check if this task has failed, allow a task that contains optional objects to fire */
1062       if (gencontains(failedtasks, currtpd)) {
1063         // Free up task parameter descriptor
1064         RUNFREE(currtpd->parameterArray);
1065         RUNFREE(currtpd);
1066         goto newtask;
1067       }
1068       int numparams=currtpd->task->numParameters;
1069       int numtotal=currtpd->task->numTotal;
1070       
1071       /* Make sure that the parameters are still in the queues */
1072       for(i=0;i<numparams;i++) {
1073         void * parameter=currtpd->parameterArray[i];
1074         struct parameterdescriptor * pd=currtpd->task->descriptorarray[i];
1075         struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
1076         int j;
1077         /* Check that object is still in queue */
1078 #ifdef OPTIONAL
1079         {
1080           int UNUSED, UNUSED2;
1081           int *flags;
1082           int numflags, isnonfailed;
1083           int failed=currtpd->failed[i];
1084           if (!ObjectHashget(pw->objectset, (int) parameter, &UNUSED, (int *) &flags, &numflags, &isnonfailed)) {
1085             RUNFREE(currtpd->parameterArray);
1086             RUNFREE(currtpd->failed);
1087             RUNFREE(currtpd);
1088             goto newtask;
1089           } else {
1090             if (failed&&(flags!=NULL)) {
1091               //Failed parameter
1092               fsesarray[i]=flags;
1093               numfsesarray[i]=numflags;
1094             } else if (!failed && isnonfailed) {
1095               //Non-failed parameter
1096               fsesarray[i]=NULL;
1097               numfsesarray[i]=0;
1098             } else {
1099               RUNFREE(currtpd->parameterArray);
1100               RUNFREE(currtpd->failed);
1101               RUNFREE(currtpd);
1102               goto newtask;
1103             }
1104           }
1105         }
1106 #else
1107         {
1108           if (!ObjectHashcontainskey(pw->objectset, (int) parameter)) {
1109             RUNFREE(currtpd->parameterArray);
1110             RUNFREE(currtpd);
1111             goto newtask;
1112           }
1113         }
1114 #endif
1115       parameterpresent:
1116         ;
1117         /* Check that object still has necessary tags */
1118         for(j=0;j<pd->numbertags;j++) {
1119           int slotid=pd->tagarray[2*j]+numparams;
1120           struct ___TagDescriptor___ *tagd=currtpd->parameterArray[slotid];
1121           if (!containstag(parameter, tagd)) {
1122             RUNFREE(currtpd->parameterArray);
1123             RUNFREE(currtpd);
1124             goto newtask;
1125           }
1126         }
1127         
1128         taskpointerarray[i+OFFSET]=parameter;
1129       }
1130       /* Copy the tags */
1131       for(;i<numtotal;i++) {
1132         taskpointerarray[i+OFFSET]=currtpd->parameterArray[i];
1133       }
1134
1135       {
1136         /* Checkpoint the state */
1137         forward=allocateRuntimeHash(100);
1138         reverse=allocateRuntimeHash(100);
1139         void ** checkpoint=makecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, forward, reverse);
1140         int x;
1141         if (x=setjmp(error_handler)) {
1142           int counter;
1143           /* Recover */
1144 #ifdef DEBUG
1145           printf("Fatal Error=%d, Recovering!\n",x);
1146 #endif
1147           genputtable(failedtasks,currtpd,currtpd);
1148           restorecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, checkpoint, forward, reverse);
1149
1150 #ifdef OPTIONAL
1151           for(counter=0; counter<currtpd->task->numParameters; counter++){
1152             //enqueue as failed
1153             enqueueoptional(currtpd->parameterArray[counter], numfsesarray[counter], fsesarray[counter], currtpd->task, counter);
1154
1155             //free fses copies
1156             if (fsesarray[counter]!=NULL)
1157               RUNFREE(fsesarray[counter]);
1158           }
1159 #endif
1160           freeRuntimeHash(forward);
1161           freeRuntimeHash(reverse);
1162           freemalloc();
1163           forward=NULL;
1164           reverse=NULL;
1165         } else {
1166           if (injectfailures) {
1167             if ((((double)random())/RAND_MAX)<failurechance) {
1168               printf("\nINJECTING TASK FAILURE to %s\n", currtpd->task->name);
1169               longjmp(error_handler,10);
1170             }
1171           }
1172           /* Actually call task */
1173 #ifdef PRECISE_GC
1174           ((int *)taskpointerarray)[0]=currtpd->task->numParameters;
1175           taskpointerarray[1]=NULL;
1176 #endif
1177 #ifdef OPTIONAL
1178           //get the task flags set
1179           for(i=0;i<numparams;i++) {
1180             oldfsesarray[i]=((struct ___Object___ *)taskpointerarray[i+OFFSET])->fses;
1181             fsesarray[i]=fsescopy(fsesarray[i], numfsesarray[i]);
1182             ((struct ___Object___ *)taskpointerarray[i+OFFSET])->fses=fsesarray[i];         
1183           }
1184 #endif
1185           if(debugtask){
1186             printf("ENTER %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
1187             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
1188             printf("EXIT %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
1189           } else
1190             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
1191
1192           for(i=0;i<numparams;i++) {
1193             //free old fses
1194             if(oldfsesarray[i]!=NULL)
1195               RUNFREE(oldfsesarray[i]);
1196           }
1197           
1198           freeRuntimeHash(forward);
1199           freeRuntimeHash(reverse);
1200           freemalloc();
1201           // Free up task parameter descriptor
1202           RUNFREE(currtpd->parameterArray);
1203           RUNFREE(currtpd);
1204           forward=NULL;
1205           reverse=NULL;
1206         }
1207       }
1208     }
1209   }
1210 }
1211  
1212 /* This function processes an objects tags */
1213 void processtags(struct parameterdescriptor *pd, int index, struct parameterwrapper *parameter, int * iteratorcount, int *statusarray, int numparams) {
1214   int i;
1215   
1216   for(i=0;i<pd->numbertags;i++) {
1217     int slotid=pd->tagarray[2*i];
1218     int tagid=pd->tagarray[2*i+1];
1219     
1220     if (statusarray[slotid+numparams]==0) {
1221       parameter->iterators[*iteratorcount].istag=1;
1222       parameter->iterators[*iteratorcount].tagid=tagid;
1223       parameter->iterators[*iteratorcount].slot=slotid+numparams;
1224       parameter->iterators[*iteratorcount].tagobjectslot=index;
1225       statusarray[slotid+numparams]=1;
1226       (*iteratorcount)++;
1227     }
1228   }
1229 }
1230
1231
1232 void processobject(struct parameterwrapper *parameter, int index, struct parameterdescriptor *pd, int *iteratorcount, int * statusarray, int numparams) {
1233   int i;
1234   int tagcount=0;
1235   struct ObjectHash * objectset=((struct parameterwrapper *)pd->queue)->objectset;
1236
1237   parameter->iterators[*iteratorcount].istag=0;
1238   parameter->iterators[*iteratorcount].slot=index;
1239   parameter->iterators[*iteratorcount].objectset=objectset;
1240   statusarray[index]=1;
1241
1242   for(i=0;i<pd->numbertags;i++) {
1243     int slotid=pd->tagarray[2*i];
1244     int tagid=pd->tagarray[2*i+1];
1245     if (statusarray[slotid+numparams]!=0) {
1246       /* This tag has already been enqueued, use it to narrow search */
1247       parameter->iterators[*iteratorcount].tagbindings[tagcount]=slotid+numparams;
1248       tagcount++;
1249     }
1250   }
1251   parameter->iterators[*iteratorcount].numtags=tagcount;
1252
1253   (*iteratorcount)++;
1254 }
1255
1256 /* This function builds the iterators for a task & parameter */
1257
1258 void builditerators(struct taskdescriptor * task, int index, struct parameterwrapper * parameter) {
1259   int statusarray[MAXTASKPARAMS];
1260   int i;
1261   int numparams=task->numParameters;
1262   int iteratorcount=0;
1263   for(i=0;i<MAXTASKPARAMS;i++) statusarray[i]=0;
1264
1265   statusarray[index]=1; /* Initial parameter */
1266   /* Process tags for initial iterator */
1267   
1268   processtags(task->descriptorarray[index], index, parameter, & iteratorcount, statusarray, numparams);
1269   
1270   while(1) {
1271   loopstart:
1272     /* Check for objects with existing tags */
1273     for(i=0;i<numparams;i++) {
1274       if (statusarray[i]==0) {
1275         struct parameterdescriptor *pd=task->descriptorarray[i];
1276         int j;
1277         for(j=0;j<pd->numbertags;j++) {
1278           int slotid=pd->tagarray[2*j];
1279           if(statusarray[slotid+numparams]!=0) {
1280             processobject(parameter, i, pd, &iteratorcount, statusarray, numparams);
1281             processtags(pd, i, parameter, &iteratorcount, statusarray, numparams);
1282             goto loopstart;
1283           }
1284         }
1285       }
1286     }
1287
1288     /* Next do objects w/ unbound tags*/
1289
1290     for(i=0;i<numparams;i++) {
1291       if (statusarray[i]==0) {
1292         struct parameterdescriptor *pd=task->descriptorarray[i];
1293         if (pd->numbertags>0) {
1294           processobject(parameter, i, pd, &iteratorcount, statusarray, numparams);
1295           processtags(pd, i, parameter, &iteratorcount, statusarray, numparams);
1296           goto loopstart;
1297         }
1298       }
1299     }
1300
1301     /* Nothing with a tag enqueued */
1302
1303     for(i=0;i<numparams;i++) {
1304       if (statusarray[i]==0) {
1305         struct parameterdescriptor *pd=task->descriptorarray[i];
1306         processobject(parameter, i, pd, &iteratorcount, statusarray, numparams);
1307         processtags(pd, i, parameter, &iteratorcount, statusarray, numparams);
1308         goto loopstart;
1309       }
1310     }
1311
1312     /* Nothing left */
1313     return;
1314   }
1315 }
1316
1317
1318  
1319
1320 /* This function processes the task information to create queues for
1321    each parameter type. */
1322
1323 void processtasks() {
1324   int i;
1325   for(i=0;i<numtasks;i++) {
1326     struct taskdescriptor * task=taskarray[i];
1327     int j;
1328
1329     for(j=0;j<task->numParameters;j++) {
1330       struct parameterdescriptor *param=task->descriptorarray[j];
1331       struct parameterwrapper * parameter=RUNMALLOC(sizeof(struct parameterwrapper));
1332       struct parameterwrapper ** ptr=&objectqueues[param->type];
1333
1334       param->queue=parameter;
1335       parameter->objectset=allocateObjectHash(10);
1336       parameter->numberofterms=param->numberterms;
1337       parameter->intarray=param->intarray;
1338       parameter->numbertags=param->numbertags;
1339       parameter->tagarray=param->tagarray;
1340       parameter->task=task;
1341       /* Link new queue in */
1342       while((*ptr)!=NULL)
1343         ptr=&((*ptr)->next);
1344       (*ptr)=parameter;
1345     }
1346
1347     /* Build iterators for parameters */
1348     for(j=0;j<task->numParameters;j++) {
1349       struct parameterdescriptor *param=task->descriptorarray[j];
1350       struct parameterwrapper *parameter=param->queue;      
1351       parameter->slot=j;
1352       builditerators(task, j, parameter);
1353     }
1354   }
1355 }
1356
1357 void toiReset(struct tagobjectiterator * it) {
1358   if (it->istag) {
1359     it->tagobjindex=0;
1360   } else if (it->numtags>0) {
1361     it->tagobjindex=0;
1362 #ifdef OPTIONAL
1363     it->failedstate=0;
1364 #endif
1365   } else {
1366     ObjectHashiterator(it->objectset, &it->it);
1367 #ifdef OPTIONAL
1368     it->failedstate=0;
1369 #endif
1370   }
1371 }
1372
1373 int toiHasNext(struct tagobjectiterator *it, void ** objectarray OPTARG(int * failed)) {
1374   if (it->istag) {
1375     /* Iterate tag */
1376     /* Get object with tags */
1377     struct ___Object___ *obj=objectarray[it->tagobjectslot];
1378     struct ___Object___ *tagptr=obj->___tags___;
1379     if (tagptr->type==TAGTYPE) {
1380       if ((it->tagobjindex==0)&& /* First object */
1381           (it->tagid==((struct ___TagDescriptor___ *)tagptr)->flag)) /* Right tag type */
1382         return 1;
1383       else
1384         return 0;
1385     } else {
1386       struct ArrayObject *ao=(struct ArrayObject *) tagptr;
1387       int tagindex=it->tagobjindex;
1388       for(;tagindex<ao->___cachedCode___;tagindex++) {
1389         struct ___TagDescriptor___ *td=ARRAYGET(ao, struct ___TagDescriptor___ *, tagindex);
1390         if (td->flag==it->tagid) {
1391           it->tagobjindex=tagindex; /* Found right type of tag */
1392           return 1;
1393         }
1394       }
1395       return 0;
1396     }
1397   } else if (it->numtags>0) {
1398     /* Use tags to locate appropriate objects */
1399     struct ___TagDescriptor___ *tag=objectarray[it->tagbindings[0]];
1400     struct ___Object___ *objptr=tag->flagptr;
1401     int i;
1402     if (objptr->type!=OBJECTARRAYTYPE) {
1403       if (it->tagobjindex>0)
1404         return 0;
1405       if (!ObjectHashcontainskey(it->objectset, (int) objptr))
1406         return 0;
1407       for(i=1;i<it->numtags;i++) {
1408         struct ___TagDescriptor___ *tag2=objectarray[it->tagbindings[i]];
1409         if (!containstag(objptr,tag2))
1410           return 0;
1411       }
1412 #ifdef OPTIONAL
1413       if (it->failedstate==1) {
1414         int UNUSED, UNUSED2;
1415         int * flags;
1416         int isnonfailed;
1417         ObjectHashget(it->objectset, (int) objptr, &UNUSED, (int *) &flags, &UNUSED2, &isnonfailed);
1418         if (flags!=NULL) {
1419           return 1;
1420         } else {
1421           it->tagobjindex++;
1422           it->failedstate=0;
1423           return 0;
1424         }
1425       } else {
1426         int UNUSED, UNUSED2;
1427         int * flags;
1428         int isnonfailed;
1429         ObjectHashget(it->objectset, (int) objptr, &UNUSED, (int *) &flags, &UNUSED2, &isnonfailed);
1430         if (!isnonfailed) {
1431           it->failedstate=1;
1432         }
1433         return 1;
1434       }
1435 #endif      
1436       return 1;
1437     } else {
1438       struct ArrayObject *ao=(struct ArrayObject *) objptr;
1439       int tagindex;
1440       int i;
1441 #ifdef OPTIONAL
1442       if (it->failedstate==1) {
1443         int UNUSED, UNUSED2;
1444         int * flags;
1445         int isnonfailed;
1446         struct ___Object___ *objptr=ARRAYGET(ao, struct ___Object___*, it->tagobjindex);
1447         ObjectHashget(it->objectset, (int) objptr, &UNUSED, (int *) &flags, &UNUSED2, &isnonfailed);
1448         if (flags!=NULL) {
1449           return 1;
1450         } else {
1451           it->failedstate=0;
1452           it->tagobjindex++;
1453         }
1454       }
1455 #endif
1456       for(tagindex=it->tagobjindex;tagindex<ao->___cachedCode___;tagindex++) {
1457         struct ___Object___ *objptr=ARRAYGET(ao, struct ___Object___*, tagindex);
1458         if (!ObjectHashcontainskey(it->objectset, (int) objptr))
1459           continue;
1460         for(i=1;i<it->numtags;i++) {
1461           struct ___TagDescriptor___ *tag2=objectarray[it->tagbindings[i]];
1462           if (!containstag(objptr,tag2))
1463             goto nexttag;
1464         }
1465 #ifdef OPTIONAL
1466         {
1467           int UNUSED, UNUSED2;
1468           int flags, isnonfailed;
1469           struct ___Object___ *objptr=ARRAYGET(ao, struct ___Object___*, tagindex);
1470           ObjectHashget(it->objectset, (int) objptr, &UNUSED, &flags, &UNUSED2, &isnonfailed);
1471           if (!isnonfailed) {
1472             it->failedstate=1;
1473           }
1474         }
1475 #endif
1476         it->tagobjindex=tagindex;
1477         return 1;
1478       nexttag:
1479         ;
1480       }
1481       it->tagobjindex=tagindex;
1482       return 0;
1483     }
1484   } else {
1485 #ifdef OPTIONAL
1486     if (it->failedstate==1) {
1487       if (Objdata2(&it->it))
1488         return 1;
1489       else {
1490         it->failedstate=0;
1491         Objnext(&it->it);
1492       }
1493     }
1494     if (ObjhasNext(&it->it)) {
1495       if (!Objdata4(&it->it)) {
1496         //failed state only
1497         it->failedstate=1;
1498       }
1499       return 1;
1500     } else
1501       return 0;
1502 #else
1503     return ObjhasNext(&it->it);
1504 #endif
1505   }
1506 }
1507
1508 int containstag(struct ___Object___ *ptr, struct ___TagDescriptor___ *tag) {
1509   int j;
1510   struct ___Object___ * objptr=tag->flagptr;
1511   if (objptr->type==OBJECTARRAYTYPE) {
1512     struct ArrayObject *ao=(struct ArrayObject *)objptr;
1513     for(j=0;j<ao->___cachedCode___;j++) {
1514       if (ptr==ARRAYGET(ao, struct ___Object___*, j))
1515         return 1;
1516     }
1517     return 0;
1518   } else
1519     return objptr==ptr;
1520 }
1521
1522 void toiNext(struct tagobjectiterator *it , void ** objectarray OPTARG(int * failed)) {
1523   /* hasNext has all of the intelligence */
1524   if(it->istag) {
1525     /* Iterate tag */
1526     /* Get object with tags */
1527     struct ___Object___ *obj=objectarray[it->tagobjectslot];
1528     struct ___Object___ *tagptr=obj->___tags___;
1529     if (tagptr->type==TAGTYPE) {
1530       it->tagobjindex++;
1531       objectarray[it->slot]=tagptr;
1532     } else {
1533       struct ArrayObject *ao=(struct ArrayObject *) tagptr;
1534       objectarray[it->slot]=ARRAYGET(ao, struct ___TagDescriptor___ *, it->tagobjindex++);
1535     }
1536   } else if (it->numtags>0) {
1537     /* Use tags to locate appropriate objects */
1538     struct ___TagDescriptor___ *tag=objectarray[it->tagbindings[0]];
1539     struct ___Object___ *objptr=tag->flagptr;
1540     if (objptr->type!=OBJECTARRAYTYPE) {
1541 #ifdef OPTIONAL
1542     failed[it->slot]=it->failedstate;
1543     objectarray[it->slot]=objptr;
1544     if (it->failedstate==0) {
1545       it->failedstate=1;
1546     } else {
1547       it->failedstate=0;
1548       it->tagobjindex++;
1549     }
1550 #else
1551       it->tagobjindex++;
1552       objectarray[it->slot]=objptr;
1553 #endif
1554     } else {
1555       struct ArrayObject *ao=(struct ArrayObject *) objptr;
1556 #ifdef OPTIONAL
1557     failed[it->slot]=it->failedstate;
1558     objectarray[it->slot]=ARRAYGET(ao, struct ___Object___ *, it->tagobjindex);
1559     if (it->failedstate==0) {
1560       it->failedstate=1;
1561     } else {
1562       it->failedstate=0;
1563       it->tagobjindex++;
1564     }
1565 #else
1566       objectarray[it->slot]=ARRAYGET(ao, struct ___Object___ *, it->tagobjindex++);
1567 #endif
1568     }
1569   } else {
1570     /* Iterate object */
1571     objectarray[it->slot]=(void *)Objkey(&it->it);
1572 #ifdef OPTIONAL
1573     failed[it->slot]=it->failedstate;
1574     if (it->failedstate==0) {
1575       it->failedstate=1;
1576     } else {
1577       it->failedstate=0;
1578       Objnext(&it->it);
1579     }
1580 #else
1581     Objnext(&it->it);
1582 #endif
1583   }
1584 }
1585 #endif