7a7de4651e0a0a47c67a27cd4251fe6cd417a054
[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
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             if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
313               flagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
314             }
315           }
316         }
317       }
318     }
319
320     /* See if there are any active tasks */
321     if (!isEmpty(activetasks)) {
322       int i;
323       struct QueueItem * qi=(struct QueueItem *) getTail(activetasks);
324       currtpd=(struct taskparamdescriptor *) qi->objectptr;
325       removeItem(activetasks, qi);
326
327       /* Check if this task has failed */
328       if (gencontains(failedtasks, currtpd)) {
329         // Free up task parameter descriptor
330         RUNFREE(currtpd->parameterArray);
331         RUNFREE(currtpd);
332         goto newtask;
333       }
334       
335       /* Make sure that the parameters are still in the queues */
336       for(i=0;i<currtpd->task->numParameters;i++) {
337         void * parameter=currtpd->parameterArray[i];
338         struct parameterdescriptor * pd=currtpd->task->descriptorarray[i];
339         struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
340         if (!RuntimeHashcontainskey(pw->objectset, (int) parameter)) {
341           RUNFREE(currtpd->parameterArray);
342           RUNFREE(currtpd);
343           goto newtask;
344         }
345         taskpointerarray[i+OFFSET]=parameter;
346       }
347       {
348         /* Checkpoint the state */
349         forward=allocateRuntimeHash(100);
350         reverse=allocateRuntimeHash(100);
351         void ** checkpoint=makecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, forward, reverse);
352         int x;
353         if (x=setjmp(error_handler)) {
354           /* Recover */
355           int h;
356 #ifdef DEBUG
357           printf("Fatal Error=%d, Recovering!\n",x);
358 #endif
359           genputtable(failedtasks,currtpd,currtpd);
360           restorecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, checkpoint, forward, reverse);
361           freeRuntimeHash(forward);
362           freeRuntimeHash(reverse);
363           freemalloc();
364           forward=NULL;
365           reverse=NULL;
366         } else {
367           if (injectfailures) {
368             if ((((double)random())/RAND_MAX)<failurechance) {
369               printf("\nINJECTING TASK FAILURE to %s\n", currtpd->task->name);
370               longjmp(error_handler,10);
371             }
372           }
373           /* Actually call task */
374 #ifdef PRECISE_GC
375           ((int *)taskpointerarray)[0]=currtpd->task->numParameters;
376           taskpointerarray[1]=NULL;
377 #endif
378
379           if (debugtask) {
380             printf("ENTER %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
381             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
382             printf("EXIT %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
383           } else
384             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
385           freeRuntimeHash(forward);
386           freeRuntimeHash(reverse);
387           freemalloc();
388           // Free up task parameter descriptor
389           RUNFREE(currtpd->parameterArray);
390           RUNFREE(currtpd);
391           forward=NULL;
392           reverse=NULL;
393         }
394       }
395     }
396   }
397 }
398
399 /* This function processes the task information to create queues for
400    each parameter type. */
401
402 void processtasks() {
403   int i;
404   for(i=0;i<numtasks;i++) {
405     struct taskdescriptor * task=taskarray[i];
406     int j;
407
408     for(j=0;j<task->numParameters;j++) {
409       struct parameterdescriptor *param=task->descriptorarray[j];
410       struct parameterwrapper * parameter=RUNMALLOC(sizeof(struct parameterwrapper));
411       struct parameterwrapper ** ptr=&objectqueues[param->type];
412
413       param->queue=parameter;
414       parameter->objectset=allocateRuntimeHash(10);
415       parameter->numberofterms=param->numberterms;
416       parameter->intarray=param->intarray;
417       parameter->task=task;
418       /* Link new queue in */
419       while((*ptr)!=NULL)
420         ptr=&((*ptr)->next);
421       (*ptr)=parameter;
422     }
423   }
424 }
425
426 #endif
427
428 /* This function inject failures */
429
430 void injectinstructionfailure() {
431 #ifdef TASK
432   if (injectinstructionfailures) {
433     if (numfailures==0)
434       return;
435     instructioncount=failurecount;    
436     instaccum+=failurecount;
437     if ((((double)random())/RAND_MAX)<instfailurechance) {
438       if (numfailures>0)
439         numfailures--;
440       printf("FAILURE!!! %d\n",numfailures);
441       longjmp(error_handler,11);
442     }
443   }
444 #else
445 #ifdef THREADS
446   if (injectinstructionfailures) {
447     if (numfailures==0)
448       return;
449     instaccum+=failurecount;
450     if ((((double)random())/RAND_MAX)<instfailurechance) {
451       if (numfailures>0)
452         numfailures--;
453       printf("FAILURE!!! %d\n",numfailures);
454       threadexit();
455     }
456   }
457 #endif
458 #endif
459 }
460
461 void CALL01(___System______printString____L___String___,struct ___String___ * ___s___) {
462     struct ArrayObject * chararray=VAR(___s___)->___value___;
463     int i;
464     int offset=VAR(___s___)->___offset___;
465     for(i=0;i<VAR(___s___)->___count___;i++) {
466         short sc=((short *)(((char *)& chararray->___length___)+sizeof(int)))[i+offset];
467         putchar(sc);
468     }
469 }
470
471 /* Object allocation function */
472
473 #ifdef PRECISE_GC
474 void * allocate_new(void * ptr, int type) {
475   struct ___Object___ * v=(struct ___Object___ *) mygcmalloc((struct garbagelist *) ptr, classsize[type]);
476   v->type=type;
477 #ifdef THREADS
478   v->tid=0;
479   v->lockentry=0;
480   v->lockcount=0;
481 #endif
482   return v;
483 }
484
485 /* Array allocation function */
486
487 struct ArrayObject * allocate_newarray(void * ptr, int type, int length) {
488   struct ArrayObject * v=mygcmalloc((struct garbagelist *) ptr, sizeof(struct ArrayObject)+length*classsize[type]);
489   v->type=type;
490   if (length<0) {
491     printf("ERROR: negative array\n");
492     return NULL;
493   }
494   v->___length___=length;
495 #ifdef THREADS
496   v->tid=0;
497   v->lockentry=0;
498   v->lockcount=0;
499 #endif
500   return v;
501 }
502
503 #else
504 void * allocate_new(int type) {
505   void * v=FREEMALLOC(classsize[type]);
506   *((int *)v)=type;
507   return v;
508 }
509
510 /* Array allocation function */
511
512 struct ArrayObject * allocate_newarray(int type, int length) {
513   struct ArrayObject * v=FREEMALLOC(sizeof(struct ArrayObject)+length*classsize[type]);
514   v->type=type;
515   v->___length___=length;
516   return v;
517 }
518 #endif
519
520
521 /* Converts C character arrays into Java strings */
522 #ifdef PRECISE_GC
523 struct ___String___ * NewString(void * ptr, const char *str,int length) {
524 #else
525 struct ___String___ * NewString(const char *str,int length) {
526 #endif
527   int i;
528 #ifdef PRECISE_GC
529   struct ArrayObject * chararray=allocate_newarray((struct garbagelist *)ptr, CHARARRAYTYPE, length);
530   int ptrarray[]={1, (int) ptr, (int) chararray};
531   struct ___String___ * strobj=allocate_new((struct garbagelist *) &ptrarray, STRINGTYPE);
532   chararray=(struct ArrayObject *) ptrarray[2];
533 #else
534   struct ArrayObject * chararray=allocate_newarray(CHARARRAYTYPE, length);
535   struct ___String___ * strobj=allocate_new(STRINGTYPE);
536 #endif
537   strobj->___value___=chararray;
538   strobj->___count___=length;
539   strobj->___offset___=0;
540
541   for(i=0;i<length;i++) {
542     ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i]=(short)str[i];  }
543   return strobj;
544 }
545
546 /* Generated code calls this if we fail a bounds check */
547
548 void failedboundschk() {
549 #ifndef TASK
550   printf("Array out of bounds\n");
551 #ifdef THREADS
552   threadexit();
553 #else
554   exit(-1);
555 #endif
556 #else
557   longjmp(error_handler,2);
558 #endif
559 }
560
561 /* Abort task call */
562 void abort_task() {
563 #ifdef TASK
564   longjmp(error_handler,4);
565 #else
566   printf("Aborting\n");
567   exit(-1);
568 #endif
569 }