Index: /trunk/FACT++/src/EventBuilder.c
===================================================================
--- /trunk/FACT++/src/EventBuilder.c	(revision 12371)
+++ /trunk/FACT++/src/EventBuilder.c	(revision 12372)
@@ -125,4 +125,130 @@
 WRK_DATA mBuffer[MAX_EVT * MAX_RUN];    //local working space
 
+#define MXSTR 1000
+char str[MXSTR];
+
+//ETIENNE
+#define MAX_SLOTS_PER_CHUNK 100
+
+typedef struct {
+    int32_t eventNumber;
+    int32_t chunk;
+    int32_t slot;
+} CHUNK_MAPPING;
+
+CHUNK_MAPPING mBufferMapping[MAX_EVT * MAX_RUN];
+
+#define MAX_EVT_MEM (sizeof(EVENT) + NPIX*1024*2 + NTMARK*1024*2)
+#define MAX_HEAD_MEM (NBOARDS * sizeof(PEVNT_HEADER))
+#define MAX_SLOT_SIZE (MAX_EVT_MEM + MAX_HEAD_MEM)
+#define MAX_CHUNK_SIZE (MAX_SLOT_SIZE*MAX_SLOTS_PER_CHUNK)
+
+typedef struct {
+    void * pointers[MAX_SLOTS_PER_CHUNK];
+    int32_t events[MAX_SLOTS_PER_CHUNK];
+    int32_t nFreeSlots;
+    int32_t nSlots;
+} ETI_CHUNK;
+
+int32_t numAllocatedChunks = 0;
+
+#define MAX_CHUNKS 8096
+ETI_CHUNK EtiMemoryChunks[MAX_CHUNKS];
+
+void* ETI_Malloc(int evtId, int evtIndex)
+{
+    int i,j;
+    for (i=0;i<numAllocatedChunks;i++) {
+        if (EtiMemoryChunks[i].nFreeSlots > 0) {
+            for (j=0;j<EtiMemoryChunks[i].nSlots;j++)
+            {
+                if (EtiMemoryChunks[i].events[j] == -1)
+                {
+                    EtiMemoryChunks[i].events[j] = evtId;
+                    EtiMemoryChunks[i].nFreeSlots--;
+                    mBufferMapping[evtIndex].eventNumber = evtId;
+                    mBufferMapping[evtIndex].chunk = i;
+                    mBufferMapping[evtIndex].slot = j;
+                    return EtiMemoryChunks[i].pointers[j];
+                }
+            }
+            //If I reach this point then we have a problem because it should have found
+            //a free spot just above.
+        }
+    }
+    //If we reach this point this means that we should allocate more memory
+    int32_t numNewSlots = 0;
+    if ((numAllocatedChunks + 1)*MAX_CHUNK_SIZE < g_maxMem)
+        numNewSlots = MAX_SLOTS_PER_CHUNK;
+    else
+        numNewSlots = (g_maxMem - numAllocatedChunks*MAX_CHUNK_SIZE)/MAX_SLOT_SIZE;
+
+    if (numNewSlots == 0)//cannot allocate more without exceeding the max mem limit
+    {
+        return NULL;
+    }
+
+    EtiMemoryChunks[numAllocatedChunks].pointers[0] = malloc(MAX_SLOT_SIZE*numNewSlots);
+    if (EtiMemoryChunks[numAllocatedChunks].pointers[0] == NULL)
+    {
+        snprintf (str, MXSTR, "could not allocate %lu bytes. %d chunks are currently allocated (max allowed %lu bytes)", MAX_CHUNK_SIZE, numAllocatedChunks, g_maxMem);
+        factOut (kError, 000, str);
+        return NULL;
+    }
+
+    EtiMemoryChunks[numAllocatedChunks].nSlots = numNewSlots;
+    EtiMemoryChunks[numAllocatedChunks].events[0] = evtId;
+    EtiMemoryChunks[numAllocatedChunks].nFreeSlots = numNewSlots-1;
+    mBufferMapping[evtIndex].eventNumber = evtId;
+    mBufferMapping[evtIndex].chunk = numAllocatedChunks;
+    mBufferMapping[evtIndex].slot = 0;
+
+    for (i=1;i<numNewSlots;i++)
+    {
+        EtiMemoryChunks[numAllocatedChunks].pointers[i] = &(((char*)(EtiMemoryChunks[numAllocatedChunks].pointers[i-1]))[MAX_SLOT_SIZE]);
+        EtiMemoryChunks[numAllocatedChunks].events[i] = -1;
+    }
+    numAllocatedChunks++;
+
+    return EtiMemoryChunks[numAllocatedChunks-1].pointers[0];
+}
+
+void ETI_Free(int evtId, int evtIndex)
+{
+    ETI_CHUNK* currentChunk = &EtiMemoryChunks[mBufferMapping[evtIndex].chunk];
+    if (currentChunk->events[mBufferMapping[evtIndex].slot] != evtId)
+    {
+        snprintf (str, MXSTR, "Mismatch in chunk mapping table. expected evtId %d. Got %d. No memory was freed.", evtId, currentChunk->events[mBufferMapping[evtIndex].slot]);
+        factOut (kError, 000, str);
+        return;
+    }
+    currentChunk->events[mBufferMapping[evtIndex].slot] = -1;
+    currentChunk->nFreeSlots++;
+    //check if some chunks should be freed
+    int i;
+    for (i=0;i<numAllocatedChunks;i++)
+    {
+        if (EtiMemoryChunks[i].nFreeSlots == EtiMemoryChunks[i].nSlots)
+        {
+            snprintf(str, MXSTR, "Slot %d could be freed", i);
+            factOut(kError, 000, str);
+        }
+    }
+    int chunkIndex = mBufferMapping[evtIndex].chunk;
+    if (chunkIndex != numAllocatedChunks-1)
+        return;
+
+    while (EtiMemoryChunks[chunkIndex].nFreeSlots == EtiMemoryChunks[chunkIndex].nSlots)
+    {//free this chunk
+        snprintf(str, MXSTR, "Freeing chunk #%d", numAllocatedChunks);
+        factOut(kError, 000, str);
+        free(EtiMemoryChunks[chunkIndex].pointers[0]);
+        numAllocatedChunks--;
+        chunkIndex--;
+        if (numAllocatedChunks == 0)
+            break;
+    }
+}
+//END ETIENNE
 
 
@@ -189,7 +315,4 @@
 
 
-#define MXSTR 1000
-char str[MXSTR];
-
 SHORT_BYTE start, stop;
 
