add linux support
[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 #ifdef LINUX
239 void myhandler(int sig, siginfo_t *info, void *uap) {
240 #else
241 void myhandler(int sig, struct __siginfo *info, void *uap) {
242 #endif
243 #ifdef DEBUG
244   printf("sig=%d\n",sig);
245   printf("signal\n");
246 #endif
247   longjmp(error_handler,1);
248 }
249
250 fd_set readfds;
251 int maxreadfd;
252 struct RuntimeHash *fdtoobject;
253
254 void addreadfd(int fd) {
255   if (fd>=maxreadfd)
256     maxreadfd=fd+1;
257   FD_SET(fd, &readfds);
258 }
259
260 void removereadfd(int fd) {
261   FD_CLR(fd, &readfds);
262   if (maxreadfd==(fd+1)) {
263     maxreadfd--;
264     while(maxreadfd>0&&!FD_ISSET(maxreadfd-1, &readfds))
265       maxreadfd--;
266   }
267 }
268
269 /*
270 void restoreObject(void * obj) {
271   if (gencontains(failedobjects, obj)) {
272     struct tpdlist *tpd=gengettable(failedobjects, obj);
273     genfreekey(failedobjects, obj);
274     while(tpd!=NULL) {
275       int i;
276       struct taskparamdescriptor *task=tpd->task;
277       genfreekey(failedtasks, task);
278       for(i=0;i<task->numParameters;i++) {
279         void *objother=task->parameterArray[i];
280         struct tpdlist *tpdother=gengettable(failedobjects, objother);
281         struct tpdlist *tmpptr;
282         genfreekey(failedobjects, objother);
283         struct tpdlist **tpdptr=&tpdother;
284         while((*tpdptr)->task!=task)
285           tpdptr=&((*tpdptr)->next);
286         tmpptr=*tpdptr;
287         (*tpdptr)=(*tpdptr)->next;
288         RUNFREE(tmpptr);
289         if (tpdother!=NULL)
290           genputtable(failedobjects, objother, tpdother);
291       }
292       RUNFREE(task);
293       {
294         struct tpdlist *old=tpd;
295         tpd=tpd->next;
296         RUNFREE(old);
297       }
298     }
299   }
300 }
301 */
302
303 void executetasks() {
304   void * taskpointerarray[MAXTASKPARAMS];
305
306   /* Set up signal handlers */
307   struct sigaction sig;
308   sig.sa_sigaction=&myhandler;
309   sig.sa_flags=SA_SIGINFO;
310   sigemptyset(&sig.sa_mask);
311
312   /* Catch bus errors, segmentation faults, and floating point exceptions*/
313   sigaction(SIGBUS,&sig,0);
314   sigaction(SIGSEGV,&sig,0);
315   sigaction(SIGFPE,&sig,0);
316
317   /* Zero fd set */
318   FD_ZERO(&readfds);
319   maxreadfd=0;
320   fdtoobject=allocateRuntimeHash(100);
321
322   /* Map first block of memory to protected, anonymous page */
323   mmap(0, 0x1000, 0, MAP_SHARED|MAP_FIXED|MAP_ANON, -1, 0);
324
325   newtask:
326   while(!isEmpty(activetasks)||(maxreadfd>0)) {
327
328     /* Check if any filedescriptors have IO pending */
329     if (maxreadfd>0) {
330       int i;
331       struct timeval timeout={0,0};
332       fd_set tmpreadfds;
333       int numselect;
334       tmpreadfds=readfds;
335       numselect=select(maxreadfd, &tmpreadfds, NULL, NULL, &timeout);
336       if (numselect>0) {
337         /* Process ready fd's */
338         int fd;
339         for(fd=0;fd<maxreadfd;fd++) {
340           if (FD_ISSET(fd, &tmpreadfds)) {
341             /* Set ready flag on object */
342             void * objptr;
343             if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
344               flagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
345             }
346           }
347         }
348       }
349     }
350
351     /* See if there are any active tasks */
352     if (!isEmpty(activetasks)) {
353       int i;
354       struct QueueItem * qi=(struct QueueItem *) getTail(activetasks);
355       struct taskparamdescriptor *tpd=(struct taskparamdescriptor *) qi->objectptr;
356       removeItem(activetasks, qi);
357
358       /* Check if this task has failed */
359       if (gencontains(failedtasks, tpd))
360         goto newtask;
361       
362       /* Make sure that the parameters are still in the queues */
363       for(i=0;i<tpd->task->numParameters;i++) {
364         void * parameter=tpd->parameterArray[i];
365         struct parameterdescriptor * pd=tpd->task->descriptorarray[i];
366         struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
367         if (!RuntimeHashcontainskey(pw->objectset, (int) parameter))
368           goto newtask;
369         taskpointerarray[i]=parameter;
370       }
371       {
372         /* Checkpoint the state */
373         struct RuntimeHash * forward=allocateRuntimeHash(100);
374         struct RuntimeHash * reverse=allocateRuntimeHash(100);
375         void ** checkpoint=makecheckpoint(tpd->task->numParameters, taskpointerarray, forward, reverse);
376         int x;
377         if (x=setjmp(error_handler)) {
378           /* Recover */
379           int h;
380 #ifdef DEBUG
381           printf("Fatal Error=%d, Recovering!\n",x);
382 #endif
383           genputtable(failedtasks,tpd,tpd);
384        /* for(i=0;i<tpd->task->numParameters;i++) {
385             void *parameter=tpd->parameterArray[i];
386             {
387               // Create mapping from object -> failed tasks 
388               struct tpdlist * tpnew=RUNMALLOC(sizeof(struct tpdlist));
389               tpnew->task=tpd;
390               if (gencontains(failedobjects, parameter)) {
391                 struct tpdlist * tpdptr=gengettable(failedobjects, parameter);
392                 tpnew->next=tpdptr->next;
393                 tpdptr->next=tpnew;
394               } else {
395                 tpnew->next=NULL;
396                 genputtable(failedobjects, parameter, tpnew);
397               }
398             }
399           }  */
400           restorecheckpoint(tpd->task->numParameters, taskpointerarray, checkpoint, forward, reverse);
401         } else {
402           if (injectfailures) {
403             if ((((double)random())/RAND_MAX)<failurechance) {
404               printf("\nINJECTING TASK FAILURE to %s\n", tpd->task->name);
405               longjmp(error_handler,10);
406             }
407           }
408           /* Actually call task */
409           if (debugtask) {
410             printf("ENTER %s\n",tpd->task->name);
411             ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
412             printf("EXIT %s\n",tpd->task->name);
413           } else
414             ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
415         }
416       }
417     }
418   }
419 }
420
421 /* This function processes the task information to create queues for
422    each parameter type. */
423
424 void processtasks() {
425   int i;
426   for(i=0;i<numtasks;i++) {
427     struct taskdescriptor * task=taskarray[i];
428     int j;
429
430     for(j=0;j<task->numParameters;j++) {
431       struct parameterdescriptor *param=task->descriptorarray[j];
432       struct parameterwrapper * parameter=RUNMALLOC(sizeof(struct parameterwrapper));
433       struct parameterwrapper ** ptr=&objectqueues[param->type];
434
435       param->queue=parameter;
436       parameter->objectset=allocateRuntimeHash(10);
437       parameter->numberofterms=param->numberterms;
438       parameter->intarray=param->intarray;
439       parameter->task=task;
440       /* Link new queue in */
441       while((*ptr)!=NULL)
442         ptr=&((*ptr)->next);
443       (*ptr)=parameter;
444     }
445   }
446 }
447
448 #endif
449
450 /* This function inject failures */
451
452 void injectinstructionfailure() {
453 #ifdef TASK
454   if (injectinstructionfailures) {
455     instructioncount=failurecount;    
456     if ((((double)random())/RAND_MAX)<instfailurechance) {
457       printf("FAILURE!!!\n");
458       longjmp(error_handler,11);
459     }
460   }
461 #else
462 #endif
463 }
464
465 int ___Object______hashCode____(struct ___Object___ * ___this___) {
466   return (int) ___this___;
467 }
468
469 int ___Object______getType____(struct ___Object___ * ptr) {
470   return ((int *)ptr)[0];
471 }
472
473 void ___System______printString____L___String___(struct ___String___ * s) {
474     struct ArrayObject * chararray=s->___value___;
475     int i;
476     int offset=s->___offset___;
477     for(i=0;i<s->___count___;i++) {
478         short s= ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i+offset];
479         putchar(s);
480     }
481 }
482
483 void * allocate_new(int type) {
484   void * v=FREEMALLOC(classsize[type]);
485   *((int *)v)=type;
486   return v;
487 }
488
489 struct ArrayObject * allocate_newarray(int type, int length) {
490   struct ArrayObject * v=FREEMALLOC(sizeof(struct ArrayObject)+length*classsize[type]);
491   v->type=type;
492   v->___length___=length;
493   return v;
494 }
495
496 struct ___String___ * NewString(const char *str,int length) {
497   struct ArrayObject * chararray=allocate_newarray(CHARARRAYTYPE, length);
498   struct ___String___ * strobj=allocate_new(STRINGTYPE);
499   int i;
500   strobj->___value___=chararray;
501   strobj->___count___=length;
502   strobj->___offset___=0;
503
504   for(i=0;i<length;i++) {
505     ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i]=(short)str[i];  }
506   return strobj;
507 }
508
509 /* Generated code calls this if we fail a bounds check */
510 void failedboundschk() {
511 #ifndef TASK
512   printf("Array out of bounds\n");
513   exit(-1);
514 #else
515   longjmp(error_handler,2);
516 #endif
517 }
518
519 void abort_task() {
520 #ifdef TASK
521   longjmp(error_handler,4);
522 #else
523   printf("Aborting\n");
524   exit(-1);
525 #endif
526 }