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