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