move socket code out of runtime.c
[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 */
237 void myhandler(int sig, struct __siginfo *info, void *uap) {
238 #ifdef DEBUG
239   printf("sig=%d\n",sig);
240   printf("signal\n");
241 #endif
242   longjmp(error_handler,1);
243 }
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     if (maxreadfd>0) {
325       int i;
326       struct timeval timeout={0,0};
327       fd_set tmpreadfds;
328       int numselect;
329       FD_COPY(&readfds, &tmpreadfds);
330       numselect=select(maxreadfd, &tmpreadfds, NULL, NULL, &timeout);
331       if (numselect>0) {
332         /* Process ready fd's */
333         int fd;
334         for(fd=0;fd<maxreadfd;fd++) {
335           if (FD_ISSET(fd, &tmpreadfds)) {
336             /* Set ready flag on object */
337             void * objptr;
338             if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
339               flagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
340             }
341           }
342         }
343       }
344     }
345
346     if (!isEmpty(activetasks)) {
347       int i;
348       struct QueueItem * qi=(struct QueueItem *) getTail(activetasks);
349       struct taskparamdescriptor *tpd=(struct taskparamdescriptor *) qi->objectptr;
350       removeItem(activetasks, qi);
351       
352       for(i=0;i<tpd->task->numParameters;i++) {
353         void * parameter=tpd->parameterArray[i];
354         struct parameterdescriptor * pd=tpd->task->descriptorarray[i];
355         struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
356         if (!RuntimeHashcontainskey(pw->objectset, (int) parameter))
357           goto newtask;
358         taskpointerarray[i]=parameter;
359       }
360       {
361         struct RuntimeHash * forward=allocateRuntimeHash(100);
362         struct RuntimeHash * reverse=allocateRuntimeHash(100);
363         void ** checkpoint=makecheckpoint(tpd->task->numParameters, taskpointerarray, forward, reverse);
364         int x;
365         if (x=setjmp(error_handler)) {
366           /* Recover */
367           int h;
368 #ifdef DEBUG
369           printf("Fatal Error=%d, Recovering!\n",x);
370 #endif
371           genputtable(failedtasks,tpd,tpd);
372        /* for(i=0;i<tpd->task->numParameters;i++) {
373             void *parameter=tpd->parameterArray[i];
374             {
375               // Create mapping from object -> failed tasks 
376               struct tpdlist * tpnew=RUNMALLOC(sizeof(struct tpdlist));
377               tpnew->task=tpd;
378               if (gencontains(failedobjects, parameter)) {
379                 struct tpdlist * tpdptr=gengettable(failedobjects, parameter);
380                 tpnew->next=tpdptr->next;
381                 tpdptr->next=tpnew;
382               } else {
383                 tpnew->next=NULL;
384                 genputtable(failedobjects, parameter, tpnew);
385               }
386             }
387           }  */
388           restorecheckpoint(tpd->task->numParameters, taskpointerarray, checkpoint, forward, reverse);
389         } else {
390           if (injectfailures) {
391             if ((((double)random())/RAND_MAX)<failurechance) {
392               printf("\nINJECTING TASK FAILURE to %s\n", tpd->task->name);
393               longjmp(error_handler,10);
394             }
395           }
396           /* Actually call task */
397           if (debugtask) {
398             printf("ENTER %s\n",tpd->task->name);
399             ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
400             printf("EXIT %s\n",tpd->task->name);
401           } else
402             ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
403         }
404       }
405     }
406   }
407 }
408
409 void processtasks() {
410   int i;
411   for(i=0;i<numtasks;i++) {
412     struct taskdescriptor * task=taskarray[i];
413     int j;
414
415     for(j=0;j<task->numParameters;j++) {
416       struct parameterdescriptor *param=task->descriptorarray[j];
417       struct parameterwrapper * parameter=RUNMALLOC(sizeof(struct parameterwrapper));
418       struct parameterwrapper ** ptr=&objectqueues[param->type];
419
420       param->queue=parameter;
421       parameter->objectset=allocateRuntimeHash(10);
422       parameter->numberofterms=param->numberterms;
423       parameter->intarray=param->intarray;
424       parameter->task=task;
425       /* Link new queue in */
426       while((*ptr)!=NULL)
427         ptr=&((*ptr)->next);
428       (*ptr)=parameter;
429     }
430   }
431 }
432
433 #endif
434
435
436 void injectinstructionfailure() {
437 #ifdef TASK
438   if (injectinstructionfailures) {
439     instructioncount=failurecount;    
440     if ((((double)random())/RAND_MAX)<instfailurechance) {
441       printf("FAILURE!!!\n");
442       longjmp(error_handler,11);
443     }
444   }
445 #else
446 #endif
447 }
448
449 int ___Object______hashcode____(struct ___Object___ * ___this___) {
450   return (int) ___this___;
451 }
452
453 void ___System______printString____L___String___(struct ___String___ * s) {
454     struct ArrayObject * chararray=s->___value___;
455     int i;
456     int offset=s->___offset___;
457     for(i=0;i<s->___count___;i++) {
458         short s= ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i+offset];
459         putchar(s);
460     }
461 }
462
463 void * allocate_new(int type) {
464   void * v=FREEMALLOC(classsize[type]);
465   *((int *)v)=type;
466   return v;
467 }
468
469 struct ArrayObject * allocate_newarray(int type, int length) {
470   struct ArrayObject * v=FREEMALLOC(sizeof(struct ArrayObject)+length*classsize[type]);
471   v->type=type;
472   v->___length___=length;
473   return v;
474 }
475
476 struct ___String___ * NewString(const char *str,int length) {
477   struct ArrayObject * chararray=allocate_newarray(CHARARRAYTYPE, length);
478   struct ___String___ * strobj=allocate_new(STRINGTYPE);
479   int i;
480   strobj->___value___=chararray;
481   strobj->___count___=length;
482   strobj->___offset___=0;
483
484   for(i=0;i<length;i++) {
485     ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i]=(short)str[i];  }
486   return strobj;
487 }
488
489 void failedboundschk() {
490 #ifndef TASK
491   printf("Array out of bounds\n");
492   exit(-1);
493 #else
494   longjmp(error_handler,2);
495 #endif
496 }
497
498 void failednullptr() {
499 #ifndef TASK
500   printf("Dereferenced a null pointer\n");
501   exit(-1);
502 #else
503   longjmp(error_handler,3);
504 #endif
505 }
506
507 void abort_task() {
508 #ifndef TASK
509   printf("Aborting\n");
510   exit(-1);
511 #else
512   longjmp(error_handler,4);
513 #endif
514 }