2
$Id: heap.inc,v 1.29 2004/04/26 16:20:54 peter Exp $
3
This file is part of the Free Pascal run time library.
4
Copyright (c) 1999-2000 by the Free Pascal development team.
6
functions for heap management in the data segment
8
See the file COPYING.FPC, included in this distribution,
9
for details about the copyright.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
**********************************************************************}
17
{****************************************************************************}
19
{ Reuse bigger blocks instead of allocating a new block at freelist/heapptr.
20
the tried bigger blocks are always multiple sizes of the current block }
23
{ Allocate small blocks at heapptr instead of walking the freelist }
24
{ define SMALLATHEAPPTR}
26
{ Try to find the best matching block in general freelist }
29
{ Concat free blocks when placing big blocks in the mainlist }
32
{ DEBUG: Dump info when the heap needs to grow }
35
{ DEBUG: Test the FreeList on correctness }
37
{$define TestFreeLists}
42
blocksize = 32; { at least size of freerecord }
43
blockshr = 5; { shr value for blocksize=2^blockshr}
44
maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
46
blocksize = 16; { at least size of freerecord }
47
blockshr = 4; { shr value for blocksize=2^blockshr}
48
maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
50
maxblock = maxblocksize div blocksize;
51
maxreusebigger = 8; { max reuse bigger tries }
53
usedmask = 1; { flag if the block is used or not }
54
beforeheapendmask = 2; { flag if the block is just before a heapptr }
55
sizemask = not(blocksize-1);
57
{****************************************************************************}
64
procedure SysHeapMutexInit;forward;
65
procedure SysHeapMutexDone;forward;
66
procedure SysHeapMutexLock;forward;
67
procedure SysHeapMutexUnlock;forward;
71
MemoryManager: TMemoryManager = (
75
FreeMemSize: @SysFreeMemSize;
76
AllocMem: @SysAllocMem;
77
ReAllocMem: @SysReAllocMem;
79
MemAvail: @SysMemAvail;
80
MaxAvail: @SysMaxAvail;
81
HeapSize: @SysHeapSize;
84
MemoryMutexManager: TMemoryMutexManager = (
85
MutexInit: @SysHeapMutexInit;
86
MutexDone: @SysHeapMutexDone;
87
MutexLock: @SysHeapMutexLock;
88
MutexUnlock: @SysHeapMutexUnlock;
92
ppfreerecord = ^pfreerecord;
93
pfreerecord = ^tfreerecord;
100
pheaprecord = ^theaprecord;
102
{ this should overlap with tfreerecord }
106
tfreelists = array[0..maxblock] of pfreerecord;
108
tfreecount = array[0..maxblock] of dword;
110
pfreelists = ^tfreelists;
113
internal_memavail : ptrint;
114
internal_heapsize : ptrint;
115
freelists : tfreelists;
116
before_heapend_block : pfreerecord;
118
freecount : tfreecount;
120
{$ifdef TestFreeLists}
121
{ this can be turned on by debugger }
123
test_each : boolean = false;
124
{$endif TestFreeLists}
126
{*****************************************************************************
128
*****************************************************************************}
130
procedure SetMemoryMutexManager(var MutexMgr: TMemoryMutexManager);
132
{ Release old mutexmanager, the default manager does nothing so
133
calling this without initializing is safe }
134
MemoryMutexManager.MutexDone;
135
{ Copy new mutexmanager }
136
MemoryMutexManager:=MutexMgr;
137
{ Init new mutexmanager }
138
MemoryMutexManager.MutexInit;
142
procedure GetMemoryManager(var MemMgr:TMemoryManager);
144
if IsMultiThread and MemoryManager.NeedLock then
147
MemoryMutexManager.MutexLock;
148
MemMgr:=MemoryManager;
150
MemoryMutexManager.MutexUnlock;
155
MemMgr:=MemoryManager;
160
procedure SetMemoryManager(const MemMgr:TMemoryManager);
162
if IsMultiThread and MemoryManager.NeedLock then
165
MemoryMutexManager.MutexLock;
166
MemoryManager:=MemMgr;
168
MemoryMutexManager.MutexUnlock;
173
MemoryManager:=MemMgr;
178
function IsMemoryManagerSet:Boolean;
180
if IsMultiThread and MemoryManager.NeedLock then
183
MemoryMutexManager.MutexLock;
184
IsMemoryManagerSet:=(MemoryManager.GetMem<>@SysGetMem) or
185
(MemoryManager.FreeMem<>@SysFreeMem);
187
MemoryMutexManager.MutexUnlock;
192
IsMemoryManagerSet:=(MemoryManager.GetMem<>@SysGetMem) or
193
(MemoryManager.FreeMem<>@SysFreeMem);
198
procedure GetMem(Var p:pointer;Size:ptrint);
200
if IsMultiThread and MemoryManager.NeedLock then
203
MemoryMutexManager.MutexLock;
204
p:=MemoryManager.GetMem(Size);
206
MemoryMutexManager.MutexUnlock;
211
p:=MemoryManager.GetMem(Size);
215
procedure GetMemory(Var p:pointer;Size:ptrint);
220
procedure FreeMem(p:pointer;Size:ptrint);
222
if IsMultiThread and MemoryManager.NeedLock then
225
MemoryMutexManager.MutexLock;
226
MemoryManager.FreeMemSize(p,Size);
228
MemoryMutexManager.MutexUnlock;
233
MemoryManager.FreeMemSize(p,Size);
237
procedure FreeMemory(p:pointer;Size:ptrint);
242
function MaxAvail:ptrint;
244
if IsMultiThread and MemoryManager.NeedLock then
247
MemoryMutexManager.MutexLock;
248
MaxAvail:=MemoryManager.MaxAvail();
250
MemoryMutexManager.MutexUnlock;
255
MaxAvail:=MemoryManager.MaxAvail();
260
function MemAvail:ptrint;
262
if IsMultiThread and MemoryManager.NeedLock then
265
MemoryMutexManager.MutexLock;
266
MemAvail:=MemoryManager.MemAvail();
268
MemoryMutexManager.MutexUnlock;
273
MemAvail:=MemoryManager.MemAvail();
279
function HeapSize:ptrint;
281
if IsMultiThread and MemoryManager.NeedLock then
284
MemoryMutexManager.MutexLock;
285
HeapSize:=MemoryManager.HeapSize();
287
MemoryMutexManager.MutexUnlock;
292
HeapSize:=MemoryManager.HeapSize();
297
function MemSize(p:pointer):ptrint;
299
if IsMultiThread and MemoryManager.NeedLock then
302
MemoryMutexManager.MutexLock;
303
MemSize:=MemoryManager.MemSize(p);
305
MemoryMutexManager.MutexUnlock;
310
MemSize:=MemoryManager.MemSize(p);
316
function FreeMem(p:pointer):ptrint;
318
if IsMultiThread and MemoryManager.NeedLock then
321
MemoryMutexManager.MutexLock;
322
Freemem:=MemoryManager.FreeMem(p);
324
MemoryMutexManager.MutexUnlock;
329
Freemem:=MemoryManager.FreeMem(p);
333
function FreeMemory(p:pointer):ptrint;
336
FreeMemory:=FreeMem(p);
339
function GetMem(size:ptrint):pointer;
341
if IsMultiThread and MemoryManager.NeedLock then
344
MemoryMutexManager.MutexLock;
345
GetMem:=MemoryManager.GetMem(Size);
347
MemoryMutexManager.MutexUnlock;
352
GetMem:=MemoryManager.GetMem(Size);
356
function GetMemory(size:ptrint):pointer;
359
GetMemory:=Getmem(size);
362
function AllocMem(Size:ptrint):pointer;
364
if IsMultiThread and MemoryManager.NeedLock then
367
MemoryMutexManager.MutexLock;
368
AllocMem:=MemoryManager.AllocMem(size);
370
MemoryMutexManager.MutexUnlock;
375
AllocMem:=MemoryManager.AllocMem(size);
380
function ReAllocMem(var p:pointer;Size:ptrint):pointer;
382
if IsMultiThread and MemoryManager.NeedLock then
385
MemoryMutexManager.MutexLock;
386
ReAllocMem:=MemoryManager.ReAllocMem(p,size);
388
MemoryMutexManager.MutexUnlock;
393
ReAllocMem:=MemoryManager.ReAllocMem(p,size);
398
function ReAllocMemory(var p:pointer;Size:ptrint):pointer;
401
ReAllocMemory:=ReAllocMem(p,size);
406
{ Needed for calls from Assembler }
407
function fpc_getmem(size:ptrint):pointer;compilerproc;[public,alias:'FPC_GETMEM'];
409
if IsMultiThread and MemoryManager.NeedLock then
412
MemoryMutexManager.MutexLock;
413
fpc_GetMem:=MemoryManager.GetMem(size);
415
MemoryMutexManager.MutexUnlock;
420
fpc_GetMem:=MemoryManager.GetMem(size);
426
{ Needed for calls from Assembler }
427
procedure AsmGetMem(var p:pointer;size:ptrint);[public,alias:'FPC_GETMEM'];
429
p:=MemoryManager.GetMem(size);
434
{$ifdef ValueFreemem}
436
procedure fpc_freemem(p:pointer);compilerproc;[public,alias:'FPC_FREEMEM'];
438
if IsMultiThread and MemoryManager.NeedLock then
441
MemoryMutexManager.MutexLock;
443
MemoryManager.FreeMem(p);
445
MemoryMutexManager.MutexUnlock;
451
MemoryManager.FreeMem(p);
457
procedure AsmFreeMem(var p:pointer);[public,alias:'FPC_FREEMEM'];
460
MemoryManager.FreeMem(p);
463
{$endif ValueFreemem}
466
{*****************************************************************************
467
Heapsize,Memavail,MaxAvail
468
*****************************************************************************}
470
function SysHeapsize : ptrint;
472
Sysheapsize:=internal_heapsize;
476
function SysMemavail : ptrint;
478
Sysmemavail:=internal_memavail;
482
function SysMaxavail : ptrint;
486
Sysmaxavail:=heapend-heapptr;
488
while assigned(hp) do
490
if hp^.size>Sysmaxavail then
491
Sysmaxavail:=hp^.size;
498
procedure DumpBlocks;
503
for i:=1 to maxblock do
507
while assigned(hp) do
512
writeln('Block ',i*blocksize,': ',j);
518
while assigned(hp) do
525
writeln('Main: ',j,' maxsize: ',s);
530
{$ifdef TestFreeLists}
531
procedure TestFreeLists;
536
for i:=0 to maxblock do
540
while assigned(hp) do
543
if (i>0) and ((hp^.size and sizemask) <> i * blocksize) then
547
if j<>freecount[i] then
551
{$endif TestFreeLists}
555
{*****************************************************************************
556
Try concat freerecords
557
*****************************************************************************}
559
procedure TryConcatFreeRecord(pcurr:pfreerecord);
562
pcurrsize,s1 : ptrint;
564
pcurrsize:=pcurr^.size and sizemask;
567
{ block used or before a heapend ? }
568
if (hp^.size and beforeheapendmask)<>0 then
570
{ Peter, why can't we add this one if free ?? }
571
{ It's already added in the previous iteration, we only go to the }
572
{ next heap record after this check (JM) }
573
pcurr^.size:=pcurrsize or beforeheapendmask;
574
{ keep track of the block that lies before the current heapend }
575
if (pointer(pcurr)+pcurrsize+sizeof(tfreerecord) >= heapend) then
576
before_heapend_block := pcurr;
579
{ the size of this block can never be 0. when it is 0 we'll get in
580
an infinite loop, so we throw a RTE instead (PFV) }
581
if (hp^.size and sizemask)=0 then
584
hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
585
{ when we're at heapptr then we can stop and set heapptr to pcurr }
590
if assigned(pcurr^.next) then
591
pcurr^.next^.prev := pcurr^.prev;
592
if assigned(pcurr^.prev) then
593
pcurr^.prev^.next := pcurr^.next
595
freelists[0] := pcurr^.next;
601
{ block is used? then we stop and add the block to the freelist }
602
if (hp^.size and usedmask)<>0 then
604
pcurr^.size:=pcurrsize;
607
{ remove block from freelist and increase the size }
608
s1:=hp^.size and sizemask;
613
if assigned(hp^.next) then
614
hp^.next^.prev:=hp^.prev;
615
if assigned(hp^.prev) then
616
hp^.prev^.next:=hp^.next
618
freelists[s1]:=hp^.next;
626
{*****************************************************************************
628
*****************************************************************************}
630
function SysGetMem(size : ptrint):pointer;
632
heaperrorproc=function(size:ptrint):integer;
634
proc : heaperrorproc;
643
{ Something to allocate ? }
646
{ give an error for < 0 }
649
{ we always need to allocate something, using heapend is not possible,
650
because heappend can be changed by growheap (PFV) }
653
{ calc to multiply of 16 after adding the needed 8 bytes heaprecord }
654
size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
655
dec(internal_memavail,size);
656
{ try to find a block in one of the freelists per size }
657
s:=size shr blockshr;
661
{ correct size match ? }
662
if assigned(pcurr) then
664
{ create the block we should return }
665
sysgetmem:=pointer(pcurr)+sizeof(theaprecord);
667
pcurr^.size:=pcurr^.size or usedmask;
669
freelists[s]:=pcurr^.next;
673
if assigned(freelists[s]) then
674
freelists[s]^.prev:=nil;
675
{$ifdef TestFreeLists}
678
{$endif TestFreeLists}
681
{$ifdef SMALLATHEAPPTR}
682
if heapend-heapptr>=size then
685
{ set end flag if we do not have enough room to add
686
another tfreerecord behind }
687
if (heapptr+size+sizeof(tfreerecord)>=heapend) then
689
pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
690
{ keep track of the block that lies before the current heapend }
691
before_heapend_block := sysgetmem;
694
pheaprecord(sysgetmem)^.size:=size or usedmask;
695
inc(sysgetmem,sizeof(theaprecord));
697
{$ifdef TestFreeLists}
700
{$endif TestFreeLists}
705
{ try a bigger block }
707
maxs1:=s1+maxreusebigger;
708
if maxblock<maxs1 then
712
if freelists[s1]<>nil then
715
pcurr:=freelists[s1];
725
{ not found, then check the main freelist for the first match }
726
if not(assigned(pcurr)) then
733
while assigned(pcurr) do
736
if pcurr^.size=size then
740
if (pcurr^.size>size) then
742
if (not assigned(pbest)) or
743
(pcurr^.size<pbest^.size) then
749
TryConcatFreeRecord(pcurr);
750
if (pcurr <> heapptr) then
752
if pcurr^.size>=size then
761
if pcurr^.size>=size then
768
if not assigned(pcurr) then
772
{ have we found a block, then get it and free up the other left part,
773
if no blocks are found then allocated at the heapptr or grow the heap }
774
if assigned(pcurr) then
776
{ get pointer of the block we should return }
777
sysgetmem:=pointer(pcurr);
778
{ remove the current block from the freelist }
779
if assigned(pcurr^.next) then
780
pcurr^.next^.prev:=pcurr^.prev;
781
if assigned(pcurr^.prev) then
782
pcurr^.prev^.next:=pcurr^.next
784
freelists[s]:=pcurr^.next;
788
{ create the left over freelist block, if at least 16 bytes are free }
789
sizeleft:=pcurr^.size-size;
790
if sizeleft>=sizeof(tfreerecord) then
792
pcurr:=pfreerecord(pointer(pcurr)+size);
793
{ inherit the beforeheapendmask }
794
pcurr^.size:=sizeleft or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
795
{ the block we return does not lie before any heapend anymore (there's now }
796
{ a block after it) }
797
pheaprecord(sysgetmem)^.size := pheaprecord(sysgetmem)^.size and not(beforeheapendmask);
798
{ keep track of the block that lies before the current heapend }
799
if (pointer(pcurr)+(pcurr^.size and sizemask)+sizeof(tfreerecord) >= heapend) then
800
before_heapend_block := pcurr;
801
{ insert the block in the freelist }
803
s1:=sizeleft shr blockshr;
806
pcurr^.next:=freelists[s1];
807
if assigned(freelists[s1]) then
808
freelists[s1]^.prev:=pcurr;
809
freelists[s1]:=pcurr;
813
{ create the block we need to return }
814
pheaprecord(sysgetmem)^.size:=size or usedmask;
818
{ create the block we need to return }
819
pheaprecord(sysgetmem)^.size:=size or usedmask or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
822
inc(sysgetmem,sizeof(theaprecord));
823
{$ifdef TestFreeLists}
826
{$endif TestFreeLists}
829
{ Lastly, the top of the heap is checked, to see if there is }
830
{ still memory available. }
833
if heapend-heapptr>=size then
836
if (heapptr+size+sizeof(tfreerecord)>=heapend) then
838
pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask);
839
{ keep track of the block that lies before the current heapend }
840
before_heapend_block := sysgetmem;
843
pheaprecord(sysgetmem)^.size:=size or usedmask;
844
inc(sysgetmem,sizeof(theaprecord));
846
{$ifdef TestFreeLists}
849
{$endif TestFreeLists}
852
{ Call the heaperror proc }
853
if assigned(heaperror) then
855
proc:=heaperrorproc(heaperror);
857
0 : HandleError(203);
865
{$ifdef TestFreeLists}
868
{$endif TestFreeLists}
872
{*****************************************************************************
874
*****************************************************************************}
876
Function SysFreeMem(p : pointer):ptrint;
878
pcurrsize,s : ptrint;
883
{ fix p to point to the heaprecord }
884
pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
885
pcurrsize:=pcurr^.size and sizemask;
886
inc(internal_memavail,pcurrsize);
887
{ insert the block in it's freelist }
888
pcurr^.size:=pcurr^.size and (not usedmask);
890
s:=pcurrsize shr blockshr;
893
pcurr^.next:=freelists[s];
894
if assigned(pcurr^.next) then
895
pcurr^.next^.prev:=pcurr;
900
SysFreeMem:=pcurrsize;
901
{$ifdef TestFreeLists}
904
{$endif TestFreeLists}
908
{*****************************************************************************
910
*****************************************************************************}
912
Function SysFreeMemSize(p : pointer;size : ptrint):ptrint;
914
pcurrsize,s : ptrint;
926
{ fix p to point to the heaprecord }
927
pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
928
pcurrsize:=pcurr^.size and sizemask;
929
inc(internal_memavail,pcurrsize);
931
size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
932
if size<>pcurrsize then
934
{ insert the block in it's freelist }
935
pcurr^.size:=pcurr^.size and (not usedmask);
937
{ set the return values }
938
s:=pcurrsize shr blockshr;
941
pcurr^.next:=freelists[s];
942
if assigned(pcurr^.next) then
943
pcurr^.next^.prev:=pcurr;
948
SysFreeMemSize:=pcurrsize;
949
{$ifdef TestFreeLists}
952
{$endif TestFreeLists}
956
{*****************************************************************************
958
*****************************************************************************}
960
function SysMemSize(p:pointer):ptrint;
962
SysMemSize:=(pheaprecord(pointer(p)-sizeof(theaprecord))^.size and sizemask)-sizeof(theaprecord);
966
{*****************************************************************************
968
*****************************************************************************}
970
function SysAllocMem(size : ptrint):pointer;
972
sysallocmem:=MemoryManager.GetMem(size);
973
if sysallocmem<>nil then
974
FillChar(sysallocmem^,size,0);
978
{*****************************************************************************
980
*****************************************************************************}
982
function SysTryResizeMem(var p:pointer;size : ptrint):boolean;
989
wasbeforeheapend : boolean;
995
size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
996
{ fix p to point to the heaprecord }
997
pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
998
currsize:=pcurr^.size and sizemask;
1000
wasbeforeheapend:=(pcurr^.size and beforeheapendmask)<>0;
1001
{ is the allocated block still correct? }
1002
if currsize=size then
1004
SysTryResizeMem:=true;
1005
{$ifdef TestFreeLists}
1008
{$endif TestFreeLists}
1011
{ do we need to allocate more memory ? }
1012
if size>currsize then
1014
{ the size is bigger than the previous size, we need to allocated more mem.
1015
We first check if the blocks after the current block are free. If not we
1016
simply call getmem/freemem to get the new block }
1020
inc(foundsize,hp^.size and sizemask);
1021
{ block used or before a heapptr ? }
1022
if (hp^.size and beforeheapendmask)<>0 then
1024
wasbeforeheapend:=true;
1028
hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
1029
{ when we're at heapptr then we can stop }
1030
if (hp=heapptr) then
1032
inc(foundsize,heapend-heapptr);
1035
if (hp^.size and usedmask)<>0 then
1037
until (foundsize>=size);
1038
{ found enough free blocks? }
1039
if foundsize>=size then
1041
{ we walk the list again and remove all blocks }
1042
foundsize:=pcurr^.size and sizemask;
1046
hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
1047
{ when we're at heapptr then we can increase it, if there is enough
1048
room is already checked }
1049
if (hp=heapptr) then
1051
inc(heapptr,size-foundsize);
1053
if (heapend-heapptr)<sizeof(tfreerecord) then
1054
wasbeforeheapend:=true;
1057
s:=hp^.size and sizemask;
1059
{ remove block from freelist }
1063
if assigned(hp^.next) then
1064
hp^.next^.prev:=hp^.prev;
1065
if assigned(hp^.prev) then
1066
hp^.prev^.next:=hp^.next
1068
freelists[s]:=hp^.next;
1069
{$ifdef SYSTEMDEBUG}
1071
{$endif SYSTEMDEBUG}
1072
until (foundsize>=size);
1073
if wasbeforeheapend then
1075
pcurr^.size:=foundsize or usedmask or beforeheapendmask;
1076
{ keep track of the block that lies before the current heapend }
1077
if (pointer(pcurr)+foundsize+sizeof(tfreerecord) >= heapend) then
1078
before_heapend_block := pcurr;
1081
pcurr^.size:=foundsize or usedmask;
1085
{ we need to call getmem/move/freemem }
1086
SysTryResizeMem:=false;
1087
{$ifdef TestFreeLists}
1090
{$endif TestFreeLists}
1093
currsize:=pcurr^.size and sizemask;
1095
{ is the size smaller then we can adjust the block to that size and insert
1096
the other part into the freelist }
1097
if size<currsize then
1099
{ create the left over freelist block, if at least 16 bytes are free }
1100
sizeleft:=currsize-size;
1101
if sizeleft>sizeof(tfreerecord) then
1103
pnew:=pfreerecord(pointer(pcurr)+size);
1104
pnew^.size:=sizeleft or (pcurr^.size and beforeheapendmask);
1105
{ keep track of the block that lies before the current heapend }
1106
if (pointer(pnew)+(pnew^.size and sizemask)+sizeof(tfreerecord) >= heapend) then
1107
before_heapend_block := pnew;
1108
{ pcurr does not lie before the heapend anymore }
1109
pcurr^.size := pcurr^.size and not(beforeheapendmask);
1110
{ insert the block in the freelist }
1112
s:=sizeleft shr blockshr;
1115
pnew^.next:=freelists[s];
1116
if assigned(freelists[s]) then
1117
freelists[s]^.prev:=pnew;
1119
{$ifdef SYSTEMDEBUG}
1121
{$endif SYSTEMDEBUG}
1122
{ fix the size of the current block and leave }
1123
pcurr^.size:=size or usedmask;
1127
{ fix the size of the current block and leave }
1128
pcurr^.size:=size or usedmask or (pcurr^.size and beforeheapendmask);
1131
dec(internal_memavail,size-oldsize);
1132
SysTryResizeMem:=true;
1133
{$ifdef TestFreeLists}
1136
{$endif TestFreeLists}
1140
{*****************************************************************************
1142
*****************************************************************************}
1144
function SysReAllocMem(var p:pointer;size : ptrint):pointer;
1154
MemoryManager.FreeMem(p);
1159
{ Allocate a new block? }
1162
p:=MemoryManager.GetMem(size);
1166
if not SysTryResizeMem(p,size) then
1168
oldsize:=MemoryManager.MemSize(p);
1169
p2:=MemoryManager.GetMem(size);
1171
Move(p^,p2^,oldsize);
1172
MemoryManager.FreeMem(p);
1179
{*****************************************************************************
1181
*****************************************************************************}
1183
procedure release(var p : pointer);
1188
procedure mark(var p : pointer);
1193
{*****************************************************************************
1195
*****************************************************************************}
1197
function growheap(size : SizeInt) : integer;
1199
sizeleft,s1 : longword;
1201
pcurr : pfreerecord;
1204
writeln('growheap(',size,') allocating ',(size+$ffff) and $ffff0000);
1207
{ Allocate by 64K size }
1208
size:=(size+$ffff) and $ffff0000;
1209
{ first try 256K (default) }
1210
if size<=GrowHeapSize1 then
1212
NewPos:=Sbrk(GrowHeapSize1);
1214
size:=GrowHeapSize1;
1217
{ second try 1024K (default) }
1218
if size<=GrowHeapSize2 then
1220
NewPos:=Sbrk(GrowHeapSize2);
1222
size:=GrowHeapSize2;
1224
{ else allocate the needed bytes }
1233
if ReturnNilIfGrowHeapFails then
1240
{ increase heapend or add to freelist }
1241
if heapend=newpos then
1243
heapend:=newpos+size;
1244
{ the block that was marked as "before heapend" is no longer right before the heapend }
1245
if assigned(before_heapend_block) then
1247
before_heapend_block^.size := before_heapend_block^.size and not(beforeheapendmask);
1248
before_heapend_block := nil;
1253
{ create freelist entry for old heapptr-heapend }
1254
sizeleft:=heapend-heapptr;
1255
if sizeleft>=sizeof(tfreerecord) then
1257
pcurr:=pfreerecord(heapptr);
1258
pcurr^.size:=sizeleft or beforeheapendmask;
1259
{ keep track of the block that lies before the current heapend }
1260
{ insert the block in the freelist }
1261
s1:=sizeleft shr blockshr;
1264
pcurr^.next:=freelists[s1];
1266
if assigned(freelists[s1]) then
1267
freelists[s1]^.prev:=pcurr;
1268
freelists[s1]:=pcurr;
1269
{$ifdef SYSTEMDEBUG}
1271
{$endif SYSTEMDEBUG}
1273
{ now set the new heapptr,heapend to the new block }
1275
heapend:=newpos+size;
1276
{ no block lies before the current heapend, and the one that lay before }
1277
{ the previous one will remain before a heapend indefinitely }
1278
before_heapend_block := nil;
1280
{ set the total new heap size }
1281
inc(internal_memavail,size);
1282
inc(internal_heapsize,size);
1285
{$ifdef TestFreeLists}
1287
{$endif TestFreeLists}
1291
{*****************************************************************************
1292
MemoryMutexManager default hooks
1293
*****************************************************************************}
1295
procedure SysHeapMutexInit;
1300
procedure SysHeapMutexDone;
1305
procedure SysHeapMutexLock;
1307
{ give an runtime error. the program is running multithreaded without
1308
any heap protection. this will result in unpredictable errors so
1309
stopping here with an error is more safe (PFV) }
1313
procedure SysHeapMutexUnLock;
1315
{ see SysHeapMutexLock for comment }
1320
{*****************************************************************************
1322
*****************************************************************************}
1324
{ This function will initialize the Heap manager and need to be called from
1325
the initialization of the system unit }
1328
FillChar(FreeLists,sizeof(TFreeLists),0);
1329
{$ifdef SYSTEMDEBUG}
1330
FillChar(FreeCount,sizeof(TFreeCount),0);
1331
{$endif SYSTEMDEBUG}
1332
before_heapend_block := nil;
1333
internal_heapsize:=GetHeapSize;
1334
internal_memavail:=internal_heapsize;
1335
HeapOrg:=GetHeapStart;
1337
HeapEnd:=HeapOrg+internal_memavail;
1338
HeapError:=@GrowHeap;
1343
Revision 1.29 2004/04/26 16:20:54 peter
1346
Revision 1.28 2004/03/15 21:48:26 peter
1348
* longint replaced with ptrint in heapmanagers
1350
Revision 1.27 2004/03/15 20:42:39 peter
1351
* exit with rte 204 instead of looping infinite when a heap record
1352
size is overwritten with 0
1354
Revision 1.26 2004/01/29 22:45:25 jonas
1355
* improved beforeheapend inheritance (remove flag again when possible,
1356
sometimes resulting in more opportunities for TryConcatFreeRecord)
1358
Revision 1.25 2003/12/15 21:39:16 daniel
1359
* Small microoptimization
1361
Revision 1.24 2003/10/02 14:03:24 marco
1364
Revision 1.23 2003/09/28 12:43:48 peter
1365
* fixed wrong check when allocation of a block > 1mb failed
1367
Revision 1.22 2003/09/27 11:52:35 peter
1368
* sbrk returns pointer
1370
Revision 1.21 2003/05/23 14:53:48 peter
1371
* check newpos < 0 instead of = -1
1373
Revision 1.20 2003/05/01 08:05:23 florian
1374
* started to make the rtl 64 bit save by introducing SizeInt and SizeUInt (similar to size_t of C)
1376
Revision 1.19 2002/11/01 17:38:04 peter
1377
* fix setmemorymutexmanager to call mutexdone on the already
1378
installed manager instead of the passed manager
1380
Revision 1.18 2002/10/30 20:39:13 peter
1381
* MemoryManager record has a field NeedLock if the wrapper functions
1382
need to provide locking for multithreaded programs
1384
Revision 1.17 2002/10/30 19:54:19 peter
1385
* remove wrong lock from SysMemSize, MemSize() does the locking
1388
Revision 1.16 2002/10/14 19:39:17 peter
1389
* threads unit added for thread support
1391
Revision 1.15 2002/09/07 15:07:45 peter
1392
* old logs removed and tabs fixed
1394
Revision 1.14 2002/06/17 08:33:04 jonas
1395
* heap manager now fragments the heap much less
1397
Revision 1.13 2002/04/21 18:56:59 peter
1398
* fpc_freemem and fpc_getmem compilerproc
1400
Revision 1.12 2002/02/10 15:33:45 carl
1401
* fixed some missing IsMultiThreaded variables
1403
Revision 1.11 2002/01/02 13:43:09 jonas
1404
* fix for web bug 1727 from Peter (corrected)