Browse Source

fix for heap problem

pierre 25 years ago
parent
commit
e574245b0e
1 changed files with 152 additions and 12 deletions
  1. 152 12
      rtl/inc/heap.inc

+ 152 - 12
rtl/inc/heap.inc

@@ -32,7 +32,12 @@
 { DEBUG: Dump info when the heap needs to grow }
 { define DUMPGROW}
 
-{ Default heap settings }
+{$ifdef SYSTEMDEBUG}
+{$define TestFreeLists}
+{ define withbug this leads to crashes below }
+{$endif SYSTEMDEBUG}
+
+
 const
   blocksize    = 16;  { at least size of freerecord }
   blockshr     = 4;   { shr value for blocksize=2^blockshr}
@@ -80,12 +85,23 @@ type
   end; { 4 bytes }
 
   tfreelists   = array[0..maxblock] of pfreerecord;
+{$ifdef SYSTEMDEBUG}
+  tfreecount   = array[0..maxblock] of dword;
+{$endif SYSTEMDEBUG}
   pfreelists   = ^tfreelists;
 
 var
   internal_memavail  : longint;
   internal_heapsize  : longint;
   freelists          : tfreelists;
+{$ifdef SYSTEMDEBUG}
+  freecount : tfreecount;
+{$endif SYSTEMDEBUG}
+{$ifdef TestFreeLists}
+{ this can be turned on by debugger }
+const
+  test_each : boolean = false;
+{$endif TestFreeLists}
 
 {*****************************************************************************
                              Memory Manager
@@ -253,6 +269,28 @@ begin
 end;
 {$endif}
 
+{$ifdef TestFreeLists}
+  procedure TestFreeLists;
+var
+  i,j : longint;
+  hp  : pfreerecord;
+begin
+  for i:=0 to maxblock do
+   begin
+     j:=0;
+     hp:=freelists[i];
+     while assigned(hp) do
+      begin
+        inc(j);
+        if (i>0) and ((hp^.size and sizemask) <> i * blocksize) then
+          RunError(204);
+        hp:=hp^.next;
+      end;
+      if j<>freecount[i] then
+        RunError(204);
+    end;
+end;
+{$endif TestFreeLists}
 
 {*****************************************************************************
                                  SysGetMem
@@ -298,20 +336,33 @@ begin
         pcurr^.size:=pcurr^.size or usedmask;
         { update freelist }
         freelists[s]:=pcurr^.next;
+{$ifdef SYSTEMDEBUG}
+        dec(freecount[s]);
+{$endif SYSTEMDEBUG}
         if assigned(freelists[s]) then
          freelists[s]^.prev:=nil;
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
         exit;
       end;
 {$ifdef SMALLATHEAPPTR}
-     if heapend-heapptr>size then
+     if heapend-heapptr>=size then
       begin
         sysgetmem:=heapptr;
-        if (heapptr+size=heapend) then
+        { set end flag if we do not have enough room to add
+          another tfreerecord behind }
+        if (heapptr+size+sizeof(tfreerecord)>=heapend) then
          pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
         else
          pheaprecord(sysgetmem)^.size:=size or usedmask;
         inc(sysgetmem,sizeof(theaprecord));
         inc(heapptr,size);
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
         exit;
       end;
 {$endif}
@@ -380,9 +431,12 @@ begin
       pcurr^.prev^.next:=pcurr^.next
      else
       freelists[s]:=pcurr^.next;
+{$ifdef SYSTEMDEBUG}
+     dec(freecount[s]);
+{$endif SYSTEMDEBUG}
      { create the left over freelist block, if at least 16 bytes are free }
      sizeleft:=pcurr^.size-size;
-     if sizeleft>sizeof(tfreerecord) then
+     if sizeleft>=sizeof(tfreerecord) then
       begin
         pcurr:=pfreerecord(pointer(pcurr)+size);
         { inherit the beforeheapendmask }
@@ -396,6 +450,9 @@ begin
         if assigned(freelists[s1]) then
          freelists[s1]^.prev:=pcurr;
         freelists[s1]:=pcurr;
+{$ifdef SYSTEMDEBUG}
+        inc(freecount[s1]);
+{$endif SYSTEMDEBUG}
         { create the block we need to return }
         pheaprecord(sysgetmem)^.size:=size or usedmask;
       end
@@ -406,21 +463,29 @@ begin
       end;
 
      inc(sysgetmem,sizeof(theaprecord));
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
      exit;
    end;
   { Lastly, the top of the heap is checked, to see if there is }
   { still memory available.                                   }
   repeat
     again:=false;
-    if heapend-heapptr>size then
+    if heapend-heapptr>=size then
      begin
        sysgetmem:=heapptr;
-       if (heapptr+size=heapend) then
+       if (heapptr+size+sizeof(tfreerecord)>=heapend) then
         pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
        else
         pheaprecord(sysgetmem)^.size:=size or usedmask;
        inc(sysgetmem,sizeof(theaprecord));
        inc(heapptr,size);
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
        exit;
      end;
     { Call the heaperror proc }
@@ -436,9 +501,14 @@ begin
     else
      HandleError(203);
   until not again;
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
 end;
 
 
+{$ifdef CONCATFREE}
 {*****************************************************************************
                          Try concat freerecords
 *****************************************************************************}
@@ -451,14 +521,18 @@ begin
   pcurrsize:=pcurr^.size and sizemask;
   hp:=pcurr;
   repeat
-    { block used or before a heapptr ? }
+    { block used or before a heapend ? }
     if (hp^.size and beforeheapendmask)<>0 then
      begin
+       { Peter, why can't we add this one if free ?? }
        pcurr^.size:=pcurrsize or beforeheapendmask;
        pcurr^.next:=freelists[0];
        if assigned(pcurr^.next) then
         pcurr^.next^.prev:=pcurr;
        freelists[0]:=pcurr;
+{$ifdef SYSTEMDEBUG}
+       inc(freecount[0]);
+{$endif SYSTEMDEBUG}
        break;
      end;
     { get next block }
@@ -477,6 +551,9 @@ begin
        if assigned(pcurr^.next) then
         pcurr^.next^.prev:=pcurr;
        freelists[0]:=pcurr;
+{$ifdef SYSTEMDEBUG}
+       inc(freecount[0]);
+{$endif SYSTEMDEBUG}
        break;
      end;
     { remove block from freelist and increase the size }
@@ -491,9 +568,12 @@ begin
      hp^.prev^.next:=hp^.next
     else
      freelists[s1]:=hp^.next;
+{$ifdef SYSTEMDEBUG}
+    dec(freecount[s1]);
+{$endif SYSTEMDEBUG}
   until false;
 end;
-
+{$endif CONCATFREE}
 
 {*****************************************************************************
                                SysFreeMem
@@ -526,9 +606,16 @@ begin
      if assigned(pcurr^.next) then
      pcurr^.next^.prev:=pcurr;
      freelists[s]:=pcurr;
+{$ifdef SYSTEMDEBUG}
+     inc(freecount[s]);
+{$endif SYSTEMDEBUG}
    end;
   p:=nil;
   SysFreeMem:=pcurrsize;
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
 end;
 
 
@@ -576,9 +663,16 @@ begin
      if assigned(pcurr^.next) then
      pcurr^.next^.prev:=pcurr;
      freelists[s]:=pcurr;
+{$ifdef SYSTEMDEBUG}
+     inc(freecount[s]);
+{$endif SYSTEMDEBUG}
    end;
   p:=nil;
   SysFreeMemSize:=pcurrsize;
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
 end;
 
 
@@ -631,6 +725,10 @@ begin
   if currsize=size then
    begin
      SysTryResizeMem:=true;
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
      exit;
    end;
 { do we need to allocate more memory ? }
@@ -689,6 +787,9 @@ begin
            hp^.prev^.next:=hp^.next
           else
            freelists[s]:=hp^.next;
+{$ifdef SYSTEMDEBUG}
+          dec(freecount[s]);
+{$endif SYSTEMDEBUG}
         until (foundsize>=size);
         if wasbeforeheapend then
          pcurr^.size:=foundsize or usedmask or beforeheapendmask
@@ -699,6 +800,10 @@ begin
       begin
         { we need to call getmem/move/freemem }
         SysTryResizeMem:=false;
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
         exit;
       end;
      currsize:=pcurr^.size and sizemask;
@@ -722,6 +827,9 @@ begin
         if assigned(freelists[s]) then
          freelists[s]^.prev:=pnew;
         freelists[s]:=pnew;
+{$ifdef SYSTEMDEBUG}
+        inc(freecount[s]);
+{$endif SYSTEMDEBUG}
         { fix the size of the current block and leave }
         pcurr^.size:=size or usedmask;
       end
@@ -733,6 +841,10 @@ begin
    end;
   dec(internal_memavail,size-oldsize);
   SysTryResizeMem:=true;
+{$ifdef TestFreeLists}
+  if test_each then
+    TestFreeLists;
+{$endif TestFreeLists}
 end;
 
 
@@ -792,7 +904,7 @@ end;
 
 function growheap(size :longint) : integer;
 var
-  sizeleft,
+  sizeleft,s1,
   NewPos    : longint;
   pcurr     : pfreerecord;
 begin
@@ -842,16 +954,35 @@ begin
    begin
      { create freelist entry for old heapptr-heapend }
      sizeleft:=heapend-heapptr;
-     if sizeleft>sizeof(tfreerecord) then
+     if sizeleft>=sizeof(tfreerecord) then
       begin
         pcurr:=pfreerecord(heapptr);
         pcurr^.size:=sizeleft or beforeheapendmask;
-        { insert the block in the freelist }
+{$ifdef Withbug}
+      { this code was wrong because
+        in TryConcat an freerecord sets freelists[s] where s is size shr blockshr PM }
         pcurr^.next:=freelists[0];
         pcurr^.prev:=nil;
         if assigned(freelists[0]) then
          freelists[0]^.prev:=pcurr;
         freelists[0]:=pcurr;
+{$ifdef SYSTEMDEBUG}
+        inc(freecount[0]);
+{$endif SYSTEMDEBUG}
+{$else not Withbug}
+        { insert the block in the freelist }
+        s1:=sizeleft shr blockshr;
+        if s1>maxblock then
+         s1:=0;
+        pcurr^.next:=freelists[s1];
+        pcurr^.prev:=nil;
+        if assigned(freelists[s1]) then
+         freelists[s1]^.prev:=pcurr;
+        freelists[s1]:=pcurr;
+{$ifdef SYSTEMDEBUG}
+        inc(freecount[s1]);
+{$endif SYSTEMDEBUG}
+{$endif Withbug}
       end;
      { now set the new heapptr,heapend to the new block }
      heapptr:=pointer(newpos);
@@ -862,6 +993,9 @@ begin
   inc(internal_heapsize,size);
 { try again }
   GrowHeap:=2;
+{$ifdef TestFreeLists}
+  TestFreeLists;
+{$endif TestFreeLists}
 end;
 
 
@@ -874,6 +1008,9 @@ end;
 procedure InitHeap;
 begin
   FillChar(FreeLists,sizeof(TFreeLists),0);
+{$ifdef SYSTEMDEBUG}
+  FillChar(FreeCount,sizeof(TFreeCount),0);
+{$endif SYSTEMDEBUG}
   internal_heapsize:=GetHeapSize;
   internal_memavail:=internal_heapsize;
   HeapOrg:=GetHeapStart;
@@ -884,7 +1021,10 @@ end;
 
 {
   $Log$
-  Revision 1.37  2000-04-07 21:10:35  pierre
+  Revision 1.38  2000-04-20 15:29:15  pierre
+  fix for heap problem
+
+  Revision 1.37  2000/04/07 21:10:35  pierre
     + ReturnNilIfGrowHeapFails used in objects unit
       to handle TMemoryStream out of memory properly
       as MaxAvail is not a good test anymore.