changes
[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   struct RuntimeHash *flagptr=(struct RuntimeHash *)(((int*)ptr)[2]);
128   int flag=ormask|oldflag;
129   flag&=andmask;
130   if (flag==oldflag) /* Don't do anything */
131     return;
132   ((int*)ptr)[1]=flag;
133
134   /*Remove object from all queues */
135   while(flagptr!=NULL) {
136     struct RuntimeHash *next;
137     RuntimeHashget(flagptr, (int) ptr, (int *) &next);
138     RuntimeHashremove(flagptr, (int)ptr, (int) next);
139     flagptr=next;
140   }
141   
142   {
143     struct QueueItem *tmpptr;
144     struct parameterwrapper * parameter=objectqueues[((int *)ptr)[0]];
145     int i;
146     struct RuntimeHash * prevptr=NULL;
147     while(parameter!=NULL) {
148       for(i=0;i<parameter->numberofterms;i++) {
149         int andmask=parameter->intarray[i*2];
150         int checkmask=parameter->intarray[i*2+1];
151         if ((flag&andmask)==checkmask) {
152           RuntimeHashadd(parameter->objectset, (int) ptr, (int) prevptr);
153           prevptr=parameter->objectset;
154           {
155             struct RuntimeIterator iteratorarray[MAXTASKPARAMS];
156             void * taskpointerarray[MAXTASKPARAMS];
157             int j;
158             int numparams=parameter->task->numParameters;
159             int done=1;
160             struct taskdescriptor * task=parameter->task;
161             int newindex=-1;
162             for(j=0;j<numparams;j++) {
163               struct parameterwrapper *pw=(struct parameterwrapper *)task->descriptorarray[j]->queue;
164               if (parameter==pw) {
165                 taskpointerarray[j]=ptr;
166                 newindex=j;
167               } else {
168                 RuntimeHashiterator(pw->objectset, &iteratorarray[j]);
169                 if (RunhasNext(&iteratorarray[j])) {
170                   taskpointerarray[j]=(void *) Runkey(&iteratorarray[j]);
171                   Runnext(&iteratorarray[j]);
172                 } else {
173                   done=0;
174                   break; /* No tasks to dispatch */
175                 }
176               }
177             }
178             /* Queue task items... */
179
180             while(done) {
181               struct taskparamdescriptor *tpd=RUNMALLOC(sizeof(struct taskparamdescriptor));
182               tpd->task=task;
183               tpd->numParameters=numparams;
184               tpd->parameterArray=RUNMALLOC(sizeof(void *)*numparams);
185               for(j=0;j<numparams;j++)
186                 tpd->parameterArray[j]=taskpointerarray[j];
187               /* Queue task */
188               if (!gencontains(failedtasks, tpd))
189                 addNewItem(activetasks, tpd);
190               else {
191                 RUNFREE(tpd->parameterArray);
192                 RUNFREE(tpd);
193               }
194
195               /* This loop iterates to the next parameter combination */
196               for(j=0;j<numparams;j++) {
197                 if (j==newindex) {
198                   if ((j+1)==numparams)
199                     done=0;
200                   continue;
201                 }
202                 if (RunhasNext(&iteratorarray[j])) {
203                   taskpointerarray[j]=(void *) Runkey(&iteratorarray[j]);
204                   Runnext(&iteratorarray[j]);
205                   break;
206                 } else if ((j+1)!=numparams) {
207                   RuntimeHashiterator(task->descriptorarray[j]->queue, &iteratorarray[j]);
208                 } else {
209                   done=0;
210                   break;
211                 }
212               }
213             }
214           }
215           break;
216         }
217       }
218       parameter=parameter->next;
219     }
220     ((struct RuntimeHash **)ptr)[2]=prevptr;
221   }
222 }
223
224 /* Handler for signals. The signals catch null pointer errors and
225    arithmatic errors. */
226
227 void myhandler(int sig, siginfo_t *info, void *uap) {
228 #ifdef DEBUG
229   printf("sig=%d\n",sig);
230   printf("signal\n");
231 #endif
232   longjmp(error_handler,1);
233 }
234
235 fd_set readfds;
236 int maxreadfd;
237 struct RuntimeHash *fdtoobject;
238
239 void addreadfd(int fd) {
240   if (fd>=maxreadfd)
241     maxreadfd=fd+1;
242   FD_SET(fd, &readfds);
243 }
244
245 void removereadfd(int fd) {
246   FD_CLR(fd, &readfds);
247   if (maxreadfd==(fd+1)) {
248     maxreadfd--;
249     while(maxreadfd>0&&!FD_ISSET(maxreadfd-1, &readfds))
250       maxreadfd--;
251   }
252 }
253
254 #ifdef PRECISE_GC
255 #define OFFSET 2
256 #else
257 #define OFFSET 0
258 #endif
259
260 void executetasks() {
261   void * taskpointerarray[MAXTASKPARAMS+OFFSET];
262
263   /* Set up signal handlers */
264   struct sigaction sig;
265   sig.sa_sigaction=&myhandler;
266   sig.sa_flags=SA_SIGINFO;
267   sigemptyset(&sig.sa_mask);
268
269   /* Catch bus errors, segmentation faults, and floating point exceptions*/
270   sigaction(SIGBUS,&sig,0);
271   sigaction(SIGSEGV,&sig,0);
272   sigaction(SIGFPE,&sig,0);
273   sigaction(SIGPIPE,&sig,0);
274
275   /* Zero fd set */
276   FD_ZERO(&readfds);
277   maxreadfd=0;
278   fdtoobject=allocateRuntimeHash(100);
279
280   /* Map first block of memory to protected, anonymous page */
281   mmap(0, 0x1000, 0, MAP_SHARED|MAP_FIXED|MAP_ANON, -1, 0);
282
283   newtask:
284   while(!isEmpty(activetasks)||(maxreadfd>0)) {
285
286     /* Check if any filedescriptors have IO pending */
287     if (maxreadfd>0) {
288       int i;
289       struct timeval timeout={0,0};
290       fd_set tmpreadfds;
291       int numselect;
292       tmpreadfds=readfds;
293       numselect=select(maxreadfd, &tmpreadfds, NULL, NULL, &timeout);
294       if (numselect>0) {
295         /* Process ready fd's */
296         int fd;
297         for(fd=0;fd<maxreadfd;fd++) {
298           if (FD_ISSET(fd, &tmpreadfds)) {
299             /* Set ready flag on object */
300             void * objptr;
301             if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
302               flagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
303             }
304           }
305         }
306       }
307     }
308
309     /* See if there are any active tasks */
310     if (!isEmpty(activetasks)) {
311       int i;
312       struct QueueItem * qi=(struct QueueItem *) getTail(activetasks);
313       currtpd=(struct taskparamdescriptor *) qi->objectptr;
314       removeItem(activetasks, qi);
315
316       /* Check if this task has failed */
317       if (gencontains(failedtasks, currtpd)) {
318         // Free up task parameter descriptor
319         RUNFREE(currtpd->parameterArray);
320         RUNFREE(currtpd);
321         goto newtask;
322       }
323       
324       /* Make sure that the parameters are still in the queues */
325       for(i=0;i<currtpd->task->numParameters;i++) {
326         void * parameter=currtpd->parameterArray[i];
327         struct parameterdescriptor * pd=currtpd->task->descriptorarray[i];
328         struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
329         if (!RuntimeHashcontainskey(pw->objectset, (int) parameter)) {
330           RUNFREE(currtpd->parameterArray);
331           RUNFREE(currtpd);
332           goto newtask;
333         }
334         taskpointerarray[i+OFFSET]=parameter;
335       }
336       {
337         /* Checkpoint the state */
338         forward=allocateRuntimeHash(100);
339         reverse=allocateRuntimeHash(100);
340         void ** checkpoint=makecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, forward, reverse);
341         int x;
342         if (x=setjmp(error_handler)) {
343           /* Recover */
344           int h;
345 #ifdef DEBUG
346           printf("Fatal Error=%d, Recovering!\n",x);
347 #endif
348           genputtable(failedtasks,currtpd,currtpd);
349           restorecheckpoint(currtpd->task->numParameters, currtpd->parameterArray, checkpoint, forward, reverse);
350           freeRuntimeHash(forward);
351           freeRuntimeHash(reverse);
352           freemalloc();
353           forward=NULL;
354           reverse=NULL;
355         } else {
356           if (injectfailures) {
357             if ((((double)random())/RAND_MAX)<failurechance) {
358               printf("\nINJECTING TASK FAILURE to %s\n", currtpd->task->name);
359               longjmp(error_handler,10);
360             }
361           }
362           /* Actually call task */
363 #ifdef PRECISE_GC
364           ((int *)taskpointerarray)[0]=currtpd->task->numParameters;
365           taskpointerarray[1]=NULL;
366 #endif
367
368           if (debugtask) {
369             printf("ENTER %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
370             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
371             printf("EXIT %s count=%d\n",currtpd->task->name, (instaccum-instructioncount));
372           } else
373             ((void (*) (void **)) currtpd->task->taskptr)(taskpointerarray);
374           freeRuntimeHash(forward);
375           freeRuntimeHash(reverse);
376           freemalloc();
377           // Free up task parameter descriptor
378           RUNFREE(currtpd->parameterArray);
379           RUNFREE(currtpd);
380           forward=NULL;
381           reverse=NULL;
382         }
383       }
384     }
385   }
386 }
387
388 /* This function processes the task information to create queues for
389    each parameter type. */
390
391 void processtasks() {
392   int i;
393   for(i=0;i<numtasks;i++) {
394     struct taskdescriptor * task=taskarray[i];
395     int j;
396
397     for(j=0;j<task->numParameters;j++) {
398       struct parameterdescriptor *param=task->descriptorarray[j];
399       struct parameterwrapper * parameter=RUNMALLOC(sizeof(struct parameterwrapper));
400       struct parameterwrapper ** ptr=&objectqueues[param->type];
401
402       param->queue=parameter;
403       parameter->objectset=allocateRuntimeHash(10);
404       parameter->numberofterms=param->numberterms;
405       parameter->intarray=param->intarray;
406       parameter->task=task;
407       /* Link new queue in */
408       while((*ptr)!=NULL)
409         ptr=&((*ptr)->next);
410       (*ptr)=parameter;
411     }
412   }
413 }
414
415 #endif
416
417 /* This function inject failures */
418
419 void injectinstructionfailure() {
420 #ifdef TASK
421   if (injectinstructionfailures) {
422     if (numfailures==0)
423       return;
424     instructioncount=failurecount;    
425     instaccum+=failurecount;
426     if ((((double)random())/RAND_MAX)<instfailurechance) {
427       if (numfailures>0)
428         numfailures--;
429       printf("FAILURE!!! %d\n",numfailures);
430       longjmp(error_handler,11);
431     }
432   }
433 #else
434 #ifdef THREADS
435   if (injectinstructionfailures) {
436     if (numfailures==0)
437       return;
438     instaccum+=failurecount;
439     if ((((double)random())/RAND_MAX)<instfailurechance) {
440       if (numfailures>0)
441         numfailures--;
442       printf("FAILURE!!! %d\n",numfailures);
443       threadexit();
444     }
445   }
446 #endif
447 #endif
448 }
449
450 void CALL01(___System______printString____L___String___,struct ___String___ * ___s___) {
451     struct ArrayObject * chararray=VAR(___s___)->___value___;
452     int i;
453     int offset=VAR(___s___)->___offset___;
454     for(i=0;i<VAR(___s___)->___count___;i++) {
455         short sc=((short *)(((char *)& chararray->___length___)+sizeof(int)))[i+offset];
456         putchar(sc);
457     }
458 }
459
460 /* Object allocation function */
461
462 #ifdef PRECISE_GC
463 void * allocate_new(void * ptr, int type) {
464   struct ___Object___ * v=(struct ___Object___ *) mygcmalloc((struct garbagelist *) ptr, classsize[type]);
465   v->type=type;
466 #ifdef THREADS
467   v->tid=0;
468   v->lockentry=0;
469   v->lockcount=0;
470 #endif
471   return v;
472 }
473
474 /* Array allocation function */
475
476 struct ArrayObject * allocate_newarray(void * ptr, int type, int length) {
477   struct ArrayObject * v=mygcmalloc((struct garbagelist *) ptr, sizeof(struct ArrayObject)+length*classsize[type]);
478   v->type=type;
479   if (length<0) {
480     printf("ERROR: negative array\n");
481     return NULL;
482   }
483   v->___length___=length;
484 #ifdef THREADS
485   v->tid=0;
486   v->lockentry=0;
487   v->lockcount=0;
488 #endif
489   return v;
490 }
491
492 #else
493 void * allocate_new(int type) {
494   void * v=FREEMALLOC(classsize[type]);
495   *((int *)v)=type;
496   return v;
497 }
498
499 /* Array allocation function */
500
501 struct ArrayObject * allocate_newarray(int type, int length) {
502   struct ArrayObject * v=FREEMALLOC(sizeof(struct ArrayObject)+length*classsize[type]);
503   v->type=type;
504   v->___length___=length;
505   return v;
506 }
507 #endif
508
509
510 /* Converts C character arrays into Java strings */
511 #ifdef PRECISE_GC
512 struct ___String___ * NewString(void * ptr, const char *str,int length) {
513 #else
514 struct ___String___ * NewString(const char *str,int length) {
515 #endif
516   int i;
517 #ifdef PRECISE_GC
518   struct ArrayObject * chararray=allocate_newarray((struct garbagelist *)ptr, CHARARRAYTYPE, length);
519   int ptrarray[]={1, (int) ptr, (int) chararray};
520   struct ___String___ * strobj=allocate_new((struct garbagelist *) &ptrarray, STRINGTYPE);
521   chararray=(struct ArrayObject *) ptrarray[2];
522 #else
523   struct ArrayObject * chararray=allocate_newarray(CHARARRAYTYPE, length);
524   struct ___String___ * strobj=allocate_new(STRINGTYPE);
525 #endif
526   strobj->___value___=chararray;
527   strobj->___count___=length;
528   strobj->___offset___=0;
529
530   for(i=0;i<length;i++) {
531     ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i]=(short)str[i];  }
532   return strobj;
533 }
534
535 /* Generated code calls this if we fail a bounds check */
536
537 void failedboundschk() {
538 #ifndef TASK
539   printf("Array out of bounds\n");
540 #ifdef THREADS
541   threadexit();
542 #else
543   exit(-1);
544 #endif
545 #else
546   longjmp(error_handler,2);
547 #endif
548 }
549
550 /* Abort task call */
551 void abort_task() {
552 #ifdef TASK
553   longjmp(error_handler,4);
554 #else
555   printf("Aborting\n");
556   exit(-1);
557 #endif
558 }