don't need separate flag after all
[IRC.git] / Robust / src / Runtime / runtime.c
1 #include "runtime.h"
2 #include "structdefs.h"
3 #include <string.h>
4 #include <signal.h>
5 #include "mem.h"
6 #include<fcntl.h>
7 #include<sys/types.h>
8 #include<sys/mman.h>
9 #include<errno.h>
10 #include<signal.h>
11 #include<stdio.h>
12
13 extern int classsize[];
14 jmp_buf error_handler;
15 int instructioncount;
16
17 #ifdef TASK
18 #include "checkpoint.h"
19 #include "Queue.h"
20 #include "SimpleHash.h"
21 #include "GenericHashtable.h"
22 #include <sys/select.h>
23
24 #ifdef CONSCHECK
25 #include "instrument.h"
26 #endif
27
28 struct Queue * activetasks;
29 struct parameterwrapper * objectqueues[NUMCLASSES];
30 struct genhashtable * failedtasks;
31 /*struct genhashtable * failedobjects;*/
32 extern char ** environ;
33 char *options;
34 int injectfailures=0;
35 float failurechance=0;
36 int debugtask=0;
37 int injectinstructionfailures;
38 int failurecount;
39 float instfailurechance=0;
40
41 void processOptions() {
42   int i;
43   options=NULL;
44   for(i=0;environ[i]!=0;i++) {
45     if (strncmp(environ[i],"BRISTLECONE=",12)==0) {
46       options=environ[i]+12;
47       break;
48     }
49   }
50   
51   while(options!=NULL) {
52     if (strncmp(options,"-injectfailures",sizeof("-injectfailures")-1)==0) {
53       options=strchr(options,' ');
54       if (options!=NULL) options++;
55       if (options==NULL)
56         break;
57       sscanf(options, "%f", &failurechance);
58       injectfailures=1;
59       printf("Injecting errors with chance=%f\n",failurechance);
60       options=strchr(options,' ');
61       if (options!=NULL) options++;
62     } else if (strncmp(options,"-injectinstructionfailures",sizeof("-injectinstructionfailures")-1)==0) {
63       options=strchr(options,' ');
64       if (options!=NULL) options++;
65       if (options==NULL)
66         break;
67       sscanf(options, "%d", &failurecount);
68       options=strchr(options,' ');
69       if (options!=NULL) options++;
70       if (options==NULL)
71         break;
72       sscanf(options, "%f", &instfailurechance);
73       options=strchr(options,' ');
74       if (options!=NULL) options++;
75       instructioncount=failurecount;
76       injectinstructionfailures=1;
77       printf("Injecting errors with count=%d\n",failurecount);
78       printf("Injecting errors with chance=%f\n",instfailurechance);
79
80     } else if (strncmp(options, "-debugtask",sizeof("-debugtask")-1)==0) {
81       options=strchr(options,' ');
82       if (options!=NULL) options++;
83       debugtask=1;
84       printf("Debug task option on.\n");
85     } else
86       break;
87   }
88 }
89
90 int main(int argc, char **argv) {
91   GC_init(); // Initialize the garbage collector
92 #ifdef CONSCHECK
93   initializemmap();
94 #endif
95   processOptions();
96
97   {
98   int i;
99   /* Allocate startup object */
100   struct ___StartupObject___ *startupobject=(struct ___StartupObject___*) allocate_new(STARTUPTYPE);
101   struct ArrayObject * stringarray=allocate_newarray(STRINGARRAYTYPE, argc-1); 
102   failedtasks=genallocatehashtable((unsigned int (*)(void *)) &hashCodetpd, 
103                                    (int (*)(void *,void *)) &comparetpd);
104   /*  failedobjects=genallocatehashtable(NULL,NULL);*/
105   
106   activetasks=createQueue();
107
108   /* Set flags */
109   processtasks();
110   flagorand(startupobject,1,0xFFFFFFFF);
111
112   /* Build array of strings */
113
114   startupobject->___parameters___=stringarray;
115
116   for(i=1;i<argc;i++) {
117     int length=strlen(argv[i]);
118     struct ___String___ *newstring=NewString(argv[i],length);
119     ((void **)(((char *)& stringarray->___length___)+sizeof(int)))[i-1]=newstring;
120   }
121   executetasks();
122   }
123 }
124
125 int hashCodetpd(struct taskparamdescriptor *ftd) {
126   int hash=(int)ftd->task;
127   int i;
128   for(i=0;i<ftd->numParameters;i++) {
129     hash^=(int)ftd->parameterArray[i];
130   }
131   return hash;
132 }
133
134 int comparetpd(struct taskparamdescriptor *ftd1, struct taskparamdescriptor *ftd2) {
135   int i;
136   if (ftd1->task!=ftd2->task)
137     return 0;
138   for(i=0;i<ftd1->numParameters;i++)
139     if (ftd1->parameterArray[i]!=ftd2->parameterArray[i])
140       return 0;
141   return 1;
142 }
143
144 void flagorand(void * ptr, int ormask, int andmask) {
145   int flag=((int *)ptr)[1];
146   struct RuntimeHash *flagptr=(struct RuntimeHash *)(((int*)ptr)[2]);
147   flag|=ormask;
148   flag&=andmask;
149   ((int*)ptr)[1]=flag;
150   /*Remove from all queues */
151   while(flagptr!=NULL) {
152     struct RuntimeHash *next;
153     RuntimeHashget(flagptr, (int) ptr, (int *) &next);
154     RuntimeHashremove(flagptr, (int)ptr, (int) next);
155     flagptr=next;
156   }
157   
158   {
159     struct QueueItem *tmpptr;
160     struct parameterwrapper * parameter=objectqueues[((int *)ptr)[0]];
161     int i;
162     struct RuntimeHash * prevptr=NULL;
163     while(parameter!=NULL) {
164       for(i=0;i<parameter->numberofterms;i++) {
165         int andmask=parameter->intarray[i*2];
166         int checkmask=parameter->intarray[i*2+1];
167         if ((flag&andmask)==checkmask) {
168           RuntimeHashadd(parameter->objectset, (int) ptr, (int) prevptr);
169           prevptr=parameter->objectset;
170           {
171             struct RuntimeIterator iteratorarray[MAXTASKPARAMS];
172             void * taskpointerarray[MAXTASKPARAMS];
173             int j;
174             int numparams=parameter->task->numParameters;
175             int done=1;
176             struct taskdescriptor * task=parameter->task;
177             int newindex=-1;
178             for(j=0;j<numparams;j++) {
179               struct parameterwrapper *pw=(struct parameterwrapper *)task->descriptorarray[j]->queue;
180               if (parameter==pw) {
181                 taskpointerarray[j]=ptr;
182                 newindex=j;
183               } else {
184                 RuntimeHashiterator(pw->objectset, &iteratorarray[j]);
185                 if (RunhasNext(&iteratorarray[j])) {
186                   taskpointerarray[j]=(void *) Runkey(&iteratorarray[j]);
187                   Runnext(&iteratorarray[j]);
188                 } else {
189                   done=0;
190                   break; /* No tasks to dispatch */
191                 }
192               }
193             }
194             /* Queue task items... */
195
196             while(done) {
197               struct taskparamdescriptor *tpd=RUNMALLOC(sizeof(struct taskparamdescriptor));
198               tpd->task=task;
199               tpd->numParameters=numparams;
200               tpd->parameterArray=RUNMALLOC(sizeof(void *)*numparams);
201               for(j=0;j<numparams;j++)
202                 tpd->parameterArray[j]=taskpointerarray[j];
203               /* Queue task */
204               if (!gencontains(failedtasks, tpd))
205                 addNewItem(activetasks, tpd);
206               
207               /* This loop iterates to the next parameter combination */
208               for(j=0;j<numparams;j++) {
209                 if (j==newindex) {
210                   if ((j+1)==numparams)
211                     done=0;
212                   continue;
213                 }
214                 if (RunhasNext(&iteratorarray[j])) {
215                   taskpointerarray[j]=(void *) Runkey(&iteratorarray[j]);
216                   Runnext(&iteratorarray[j]);
217                   break;
218                 } else if ((j+1)!=numparams) {
219                   RuntimeHashiterator(task->descriptorarray[j]->queue, &iteratorarray[j]);
220                 } else {
221                   done=0;
222                   break;
223                 }
224               }
225             }
226           }
227           break;
228         }
229       }
230       parameter=parameter->next;
231     }
232     ((struct RuntimeHash **)ptr)[2]=prevptr;
233   }
234 }
235
236 /* Handler for signals. The signals catch null pointer errors and
237    arithmatic errors. */
238 void myhandler(int sig, siginfo_t *info, void *uap) {
239 #ifdef DEBUG
240   printf("sig=%d\n",sig);
241   printf("signal\n");
242 #endif
243   longjmp(error_handler,1);
244 }
245
246 fd_set readfds;
247 int maxreadfd;
248 struct RuntimeHash *fdtoobject;
249
250 void addreadfd(int fd) {
251   if (fd>=maxreadfd)
252     maxreadfd=fd+1;
253   FD_SET(fd, &readfds);
254 }
255
256 void removereadfd(int fd) {
257   FD_CLR(fd, &readfds);
258   if (maxreadfd==(fd+1)) {
259     maxreadfd--;
260     while(maxreadfd>0&&!FD_ISSET(maxreadfd-1, &readfds))
261       maxreadfd--;
262   }
263 }
264
265 /*
266 void restoreObject(void * obj) {
267   if (gencontains(failedobjects, obj)) {
268     struct tpdlist *tpd=gengettable(failedobjects, obj);
269     genfreekey(failedobjects, obj);
270     while(tpd!=NULL) {
271       int i;
272       struct taskparamdescriptor *task=tpd->task;
273       genfreekey(failedtasks, task);
274       for(i=0;i<task->numParameters;i++) {
275         void *objother=task->parameterArray[i];
276         struct tpdlist *tpdother=gengettable(failedobjects, objother);
277         struct tpdlist *tmpptr;
278         genfreekey(failedobjects, objother);
279         struct tpdlist **tpdptr=&tpdother;
280         while((*tpdptr)->task!=task)
281           tpdptr=&((*tpdptr)->next);
282         tmpptr=*tpdptr;
283         (*tpdptr)=(*tpdptr)->next;
284         RUNFREE(tmpptr);
285         if (tpdother!=NULL)
286           genputtable(failedobjects, objother, tpdother);
287       }
288       RUNFREE(task);
289       {
290         struct tpdlist *old=tpd;
291         tpd=tpd->next;
292         RUNFREE(old);
293       }
294     }
295   }
296 }
297 */
298
299 void executetasks() {
300   void * taskpointerarray[MAXTASKPARAMS];
301
302   /* Set up signal handlers */
303   struct sigaction sig;
304   sig.sa_sigaction=&myhandler;
305   sig.sa_flags=SA_SIGINFO;
306   sigemptyset(&sig.sa_mask);
307
308   /* Catch bus errors, segmentation faults, and floating point exceptions*/
309   sigaction(SIGBUS,&sig,0);
310   sigaction(SIGSEGV,&sig,0);
311   sigaction(SIGFPE,&sig,0);
312
313   /* Zero fd set */
314   FD_ZERO(&readfds);
315   maxreadfd=0;
316   fdtoobject=allocateRuntimeHash(100);
317
318   /* Map first block of memory to protected, anonymous page */
319   mmap(0, 0x1000, 0, MAP_SHARED|MAP_FIXED|MAP_ANON, -1, 0);
320
321   newtask:
322   while(!isEmpty(activetasks)||(maxreadfd>0)) {
323
324     /* Check if any filedescriptors have IO pending */
325     if (maxreadfd>0) {
326       int i;
327       struct timeval timeout={0,0};
328       fd_set tmpreadfds;
329       int numselect;
330       tmpreadfds=readfds;
331       numselect=select(maxreadfd, &tmpreadfds, NULL, NULL, &timeout);
332       if (numselect>0) {
333         /* Process ready fd's */
334         int fd;
335         for(fd=0;fd<maxreadfd;fd++) {
336           if (FD_ISSET(fd, &tmpreadfds)) {
337             /* Set ready flag on object */
338             void * objptr;
339             if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
340               flagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
341             }
342           }
343         }
344       }
345     }
346
347     /* See if there are any active tasks */
348     if (!isEmpty(activetasks)) {
349       int i;
350       struct QueueItem * qi=(struct QueueItem *) getTail(activetasks);
351       struct taskparamdescriptor *tpd=(struct taskparamdescriptor *) qi->objectptr;
352       removeItem(activetasks, qi);
353
354       /* Check if this task has failed */
355       if (gencontains(failedtasks, tpd))
356         goto newtask;
357       
358       /* Make sure that the parameters are still in the queues */
359       for(i=0;i<tpd->task->numParameters;i++) {
360         void * parameter=tpd->parameterArray[i];
361         struct parameterdescriptor * pd=tpd->task->descriptorarray[i];
362         struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
363         if (!RuntimeHashcontainskey(pw->objectset, (int) parameter))
364           goto newtask;
365         taskpointerarray[i]=parameter;
366       }
367       {
368         /* Checkpoint the state */
369         struct RuntimeHash * forward=allocateRuntimeHash(100);
370         struct RuntimeHash * reverse=allocateRuntimeHash(100);
371         void ** checkpoint=makecheckpoint(tpd->task->numParameters, taskpointerarray, forward, reverse);
372         int x;
373         if (x=setjmp(error_handler)) {
374           /* Recover */
375           int h;
376 #ifdef DEBUG
377           printf("Fatal Error=%d, Recovering!\n",x);
378 #endif
379           genputtable(failedtasks,tpd,tpd);
380        /* for(i=0;i<tpd->task->numParameters;i++) {
381             void *parameter=tpd->parameterArray[i];
382             {
383               // Create mapping from object -> failed tasks 
384               struct tpdlist * tpnew=RUNMALLOC(sizeof(struct tpdlist));
385               tpnew->task=tpd;
386               if (gencontains(failedobjects, parameter)) {
387                 struct tpdlist * tpdptr=gengettable(failedobjects, parameter);
388                 tpnew->next=tpdptr->next;
389                 tpdptr->next=tpnew;
390               } else {
391                 tpnew->next=NULL;
392                 genputtable(failedobjects, parameter, tpnew);
393               }
394             }
395           }  */
396           restorecheckpoint(tpd->task->numParameters, taskpointerarray, checkpoint, forward, reverse);
397         } else {
398           if (injectfailures) {
399             if ((((double)random())/RAND_MAX)<failurechance) {
400               printf("\nINJECTING TASK FAILURE to %s\n", tpd->task->name);
401               longjmp(error_handler,10);
402             }
403           }
404           /* Actually call task */
405           if (debugtask) {
406             printf("ENTER %s\n",tpd->task->name);
407             ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
408             printf("EXIT %s\n",tpd->task->name);
409           } else
410             ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
411         }
412       }
413     }
414   }
415 }
416
417 /* This function processes the task information to create queues for
418    each parameter type. */
419
420 void processtasks() {
421   int i;
422   for(i=0;i<numtasks;i++) {
423     struct taskdescriptor * task=taskarray[i];
424     int j;
425
426     for(j=0;j<task->numParameters;j++) {
427       struct parameterdescriptor *param=task->descriptorarray[j];
428       struct parameterwrapper * parameter=RUNMALLOC(sizeof(struct parameterwrapper));
429       struct parameterwrapper ** ptr=&objectqueues[param->type];
430
431       param->queue=parameter;
432       parameter->objectset=allocateRuntimeHash(10);
433       parameter->numberofterms=param->numberterms;
434       parameter->intarray=param->intarray;
435       parameter->task=task;
436       /* Link new queue in */
437       while((*ptr)!=NULL)
438         ptr=&((*ptr)->next);
439       (*ptr)=parameter;
440     }
441   }
442 }
443
444 #endif
445
446 /* This function inject failures */
447
448 void injectinstructionfailure() {
449 #ifdef TASK
450   if (injectinstructionfailures) {
451     instructioncount=failurecount;    
452     if ((((double)random())/RAND_MAX)<instfailurechance) {
453       printf("FAILURE!!!\n");
454       longjmp(error_handler,11);
455     }
456   }
457 #else
458 #endif
459 }
460
461 int ___Object______hashCode____(struct ___Object___ * ___this___) {
462   return (int) ___this___;
463 }
464
465 int ___Object______getType____(struct ___Object___ * ptr) {
466   return ((int *)ptr)[0];
467 }
468
469 void ___System______printString____L___String___(struct ___String___ * s) {
470     struct ArrayObject * chararray=s->___value___;
471     int i;
472     int offset=s->___offset___;
473     for(i=0;i<s->___count___;i++) {
474         short s= ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i+offset];
475         putchar(s);
476     }
477 }
478
479 void * allocate_new(int type) {
480   void * v=FREEMALLOC(classsize[type]);
481   *((int *)v)=type;
482   return v;
483 }
484
485 struct ArrayObject * allocate_newarray(int type, int length) {
486   struct ArrayObject * v=FREEMALLOC(sizeof(struct ArrayObject)+length*classsize[type]);
487   v->type=type;
488   v->___length___=length;
489   return v;
490 }
491
492 struct ___String___ * NewString(const char *str,int length) {
493   struct ArrayObject * chararray=allocate_newarray(CHARARRAYTYPE, length);
494   struct ___String___ * strobj=allocate_new(STRINGTYPE);
495   int i;
496   strobj->___value___=chararray;
497   strobj->___count___=length;
498   strobj->___offset___=0;
499
500   for(i=0;i<length;i++) {
501     ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i]=(short)str[i];  }
502   return strobj;
503 }
504
505 /* Generated code calls this if we fail a bounds check */
506 void failedboundschk() {
507 #ifndef TASK
508   printf("Array out of bounds\n");
509   exit(-1);
510 #else
511   longjmp(error_handler,2);
512 #endif
513 }
514
515 void abort_task() {
516 #ifdef TASK
517   longjmp(error_handler,4);
518 #else
519   printf("Aborting\n");
520   exit(-1);
521 #endif
522 }