mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-24 11:50:04 +02:00
* heap manager: handle freeing of block owned by exited thread
* heap trace: ditto git-svn-id: trunk@7649 -
This commit is contained in:
parent
c7037df254
commit
c226f6fd44
307
rtl/inc/heap.inc
307
rtl/inc/heap.inc
@ -134,8 +134,10 @@ type
|
|||||||
poschunk = ^toschunk;
|
poschunk = ^toschunk;
|
||||||
toschunk = record
|
toschunk = record
|
||||||
size : ptrint;
|
size : ptrint;
|
||||||
next : poschunk;
|
next_free : poschunk;
|
||||||
used : ptrint;
|
prev_any : poschunk;
|
||||||
|
next_any : poschunk;
|
||||||
|
used : ptrint; { 0: free, >0: fixed, -1: var }
|
||||||
freelists : pfreelists;
|
freelists : pfreelists;
|
||||||
{ padding inserted automatically by alloc_oschunk }
|
{ padding inserted automatically by alloc_oschunk }
|
||||||
end;
|
end;
|
||||||
@ -178,8 +180,9 @@ type
|
|||||||
tfixedfreelists = array[1..maxblockindex] of pmemchunk_fixed;
|
tfixedfreelists = array[1..maxblockindex] of pmemchunk_fixed;
|
||||||
|
|
||||||
tfreelists = record
|
tfreelists = record
|
||||||
oslist : poschunk;
|
oslist : poschunk; { os chunks free, available for use }
|
||||||
oscount : dword;
|
oscount : dword; { number of os chunks on oslist }
|
||||||
|
oslist_all : poschunk; { all os chunks allocated }
|
||||||
fixedlists : tfixedfreelists;
|
fixedlists : tfixedfreelists;
|
||||||
varlist : pmemchunk_var;
|
varlist : pmemchunk_var;
|
||||||
{ chunks waiting to be freed from other thread }
|
{ chunks waiting to be freed from other thread }
|
||||||
@ -205,6 +208,8 @@ const
|
|||||||
var
|
var
|
||||||
main_orig_freelists : pfreelists;
|
main_orig_freelists : pfreelists;
|
||||||
main_relo_freelists : pfreelists;
|
main_relo_freelists : pfreelists;
|
||||||
|
orphaned_freelists : tfreelists;
|
||||||
|
orphaned_oslist_lock : trtlcriticalsection;
|
||||||
threadvar
|
threadvar
|
||||||
freelists : tfreelists;
|
freelists : tfreelists;
|
||||||
|
|
||||||
@ -398,6 +403,14 @@ end;
|
|||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
|
||||||
|
{*****************************************************************************
|
||||||
|
Forwards
|
||||||
|
*****************************************************************************}
|
||||||
|
|
||||||
|
procedure finish_waitfixedlist(loc_freelists: pfreelists); forward;
|
||||||
|
procedure finish_waitvarlist(loc_freelists: pfreelists); forward;
|
||||||
|
function try_finish_waitfixedlist(loc_freelists: pfreelists): boolean; forward;
|
||||||
|
procedure try_finish_waitvarlist(loc_freelists: pfreelists); forward;
|
||||||
|
|
||||||
{*****************************************************************************
|
{*****************************************************************************
|
||||||
List adding/removal
|
List adding/removal
|
||||||
@ -453,12 +466,19 @@ begin
|
|||||||
freelists.varlist := pmc^.next_var;
|
freelists.varlist := pmc^.next_var;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure remove_all_from_list_fixed(chunksize: ptrint; poc: poschunk);
|
procedure remove_freed_fixed_chunks(poc: poschunk);
|
||||||
|
{ remove all fixed chunks from the fixed free list, as this os chunk
|
||||||
|
is going to be used for other purpose }
|
||||||
var
|
var
|
||||||
pmc, pmc_end: pmemchunk_fixed;
|
pmc, pmc_end: pmemchunk_fixed;
|
||||||
fixedlist: ppmemchunk_fixed;
|
fixedlist: ppmemchunk_fixed;
|
||||||
|
chunksize: ptrint;
|
||||||
begin
|
begin
|
||||||
|
{ exit if this is a var size os chunk, function only applicable to fixed size }
|
||||||
|
if poc^.used < 0 then
|
||||||
|
exit;
|
||||||
pmc := pmemchunk_fixed(pointer(poc)+fixedfirstoffset);
|
pmc := pmemchunk_fixed(pointer(poc)+fixedfirstoffset);
|
||||||
|
chunksize := pmc^.size and fixedsizemask;
|
||||||
pmc_end := pmemchunk_fixed(pointer(poc)+(poc^.size and sizemask)-chunksize);
|
pmc_end := pmemchunk_fixed(pointer(poc)+(poc^.size and sizemask)-chunksize);
|
||||||
fixedlist := @poc^.freelists^.fixedlists[chunksize shr blockshift];
|
fixedlist := @poc^.freelists^.fixedlists[chunksize shr blockshift];
|
||||||
repeat
|
repeat
|
||||||
@ -467,9 +487,24 @@ begin
|
|||||||
until pmc > pmc_end;
|
until pmc > pmc_end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure append_to_oslist(poc: poschunk; chunksize: ptrint);
|
procedure free_oschunk(loc_freelists: pfreelists; poc: poschunk);
|
||||||
var
|
var
|
||||||
pocsize: ptrint;
|
pocsize: ptrint;
|
||||||
|
begin
|
||||||
|
remove_freed_fixed_chunks(poc);
|
||||||
|
if assigned(poc^.prev_any) then
|
||||||
|
poc^.prev_any^.next_any := poc^.next_any
|
||||||
|
else
|
||||||
|
loc_freelists^.oslist_all := poc^.next_any;
|
||||||
|
if assigned(poc^.next_any) then
|
||||||
|
poc^.next_any^.prev_any := poc^.prev_any;
|
||||||
|
pocsize := poc^.size and sizemask;
|
||||||
|
dec(loc_freelists^.internal_status.currheapsize, pocsize);
|
||||||
|
SysOSFree(poc, pocsize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure append_to_oslist(poc: poschunk);
|
||||||
|
var
|
||||||
loc_freelists: pfreelists;
|
loc_freelists: pfreelists;
|
||||||
begin
|
begin
|
||||||
loc_freelists := poc^.freelists;
|
loc_freelists := poc^.freelists;
|
||||||
@ -482,32 +517,22 @@ begin
|
|||||||
end;
|
end;
|
||||||
{ decide whether to free block or add to list }
|
{ decide whether to free block or add to list }
|
||||||
{$ifdef HAS_SYSOSFREE}
|
{$ifdef HAS_SYSOSFREE}
|
||||||
pocsize := poc^.size and sizemask;
|
|
||||||
if (loc_freelists^.oscount >= MaxKeptOSChunks) or
|
if (loc_freelists^.oscount >= MaxKeptOSChunks) or
|
||||||
(pocsize > growheapsize2) then
|
((poc^.size and sizemask) > growheapsize2) then
|
||||||
begin
|
begin
|
||||||
if chunksize <> 0 then
|
free_oschunk(loc_freelists, poc);
|
||||||
remove_all_from_list_fixed(chunksize, poc);
|
|
||||||
dec(loc_freelists^.internal_status.currheapsize, pocsize);
|
|
||||||
SysOSFree(poc, pocsize);
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
{$endif}
|
{$endif}
|
||||||
poc^.next := loc_freelists^.oslist;
|
poc^.next_free := loc_freelists^.oslist;
|
||||||
loc_freelists^.oslist := poc;
|
loc_freelists^.oslist := poc;
|
||||||
inc(loc_freelists^.oscount);
|
inc(loc_freelists^.oscount);
|
||||||
{$ifdef HAS_SYSOSFREE}
|
{$ifdef HAS_SYSOSFREE}
|
||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure clear_oschunk_on_freelist_fixed_flag(poc: poschunk); inline;
|
|
||||||
{ prevent thinking this os chunk is on the fixed freelists }
|
|
||||||
begin
|
|
||||||
pmemchunk_fixed(pointer(poc) + fixedfirstoffset)^.size := 0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure append_to_oslist_var(pmc: pmemchunk_var);
|
procedure append_to_oslist_var(pmc: pmemchunk_var);
|
||||||
var
|
var
|
||||||
poc: poschunk;
|
poc: poschunk;
|
||||||
@ -515,8 +540,42 @@ begin
|
|||||||
// block eligable for freeing
|
// block eligable for freeing
|
||||||
poc := pointer(pmc)-varfirstoffset;
|
poc := pointer(pmc)-varfirstoffset;
|
||||||
remove_from_list_var(pmc);
|
remove_from_list_var(pmc);
|
||||||
clear_oschunk_on_freelist_fixed_flag(poc);
|
append_to_oslist(poc);
|
||||||
append_to_oslist(poc, 0);
|
end;
|
||||||
|
|
||||||
|
procedure modify_oschunk_freelists(poc: poschunk; new_freelists: pfreelists);
|
||||||
|
var
|
||||||
|
pmcv: pmemchunk_var;
|
||||||
|
begin
|
||||||
|
poc^.freelists := new_freelists;
|
||||||
|
{ only if oschunk contains var memchunks, we need additional assignments }
|
||||||
|
if poc^.used <> -1 then exit;
|
||||||
|
pmcv := pmemchunk_var(pointer(poc)+varfirstoffset);
|
||||||
|
repeat
|
||||||
|
pmcv^.freelists := new_freelists;
|
||||||
|
if (pmcv^.size and lastblockflag) <> 0 then
|
||||||
|
break;
|
||||||
|
pmcv := pmemchunk_var(pointer(pmcv)+(pmcv^.size and sizemask));
|
||||||
|
until false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function modify_freelists(loc_freelists, new_freelists: pfreelists): poschunk;
|
||||||
|
var
|
||||||
|
poc: poschunk;
|
||||||
|
begin
|
||||||
|
poc := loc_freelists^.oslist_all;
|
||||||
|
if assigned(poc) then
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
{ fixed and var freelist for orphaned freelists do not need maintenance }
|
||||||
|
{ we assume the heap is not severely fragmented at thread exit }
|
||||||
|
modify_oschunk_freelists(poc, new_freelists);
|
||||||
|
if not assigned(poc^.next_any) then
|
||||||
|
exit(poc);
|
||||||
|
poc := poc^.next_any;
|
||||||
|
until false;
|
||||||
|
end;
|
||||||
|
modify_freelists := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{*****************************************************************************
|
{*****************************************************************************
|
||||||
@ -627,6 +686,47 @@ end;
|
|||||||
Grow Heap
|
Grow Heap
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|
||||||
|
function find_free_oschunk(loc_freelists: pfreelists;
|
||||||
|
minsize, maxsize: ptrint; var size: ptrint): poschunk;
|
||||||
|
var
|
||||||
|
pmc: pmemchunk_fixed;
|
||||||
|
prev_poc, poc: poschunk;
|
||||||
|
pocsize: ptrint;
|
||||||
|
begin
|
||||||
|
poc := loc_freelists^.oslist;
|
||||||
|
prev_poc := nil;
|
||||||
|
while poc <> nil do
|
||||||
|
begin
|
||||||
|
if (poc^.size and ocrecycleflag) <> 0 then
|
||||||
|
begin
|
||||||
|
{ oops! we recycled this chunk; remove it from list }
|
||||||
|
poc^.size := poc^.size and not ocrecycleflag;
|
||||||
|
poc := poc^.next_free;
|
||||||
|
if prev_poc = nil then
|
||||||
|
loc_freelists^.oslist := poc
|
||||||
|
else
|
||||||
|
prev_poc^.next_free := poc;
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
|
pocsize := poc^.size and sizemask;
|
||||||
|
if (pocsize >= minsize) and
|
||||||
|
(pocsize <= maxsize) then
|
||||||
|
begin
|
||||||
|
size := pocsize;
|
||||||
|
if prev_poc = nil then
|
||||||
|
loc_freelists^.oslist := poc^.next_free
|
||||||
|
else
|
||||||
|
prev_poc^.next_free := poc^.next_free;
|
||||||
|
dec(loc_freelists^.oscount);
|
||||||
|
remove_freed_fixed_chunks(poc);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
prev_poc := poc;
|
||||||
|
poc := poc^.next_free;
|
||||||
|
end;
|
||||||
|
result := poc;
|
||||||
|
end;
|
||||||
|
|
||||||
function alloc_oschunk(loc_freelists: pfreelists; chunkindex, size: ptrint): pointer;
|
function alloc_oschunk(loc_freelists: pfreelists; chunkindex, size: ptrint): pointer;
|
||||||
var
|
var
|
||||||
pmc,
|
pmc,
|
||||||
@ -650,38 +750,35 @@ begin
|
|||||||
else
|
else
|
||||||
maxsize := high(ptrint);
|
maxsize := high(ptrint);
|
||||||
{ blocks available in freelist? }
|
{ blocks available in freelist? }
|
||||||
poc := loc_freelists^.oslist;
|
poc := find_free_oschunk(loc_freelists, minsize, maxsize, size);
|
||||||
prev_poc := nil;
|
if not assigned(poc) and (assigned(orphaned_freelists.waitfixed)
|
||||||
while poc <> nil do
|
or assigned(orphaned_freelists.waitvar) or (orphaned_freelists.oscount > 0)) then
|
||||||
begin
|
begin
|
||||||
if (poc^.size and ocrecycleflag) <> 0 then
|
entercriticalsection(orphaned_oslist_lock);
|
||||||
begin
|
try_finish_waitfixedlist(@orphaned_freelists);
|
||||||
{ oops! we recycled this chunk; remove it from list }
|
try_finish_waitvarlist(@orphaned_freelists);
|
||||||
poc^.size := poc^.size and not ocrecycleflag;
|
if orphaned_freelists.oscount > 0 then
|
||||||
poc := poc^.next;
|
|
||||||
if prev_poc = nil then
|
|
||||||
loc_freelists^.oslist := poc
|
|
||||||
else
|
|
||||||
prev_poc^.next := poc;
|
|
||||||
continue;
|
|
||||||
end;
|
|
||||||
pocsize := poc^.size and sizemask;
|
|
||||||
if (pocsize >= minsize) and
|
|
||||||
(pocsize <= maxsize) then
|
|
||||||
begin
|
begin
|
||||||
size := pocsize;
|
{ blocks available in orphaned freelist ? }
|
||||||
if prev_poc = nil then
|
poc := find_free_oschunk(@orphaned_freelists, minsize, maxsize, size);
|
||||||
loc_freelists^.oslist := poc^.next
|
if assigned(poc) then
|
||||||
else
|
begin
|
||||||
prev_poc^.next := poc^.next;
|
{ adopt this os chunk }
|
||||||
dec(loc_freelists^.oscount);
|
poc^.freelists := loc_freelists;
|
||||||
pmc := pmemchunk_fixed(pointer(poc)+fixedfirstoffset);
|
if assigned(poc^.prev_any) then
|
||||||
if pmc^.size <> 0 then
|
poc^.prev_any^.next_any := poc^.next_any
|
||||||
remove_all_from_list_fixed(pmc^.size and fixedsizemask, poc);
|
else
|
||||||
break;
|
orphaned_freelists.oslist_all := poc^.next_any;
|
||||||
|
if assigned(poc^.next_any) then
|
||||||
|
poc^.next_any^.prev_any := poc^.prev_any;
|
||||||
|
poc^.next_any := loc_freelists^.oslist_all;
|
||||||
|
if assigned(loc_freelists^.oslist_all) then
|
||||||
|
loc_freelists^.oslist_all^.prev_any := poc;
|
||||||
|
poc^.prev_any := nil;
|
||||||
|
loc_freelists^.oslist_all := poc;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
prev_poc := poc;
|
leavecriticalsection(orphaned_oslist_lock);
|
||||||
poc := poc^.next;
|
|
||||||
end;
|
end;
|
||||||
if poc = nil then
|
if poc = nil then
|
||||||
begin
|
begin
|
||||||
@ -730,10 +827,13 @@ begin
|
|||||||
HandleError(203);
|
HandleError(203);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
{ prevent thinking this os chunk is on some freelist }
|
poc^.next_free := nil;
|
||||||
clear_oschunk_on_freelist_fixed_flag(poc);
|
|
||||||
poc^.next := nil;
|
|
||||||
poc^.freelists := loc_freelists;
|
poc^.freelists := loc_freelists;
|
||||||
|
poc^.prev_any := nil;
|
||||||
|
poc^.next_any := loc_freelists^.oslist_all;
|
||||||
|
if assigned(loc_freelists^.oslist_all) then
|
||||||
|
loc_freelists^.oslist_all^.prev_any := poc;
|
||||||
|
loc_freelists^.oslist_all := poc;
|
||||||
{ set the total new heap size }
|
{ set the total new heap size }
|
||||||
status := @loc_freelists^.internal_status;
|
status := @loc_freelists^.internal_status;
|
||||||
inc(status^.currheapsize, size);
|
inc(status^.currheapsize, size);
|
||||||
@ -741,10 +841,10 @@ begin
|
|||||||
status^.maxheapsize := status^.currheapsize;
|
status^.maxheapsize := status^.currheapsize;
|
||||||
end;
|
end;
|
||||||
{ initialize os-block }
|
{ initialize os-block }
|
||||||
poc^.used := 0;
|
|
||||||
poc^.size := size;
|
poc^.size := size;
|
||||||
if chunkindex<>0 then
|
if chunkindex<>0 then
|
||||||
begin
|
begin
|
||||||
|
poc^.used := 0;
|
||||||
{ chop os chunk in fixedsize parts,
|
{ chop os chunk in fixedsize parts,
|
||||||
maximum of $ffff elements are allowed, otherwise
|
maximum of $ffff elements are allowed, otherwise
|
||||||
there will be an overflow }
|
there will be an overflow }
|
||||||
@ -774,6 +874,7 @@ begin
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
poc^.used := -1;
|
||||||
{ we need to align the user pointers to 8 byte at least for
|
{ we need to align the user pointers to 8 byte at least for
|
||||||
mmx/sse and doubles on sparc, align to 16 bytes }
|
mmx/sse and doubles on sparc, align to 16 bytes }
|
||||||
result := pointer(poc)+varfirstoffset;
|
result := pointer(poc)+varfirstoffset;
|
||||||
@ -789,9 +890,6 @@ end;
|
|||||||
SysGetMem
|
SysGetMem
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|
||||||
function finish_waitfixedlist(loc_freelists: pfreelists): boolean; forward;
|
|
||||||
procedure finish_waitvarlist(loc_freelists: pfreelists); forward;
|
|
||||||
|
|
||||||
function SysGetMem_Fixed(chunksize: ptrint): pointer;
|
function SysGetMem_Fixed(chunksize: ptrint): pointer;
|
||||||
var
|
var
|
||||||
pmc, pmc_next: pmemchunk_fixed;
|
pmc, pmc_next: pmemchunk_fixed;
|
||||||
@ -814,7 +912,7 @@ begin
|
|||||||
dec(loc_freelists^.oscount);
|
dec(loc_freelists^.oscount);
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else if finish_waitfixedlist(loc_freelists) then
|
else if try_finish_waitfixedlist(loc_freelists) then
|
||||||
{ freed some to-be freed chunks, retry allocation }
|
{ freed some to-be freed chunks, retry allocation }
|
||||||
exit(SysGetMem_Fixed(chunksize))
|
exit(SysGetMem_Fixed(chunksize))
|
||||||
else
|
else
|
||||||
@ -856,7 +954,7 @@ begin
|
|||||||
result:=nil;
|
result:=nil;
|
||||||
{ free pending items }
|
{ free pending items }
|
||||||
loc_freelists := @freelists;
|
loc_freelists := @freelists;
|
||||||
finish_waitvarlist(loc_freelists);
|
try_finish_waitvarlist(loc_freelists);
|
||||||
pbest := nil;
|
pbest := nil;
|
||||||
pcurr := loc_freelists^.varlist;
|
pcurr := loc_freelists^.varlist;
|
||||||
iter := high(longint);
|
iter := high(longint);
|
||||||
@ -893,7 +991,6 @@ begin
|
|||||||
size := split_block(pcurr, size);
|
size := split_block(pcurr, size);
|
||||||
{ flag block as used }
|
{ flag block as used }
|
||||||
pcurr^.size := pcurr^.size or usedflag;
|
pcurr^.size := pcurr^.size or usedflag;
|
||||||
pcurr^.freelists := loc_freelists;
|
|
||||||
{ statistics }
|
{ statistics }
|
||||||
with loc_freelists^.internal_status do
|
with loc_freelists^.internal_status do
|
||||||
begin
|
begin
|
||||||
@ -999,10 +1096,10 @@ begin
|
|||||||
if poc^.used <= 0 then
|
if poc^.used <= 0 then
|
||||||
begin
|
begin
|
||||||
{ decrease used blocks count }
|
{ decrease used blocks count }
|
||||||
if poc^.used=-1 then
|
if poc^.used<0 then
|
||||||
HandleError(204);
|
HandleError(204);
|
||||||
{ osblock can be freed? }
|
{ osblock can be freed? }
|
||||||
append_to_oslist(poc, chunksize);
|
append_to_oslist(poc);
|
||||||
end;
|
end;
|
||||||
result := chunksize;
|
result := chunksize;
|
||||||
end;
|
end;
|
||||||
@ -1064,14 +1161,11 @@ begin
|
|||||||
result := sysfreemem_fixed(pmc);
|
result := sysfreemem_fixed(pmc);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function finish_waitfixedlist(loc_freelists: pfreelists): boolean;
|
procedure finish_waitfixedlist(loc_freelists: pfreelists);
|
||||||
{ free to-be-freed chunks, return whether we freed anything }
|
{ free to-be-freed chunks, return whether we freed anything }
|
||||||
var
|
var
|
||||||
pmc: pmemchunk_fixed;
|
pmc: pmemchunk_fixed;
|
||||||
begin
|
begin
|
||||||
if loc_freelists^.waitfixed = nil then
|
|
||||||
exit(false);
|
|
||||||
entercriticalsection(loc_freelists^.lockfixed);
|
|
||||||
while loc_freelists^.waitfixed <> nil do
|
while loc_freelists^.waitfixed <> nil do
|
||||||
begin
|
begin
|
||||||
{ keep next_fixed, might be destroyed }
|
{ keep next_fixed, might be destroyed }
|
||||||
@ -1079,6 +1173,14 @@ begin
|
|||||||
loc_freelists^.waitfixed := pmc^.next_fixed;
|
loc_freelists^.waitfixed := pmc^.next_fixed;
|
||||||
SysFreeMem_Fixed(pmc);
|
SysFreeMem_Fixed(pmc);
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function try_finish_waitfixedlist(loc_freelists: pfreelists): boolean;
|
||||||
|
begin
|
||||||
|
if loc_freelists^.waitfixed = nil then
|
||||||
|
exit(false);
|
||||||
|
entercriticalsection(loc_freelists^.lockfixed);
|
||||||
|
finish_waitfixedlist(loc_freelists);
|
||||||
leavecriticalsection(loc_freelists^.lockfixed);
|
leavecriticalsection(loc_freelists^.lockfixed);
|
||||||
result := true;
|
result := true;
|
||||||
end;
|
end;
|
||||||
@ -1088,10 +1190,6 @@ procedure finish_waitvarlist(loc_freelists: pfreelists);
|
|||||||
var
|
var
|
||||||
pmcv: pmemchunk_var;
|
pmcv: pmemchunk_var;
|
||||||
begin
|
begin
|
||||||
loc_freelists := @freelists;
|
|
||||||
if loc_freelists^.waitvar = nil then
|
|
||||||
exit;
|
|
||||||
entercriticalsection(loc_freelists^.lockvar);
|
|
||||||
while loc_freelists^.waitvar <> nil do
|
while loc_freelists^.waitvar <> nil do
|
||||||
begin
|
begin
|
||||||
{ keep next_var, might be destroyed }
|
{ keep next_var, might be destroyed }
|
||||||
@ -1099,6 +1197,14 @@ begin
|
|||||||
loc_freelists^.waitvar := pmcv^.next_var;
|
loc_freelists^.waitvar := pmcv^.next_var;
|
||||||
SysFreeMem_Var(pmcv);
|
SysFreeMem_Var(pmcv);
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure try_finish_waitvarlist(loc_freelists: pfreelists);
|
||||||
|
begin
|
||||||
|
if loc_freelists^.waitvar = nil then
|
||||||
|
exit;
|
||||||
|
entercriticalsection(loc_freelists^.lockvar);
|
||||||
|
finish_waitvarlist(loc_freelists);
|
||||||
leavecriticalsection(loc_freelists^.lockvar);
|
leavecriticalsection(loc_freelists^.lockvar);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1344,6 +1450,7 @@ begin
|
|||||||
not loaded yet }
|
not loaded yet }
|
||||||
loc_freelists := @freelists;
|
loc_freelists := @freelists;
|
||||||
fillchar(loc_freelists^,sizeof(tfreelists),0);
|
fillchar(loc_freelists^,sizeof(tfreelists),0);
|
||||||
|
fillchar(orphaned_freelists,sizeof(orphaned_freelists),0);
|
||||||
{ main freelist will be copied in memory }
|
{ main freelist will be copied in memory }
|
||||||
main_orig_freelists := loc_freelists;
|
main_orig_freelists := loc_freelists;
|
||||||
end;
|
end;
|
||||||
@ -1358,21 +1465,64 @@ begin
|
|||||||
main_relo_freelists := loc_freelists;
|
main_relo_freelists := loc_freelists;
|
||||||
initcriticalsection(loc_freelists^.lockfixed);
|
initcriticalsection(loc_freelists^.lockfixed);
|
||||||
initcriticalsection(loc_freelists^.lockvar);
|
initcriticalsection(loc_freelists^.lockvar);
|
||||||
|
initcriticalsection(orphaned_freelists.lockfixed);
|
||||||
|
initcriticalsection(orphaned_freelists.lockvar);
|
||||||
|
initcriticalsection(orphaned_oslist_lock);
|
||||||
|
modify_freelists(loc_freelists, main_relo_freelists);
|
||||||
if MemoryManager.RelocateHeap <> nil then
|
if MemoryManager.RelocateHeap <> nil then
|
||||||
MemoryManager.RelocateHeap();
|
MemoryManager.RelocateHeap();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure FinalizeHeap;
|
procedure FinalizeHeap;
|
||||||
var
|
var
|
||||||
poc : poschunk;
|
poc, poc_next: poschunk;
|
||||||
i : longint;
|
i : longint;
|
||||||
loc_freelists: pfreelists;
|
loc_freelists: pfreelists;
|
||||||
begin
|
begin
|
||||||
loc_freelists := @freelists;
|
loc_freelists := @freelists;
|
||||||
finish_waitfixedlist(loc_freelists);
|
|
||||||
finish_waitvarlist(loc_freelists);
|
|
||||||
if main_relo_freelists <> nil then
|
if main_relo_freelists <> nil then
|
||||||
begin
|
begin
|
||||||
|
entercriticalsection(loc_freelists^.lockfixed);
|
||||||
|
finish_waitfixedlist(loc_freelists);
|
||||||
|
entercriticalsection(loc_freelists^.lockvar);
|
||||||
|
finish_waitvarlist(loc_freelists);
|
||||||
|
{$ifdef HAS_SYSOSFREE}
|
||||||
|
end;
|
||||||
|
poc := loc_freelists^.oslist;
|
||||||
|
while assigned(poc) do
|
||||||
|
begin
|
||||||
|
poc_next := poc^.next_free;
|
||||||
|
{ check if this os chunk was 'recycled' i.e. taken in use again }
|
||||||
|
if (poc^.size and ocrecycleflag) = 0 then
|
||||||
|
free_oschunk(loc_freelists, poc);
|
||||||
|
poc := poc_next;
|
||||||
|
end;
|
||||||
|
loc_freelists^.oslist := nil;
|
||||||
|
loc_freelists^.oscount := 0;
|
||||||
|
if main_relo_freelists <> nil then
|
||||||
|
begin
|
||||||
|
{$endif HAS_SYSOSFREE}
|
||||||
|
if main_relo_freelists = loc_freelists then
|
||||||
|
begin
|
||||||
|
donecriticalsection(orphaned_freelists.lockfixed);
|
||||||
|
donecriticalsection(orphaned_freelists.lockvar);
|
||||||
|
donecriticalsection(orphaned_oslist_lock);
|
||||||
|
end else begin
|
||||||
|
entercriticalsection(orphaned_oslist_lock);
|
||||||
|
entercriticalsection(orphaned_freelists.lockfixed);
|
||||||
|
entercriticalsection(orphaned_freelists.lockvar);
|
||||||
|
poc := modify_freelists(loc_freelists, @orphaned_freelists);
|
||||||
|
if assigned(poc) then
|
||||||
|
begin
|
||||||
|
poc^.next_any := orphaned_freelists.oslist_all;
|
||||||
|
if assigned(orphaned_freelists.oslist_all) then
|
||||||
|
orphaned_freelists.oslist_all^.prev_any := poc;
|
||||||
|
orphaned_freelists.oslist_all := loc_freelists^.oslist_all;
|
||||||
|
end;
|
||||||
|
leavecriticalsection(orphaned_freelists.lockvar);
|
||||||
|
leavecriticalsection(orphaned_freelists.lockfixed);
|
||||||
|
leavecriticalsection(orphaned_oslist_lock);
|
||||||
|
end;
|
||||||
donecriticalsection(loc_freelists^.lockfixed);
|
donecriticalsection(loc_freelists^.lockfixed);
|
||||||
donecriticalsection(loc_freelists^.lockvar);
|
donecriticalsection(loc_freelists^.lockvar);
|
||||||
end;
|
end;
|
||||||
@ -1388,15 +1538,6 @@ begin
|
|||||||
writeln('size >', sizeusagesize, ' usage ', maxsizeusage[sizeusageindex]);
|
writeln('size >', sizeusagesize, ' usage ', maxsizeusage[sizeusageindex]);
|
||||||
flush(output);
|
flush(output);
|
||||||
{$endif}
|
{$endif}
|
||||||
{$ifdef HAS_SYSOSFREE}
|
|
||||||
while assigned(loc_freelists^.oslist) do
|
|
||||||
begin
|
|
||||||
poc:=loc_freelists^.oslist^.next;
|
|
||||||
SysOSFree(loc_freelists^.oslist, loc_freelists^.oslist^.size and sizemask);
|
|
||||||
dec(loc_freelists^.oscount);
|
|
||||||
loc_freelists^.oslist:=poc;
|
|
||||||
end;
|
|
||||||
{$endif HAS_SYSOSFREE}
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$endif HAS_MEMORYMANAGER}
|
{$endif HAS_MEMORYMANAGER}
|
||||||
|
@ -21,6 +21,7 @@ interface
|
|||||||
|
|
||||||
{$checkpointer off}
|
{$checkpointer off}
|
||||||
{$goto on}
|
{$goto on}
|
||||||
|
{$typedpointer on}
|
||||||
|
|
||||||
{$if defined(win32) or defined(wince)}
|
{$if defined(win32) or defined(wince)}
|
||||||
{$define windows}
|
{$define windows}
|
||||||
@ -105,6 +106,7 @@ type
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
ppheap_mem_info = ^pheap_mem_info;
|
||||||
pheap_mem_info = ^theap_mem_info;
|
pheap_mem_info = ^theap_mem_info;
|
||||||
|
|
||||||
pheap_todo = ^theap_todo;
|
pheap_todo = ^theap_todo;
|
||||||
@ -136,6 +138,24 @@ type
|
|||||||
extra_info : pheap_extra_info;
|
extra_info : pheap_extra_info;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
pheap_info = ^theap_info;
|
||||||
|
theap_info = record
|
||||||
|
{$ifdef EXTRA}
|
||||||
|
heap_valid_first,
|
||||||
|
heap_valid_last : pheap_mem_info;
|
||||||
|
{$endif EXTRA}
|
||||||
|
heap_mem_root : pheap_mem_info;
|
||||||
|
heap_free_todo : theap_todo;
|
||||||
|
getmem_cnt,
|
||||||
|
freemem_cnt : ptrint;
|
||||||
|
getmem_size,
|
||||||
|
freemem_size : ptrint;
|
||||||
|
getmem8_size,
|
||||||
|
freemem8_size : ptrint;
|
||||||
|
error_in_heap : boolean;
|
||||||
|
inside_trace_getmem : boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
useownfile : boolean;
|
useownfile : boolean;
|
||||||
ownfile : text;
|
ownfile : text;
|
||||||
@ -144,22 +164,9 @@ var
|
|||||||
{$endif EXTRA}
|
{$endif EXTRA}
|
||||||
main_orig_todolist: pheap_todo;
|
main_orig_todolist: pheap_todo;
|
||||||
main_relo_todolist: pheap_todo;
|
main_relo_todolist: pheap_todo;
|
||||||
|
orphaned_info: theap_info;
|
||||||
threadvar
|
threadvar
|
||||||
{$ifdef EXTRA}
|
heap_info: theap_info;
|
||||||
heap_valid_first,
|
|
||||||
heap_valid_last : pheap_mem_info;
|
|
||||||
{$endif EXTRA}
|
|
||||||
heap_mem_root : pheap_mem_info;
|
|
||||||
heap_free_todo : theap_todo;
|
|
||||||
getmem_cnt,
|
|
||||||
freemem_cnt : ptrint;
|
|
||||||
getmem_size,
|
|
||||||
freemem_size : ptrint;
|
|
||||||
getmem8_size,
|
|
||||||
freemem8_size : ptrint;
|
|
||||||
error_in_heap : boolean;
|
|
||||||
inside_trace_getmem : boolean;
|
|
||||||
|
|
||||||
|
|
||||||
{*****************************************************************************
|
{*****************************************************************************
|
||||||
Crc 32
|
Crc 32
|
||||||
@ -249,6 +256,8 @@ end;
|
|||||||
Helpers
|
Helpers
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|
||||||
|
function InternalFreeMemSize(loc_info: pheap_info; p: pointer; pp: pheap_mem_info;
|
||||||
|
size: ptrint; release_orphaned_lock: boolean): ptrint; forward;
|
||||||
function TraceFreeMem(p: pointer): ptrint; forward;
|
function TraceFreeMem(p: pointer): ptrint; forward;
|
||||||
|
|
||||||
procedure call_stack(pp : pheap_mem_info;var ptext : text);
|
procedure call_stack(pp : pheap_mem_info;var ptext : text);
|
||||||
@ -331,13 +340,13 @@ begin
|
|||||||
call_stack(p,ptext);
|
call_stack(p,ptext);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function is_in_getmem_list (p : pheap_mem_info) : boolean;
|
function is_in_getmem_list (loc_info: pheap_info; p : pheap_mem_info) : boolean;
|
||||||
var
|
var
|
||||||
i : ptrint;
|
i : ptrint;
|
||||||
pp : pheap_mem_info;
|
pp : pheap_mem_info;
|
||||||
begin
|
begin
|
||||||
is_in_getmem_list:=false;
|
is_in_getmem_list:=false;
|
||||||
pp:=heap_mem_root;
|
pp:=loc_info^.heap_mem_root;
|
||||||
i:=0;
|
i:=0;
|
||||||
while pp<>nil do
|
while pp<>nil do
|
||||||
begin
|
begin
|
||||||
@ -355,7 +364,7 @@ begin
|
|||||||
is_in_getmem_list:=true;
|
is_in_getmem_list:=true;
|
||||||
pp:=pp^.previous;
|
pp:=pp^.previous;
|
||||||
inc(i);
|
inc(i);
|
||||||
if i>getmem_cnt-freemem_cnt then
|
if i>loc_info^.getmem_cnt-loc_info^.freemem_cnt then
|
||||||
if useownfile then
|
if useownfile then
|
||||||
writeln(ownfile,'error in linked list of heap_mem_info')
|
writeln(ownfile,'error in linked list of heap_mem_info')
|
||||||
else
|
else
|
||||||
@ -363,21 +372,31 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure finish_heap_free_todo_list;
|
procedure finish_heap_free_todo_list(loc_info: pheap_info);
|
||||||
var
|
var
|
||||||
bp: pointer;
|
bp: pointer;
|
||||||
loc_list: pheap_todo;
|
pp: pheap_mem_info;
|
||||||
|
list: ppheap_mem_info;
|
||||||
begin
|
begin
|
||||||
loc_list := @heap_free_todo;
|
list := @loc_info^.heap_free_todo.list;
|
||||||
if loc_list^.list <> nil then
|
repeat
|
||||||
|
pp := list^;
|
||||||
|
list^ := list^^.todonext;
|
||||||
|
bp := pointer(pp)+sizeof(theap_mem_info);
|
||||||
|
InternalFreeMemSize(loc_info,bp,pp,pp^.size,false);
|
||||||
|
//TraceFreeMem(bp);
|
||||||
|
until list^ = nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure try_finish_heap_free_todo_list(loc_info: pheap_info);
|
||||||
|
var
|
||||||
|
bp: pointer;
|
||||||
|
begin
|
||||||
|
if loc_info^.heap_free_todo.list <> nil then
|
||||||
begin
|
begin
|
||||||
entercriticalsection(loc_list^.lock);
|
entercriticalsection(loc_info^.heap_free_todo.lock);
|
||||||
repeat
|
finish_heap_free_todo_list(loc_info);
|
||||||
bp := pointer(loc_list^.list)+sizeof(theap_mem_info);
|
leavecriticalsection(loc_info^.heap_free_todo.lock);
|
||||||
loc_list^.list := loc_list^.list^.todonext;
|
|
||||||
TraceFreeMem(bp);
|
|
||||||
until loc_list^.list = nil;
|
|
||||||
leavecriticalsection(loc_list^.lock);
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -394,10 +413,12 @@ var
|
|||||||
pl : pdword;
|
pl : pdword;
|
||||||
p : pointer;
|
p : pointer;
|
||||||
pp : pheap_mem_info;
|
pp : pheap_mem_info;
|
||||||
|
loc_info: pheap_info;
|
||||||
begin
|
begin
|
||||||
finish_heap_free_todo_list;
|
loc_info := @heap_info;
|
||||||
inc(getmem_size,size);
|
try_finish_heap_free_todo_list(loc_info);
|
||||||
inc(getmem8_size,((size+7) div 8)*8);
|
inc(loc_info^.getmem_size,size);
|
||||||
|
inc(loc_info^.getmem8_size,((size+7) div 8)*8);
|
||||||
{ Do the real GetMem, but alloc also for the info block }
|
{ Do the real GetMem, but alloc also for the info block }
|
||||||
{$ifdef cpuarm}
|
{$ifdef cpuarm}
|
||||||
allocsize:=(size + 3) and not 3+sizeof(theap_mem_info)+extra_info_size;
|
allocsize:=(size + 3) and not 3+sizeof(theap_mem_info)+extra_info_size;
|
||||||
@ -418,7 +439,7 @@ begin
|
|||||||
inc(p,sizeof(theap_mem_info));
|
inc(p,sizeof(theap_mem_info));
|
||||||
{ Create the info block }
|
{ Create the info block }
|
||||||
pp^.sig:=$DEADBEEF;
|
pp^.sig:=$DEADBEEF;
|
||||||
pp^.todolist:=@heap_free_todo;
|
pp^.todolist:=@loc_info^.heap_free_todo;
|
||||||
pp^.todonext:=nil;
|
pp^.todonext:=nil;
|
||||||
pp^.size:=size;
|
pp^.size:=size;
|
||||||
pp^.extra_info_size:=extra_info_size;
|
pp^.extra_info_size:=extra_info_size;
|
||||||
@ -437,9 +458,9 @@ begin
|
|||||||
pp^.extra_info^.displayproc:=display_extra_info_proc;
|
pp^.extra_info^.displayproc:=display_extra_info_proc;
|
||||||
if assigned(fill_extra_info_proc) then
|
if assigned(fill_extra_info_proc) then
|
||||||
begin
|
begin
|
||||||
inside_trace_getmem:=true;
|
loc_info^.inside_trace_getmem:=true;
|
||||||
fill_extra_info_proc(@pp^.extra_info^.data);
|
fill_extra_info_proc(@pp^.extra_info^.data);
|
||||||
inside_trace_getmem:=false;
|
loc_info^.inside_trace_getmem:=false;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -466,21 +487,21 @@ begin
|
|||||||
bp:=nil;
|
bp:=nil;
|
||||||
end;
|
end;
|
||||||
{ insert in the linked list }
|
{ insert in the linked list }
|
||||||
if heap_mem_root<>nil then
|
if loc_info^.heap_mem_root<>nil then
|
||||||
heap_mem_root^.next:=pp;
|
loc_info^.heap_mem_root^.next:=pp;
|
||||||
pp^.previous:=heap_mem_root;
|
pp^.previous:=loc_info^.heap_mem_root;
|
||||||
pp^.next:=nil;
|
pp^.next:=nil;
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
pp^.prev_valid:=heap_valid_last;
|
pp^.prev_valid:=loc_info^.heap_valid_last;
|
||||||
heap_valid_last:=pp;
|
loc_info^.heap_valid_last:=pp;
|
||||||
if not assigned(heap_valid_first) then
|
if not assigned(loc_info^.heap_valid_first) then
|
||||||
heap_valid_first:=pp;
|
loc_info^.heap_valid_first:=pp;
|
||||||
{$endif EXTRA}
|
{$endif EXTRA}
|
||||||
heap_mem_root:=pp;
|
loc_info^.heap_mem_root:=pp;
|
||||||
{ must be changed before fill_extra_info is called
|
{ must be changed before fill_extra_info is called
|
||||||
because checkpointer can be called from within
|
because checkpointer can be called from within
|
||||||
fill_extra_info PM }
|
fill_extra_info PM }
|
||||||
inc(getmem_cnt);
|
inc(loc_info^.getmem_cnt);
|
||||||
{ update the signature }
|
{ update the signature }
|
||||||
if usecrc then
|
if usecrc then
|
||||||
pp^.sig:=calculate_sig(pp);
|
pp^.sig:=calculate_sig(pp);
|
||||||
@ -492,60 +513,37 @@ end;
|
|||||||
TraceFreeMem
|
TraceFreeMem
|
||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|
||||||
function TraceFreeMemSize(p:pointer;size:ptrint):ptrint;
|
function CheckFreeMemSize(loc_info: pheap_info; pp: pheap_mem_info;
|
||||||
|
size, ppsize: ptrint): boolean; inline;
|
||||||
var
|
var
|
||||||
i,ppsize : ptrint;
|
i: ptrint;
|
||||||
bp : pointer;
|
bp : pointer;
|
||||||
pp : pheap_mem_info;
|
ptext : ^text;
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
pp2 : pheap_mem_info;
|
pp2 : pheap_mem_info;
|
||||||
{$endif}
|
{$endif}
|
||||||
extra_size : ptrint;
|
|
||||||
ptext : ^text;
|
|
||||||
begin
|
begin
|
||||||
if p=nil then
|
|
||||||
begin
|
|
||||||
TraceFreeMemSize:=0;
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
pp:=pheap_mem_info(p-sizeof(theap_mem_info));
|
|
||||||
if @heap_free_todo <> pp^.todolist then
|
|
||||||
begin
|
|
||||||
if pp^.todolist = main_orig_todolist then
|
|
||||||
pp^.todolist := main_relo_todolist;
|
|
||||||
if @heap_free_todo <> pp^.todolist then
|
|
||||||
begin
|
|
||||||
entercriticalsection(pp^.todolist^.lock);
|
|
||||||
pp^.todonext := pp^.todolist^.list;
|
|
||||||
pp^.todolist^.list := pp;
|
|
||||||
leavecriticalsection(pp^.todolist^.lock);
|
|
||||||
exit(pp^.size);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
if useownfile then
|
if useownfile then
|
||||||
ptext:=@ownfile
|
ptext:=@ownfile
|
||||||
else
|
else
|
||||||
ptext:=@stderr;
|
ptext:=@stderr;
|
||||||
inc(freemem_size,size);
|
inc(loc_info^.freemem_size,size);
|
||||||
inc(freemem8_size,((size+7) div 8)*8);
|
inc(loc_info^.freemem8_size,((size+7) div 8)*8);
|
||||||
ppsize:= size + sizeof(theap_mem_info)+pp^.extra_info_size;
|
|
||||||
if add_tail then
|
|
||||||
inc(ppsize,sizeof(ptrint));
|
|
||||||
if not quicktrace then
|
if not quicktrace then
|
||||||
begin
|
begin
|
||||||
if not(is_in_getmem_list(pp)) then
|
if not(is_in_getmem_list(loc_info, pp)) then
|
||||||
RunError(204);
|
RunError(204);
|
||||||
end;
|
end;
|
||||||
if (pp^.sig=$AAAAAAAA) and not usecrc then
|
if (pp^.sig=$AAAAAAAA) and not usecrc then
|
||||||
begin
|
begin
|
||||||
error_in_heap:=true;
|
loc_info^.error_in_heap:=true;
|
||||||
dump_already_free(pp,ptext^);
|
dump_already_free(pp,ptext^);
|
||||||
if haltonerror then halt(1);
|
if haltonerror then halt(1);
|
||||||
end
|
end
|
||||||
else if ((pp^.sig<>$DEADBEEF) or usecrc) and
|
else if ((pp^.sig<>$DEADBEEF) or usecrc) and
|
||||||
((pp^.sig<>calculate_sig(pp)) or not usecrc) then
|
((pp^.sig<>calculate_sig(pp)) or not usecrc) then
|
||||||
begin
|
begin
|
||||||
error_in_heap:=true;
|
loc_info^.error_in_heap:=true;
|
||||||
dump_error(pp,ptext^);
|
dump_error(pp,ptext^);
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
dump_error(pp,error_file);
|
dump_error(pp,error_file);
|
||||||
@ -556,7 +554,7 @@ begin
|
|||||||
end
|
end
|
||||||
else if pp^.size<>size then
|
else if pp^.size<>size then
|
||||||
begin
|
begin
|
||||||
error_in_heap:=true;
|
loc_info^.error_in_heap:=true;
|
||||||
dump_wrong_size(pp,size,ptext^);
|
dump_wrong_size(pp,size,ptext^);
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
dump_wrong_size(pp,size,error_file);
|
dump_wrong_size(pp,size,error_file);
|
||||||
@ -565,8 +563,6 @@ begin
|
|||||||
{ don't release anything in this case !! }
|
{ don't release anything in this case !! }
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
{ save old values }
|
|
||||||
extra_size:=pp^.extra_info_size;
|
|
||||||
{ now it is released !! }
|
{ now it is released !! }
|
||||||
pp^.sig:=$AAAAAAAA;
|
pp^.sig:=$AAAAAAAA;
|
||||||
if not keepreleased then
|
if not keepreleased then
|
||||||
@ -575,8 +571,8 @@ begin
|
|||||||
pp^.next^.previous:=pp^.previous;
|
pp^.next^.previous:=pp^.previous;
|
||||||
if pp^.previous<>nil then
|
if pp^.previous<>nil then
|
||||||
pp^.previous^.next:=pp^.next;
|
pp^.previous^.next:=pp^.next;
|
||||||
if pp=heap_mem_root then
|
if pp=loc_info^.heap_mem_root then
|
||||||
heap_mem_root:=heap_mem_root^.previous;
|
loc_info^.heap_mem_root:=loc_info^.heap_mem_root^.previous;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@ -587,48 +583,102 @@ begin
|
|||||||
bp:=get_caller_frame(bp);
|
bp:=get_caller_frame(bp);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
inc(freemem_cnt);
|
inc(loc_info^.freemem_cnt);
|
||||||
{ clear the memory }
|
{ clear the memory, $F0 will lead to GFP if used as pointer ! }
|
||||||
fillchar(p^,size,#240); { $F0 will lead to GFP if used as pointer ! }
|
fillchar((pointer(pp)+sizeof(theap_mem_info))^,size,#240);
|
||||||
{ this way we keep all info about all released memory !! }
|
{ this way we keep all info about all released memory !! }
|
||||||
if keepreleased then
|
if keepreleased then
|
||||||
begin
|
begin
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
{ We want to check if the memory was changed after release !! }
|
{ We want to check if the memory was changed after release !! }
|
||||||
pp^.release_sig:=calculate_release_sig(pp);
|
pp^.release_sig:=calculate_release_sig(pp);
|
||||||
if pp=heap_valid_last then
|
if pp=loc_info^.heap_valid_last then
|
||||||
begin
|
begin
|
||||||
heap_valid_last:=pp^.prev_valid;
|
loc_info^.heap_valid_last:=pp^.prev_valid;
|
||||||
if pp=heap_valid_first then
|
if pp=loc_info^.heap_valid_first then
|
||||||
heap_valid_first:=nil;
|
loc_info^.heap_valid_first:=nil;
|
||||||
TraceFreememsize:=size;
|
exit(false);
|
||||||
exit;
|
|
||||||
end;
|
end;
|
||||||
pp2:=heap_valid_last;
|
pp2:=loc_info^.heap_valid_last;
|
||||||
while assigned(pp2) do
|
while assigned(pp2) do
|
||||||
begin
|
begin
|
||||||
if pp2^.prev_valid=pp then
|
if pp2^.prev_valid=pp then
|
||||||
begin
|
begin
|
||||||
pp2^.prev_valid:=pp^.prev_valid;
|
pp2^.prev_valid:=pp^.prev_valid;
|
||||||
if pp=heap_valid_first then
|
if pp=loc_info^.heap_valid_first then
|
||||||
heap_valid_first:=pp2;
|
loc_info^.heap_valid_first:=pp2;
|
||||||
TraceFreememsize:=size;
|
exit(false);
|
||||||
exit;
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
pp2:=pp2^.prev_valid;
|
pp2:=pp2^.prev_valid;
|
||||||
end;
|
end;
|
||||||
{$endif EXTRA}
|
{$endif EXTRA}
|
||||||
TraceFreememsize:=size;
|
exit(false);
|
||||||
exit;
|
|
||||||
end;
|
end;
|
||||||
{ release the normal memory at least }
|
CheckFreeMemSize:=true;
|
||||||
i:=SysFreeMemSize(pp,ppsize);
|
end;
|
||||||
{ return the correct size }
|
|
||||||
dec(i,sizeof(theap_mem_info)+extra_size);
|
function InternalFreeMemSize(loc_info: pheap_info; p: pointer; pp: pheap_mem_info;
|
||||||
if add_tail then
|
size: ptrint; release_orphaned_lock: boolean): ptrint;
|
||||||
dec(i,sizeof(ptrint));
|
var
|
||||||
TraceFreeMemSize:=i;
|
i,ppsize : ptrint;
|
||||||
|
bp : pointer;
|
||||||
|
extra_size: ptrint;
|
||||||
|
release_mem: boolean;
|
||||||
|
begin
|
||||||
|
{ save old values }
|
||||||
|
extra_size:=pp^.extra_info_size;
|
||||||
|
ppsize:= size+sizeof(theap_mem_info)+pp^.extra_info_size;
|
||||||
|
if add_tail then
|
||||||
|
inc(ppsize,sizeof(ptrint));
|
||||||
|
{ do various checking }
|
||||||
|
release_mem := CheckFreeMemSize(loc_info, pp, size, ppsize);
|
||||||
|
if release_orphaned_lock then
|
||||||
|
leavecriticalsection(orphaned_info.heap_free_todo.lock);
|
||||||
|
if release_mem then
|
||||||
|
begin
|
||||||
|
{ release the normal memory at least }
|
||||||
|
i:=SysFreeMemSize(pp,ppsize);
|
||||||
|
{ return the correct size }
|
||||||
|
dec(i,sizeof(theap_mem_info)+extra_size);
|
||||||
|
if add_tail then
|
||||||
|
dec(i,sizeof(ptrint));
|
||||||
|
InternalFreeMemSize:=i;
|
||||||
|
end else
|
||||||
|
InternalFreeMemSize:=size;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TraceFreeMemSize(p:pointer;size:ptrint):ptrint;
|
||||||
|
var
|
||||||
|
loc_info: pheap_info;
|
||||||
|
pp: pheap_mem_info;
|
||||||
|
begin
|
||||||
|
if p=nil then
|
||||||
|
begin
|
||||||
|
TraceFreeMemSize:=0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
loc_info:=@heap_info;
|
||||||
|
pp:=pheap_mem_info(p-sizeof(theap_mem_info));
|
||||||
|
if @loc_info^.heap_free_todo <> pp^.todolist then
|
||||||
|
begin
|
||||||
|
if pp^.todolist = main_orig_todolist then
|
||||||
|
pp^.todolist := main_relo_todolist;
|
||||||
|
entercriticalsection(pp^.todolist^.lock);
|
||||||
|
if pp^.todolist = @orphaned_info.heap_free_todo then
|
||||||
|
begin
|
||||||
|
loc_info := @orphaned_info;
|
||||||
|
end else
|
||||||
|
if pp^.todolist <> @loc_info^.heap_free_todo then
|
||||||
|
begin
|
||||||
|
{ allocated in different heap, push to that todolist }
|
||||||
|
pp^.todonext := pp^.todolist^.list;
|
||||||
|
pp^.todolist^.list := pp;
|
||||||
|
leavecriticalsection(pp^.todolist^.lock);
|
||||||
|
exit(pp^.size);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
TraceFreeMemSize:=InternalFreeMemSize(loc_info,p,pp,size,loc_info = @orphaned_info);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -691,6 +741,7 @@ var
|
|||||||
oldexactsize : ptrint;
|
oldexactsize : ptrint;
|
||||||
old_fill_extra_info_proc : tfillextrainfoproc;
|
old_fill_extra_info_proc : tfillextrainfoproc;
|
||||||
old_display_extra_info_proc : tdisplayextrainfoproc;
|
old_display_extra_info_proc : tdisplayextrainfoproc;
|
||||||
|
loc_info: pheap_info;
|
||||||
begin
|
begin
|
||||||
{ Free block? }
|
{ Free block? }
|
||||||
if size=0 then
|
if size=0 then
|
||||||
@ -709,12 +760,13 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
{ Resize block }
|
{ Resize block }
|
||||||
|
loc_info:=@heap_info;
|
||||||
pp:=pheap_mem_info(p-sizeof(theap_mem_info));
|
pp:=pheap_mem_info(p-sizeof(theap_mem_info));
|
||||||
{ test block }
|
{ test block }
|
||||||
if ((pp^.sig<>$DEADBEEF) or usecrc) and
|
if ((pp^.sig<>$DEADBEEF) or usecrc) and
|
||||||
((pp^.sig<>calculate_sig(pp)) or not usecrc) then
|
((pp^.sig<>calculate_sig(pp)) or not usecrc) then
|
||||||
begin
|
begin
|
||||||
error_in_heap:=true;
|
loc_info^.error_in_heap:=true;
|
||||||
if useownfile then
|
if useownfile then
|
||||||
dump_error(pp,ownfile)
|
dump_error(pp,ownfile)
|
||||||
else
|
else
|
||||||
@ -795,10 +847,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
{ adjust like a freemem and then a getmem, so you get correct
|
{ adjust like a freemem and then a getmem, so you get correct
|
||||||
results in the summary display }
|
results in the summary display }
|
||||||
inc(freemem_size,oldsize);
|
inc(loc_info^.freemem_size,oldsize);
|
||||||
inc(freemem8_size,((oldsize+7) div 8)*8);
|
inc(loc_info^.freemem8_size,((oldsize+7) div 8)*8);
|
||||||
inc(getmem_size,size);
|
inc(loc_info^.getmem_size,size);
|
||||||
inc(getmem8_size,((size+7) div 8)*8);
|
inc(loc_info^.getmem8_size,((size+7) div 8)*8);
|
||||||
{ generate new backtrace }
|
{ generate new backtrace }
|
||||||
bp:=get_caller_frame(get_frame);
|
bp:=get_caller_frame(get_frame);
|
||||||
for i:=1 to tracesize do
|
for i:=1 to tracesize do
|
||||||
@ -862,6 +914,7 @@ procedure CheckPointer(p : pointer); [public, alias : 'FPC_CHECKPOINTER'];
|
|||||||
var
|
var
|
||||||
i : ptrint;
|
i : ptrint;
|
||||||
pp : pheap_mem_info;
|
pp : pheap_mem_info;
|
||||||
|
loc_info: pheap_info;
|
||||||
{$ifdef go32v2}
|
{$ifdef go32v2}
|
||||||
get_ebp,stack_top : longword;
|
get_ebp,stack_top : longword;
|
||||||
data_end : longword;
|
data_end : longword;
|
||||||
@ -877,7 +930,7 @@ begin
|
|||||||
runerror(204);
|
runerror(204);
|
||||||
|
|
||||||
i:=0;
|
i:=0;
|
||||||
|
loc_info:=@heap_info;
|
||||||
if useownfile then
|
if useownfile then
|
||||||
ptext:=@ownfile
|
ptext:=@ownfile
|
||||||
else
|
else
|
||||||
@ -953,7 +1006,7 @@ begin
|
|||||||
{ first try valid list faster }
|
{ first try valid list faster }
|
||||||
|
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
pp:=heap_valid_last;
|
pp:=loc_info^.heap_valid_last;
|
||||||
while pp<>nil do
|
while pp<>nil do
|
||||||
begin
|
begin
|
||||||
{ inside this valid block ! }
|
{ inside this valid block ! }
|
||||||
@ -965,8 +1018,8 @@ begin
|
|||||||
if ((pp^.sig=$DEADBEEF) and not usecrc) or
|
if ((pp^.sig=$DEADBEEF) and not usecrc) or
|
||||||
((pp^.sig=calculate_sig(pp)) and usecrc) or
|
((pp^.sig=calculate_sig(pp)) and usecrc) or
|
||||||
{ special case of the fill_extra_info call }
|
{ special case of the fill_extra_info call }
|
||||||
((pp=heap_valid_last) and usecrc and (pp^.sig=$DEADBEEF)
|
((pp=loc_info^.heap_valid_last) and usecrc and (pp^.sig=$DEADBEEF)
|
||||||
and inside_trace_getmem) then
|
and loc_info^.inside_trace_getmem) then
|
||||||
goto _exit
|
goto _exit
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@ -978,7 +1031,7 @@ begin
|
|||||||
else
|
else
|
||||||
pp:=pp^.prev_valid;
|
pp:=pp^.prev_valid;
|
||||||
inc(i);
|
inc(i);
|
||||||
if i>getmem_cnt-freemem_cnt then
|
if i>loc_info^.getmem_cnt-loc_info^.freemem_cnt then
|
||||||
begin
|
begin
|
||||||
writeln(ptext^,'error in linked list of heap_mem_info');
|
writeln(ptext^,'error in linked list of heap_mem_info');
|
||||||
halt(1);
|
halt(1);
|
||||||
@ -986,7 +1039,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
i:=0;
|
i:=0;
|
||||||
{$endif EXTRA}
|
{$endif EXTRA}
|
||||||
pp:=heap_mem_root;
|
pp:=loc_info^.heap_mem_root;
|
||||||
while pp<>nil do
|
while pp<>nil do
|
||||||
begin
|
begin
|
||||||
{ inside this block ! }
|
{ inside this block ! }
|
||||||
@ -1004,7 +1057,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
pp:=pp^.previous;
|
pp:=pp^.previous;
|
||||||
inc(i);
|
inc(i);
|
||||||
if i>getmem_cnt then
|
if i>loc_info^.getmem_cnt then
|
||||||
begin
|
begin
|
||||||
writeln(ptext^,'error in linked list of heap_mem_info');
|
writeln(ptext^,'error in linked list of heap_mem_info');
|
||||||
halt(1);
|
halt(1);
|
||||||
@ -1027,16 +1080,21 @@ var
|
|||||||
ExpectedHeapFree : ptrint;
|
ExpectedHeapFree : ptrint;
|
||||||
status : TFPCHeapStatus;
|
status : TFPCHeapStatus;
|
||||||
ptext : ^text;
|
ptext : ^text;
|
||||||
|
loc_info: pheap_info;
|
||||||
begin
|
begin
|
||||||
|
loc_info:=@heap_info;
|
||||||
if useownfile then
|
if useownfile then
|
||||||
ptext:=@ownfile
|
ptext:=@ownfile
|
||||||
else
|
else
|
||||||
ptext:=@stderr;
|
ptext:=@stderr;
|
||||||
pp:=heap_mem_root;
|
pp:=loc_info^.heap_mem_root;
|
||||||
Writeln(ptext^,'Heap dump by heaptrc unit');
|
Writeln(ptext^,'Heap dump by heaptrc unit');
|
||||||
Writeln(ptext^,getmem_cnt, ' memory blocks allocated : ',getmem_size,'/',getmem8_size);
|
Writeln(ptext^,loc_info^.getmem_cnt, ' memory blocks allocated : ',
|
||||||
Writeln(ptext^,freemem_cnt,' memory blocks freed : ',freemem_size,'/',freemem8_size);
|
loc_info^.getmem_size,'/',loc_info^.getmem8_size);
|
||||||
Writeln(ptext^,getmem_cnt-freemem_cnt,' unfreed memory blocks : ',getmem_size-freemem_size);
|
Writeln(ptext^,loc_info^.freemem_cnt,' memory blocks freed : ',
|
||||||
|
loc_info^.freemem_size,'/',loc_info^.freemem8_size);
|
||||||
|
Writeln(ptext^,loc_info^.getmem_cnt-loc_info^.freemem_cnt,
|
||||||
|
' unfreed memory blocks : ',loc_info^.getmem_size-loc_info^.freemem_size);
|
||||||
status:=SysGetFPCHeapStatus;
|
status:=SysGetFPCHeapStatus;
|
||||||
Write(ptext^,'True heap size : ',status.CurrHeapSize);
|
Write(ptext^,'True heap size : ',status.CurrHeapSize);
|
||||||
if EntryMemUsed > 0 then
|
if EntryMemUsed > 0 then
|
||||||
@ -1044,11 +1102,13 @@ begin
|
|||||||
else
|
else
|
||||||
Writeln(ptext^);
|
Writeln(ptext^);
|
||||||
Writeln(ptext^,'True free heap : ',status.CurrHeapFree);
|
Writeln(ptext^,'True free heap : ',status.CurrHeapFree);
|
||||||
ExpectedHeapFree:=status.CurrHeapSize-(getmem8_size-freemem8_size)-
|
ExpectedHeapFree:=status.CurrHeapSize
|
||||||
(getmem_cnt-freemem_cnt)*(sizeof(theap_mem_info)+extra_info_size)-EntryMemUsed;
|
-(loc_info^.getmem8_size-loc_info^.freemem8_size)
|
||||||
|
-(loc_info^.getmem_cnt-loc_info^.freemem_cnt)*(sizeof(theap_mem_info)+extra_info_size)
|
||||||
|
-EntryMemUsed;
|
||||||
If ExpectedHeapFree<>status.CurrHeapFree then
|
If ExpectedHeapFree<>status.CurrHeapFree then
|
||||||
Writeln(ptext^,'Should be : ',ExpectedHeapFree);
|
Writeln(ptext^,'Should be : ',ExpectedHeapFree);
|
||||||
i:=getmem_cnt-freemem_cnt;
|
i:=loc_info^.getmem_cnt-loc_info^.freemem_cnt;
|
||||||
while pp<>nil do
|
while pp<>nil do
|
||||||
begin
|
begin
|
||||||
if i<0 then
|
if i<0 then
|
||||||
@ -1071,20 +1131,20 @@ begin
|
|||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
dump_error(pp,error_file);
|
dump_error(pp,error_file);
|
||||||
{$endif EXTRA}
|
{$endif EXTRA}
|
||||||
error_in_heap:=true;
|
loc_info^.error_in_heap:=true;
|
||||||
end
|
end
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
else if pp^.release_sig<>calculate_release_sig(pp) then
|
else if pp^.release_sig<>calculate_release_sig(pp) then
|
||||||
begin
|
begin
|
||||||
dump_change_after(pp,ptext^);
|
dump_change_after(pp,ptext^);
|
||||||
dump_change_after(pp,error_file);
|
dump_change_after(pp,error_file);
|
||||||
error_in_heap:=true;
|
loc_info^.error_in_heap:=true;
|
||||||
end
|
end
|
||||||
{$endif EXTRA}
|
{$endif EXTRA}
|
||||||
;
|
;
|
||||||
pp:=pp^.previous;
|
pp:=pp^.previous;
|
||||||
end;
|
end;
|
||||||
if HaltOnNotReleased and (getmem_cnt<>freemem_cnt) then
|
if HaltOnNotReleased and (loc_info^.getmem_cnt<>loc_info^.freemem_cnt) then
|
||||||
exitcode:=203;
|
exitcode:=203;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1104,38 +1164,93 @@ end;
|
|||||||
*****************************************************************************}
|
*****************************************************************************}
|
||||||
|
|
||||||
procedure TraceInitThread;
|
procedure TraceInitThread;
|
||||||
|
var
|
||||||
|
loc_info: pheap_info;
|
||||||
begin
|
begin
|
||||||
|
loc_info := @heap_info;
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
heap_valid_first := nil;
|
loc_info^.heap_valid_first := nil;
|
||||||
heap_valid_last := nil;
|
loc_info^.heap_valid_last := nil;
|
||||||
{$endif}
|
{$endif}
|
||||||
heap_mem_root := nil;
|
loc_info^.heap_mem_root := nil;
|
||||||
getmem_cnt := 0;
|
loc_info^.getmem_cnt := 0;
|
||||||
freemem_cnt := 0;
|
loc_info^.freemem_cnt := 0;
|
||||||
getmem_size := 0;
|
loc_info^.getmem_size := 0;
|
||||||
freemem_size := 0;
|
loc_info^.freemem_size := 0;
|
||||||
getmem8_size := 0;
|
loc_info^.getmem8_size := 0;
|
||||||
freemem8_size := 0;
|
loc_info^.freemem8_size := 0;
|
||||||
error_in_heap := false;
|
loc_info^.error_in_heap := false;
|
||||||
inside_trace_getmem := false;
|
loc_info^.inside_trace_getmem := false;
|
||||||
EntryMemUsed := SysGetFPCHeapStatus.CurrHeapUsed;
|
EntryMemUsed := SysGetFPCHeapStatus.CurrHeapUsed;
|
||||||
if main_relo_todolist <> nil then
|
if main_relo_todolist <> nil then
|
||||||
initcriticalsection(heap_free_todo.lock);
|
initcriticalsection(loc_info^.heap_free_todo.lock);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TraceRelocateHeap;
|
procedure TraceRelocateHeap;
|
||||||
begin
|
begin
|
||||||
main_relo_todolist := @heap_free_todo;
|
main_relo_todolist := @heap_info.heap_free_todo;
|
||||||
initcriticalsection(main_relo_todolist^.lock);
|
initcriticalsection(main_relo_todolist^.lock);
|
||||||
|
initcriticalsection(orphaned_info.heap_free_todo.lock);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure move_heap_info(src_info, dst_info: pheap_info);
|
||||||
|
var
|
||||||
|
heap_mem: pheap_mem_info;
|
||||||
|
begin
|
||||||
|
if src_info^.heap_free_todo.list <> nil then
|
||||||
|
finish_heap_free_todo_list(src_info);
|
||||||
|
if dst_info^.heap_free_todo.list <> nil then
|
||||||
|
finish_heap_free_todo_list(dst_info);
|
||||||
|
heap_mem := src_info^.heap_mem_root;
|
||||||
|
if heap_mem <> nil then
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
heap_mem^.todolist := @dst_info^.heap_free_todo;
|
||||||
|
if heap_mem^.previous = nil then break;
|
||||||
|
heap_mem := heap_mem^.previous;
|
||||||
|
until false;
|
||||||
|
heap_mem^.previous := dst_info^.heap_mem_root;
|
||||||
|
if dst_info^.heap_mem_root <> nil then
|
||||||
|
dst_info^.heap_mem_root^.next := heap_mem;
|
||||||
|
dst_info^.heap_mem_root := src_info^.heap_mem_root;
|
||||||
|
end;
|
||||||
|
inc(dst_info^.getmem_cnt, src_info^.getmem_cnt);
|
||||||
|
inc(dst_info^.getmem_size, src_info^.getmem_size);
|
||||||
|
inc(dst_info^.getmem8_size, src_info^.getmem8_size);
|
||||||
|
inc(dst_info^.freemem_cnt, src_info^.freemem_cnt);
|
||||||
|
inc(dst_info^.freemem_size, src_info^.freemem_size);
|
||||||
|
inc(dst_info^.freemem8_size, src_info^.freemem8_size);
|
||||||
|
dst_info^.error_in_heap := dst_info^.error_in_heap or src_info^.error_in_heap;
|
||||||
|
{$ifdef EXTRA}
|
||||||
|
if assigned(dst_info^.heap_valid_first) then
|
||||||
|
dst_info^.heap_valid_first^.prev_valid := src_info^.heap_valid_last
|
||||||
|
else
|
||||||
|
dst_info^.heap_valid_last := src_info^.heap_valid_last;
|
||||||
|
dst_info^.heap_valid_first := src_info^.heap_valid_first;
|
||||||
|
{$endif}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TraceExitThread;
|
procedure TraceExitThread;
|
||||||
|
var
|
||||||
|
loc_info: pheap_info;
|
||||||
|
heap_mem: pheap_mem_info;
|
||||||
begin
|
begin
|
||||||
finish_heap_free_todo_list;
|
loc_info := @heap_info;
|
||||||
if main_relo_todolist <> nil then
|
entercriticalsection(loc_info^.heap_free_todo.lock);
|
||||||
donecriticalsection(heap_free_todo.lock);
|
entercriticalsection(orphaned_info.heap_free_todo.lock);
|
||||||
if not error_in_heap then
|
{ if not main thread exiting, move bookkeeping to orphaned heap }
|
||||||
|
if (@loc_info^.heap_free_todo <> main_orig_todolist)
|
||||||
|
and (@loc_info^.heap_free_todo <> main_relo_todolist) then
|
||||||
|
begin
|
||||||
|
move_heap_info(loc_info, @orphaned_info);
|
||||||
|
end else
|
||||||
|
if not loc_info^.error_in_heap then
|
||||||
|
begin
|
||||||
|
move_heap_info(@orphaned_info, loc_info);
|
||||||
Dumpheap;
|
Dumpheap;
|
||||||
|
end;
|
||||||
|
leavecriticalsection(orphaned_info.heap_free_todo.lock);
|
||||||
|
donecriticalsection(loc_info^.heap_free_todo.lock);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TraceGetHeapStatus:THeapStatus;
|
function TraceGetHeapStatus:THeapStatus;
|
||||||
@ -1207,7 +1322,7 @@ const
|
|||||||
procedure TraceInit;
|
procedure TraceInit;
|
||||||
begin
|
begin
|
||||||
MakeCRC32Tbl;
|
MakeCRC32Tbl;
|
||||||
main_orig_todolist := @heap_free_todo;
|
main_orig_todolist := @heap_info.heap_free_todo;
|
||||||
main_relo_todolist := nil;
|
main_relo_todolist := nil;
|
||||||
TraceInitThread;
|
TraceInitThread;
|
||||||
SetMemoryManager(TraceManager);
|
SetMemoryManager(TraceManager);
|
||||||
@ -1246,8 +1361,9 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
TraceExitThread;
|
TraceExitThread;
|
||||||
if error_in_heap and (exitcode=0) then
|
if heap_info.error_in_heap and (exitcode=0) then
|
||||||
exitcode:=203;
|
exitcode:=203;
|
||||||
|
donecriticalsection(orphaned_info.heap_free_todo.lock);
|
||||||
{$ifdef EXTRA}
|
{$ifdef EXTRA}
|
||||||
Close(error_file);
|
Close(error_file);
|
||||||
{$endif EXTRA}
|
{$endif EXTRA}
|
||||||
|
Loading…
Reference in New Issue
Block a user