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