@@ -211,5 +334,12 @@
    return 0;
 }
-
+int
+runFinish (uint32_t runnr)
+{
+   snprintf (str, MXSTR, "Should finish run %d (but not yet possible)",
+             runnr);
+   factOut (kInfo, 173, str);   //but continue anyhow
+   return 0;
+}
 
 int
@@ -235,5 +365,5 @@
       //this is a not used socket, so do nothing ...
       rd->sockStat = 77;
-      rd->rBuf == NULL ;
+      rd->rBuf = NULL ;
       return 0;
    }
@@ -339,6 +469,11 @@
       evtCtrl.evtStat[i] = -1;
       evtCtrl.pcTime[i] = actime;       //initiate to far future
-   }
-
+
+      //ETIENNE
+      mBufferMapping[i].chunk = -1;
+      mBufferMapping[i].eventNumber = -1;
+      mBufferMapping[i].slot = -1;
+      //END ETIENNE
+   }
 
    actRun.FADhead = malloc (NBOARDS * sizeof (PEVNT_HEADER));
@@ -515,6 +650,6 @@
 
  RUNFOUND:
-
-   needmem = sizeof (EVENT) + NPIX * nRoi[0] * 2 + NTMARK * nRoi[0] * 2;        //
+ //ETIENNE
+/*   needmem = sizeof (EVENT) + NPIX * nRoi[0] * 2 + NTMARK * nRoi[0] * 2;        //
 
    headmem = NBOARDS * sizeof (PEVNT_HEADER);
@@ -534,5 +669,30 @@
       return -11;
    }
-
+*/
+   mBuffer[i].FADhead = ETI_Malloc(evID, i);
+   mBuffer[i].buffer = NULL;
+   if (mBuffer[i].FADhead != NULL)
+       mBuffer[i].fEvent = (EVENT*)&(((char*)(mBuffer[i].FADhead))[MAX_HEAD_MEM]);
+   else
+   {
+       mBuffer[i].fEvent = NULL;
+       gj.usdMem = 0;
+       for (k=0;k<numAllocatedChunks;k++)
+           gj.usdMem += EtiMemoryChunks[k].nSlots * MAX_SLOT_SIZE;
+       if (gj.usdMem > gj.maxMem)
+          gj.maxMem = gj.usdMem;
+       if (gi_memStat > 0) {
+           gi_memStat = -99;
+           snprintf (str, MXSTR, "no memory left to keep event %6d sock %3d",
+                     evID, sk);
+           factOut (kError, 882, str);
+        } else {
+           snprintf (str, MXSTR, "no memory left to keep event %6d sock %3d",
+                     evID, sk);
+           factOut (kDebug, 882, str);
+        }
+       return -11;
+   }
+   /*
    mBuffer[i].FADhead = malloc (headmem);
    if (mBuffer[i].FADhead == NULL) {
@@ -560,5 +720,6 @@
       mBuffer[i].fEvent = NULL;
       return -32;
-   }
+   }*/
+   //END ETIENNE
    //flag all boards as unused
    mBuffer[i].nBoard = 0;
