add linux support
[IRC.git] / Robust / src / Runtime / runtime.c
index abf51e71d81f738847d392c4490f7a38a19d5180..a977b6938b38a14ed0d43621995d7703becabe2b 100644 (file)
 
 extern int classsize[];
 jmp_buf error_handler;
+int instructioncount;
 
 #ifdef TASK
 #include "checkpoint.h"
 #include "Queue.h"
 #include "SimpleHash.h"
 #include "GenericHashtable.h"
+#include <sys/select.h>
+
 #ifdef CONSCHECK
 #include "instrument.h"
 #endif
@@ -25,12 +28,72 @@ jmp_buf error_handler;
 struct Queue * activetasks;
 struct parameterwrapper * objectqueues[NUMCLASSES];
 struct genhashtable * failedtasks;
+/*struct genhashtable * failedobjects;*/
+extern char ** environ;
+char *options;
+int injectfailures=0;
+float failurechance=0;
+int debugtask=0;
+int injectinstructionfailures;
+int failurecount;
+float instfailurechance=0;
+
+void processOptions() {
+  int i;
+  options=NULL;
+  for(i=0;environ[i]!=0;i++) {
+    if (strncmp(environ[i],"BRISTLECONE=",12)==0) {
+      options=environ[i]+12;
+      break;
+    }
+  }
+  
+  while(options!=NULL) {
+    if (strncmp(options,"-injectfailures",sizeof("-injectfailures")-1)==0) {
+      options=strchr(options,' ');
+      if (options!=NULL) options++;
+      if (options==NULL)
+       break;
+      sscanf(options, "%f", &failurechance);
+      injectfailures=1;
+      printf("Injecting errors with chance=%f\n",failurechance);
+      options=strchr(options,' ');
+      if (options!=NULL) options++;
+    } else if (strncmp(options,"-injectinstructionfailures",sizeof("-injectinstructionfailures")-1)==0) {
+      options=strchr(options,' ');
+      if (options!=NULL) options++;
+      if (options==NULL)
+       break;
+      sscanf(options, "%d", &failurecount);
+      options=strchr(options,' ');
+      if (options!=NULL) options++;
+      if (options==NULL)
+       break;
+      sscanf(options, "%f", &instfailurechance);
+      options=strchr(options,' ');
+      if (options!=NULL) options++;
+      instructioncount=failurecount;
+      injectinstructionfailures=1;
+      printf("Injecting errors with count=%d\n",failurecount);
+      printf("Injecting errors with chance=%f\n",instfailurechance);
+
+    } else if (strncmp(options, "-debugtask",sizeof("-debugtask")-1)==0) {
+      options=strchr(options,' ');
+      if (options!=NULL) options++;
+      debugtask=1;
+      printf("Debug task option on.\n");
+    } else
+      break;
+  }
+}
 
 int main(int argc, char **argv) {
-  GC_init();
+  GC_init(); // Initialize the garbage collector
 #ifdef CONSCHECK
   initializemmap();
 #endif
+  processOptions();
+
   {
   int i;
   /* Allocate startup object */
@@ -38,6 +101,7 @@ int main(int argc, char **argv) {
   struct ArrayObject * stringarray=allocate_newarray(STRINGARRAYTYPE, argc-1); 
   failedtasks=genallocatehashtable((unsigned int (*)(void *)) &hashCodetpd, 
                                   (int (*)(void *,void *)) &comparetpd);
+  /*  failedobjects=genallocatehashtable(NULL,NULL);*/
   
   activetasks=createQueue();
 
@@ -118,10 +182,13 @@ void flagorand(void * ptr, int ormask, int andmask) {
                newindex=j;
              } else {
                RuntimeHashiterator(pw->objectset, &iteratorarray[j]);
-               if (RunhasNext(&iteratorarray[j]))
-                 taskpointerarray[j]=(void *) Runnext(&iteratorarray[j]);
-               else
+               if (RunhasNext(&iteratorarray[j])) {
+                 taskpointerarray[j]=(void *) Runkey(&iteratorarray[j]);
+                 Runnext(&iteratorarray[j]);
+               } else {
+                 done=0;
                  break; /* No tasks to dispatch */
+               }
              }
            }
            /* Queue task items... */
@@ -137,7 +204,7 @@ void flagorand(void * ptr, int ormask, int andmask) {
              if (!gencontains(failedtasks, tpd))
                addNewItem(activetasks, tpd);
              
-             /* This loop iterates to the next paramter combination */
+             /* This loop iterates to the next parameter combination */
              for(j=0;j<numparams;j++) {
                if (j==newindex) {
                  if ((j+1)==numparams)
@@ -145,7 +212,8 @@ void flagorand(void * ptr, int ormask, int andmask) {
                  continue;
                }
                if (RunhasNext(&iteratorarray[j])) {
-                 taskpointerarray[j]=(void *) Runnext(&iteratorarray[j]);
+                 taskpointerarray[j]=(void *) Runkey(&iteratorarray[j]);
+                 Runnext(&iteratorarray[j]);
                  break;
                } else if ((j+1)!=numparams) {
                  RuntimeHashiterator(task->descriptorarray[j]->queue, &iteratorarray[j]);
@@ -165,8 +233,13 @@ void flagorand(void * ptr, int ormask, int andmask) {
   }
 }
 
-/* Handler for signals */
+/* Handler for signals. The signals catch null pointer errors and
+   arithmatic errors. */
+#ifdef LINUX
+void myhandler(int sig, siginfo_t *info, void *uap) {
+#else
 void myhandler(int sig, struct __siginfo *info, void *uap) {
+#endif
 #ifdef DEBUG
   printf("sig=%d\n",sig);
   printf("signal\n");
@@ -174,6 +247,59 @@ void myhandler(int sig, struct __siginfo *info, void *uap) {
   longjmp(error_handler,1);
 }
 
+fd_set readfds;
+int maxreadfd;
+struct RuntimeHash *fdtoobject;
+
+void addreadfd(int fd) {
+  if (fd>=maxreadfd)
+    maxreadfd=fd+1;
+  FD_SET(fd, &readfds);
+}
+
+void removereadfd(int fd) {
+  FD_CLR(fd, &readfds);
+  if (maxreadfd==(fd+1)) {
+    maxreadfd--;
+    while(maxreadfd>0&&!FD_ISSET(maxreadfd-1, &readfds))
+      maxreadfd--;
+  }
+}
+
+/*
+void restoreObject(void * obj) {
+  if (gencontains(failedobjects, obj)) {
+    struct tpdlist *tpd=gengettable(failedobjects, obj);
+    genfreekey(failedobjects, obj);
+    while(tpd!=NULL) {
+      int i;
+      struct taskparamdescriptor *task=tpd->task;
+      genfreekey(failedtasks, task);
+      for(i=0;i<task->numParameters;i++) {
+       void *objother=task->parameterArray[i];
+       struct tpdlist *tpdother=gengettable(failedobjects, objother);
+       struct tpdlist *tmpptr;
+       genfreekey(failedobjects, objother);
+       struct tpdlist **tpdptr=&tpdother;
+       while((*tpdptr)->task!=task)
+         tpdptr=&((*tpdptr)->next);
+       tmpptr=*tpdptr;
+       (*tpdptr)=(*tpdptr)->next;
+       RUNFREE(tmpptr);
+       if (tpdother!=NULL)
+         genputtable(failedobjects, objother, tpdother);
+      }
+      RUNFREE(task);
+      {
+       struct tpdlist *old=tpd;
+       tpd=tpd->next;
+       RUNFREE(old);
+      }
+    }
+  }
+}
+*/
+
 void executetasks() {
   void * taskpointerarray[MAXTASKPARAMS];
 
@@ -188,44 +314,113 @@ void executetasks() {
   sigaction(SIGSEGV,&sig,0);
   sigaction(SIGFPE,&sig,0);
 
+  /* Zero fd set */
+  FD_ZERO(&readfds);
+  maxreadfd=0;
+  fdtoobject=allocateRuntimeHash(100);
+
   /* Map first block of memory to protected, anonymous page */
   mmap(0, 0x1000, 0, MAP_SHARED|MAP_FIXED|MAP_ANON, -1, 0);
 
   newtask:
-  while(!isEmpty(activetasks)) {
-    struct QueueItem * qi=(struct QueueItem *) getTail(activetasks);
-    struct taskparamdescriptor *tpd=(struct taskparamdescriptor *) qi->objectptr;
-    int i;
-    removeItem(activetasks, qi);
-    
-    for(i=0;i<tpd->task->numParameters;i++) {
-      void * parameter=tpd->parameterArray[i];
-      struct parameterdescriptor * pd=tpd->task->descriptorarray[i];
-      struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
-      if (!RuntimeHashcontainskey(pw->objectset, (int) parameter))
-       goto newtask;
-      taskpointerarray[i]=parameter;
+  while(!isEmpty(activetasks)||(maxreadfd>0)) {
+
+    /* Check if any filedescriptors have IO pending */
+    if (maxreadfd>0) {
+      int i;
+      struct timeval timeout={0,0};
+      fd_set tmpreadfds;
+      int numselect;
+      tmpreadfds=readfds;
+      numselect=select(maxreadfd, &tmpreadfds, NULL, NULL, &timeout);
+      if (numselect>0) {
+       /* Process ready fd's */
+       int fd;
+       for(fd=0;fd<maxreadfd;fd++) {
+         if (FD_ISSET(fd, &tmpreadfds)) {
+           /* Set ready flag on object */
+           void * objptr;
+           if (RuntimeHashget(fdtoobject, fd,(int *) &objptr)) {
+             flagorand(objptr,1,0xFFFFFFFF); /* Set the first flag to 1 */
+           }
+         }
+       }
+      }
     }
-    {
-      struct RuntimeHash * forward=allocateRuntimeHash(100);
-      struct RuntimeHash * reverse=allocateRuntimeHash(100);
-      void ** checkpoint=makecheckpoint(tpd->task->numParameters, taskpointerarray, forward, reverse);
-      if (setjmp(error_handler)) {
-       /* Recover */
-       int h;
+
+    /* See if there are any active tasks */
+    if (!isEmpty(activetasks)) {
+      int i;
+      struct QueueItem * qi=(struct QueueItem *) getTail(activetasks);
+      struct taskparamdescriptor *tpd=(struct taskparamdescriptor *) qi->objectptr;
+      removeItem(activetasks, qi);
+
+      /* Check if this task has failed */
+      if (gencontains(failedtasks, tpd))
+       goto newtask;
+      
+      /* Make sure that the parameters are still in the queues */
+      for(i=0;i<tpd->task->numParameters;i++) {
+       void * parameter=tpd->parameterArray[i];
+       struct parameterdescriptor * pd=tpd->task->descriptorarray[i];
+       struct parameterwrapper *pw=(struct parameterwrapper *) pd->queue;
+       if (!RuntimeHashcontainskey(pw->objectset, (int) parameter))
+         goto newtask;
+       taskpointerarray[i]=parameter;
+      }
+      {
+       /* Checkpoint the state */
+       struct RuntimeHash * forward=allocateRuntimeHash(100);
+       struct RuntimeHash * reverse=allocateRuntimeHash(100);
+       void ** checkpoint=makecheckpoint(tpd->task->numParameters, taskpointerarray, forward, reverse);
+       int x;
+       if (x=setjmp(error_handler)) {
+         /* Recover */
+         int h;
 #ifdef DEBUG
-       printf("Recovering\n");
+         printf("Fatal Error=%d, Recovering!\n",x);
 #endif
-       genputtable(failedtasks,tpd,tpd);
-       restorecheckpoint(tpd->task->numParameters, taskpointerarray, checkpoint, forward, reverse);
-      } else {
-       /* Actually call task */
-       ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
+         genputtable(failedtasks,tpd,tpd);
+       /* for(i=0;i<tpd->task->numParameters;i++) {
+           void *parameter=tpd->parameterArray[i];
+           {
+             // Create mapping from object -> failed tasks 
+             struct tpdlist * tpnew=RUNMALLOC(sizeof(struct tpdlist));
+             tpnew->task=tpd;
+             if (gencontains(failedobjects, parameter)) {
+               struct tpdlist * tpdptr=gengettable(failedobjects, parameter);
+               tpnew->next=tpdptr->next;
+               tpdptr->next=tpnew;
+             } else {
+               tpnew->next=NULL;
+               genputtable(failedobjects, parameter, tpnew);
+             }
+           }
+         }  */
+         restorecheckpoint(tpd->task->numParameters, taskpointerarray, checkpoint, forward, reverse);
+       } else {
+         if (injectfailures) {
+           if ((((double)random())/RAND_MAX)<failurechance) {
+             printf("\nINJECTING TASK FAILURE to %s\n", tpd->task->name);
+             longjmp(error_handler,10);
+           }
+         }
+         /* Actually call task */
+         if (debugtask) {
+           printf("ENTER %s\n",tpd->task->name);
+           ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
+           printf("EXIT %s\n",tpd->task->name);
+         } else
+           ((void (*) (void **)) tpd->task->taskptr)(taskpointerarray);
+       }
       }
     }
   }
 }
 
+/* This function processes the task information to create queues for
+   each parameter type. */
+
 void processtasks() {
   int i;
   for(i=0;i<numtasks;i++) {
@@ -249,17 +444,38 @@ void processtasks() {
     }
   }
 }
+
 #endif
 
-int ___Object______hashcode____(struct ___Object___ * ___this___) {
+/* This function inject failures */
+
+void injectinstructionfailure() {
+#ifdef TASK
+  if (injectinstructionfailures) {
+    instructioncount=failurecount;    
+    if ((((double)random())/RAND_MAX)<instfailurechance) {
+      printf("FAILURE!!!\n");
+      longjmp(error_handler,11);
+    }
+  }
+#else
+#endif
+}
+
+int ___Object______hashCode____(struct ___Object___ * ___this___) {
   return (int) ___this___;
 }
 
+int ___Object______getType____(struct ___Object___ * ptr) {
+  return ((int *)ptr)[0];
+}
+
 void ___System______printString____L___String___(struct ___String___ * s) {
-    struct ArrayObject * chararray=s->___string___;
+    struct ArrayObject * chararray=s->___value___;
     int i;
-    for(i=0;i<chararray->___length___;i++) {
-       short s= ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i];
+    int offset=s->___offset___;
+    for(i=0;i<s->___count___;i++) {
+       short s= ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i+offset];
        putchar(s);
     }
 }
@@ -281,12 +497,16 @@ struct ___String___ * NewString(const char *str,int length) {
   struct ArrayObject * chararray=allocate_newarray(CHARARRAYTYPE, length);
   struct ___String___ * strobj=allocate_new(STRINGTYPE);
   int i;
-  strobj->___string___=chararray;
+  strobj->___value___=chararray;
+  strobj->___count___=length;
+  strobj->___offset___=0;
+
   for(i=0;i<length;i++) {
     ((short *)(((char *)& chararray->___length___)+sizeof(int)))[i]=(short)str[i];  }
   return strobj;
 }
 
+/* Generated code calls this if we fail a bounds check */
 void failedboundschk() {
 #ifndef TASK
   printf("Array out of bounds\n");
@@ -296,20 +516,11 @@ void failedboundschk() {
 #endif
 }
 
-void failednullptr() {
-#ifndef TASK
-  printf("Dereferenced a null pointer\n");
-  exit(-1);
-#else
-  longjmp(error_handler,3);
-#endif
-}
-
 void abort_task() {
-#ifndef TASK
+#ifdef TASK
+  longjmp(error_handler,4);
+#else
   printf("Aborting\n");
   exit(-1);
-#else
-  longjmp(error_handler,4);
 #endif
 }