fix for heap problem

This commit is contained in:
pierre 2000-04-20 15:29:15 +00:00
parent 80a9bef23a
commit e574245b0e

View File

@ -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.