@@ -588,6 +749,12 @@
    mBuffer[i].Errors[0] =
       mBuffer[i].Errors[1] = mBuffer[i].Errors[2] = mBuffer[i].Errors[3] = 0;
-
-   gj.usdMem += needmem + headmem + gi_maxSize;
+//ETIENNE
+   //gj.usdMem += needmem + headmem + gi_maxSize;
+   gj.usdMem = 0;
+   for (k=0;k<numAllocatedChunks;k++)
+   {
+       gj.usdMem += EtiMemoryChunks[k].nSlots * MAX_SLOT_SIZE;
+   }
+//END ETIENNE
    if (gj.usdMem > gj.maxMem)
       gj.maxMem = gj.usdMem;
@@ -636,19 +803,27 @@
    evid = mBuffer[i].evNum;
    freemem = mBuffer[i].evtLen;
-
-   free (mBuffer[i].fEvent);
+   //ETIENNE
+   ETI_Free(evid, i);
+//   free (mBuffer[i].fEvent);
    mBuffer[i].fEvent = NULL;
 
-   free (mBuffer[i].FADhead);
+//   free (mBuffer[i].FADhead);
    mBuffer[i].FADhead = NULL;
 
-   free (mBuffer[i].buffer);
+//   free (mBuffer[i].buffer);
    mBuffer[i].buffer = NULL;
-
+//END ETIENNE
    headmem = NBOARDS * sizeof (PEVNT_HEADER);
    mBuffer[i].evNum = mBuffer[i].nRoi = -1;
    mBuffer[i].runNum = 0;
-
-   gj.usdMem = gj.usdMem - freemem - headmem - gi_maxSize;
+//ETIENNE
+//   gj.usdMem = gj.usdMem - freemem - headmem - gi_maxSize;
+   gj.usdMem = 0;
+   int k;
+   for (k=0;k<numAllocatedChunks;k++)
+   {
+       gj.usdMem += EtiMemoryChunks[k].nSlots * MAX_SLOT_SIZE;
+   }
+//END ETIENNE
    gj.bufTot--;
 
