heap.inc 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team.
  5. functions for heap management in the data segment
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {****************************************************************************}
  13. { Reuse bigger blocks instead of allocating a new block at freelist/heapptr.
  14. the tried bigger blocks are always multiple sizes of the current block }
  15. {$define REUSEBIGGER}
  16. { Allocate small blocks at heapptr instead of walking the freelist }
  17. { define SMALLATHEAPPTR}
  18. { Try to find the best matching block in general freelist }
  19. { define BESTMATCH}
  20. { Concat free blocks when placing big blocks in the mainlist }
  21. {$define CONCATFREE}
  22. { DEBUG: Dump info when the heap needs to grow }
  23. { define DUMPGROW}
  24. { DEBUG: Test the FreeList on correctness }
  25. {$ifdef SYSTEMDEBUG}
  26. {$define TestFreeLists}
  27. {$endif SYSTEMDEBUG}
  28. {$ifdef MT}
  29. var
  30. cs_systemheap : TRTLCriticalSection;
  31. {$endif MT}
  32. const
  33. blocksize = 16; { at least size of freerecord }
  34. blockshr = 4; { shr value for blocksize=2^blockshr}
  35. maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
  36. maxblock = maxblocksize div blocksize;
  37. maxreusebigger = 8; { max reuse bigger tries }
  38. usedmask = 1; { flag if the block is used or not }
  39. beforeheapendmask = 2; { flag if the block is just before a heapptr }
  40. sizemask = not(blocksize-1);
  41. {****************************************************************************}
  42. {$ifdef DUMPGROW}
  43. {$define DUMPBLOCKS}
  44. {$endif}
  45. { Memory manager }
  46. const
  47. MemoryManager: TMemoryManager = (
  48. GetMem: @SysGetMem;
  49. FreeMem: @SysFreeMem;
  50. FreeMemSize: @SysFreeMemSize;
  51. AllocMem: @SysAllocMem;
  52. ReAllocMem: @SysReAllocMem;
  53. MemSize: @SysMemSize;
  54. MemAvail: @SysMemAvail;
  55. MaxAvail: @SysMaxAvail;
  56. HeapSize: @SysHeapSize;
  57. );
  58. type
  59. ppfreerecord = ^pfreerecord;
  60. pfreerecord = ^tfreerecord;
  61. tfreerecord = record
  62. size : longint;
  63. next,
  64. prev : pfreerecord;
  65. end; { 12 bytes }
  66. pheaprecord = ^theaprecord;
  67. theaprecord = record
  68. { this should overlap with tfreerecord }
  69. size : longint;
  70. end; { 4 bytes }
  71. tfreelists = array[0..maxblock] of pfreerecord;
  72. {$ifdef SYSTEMDEBUG}
  73. tfreecount = array[0..maxblock] of dword;
  74. {$endif SYSTEMDEBUG}
  75. pfreelists = ^tfreelists;
  76. var
  77. internal_memavail : longint;
  78. internal_heapsize : longint;
  79. freelists : tfreelists;
  80. {$ifdef SYSTEMDEBUG}
  81. freecount : tfreecount;
  82. {$endif SYSTEMDEBUG}
  83. {$ifdef TestFreeLists}
  84. { this can be turned on by debugger }
  85. const
  86. test_each : boolean = false;
  87. {$endif TestFreeLists}
  88. {*****************************************************************************
  89. Memory Manager
  90. *****************************************************************************}
  91. procedure GetMemoryManager(var MemMgr:TMemoryManager);
  92. begin
  93. {$ifdef MT}
  94. if IsMultiThread then
  95. begin
  96. try
  97. EnterCriticalSection(cs_systemheap);
  98. MemMgr:=MemoryManager;
  99. finally
  100. LeaveCriticalSection(cs_systemheap);
  101. end;
  102. end
  103. else
  104. {$endif MT}
  105. begin
  106. MemMgr:=MemoryManager;
  107. end;
  108. end;
  109. procedure SetMemoryManager(const MemMgr:TMemoryManager);
  110. begin
  111. {$ifdef MT}
  112. if IsMultiThread then
  113. begin
  114. try
  115. EnterCriticalSection(cs_systemheap);
  116. MemoryManager:=MemMgr;
  117. finally
  118. LeaveCriticalSection(cs_systemheap);
  119. end;
  120. end
  121. else
  122. {$endif MT}
  123. begin
  124. MemoryManager:=MemMgr;
  125. end;
  126. end;
  127. function IsMemoryManagerSet:Boolean;
  128. begin
  129. {$ifdef MT}
  130. if IsMultiThread then
  131. begin
  132. try
  133. EnterCriticalSection(cs_systemheap);
  134. IsMemoryManagerSet:=(MemoryManager.GetMem<>@SysGetMem) or
  135. (MemoryManager.FreeMem<>@SysFreeMem);
  136. finally
  137. LeaveCriticalSection(cs_systemheap);
  138. end;
  139. end
  140. else
  141. {$endif MT}
  142. begin
  143. IsMemoryManagerSet:=(MemoryManager.GetMem<>@SysGetMem) or
  144. (MemoryManager.FreeMem<>@SysFreeMem);
  145. end;
  146. end;
  147. procedure GetMem(Var p:pointer;Size:Longint);
  148. begin
  149. {$ifdef MT}
  150. if IsMultiThread then
  151. begin
  152. try
  153. EnterCriticalSection(cs_systemheap);
  154. p:=MemoryManager.GetMem(Size);
  155. finally
  156. LeaveCriticalSection(cs_systemheap);
  157. end;
  158. end
  159. else
  160. {$endif MT}
  161. begin
  162. p:=MemoryManager.GetMem(Size);
  163. end;
  164. end;
  165. procedure FreeMem(p:pointer;Size:Longint);
  166. begin
  167. {$ifdef MT}
  168. if IsMultiThread then
  169. begin
  170. try
  171. EnterCriticalSection(cs_systemheap);
  172. MemoryManager.FreeMemSize(p,Size);
  173. finally
  174. LeaveCriticalSection(cs_systemheap);
  175. end;
  176. end
  177. else
  178. {$endif MT}
  179. begin
  180. MemoryManager.FreeMemSize(p,Size);
  181. end;
  182. end;
  183. function MaxAvail:Longint;
  184. begin
  185. {$ifdef MT}
  186. if IsMultiThread then
  187. begin
  188. try
  189. EnterCriticalSection(cs_systemheap);
  190. MaxAvail:=MemoryManager.MaxAvail();
  191. finally
  192. LeaveCriticalSection(cs_systemheap);
  193. end;
  194. end
  195. else
  196. {$endif MT}
  197. begin
  198. MaxAvail:=MemoryManager.MaxAvail();
  199. end;
  200. end;
  201. function MemAvail:Longint;
  202. begin
  203. {$ifdef MT}
  204. if IsMultiThread then
  205. begin
  206. try
  207. EnterCriticalSection(cs_systemheap);
  208. MemAvail:=MemoryManager.MemAvail();
  209. finally
  210. LeaveCriticalSection(cs_systemheap);
  211. end;
  212. end
  213. else
  214. {$endif MT}
  215. begin
  216. MemAvail:=MemoryManager.MemAvail();
  217. end;
  218. end;
  219. { FPC Additions }
  220. function HeapSize:Longint;
  221. begin
  222. {$ifdef MT}
  223. if IsMultiThread then
  224. begin
  225. try
  226. EnterCriticalSection(cs_systemheap);
  227. HeapSize:=MemoryManager.HeapSize();
  228. finally
  229. LeaveCriticalSection(cs_systemheap);
  230. end;
  231. end
  232. else
  233. {$endif MT}
  234. begin
  235. HeapSize:=MemoryManager.HeapSize();
  236. end;
  237. end;
  238. function MemSize(p:pointer):Longint;
  239. begin
  240. {$ifdef MT}
  241. if IsMultiThread then
  242. begin
  243. try
  244. EnterCriticalSection(cs_systemheap);
  245. MemSize:=MemoryManager.MemSize(p);
  246. finally
  247. LeaveCriticalSection(cs_systemheap);
  248. end;
  249. end
  250. else
  251. {$endif MT}
  252. begin
  253. MemSize:=MemoryManager.MemSize(p);
  254. end;
  255. end;
  256. { Delphi style }
  257. function FreeMem(p:pointer):Longint;
  258. begin
  259. {$ifdef MT}
  260. if IsMultiThread then
  261. begin
  262. try
  263. EnterCriticalSection(cs_systemheap);
  264. Freemem:=MemoryManager.FreeMem(p);
  265. finally
  266. LeaveCriticalSection(cs_systemheap);
  267. end;
  268. end
  269. else
  270. {$endif MT}
  271. begin
  272. Freemem:=MemoryManager.FreeMem(p);
  273. end;
  274. end;
  275. function GetMem(size:longint):pointer;
  276. begin
  277. {$ifdef MT}
  278. if IsMultiThread then
  279. begin
  280. try
  281. EnterCriticalSection(cs_systemheap);
  282. GetMem:=MemoryManager.GetMem(Size);
  283. finally
  284. LeaveCriticalSection(cs_systemheap);
  285. end;
  286. end
  287. else
  288. {$endif MT}
  289. begin
  290. GetMem:=MemoryManager.GetMem(Size);
  291. end;
  292. end;
  293. function AllocMem(Size:Longint):pointer;
  294. begin
  295. {$ifdef MT}
  296. if IsMultiThread then
  297. begin
  298. try
  299. EnterCriticalSection(cs_systemheap);
  300. AllocMem:=MemoryManager.AllocMem(size);
  301. finally
  302. LeaveCriticalSection(cs_systemheap);
  303. end;
  304. end
  305. else
  306. {$endif MT}
  307. begin
  308. AllocMem:=MemoryManager.AllocMem(size);
  309. end;
  310. end;
  311. function ReAllocMem(var p:pointer;Size:Longint):pointer;
  312. begin
  313. {$ifdef MT}
  314. if IsMultiThread then
  315. begin
  316. try
  317. EnterCriticalSection(cs_systemheap);
  318. ReAllocMem:=MemoryManager.ReAllocMem(p,size);
  319. finally
  320. LeaveCriticalSection(cs_systemheap);
  321. end;
  322. end
  323. else
  324. {$endif MT}
  325. begin
  326. ReAllocMem:=MemoryManager.ReAllocMem(p,size);
  327. end;
  328. end;
  329. {$ifdef ValueGetmem}
  330. { Needed for calls from Assembler }
  331. function fpc_getmem(size:longint):pointer;compilerproc;[public,alias:'FPC_GETMEM'];
  332. begin
  333. {$ifdef MT}
  334. if IsMultiThread then
  335. begin
  336. try
  337. EnterCriticalSection(cs_systemheap);
  338. fpc_GetMem:=MemoryManager.GetMem(size);
  339. finally
  340. LeaveCriticalSection(cs_systemheap);
  341. end;
  342. end
  343. else
  344. {$endif MT}
  345. begin
  346. fpc_GetMem:=MemoryManager.GetMem(size);
  347. end;
  348. end;
  349. {$else ValueGetmem}
  350. { Needed for calls from Assembler }
  351. procedure AsmGetMem(var p:pointer;size:longint);[public,alias:'FPC_GETMEM'];
  352. begin
  353. p:=MemoryManager.GetMem(size);
  354. end;
  355. {$endif ValueGetmem}
  356. {$ifdef ValueFreemem}
  357. procedure fpc_freemem(p:pointer);compilerproc;[public,alias:'FPC_FREEMEM'];
  358. begin
  359. {$ifdef MT}
  360. if IsMultiThread then
  361. begin
  362. try
  363. EnterCriticalSection(cs_systemheap);
  364. if p <> nil then
  365. MemoryManager.FreeMem(p);
  366. finally
  367. LeaveCriticalSection(cs_systemheap);
  368. end;
  369. end
  370. else
  371. {$endif MT}
  372. begin
  373. if p <> nil then
  374. MemoryManager.FreeMem(p);
  375. end;
  376. end;
  377. {$else ValueFreemem}
  378. procedure AsmFreeMem(var p:pointer);[public,alias:'FPC_FREEMEM'];
  379. begin
  380. if p <> nil then
  381. MemoryManager.FreeMem(p);
  382. end;
  383. {$endif ValueFreemem}
  384. {*****************************************************************************
  385. Heapsize,Memavail,MaxAvail
  386. *****************************************************************************}
  387. function SysHeapsize : longint;
  388. begin
  389. Sysheapsize:=internal_heapsize;
  390. end;
  391. function SysMemavail : longint;
  392. begin
  393. Sysmemavail:=internal_memavail;
  394. end;
  395. function SysMaxavail : longint;
  396. var
  397. hp : pfreerecord;
  398. begin
  399. Sysmaxavail:=heapend-heapptr;
  400. hp:=freelists[0];
  401. while assigned(hp) do
  402. begin
  403. if hp^.size>Sysmaxavail then
  404. Sysmaxavail:=hp^.size;
  405. hp:=hp^.next;
  406. end;
  407. end;
  408. {$ifdef DUMPBLOCKS}
  409. procedure DumpBlocks;
  410. var
  411. s,i,j : longint;
  412. hp : pfreerecord;
  413. begin
  414. for i:=1 to maxblock do
  415. begin
  416. hp:=freelists[i];
  417. j:=0;
  418. while assigned(hp) do
  419. begin
  420. inc(j);
  421. hp:=hp^.next;
  422. end;
  423. writeln('Block ',i*blocksize,': ',j);
  424. end;
  425. { freelist 0 }
  426. hp:=freelists[0];
  427. j:=0;
  428. s:=0;
  429. while assigned(hp) do
  430. begin
  431. inc(j);
  432. if hp^.size>s then
  433. s:=hp^.size;
  434. hp:=hp^.next;
  435. end;
  436. writeln('Main: ',j,' maxsize: ',s);
  437. end;
  438. {$endif}
  439. {$ifdef TestFreeLists}
  440. procedure TestFreeLists;
  441. var
  442. i,j : longint;
  443. hp : pfreerecord;
  444. begin
  445. for i:=0 to maxblock do
  446. begin
  447. j:=0;
  448. hp:=freelists[i];
  449. while assigned(hp) do
  450. begin
  451. inc(j);
  452. if (i>0) and ((hp^.size and sizemask) <> i * blocksize) then
  453. RunError(204);
  454. hp:=hp^.next;
  455. end;
  456. if j<>freecount[i] then
  457. RunError(204);
  458. end;
  459. end;
  460. {$endif TestFreeLists}
  461. {$ifdef CONCATFREE}
  462. {*****************************************************************************
  463. Try concat freerecords
  464. *****************************************************************************}
  465. procedure TryConcatFreeRecord(pcurr:pfreerecord);
  466. var
  467. hp : pfreerecord;
  468. pcurrsize,s1 : longint;
  469. begin
  470. pcurrsize:=pcurr^.size and sizemask;
  471. hp:=pcurr;
  472. repeat
  473. { block used or before a heapend ? }
  474. if (hp^.size and beforeheapendmask)<>0 then
  475. begin
  476. { Peter, why can't we add this one if free ?? }
  477. { It's already added in the previous iteration, we only go to the }
  478. { next heap record after this check (JM) }
  479. pcurr^.size:=pcurrsize or beforeheapendmask;
  480. break;
  481. end;
  482. { get next block }
  483. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  484. { when we're at heapptr then we can stop and set heapptr to pcurr }
  485. if (hp=heapptr) then
  486. begin
  487. heapptr:=pcurr;
  488. { remove the block }
  489. if assigned(pcurr^.next) then
  490. pcurr^.next^.prev := pcurr^.prev;
  491. if assigned(pcurr^.prev) then
  492. pcurr^.prev^.next := pcurr^.next
  493. else
  494. freelists[0] := pcurr^.next;
  495. {$ifdef SYSTEMDEBUG}
  496. dec(freecount[0]);
  497. {$endif SYSTEMDEBUG}
  498. break;
  499. end;
  500. { block is used? then we stop and add the block to the freelist }
  501. if (hp^.size and usedmask)<>0 then
  502. begin
  503. pcurr^.size:=pcurrsize;
  504. break;
  505. end;
  506. { remove block from freelist and increase the size }
  507. s1:=hp^.size and sizemask;
  508. inc(pcurrsize,s1);
  509. s1:=s1 shr blockshr;
  510. if s1>maxblock then
  511. s1:=0;
  512. if assigned(hp^.next) then
  513. hp^.next^.prev:=hp^.prev;
  514. if assigned(hp^.prev) then
  515. hp^.prev^.next:=hp^.next
  516. else
  517. freelists[s1]:=hp^.next;
  518. {$ifdef SYSTEMDEBUG}
  519. dec(freecount[s1]);
  520. {$endif SYSTEMDEBUG}
  521. until false;
  522. end;
  523. {$endif CONCATFREE}
  524. {*****************************************************************************
  525. SysGetMem
  526. *****************************************************************************}
  527. function SysGetMem(size : longint):pointer;
  528. type
  529. heaperrorproc=function(size:longint):integer;
  530. var
  531. proc : heaperrorproc;
  532. pcurr : pfreerecord;
  533. again : boolean;
  534. s,s1,i,
  535. sizeleft : longint;
  536. {$ifdef BESTMATCH}
  537. pbest : pfreerecord;
  538. {$endif}
  539. begin
  540. { Something to allocate ? }
  541. if size<=0 then
  542. begin
  543. { give an error for < 0 }
  544. if size<0 then
  545. HandleError(204);
  546. { we always need to allocate something, using heapend is not possible,
  547. because heappend can be changed by growheap (PFV) }
  548. size:=1;
  549. end;
  550. { calc to multiply of 16 after adding the needed 8 bytes heaprecord }
  551. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  552. dec(internal_memavail,size);
  553. { try to find a block in one of the freelists per size }
  554. s:=size shr blockshr;
  555. if s<=maxblock then
  556. begin
  557. pcurr:=freelists[s];
  558. { correct size match ? }
  559. if assigned(pcurr) then
  560. begin
  561. { create the block we should return }
  562. sysgetmem:=pointer(pcurr)+sizeof(theaprecord);
  563. { fix size }
  564. pcurr^.size:=pcurr^.size or usedmask;
  565. { update freelist }
  566. freelists[s]:=pcurr^.next;
  567. {$ifdef SYSTEMDEBUG}
  568. dec(freecount[s]);
  569. {$endif SYSTEMDEBUG}
  570. if assigned(freelists[s]) then
  571. freelists[s]^.prev:=nil;
  572. {$ifdef TestFreeLists}
  573. if test_each then
  574. TestFreeLists;
  575. {$endif TestFreeLists}
  576. exit;
  577. end;
  578. {$ifdef SMALLATHEAPPTR}
  579. if heapend-heapptr>=size then
  580. begin
  581. sysgetmem:=heapptr;
  582. { set end flag if we do not have enough room to add
  583. another tfreerecord behind }
  584. if (heapptr+size+sizeof(tfreerecord)>=heapend) then
  585. pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
  586. else
  587. pheaprecord(sysgetmem)^.size:=size or usedmask;
  588. inc(sysgetmem,sizeof(theaprecord));
  589. inc(heapptr,size);
  590. {$ifdef TestFreeLists}
  591. if test_each then
  592. TestFreeLists;
  593. {$endif TestFreeLists}
  594. exit;
  595. end;
  596. {$endif}
  597. {$ifdef REUSEBIGGER}
  598. { try a bigger block }
  599. s1:=s+s;
  600. i:=0;
  601. while (s1<=maxblock) and (i<maxreusebigger) do
  602. begin
  603. pcurr:=freelists[s1];
  604. if assigned(pcurr) then
  605. begin
  606. s:=s1;
  607. break;
  608. end;
  609. inc(s1);
  610. inc(i);
  611. end;
  612. {$endif}
  613. end
  614. else
  615. pcurr:=nil;
  616. { not found, then check the main freelist for the first match }
  617. if not(assigned(pcurr)) then
  618. begin
  619. s:=0;
  620. {$ifdef BESTMATCH}
  621. pbest:=nil;
  622. {$endif}
  623. pcurr:=freelists[0];
  624. while assigned(pcurr) do
  625. begin
  626. {$ifdef BESTMATCH}
  627. if pcurr^.size=size then
  628. break
  629. else
  630. begin
  631. if (pcurr^.size>size) then
  632. begin
  633. if (not assigned(pbest)) or
  634. (pcurr^.size<pbest^.size) then
  635. pbest:=pcurr;
  636. end
  637. end;
  638. {$else BESTMATCH}
  639. {$ifdef CONCATFREE}
  640. TryConcatFreeRecord(pcurr);
  641. if (pcurr <> heapptr) then
  642. begin
  643. if pcurr^.size>=size then
  644. break;
  645. end
  646. else
  647. begin
  648. pcurr := nil;
  649. break;
  650. end;
  651. {$else CONCATFREE}
  652. if pcurr^.size>=size then
  653. break;
  654. {$endif CONCATFREE}
  655. {$endif BESTMATCH}
  656. pcurr:=pcurr^.next;
  657. end;
  658. {$ifdef BESTMATCH}
  659. if not assigned(pcurr) then
  660. pcurr:=pbest;
  661. {$endif}
  662. end;
  663. { have we found a block, then get it and free up the other left part,
  664. if no blocks are found then allocated at the heapptr or grow the heap }
  665. if assigned(pcurr) then
  666. begin
  667. { get pointer of the block we should return }
  668. sysgetmem:=pointer(pcurr);
  669. { remove the current block from the freelist }
  670. if assigned(pcurr^.next) then
  671. pcurr^.next^.prev:=pcurr^.prev;
  672. if assigned(pcurr^.prev) then
  673. pcurr^.prev^.next:=pcurr^.next
  674. else
  675. freelists[s]:=pcurr^.next;
  676. {$ifdef SYSTEMDEBUG}
  677. dec(freecount[s]);
  678. {$endif SYSTEMDEBUG}
  679. { create the left over freelist block, if at least 16 bytes are free }
  680. sizeleft:=pcurr^.size-size;
  681. if sizeleft>=sizeof(tfreerecord) then
  682. begin
  683. pcurr:=pfreerecord(pointer(pcurr)+size);
  684. { inherit the beforeheapendmask }
  685. pcurr^.size:=sizeleft or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
  686. { insert the block in the freelist }
  687. pcurr^.prev:=nil;
  688. s1:=sizeleft shr blockshr;
  689. if s1>maxblock then
  690. s1:=0;
  691. pcurr^.next:=freelists[s1];
  692. if assigned(freelists[s1]) then
  693. freelists[s1]^.prev:=pcurr;
  694. freelists[s1]:=pcurr;
  695. {$ifdef SYSTEMDEBUG}
  696. inc(freecount[s1]);
  697. {$endif SYSTEMDEBUG}
  698. { create the block we need to return }
  699. pheaprecord(sysgetmem)^.size:=size or usedmask;
  700. end
  701. else
  702. begin
  703. { create the block we need to return }
  704. pheaprecord(sysgetmem)^.size:=size or usedmask or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
  705. end;
  706. inc(sysgetmem,sizeof(theaprecord));
  707. {$ifdef TestFreeLists}
  708. if test_each then
  709. TestFreeLists;
  710. {$endif TestFreeLists}
  711. exit;
  712. end;
  713. { Lastly, the top of the heap is checked, to see if there is }
  714. { still memory available. }
  715. repeat
  716. again:=false;
  717. if heapend-heapptr>=size then
  718. begin
  719. sysgetmem:=heapptr;
  720. if (heapptr+size+sizeof(tfreerecord)>=heapend) then
  721. pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
  722. else
  723. pheaprecord(sysgetmem)^.size:=size or usedmask;
  724. inc(sysgetmem,sizeof(theaprecord));
  725. inc(heapptr,size);
  726. {$ifdef TestFreeLists}
  727. if test_each then
  728. TestFreeLists;
  729. {$endif TestFreeLists}
  730. exit;
  731. end;
  732. { Call the heaperror proc }
  733. if assigned(heaperror) then
  734. begin
  735. proc:=heaperrorproc(heaperror);
  736. case proc(size) of
  737. 0 : HandleError(203);
  738. 1 : sysgetmem:=nil;
  739. 2 : again:=true;
  740. end;
  741. end
  742. else
  743. HandleError(203);
  744. until not again;
  745. {$ifdef TestFreeLists}
  746. if test_each then
  747. TestFreeLists;
  748. {$endif TestFreeLists}
  749. end;
  750. {*****************************************************************************
  751. SysFreeMem
  752. *****************************************************************************}
  753. Function SysFreeMem(p : pointer):Longint;
  754. var
  755. pcurrsize,s : longint;
  756. pcurr : pfreerecord;
  757. begin
  758. if p=nil then
  759. HandleError(204);
  760. { fix p to point to the heaprecord }
  761. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  762. pcurrsize:=pcurr^.size and sizemask;
  763. inc(internal_memavail,pcurrsize);
  764. { insert the block in it's freelist }
  765. pcurr^.size:=pcurr^.size and (not usedmask);
  766. pcurr^.prev:=nil;
  767. s:=pcurrsize shr blockshr;
  768. if s>maxblock then
  769. s:=0;
  770. pcurr^.next:=freelists[s];
  771. if assigned(pcurr^.next) then
  772. pcurr^.next^.prev:=pcurr;
  773. freelists[s]:=pcurr;
  774. {$ifdef SYSTEMDEBUG}
  775. inc(freecount[s]);
  776. {$endif SYSTEMDEBUG}
  777. SysFreeMem:=pcurrsize;
  778. {$ifdef TestFreeLists}
  779. if test_each then
  780. TestFreeLists;
  781. {$endif TestFreeLists}
  782. end;
  783. {*****************************************************************************
  784. SysFreeMemSize
  785. *****************************************************************************}
  786. Function SysFreeMemSize(p : pointer;size : longint):longint;
  787. var
  788. pcurrsize,s : longint;
  789. pcurr : pfreerecord;
  790. begin
  791. SysFreeMemSize:=0;
  792. if size<=0 then
  793. begin
  794. if size<0 then
  795. HandleError(204);
  796. exit;
  797. end;
  798. if p=nil then
  799. HandleError(204);
  800. { fix p to point to the heaprecord }
  801. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  802. pcurrsize:=pcurr^.size and sizemask;
  803. inc(internal_memavail,pcurrsize);
  804. { size check }
  805. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  806. if size<>pcurrsize then
  807. HandleError(204);
  808. { insert the block in it's freelist }
  809. pcurr^.size:=pcurr^.size and (not usedmask);
  810. pcurr^.prev:=nil;
  811. { set the return values }
  812. s:=pcurrsize shr blockshr;
  813. if s>maxblock then
  814. s:=0;
  815. pcurr^.next:=freelists[s];
  816. if assigned(pcurr^.next) then
  817. pcurr^.next^.prev:=pcurr;
  818. freelists[s]:=pcurr;
  819. {$ifdef SYSTEMDEBUG}
  820. inc(freecount[s]);
  821. {$endif SYSTEMDEBUG}
  822. SysFreeMemSize:=pcurrsize;
  823. {$ifdef TestFreeLists}
  824. if test_each then
  825. TestFreeLists;
  826. {$endif TestFreeLists}
  827. end;
  828. {*****************************************************************************
  829. SysMemSize
  830. *****************************************************************************}
  831. function SysMemSize(p:pointer):longint;
  832. begin
  833. {$ifdef MT}
  834. try
  835. EnterCriticalSection(cs_systemheap);
  836. {$endif MT}
  837. SysMemSize:=(pheaprecord(pointer(p)-sizeof(theaprecord))^.size and sizemask)-sizeof(theaprecord);
  838. {$ifdef MT}
  839. finally
  840. LeaveCriticalSection(cs_systemheap);
  841. end;
  842. {$endif MT}
  843. end;
  844. {*****************************************************************************
  845. SysAllocMem
  846. *****************************************************************************}
  847. function SysAllocMem(size : longint):pointer;
  848. begin
  849. sysallocmem:=MemoryManager.GetMem(size);
  850. if sysallocmem<>nil then
  851. FillChar(sysallocmem^,size,0);
  852. end;
  853. {*****************************************************************************
  854. SysResizeMem
  855. *****************************************************************************}
  856. function SysTryResizeMem(var p:pointer;size : longint):boolean;
  857. var
  858. oldsize,
  859. currsize,
  860. foundsize,
  861. sizeleft,
  862. s : longint;
  863. wasbeforeheapend : boolean;
  864. hp,
  865. pnew,
  866. pcurr : pfreerecord;
  867. begin
  868. { fix needed size }
  869. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  870. { fix p to point to the heaprecord }
  871. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  872. currsize:=pcurr^.size and sizemask;
  873. oldsize:=currsize;
  874. wasbeforeheapend:=(pcurr^.size and beforeheapendmask)<>0;
  875. { is the allocated block still correct? }
  876. if currsize=size then
  877. begin
  878. SysTryResizeMem:=true;
  879. {$ifdef TestFreeLists}
  880. if test_each then
  881. TestFreeLists;
  882. {$endif TestFreeLists}
  883. exit;
  884. end;
  885. { do we need to allocate more memory ? }
  886. if size>currsize then
  887. begin
  888. { the size is bigger than the previous size, we need to allocated more mem.
  889. We first check if the blocks after the current block are free. If not we
  890. simply call getmem/freemem to get the new block }
  891. foundsize:=0;
  892. hp:=pcurr;
  893. repeat
  894. inc(foundsize,hp^.size and sizemask);
  895. { block used or before a heapptr ? }
  896. if (hp^.size and beforeheapendmask)<>0 then
  897. begin
  898. wasbeforeheapend:=true;
  899. break;
  900. end;
  901. { get next block }
  902. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  903. { when we're at heapptr then we can stop }
  904. if (hp=heapptr) then
  905. begin
  906. inc(foundsize,heapend-heapptr);
  907. break;
  908. end;
  909. if (hp^.size and usedmask)<>0 then
  910. break;
  911. until (foundsize>=size);
  912. { found enough free blocks? }
  913. if foundsize>=size then
  914. begin
  915. { we walk the list again and remove all blocks }
  916. foundsize:=pcurr^.size and sizemask;
  917. hp:=pcurr;
  918. repeat
  919. { get next block }
  920. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  921. { when we're at heapptr then we can increase it, if there is enough
  922. room is already checked }
  923. if (hp=heapptr) then
  924. begin
  925. inc(heapptr,size-foundsize);
  926. foundsize:=size;
  927. if (heapend-heapptr)<sizeof(tfreerecord) then
  928. wasbeforeheapend:=true;
  929. break;
  930. end;
  931. s:=hp^.size and sizemask;
  932. inc(foundsize,s);
  933. { remove block from freelist }
  934. s:=s shr blockshr;
  935. if s>maxblock then
  936. s:=0;
  937. if assigned(hp^.next) then
  938. hp^.next^.prev:=hp^.prev;
  939. if assigned(hp^.prev) then
  940. hp^.prev^.next:=hp^.next
  941. else
  942. freelists[s]:=hp^.next;
  943. {$ifdef SYSTEMDEBUG}
  944. dec(freecount[s]);
  945. {$endif SYSTEMDEBUG}
  946. until (foundsize>=size);
  947. if wasbeforeheapend then
  948. pcurr^.size:=foundsize or usedmask or beforeheapendmask
  949. else
  950. pcurr^.size:=foundsize or usedmask;
  951. end
  952. else
  953. begin
  954. { we need to call getmem/move/freemem }
  955. SysTryResizeMem:=false;
  956. {$ifdef TestFreeLists}
  957. if test_each then
  958. TestFreeLists;
  959. {$endif TestFreeLists}
  960. exit;
  961. end;
  962. currsize:=pcurr^.size and sizemask;
  963. end;
  964. { is the size smaller then we can adjust the block to that size and insert
  965. the other part into the freelist }
  966. if size<currsize then
  967. begin
  968. { create the left over freelist block, if at least 16 bytes are free }
  969. sizeleft:=currsize-size;
  970. if sizeleft>sizeof(tfreerecord) then
  971. begin
  972. pnew:=pfreerecord(pointer(pcurr)+size);
  973. pnew^.size:=sizeleft or (pcurr^.size and beforeheapendmask);
  974. { insert the block in the freelist }
  975. pnew^.prev:=nil;
  976. s:=sizeleft shr blockshr;
  977. if s>maxblock then
  978. s:=0;
  979. pnew^.next:=freelists[s];
  980. if assigned(freelists[s]) then
  981. freelists[s]^.prev:=pnew;
  982. freelists[s]:=pnew;
  983. {$ifdef SYSTEMDEBUG}
  984. inc(freecount[s]);
  985. {$endif SYSTEMDEBUG}
  986. { fix the size of the current block and leave }
  987. pcurr^.size:=size or usedmask;
  988. end
  989. else
  990. begin
  991. { fix the size of the current block and leave }
  992. pcurr^.size:=size or usedmask or (pcurr^.size and beforeheapendmask);
  993. end;
  994. end;
  995. dec(internal_memavail,size-oldsize);
  996. SysTryResizeMem:=true;
  997. {$ifdef TestFreeLists}
  998. if test_each then
  999. TestFreeLists;
  1000. {$endif TestFreeLists}
  1001. end;
  1002. {*****************************************************************************
  1003. SysResizeMem
  1004. *****************************************************************************}
  1005. function SysReAllocMem(var p:pointer;size : longint):pointer;
  1006. var
  1007. oldsize : longint;
  1008. p2 : pointer;
  1009. begin
  1010. { Free block? }
  1011. if size=0 then
  1012. begin
  1013. if p<>nil then
  1014. begin
  1015. MemoryManager.FreeMem(p);
  1016. p:=nil;
  1017. end;
  1018. end
  1019. else
  1020. { Allocate a new block? }
  1021. if p=nil then
  1022. begin
  1023. p:=MemoryManager.GetMem(size);
  1024. end
  1025. else
  1026. { Resize block }
  1027. if not SysTryResizeMem(p,size) then
  1028. begin
  1029. oldsize:=MemoryManager.MemSize(p);
  1030. p2:=MemoryManager.GetMem(size);
  1031. if p2<>nil then
  1032. Move(p^,p2^,oldsize);
  1033. MemoryManager.FreeMem(p);
  1034. p:=p2;
  1035. end;
  1036. SysReAllocMem:=p;
  1037. end;
  1038. {*****************************************************************************
  1039. Mark/Release
  1040. *****************************************************************************}
  1041. procedure release(var p : pointer);
  1042. begin
  1043. end;
  1044. procedure mark(var p : pointer);
  1045. begin
  1046. end;
  1047. {*****************************************************************************
  1048. Grow Heap
  1049. *****************************************************************************}
  1050. function growheap(size :longint) : integer;
  1051. var
  1052. sizeleft,s1,
  1053. NewPos : longint;
  1054. pcurr : pfreerecord;
  1055. begin
  1056. {$ifdef DUMPGROW}
  1057. writeln('growheap(',size,') allocating ',(size+$ffff) and $ffff0000);
  1058. DumpBlocks;
  1059. {$endif}
  1060. { Allocate by 64K size }
  1061. size:=(size+$ffff) and $ffff0000;
  1062. { first try 256K (default) }
  1063. if size<=GrowHeapSize1 then
  1064. begin
  1065. NewPos:=Sbrk(GrowHeapSize1);
  1066. if NewPos<>-1 then
  1067. size:=GrowHeapSize1;
  1068. end
  1069. else
  1070. { second try 1024K (default) }
  1071. if size<=GrowHeapSize2 then
  1072. begin
  1073. NewPos:=Sbrk(GrowHeapSize2);
  1074. if NewPos<>-1 then
  1075. size:=GrowHeapSize2;
  1076. end
  1077. { else alloate the needed bytes }
  1078. else
  1079. NewPos:=SBrk(size);
  1080. { try again }
  1081. if NewPos=-1 then
  1082. begin
  1083. NewPos:=Sbrk(size);
  1084. if NewPos=-1 then
  1085. begin
  1086. if ReturnNilIfGrowHeapFails then
  1087. GrowHeap:=1
  1088. else
  1089. GrowHeap:=0;
  1090. Exit;
  1091. end;
  1092. end;
  1093. { increase heapend or add to freelist }
  1094. if heapend=pointer(newpos) then
  1095. begin
  1096. heapend:=pointer(newpos+size);
  1097. end
  1098. else
  1099. begin
  1100. { create freelist entry for old heapptr-heapend }
  1101. sizeleft:=heapend-heapptr;
  1102. if sizeleft>=sizeof(tfreerecord) then
  1103. begin
  1104. pcurr:=pfreerecord(heapptr);
  1105. pcurr^.size:=sizeleft or beforeheapendmask;
  1106. { insert the block in the freelist }
  1107. s1:=sizeleft shr blockshr;
  1108. if s1>maxblock then
  1109. s1:=0;
  1110. pcurr^.next:=freelists[s1];
  1111. pcurr^.prev:=nil;
  1112. if assigned(freelists[s1]) then
  1113. freelists[s1]^.prev:=pcurr;
  1114. freelists[s1]:=pcurr;
  1115. {$ifdef SYSTEMDEBUG}
  1116. inc(freecount[s1]);
  1117. {$endif SYSTEMDEBUG}
  1118. end;
  1119. { now set the new heapptr,heapend to the new block }
  1120. heapptr:=pointer(newpos);
  1121. heapend:=pointer(newpos+size);
  1122. end;
  1123. { set the total new heap size }
  1124. inc(internal_memavail,size);
  1125. inc(internal_heapsize,size);
  1126. { try again }
  1127. GrowHeap:=2;
  1128. {$ifdef TestFreeLists}
  1129. TestFreeLists;
  1130. {$endif TestFreeLists}
  1131. end;
  1132. {*****************************************************************************
  1133. InitHeap
  1134. *****************************************************************************}
  1135. { This function will initialize the Heap manager and need to be called from
  1136. the initialization of the system unit }
  1137. procedure InitHeap;
  1138. begin
  1139. FillChar(FreeLists,sizeof(TFreeLists),0);
  1140. {$ifdef SYSTEMDEBUG}
  1141. FillChar(FreeCount,sizeof(TFreeCount),0);
  1142. {$endif SYSTEMDEBUG}
  1143. internal_heapsize:=GetHeapSize;
  1144. internal_memavail:=internal_heapsize;
  1145. HeapOrg:=GetHeapStart;
  1146. HeapPtr:=HeapOrg;
  1147. HeapEnd:=HeapOrg+internal_memavail;
  1148. HeapError:=@GrowHeap;
  1149. {$ifdef MT}
  1150. InitCriticalSection(cs_systemheap);
  1151. {$endif MT}
  1152. end;
  1153. {
  1154. $Log$
  1155. Revision 1.15 2002-09-07 15:07:45 peter
  1156. * old logs removed and tabs fixed
  1157. Revision 1.14 2002/06/17 08:33:04 jonas
  1158. * heap manager now fragments the heap much less
  1159. Revision 1.13 2002/04/21 18:56:59 peter
  1160. * fpc_freemem and fpc_getmem compilerproc
  1161. Revision 1.12 2002/02/10 15:33:45 carl
  1162. * fixed some missing IsMultiThreaded variables
  1163. Revision 1.11 2002/01/02 13:43:09 jonas
  1164. * fix for web bug 1727 from Peter (corrected)
  1165. }