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