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