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